CALayerWithClipRender.m 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. //
  2. // CALayerWithClipRender.m
  3. // SVGKit-iOS
  4. //
  5. // Created by David Gileadi on 8/14/14.
  6. // Copyright (c) 2014 na. All rights reserved.
  7. //
  8. #import "CALayerWithClipRender.h"
  9. @implementation CALayerWithClipRender
  10. - (void)renderInContext:(CGContextRef)ctx {
  11. CALayer *mask = nil;
  12. if( self.mask != nil ) {
  13. [CALayerWithClipRender maskLayer:self inContext:ctx];
  14. mask = self.mask;
  15. self.mask = nil;
  16. }
  17. [super renderInContext:ctx];
  18. if( mask != nil ) {
  19. self.mask = mask;
  20. }
  21. }
  22. + (void)maskLayer:(CALayer *)layer inContext:(CGContextRef)ctx {
  23. // if all that's masking is a single path, just clip to it
  24. if( layer.mask.sublayers.count == 1 && [[layer.mask.sublayers objectAtIndex:0] isKindOfClass:[CAShapeLayer class]] ) {
  25. CGPathRef maskPath = ((CAShapeLayer *) [layer.mask.sublayers objectAtIndex:0]).path;
  26. // we have to undo the offset from SVGClipPathLayer.layoutLayer
  27. CGAffineTransform offset = CGAffineTransformMakeTranslation(layer.mask.frame.origin.x, layer.mask.frame.origin.y);
  28. CGPathRef translatedPath = CGPathCreateCopyByTransformingPath(maskPath, &offset);
  29. CGContextAddPath(ctx, translatedPath);
  30. CGPathRelease(translatedPath);
  31. CGContextClip(ctx);
  32. } else {
  33. // otherwise, create an offscreen bitmap at screen resolution,
  34. CGFloat scale = MAX(layer.contentsScale, layer.mask.contentsScale);
  35. #if SVGKIT_MAC
  36. scale = MAX(scale, [[NSScreen mainScreen] backingScaleFactor]);
  37. #else
  38. scale = MAX(scale, [[UIScreen mainScreen] scale]);
  39. #endif
  40. CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
  41. CGContextRef offscreenContext = CGBitmapContextCreate(NULL,
  42. layer.bounds.size.width * scale,
  43. layer.bounds.size.height * scale,
  44. 8, 0,
  45. colorSpace,
  46. (CGBitmapInfo)kCGImageAlphaOnly);
  47. CGContextScaleCTM(offscreenContext, scale, scale);
  48. // render the mask to it, undoing the offset from SVGClipPathLayer.layoutLayer
  49. CGPoint offset = layer.mask.frame.origin;
  50. for (CALayer *child in layer.mask.sublayers)
  51. child.frame = CGRectOffset(child.frame, offset.x, offset.y);
  52. [layer.mask renderInContext:offscreenContext];
  53. for (CALayer *child in layer.mask.sublayers)
  54. child.frame = CGRectOffset(child.frame, -offset.x, -offset.y);
  55. // get an image from it,
  56. CGImageRef maskImage = CGBitmapContextCreateImage(offscreenContext);
  57. CGContextRelease(offscreenContext);
  58. CGColorSpaceRelease(colorSpace);
  59. // and mask with that
  60. CGContextClipToMask(ctx, layer.bounds, maskImage);
  61. CFRelease(maskImage);
  62. }
  63. }
  64. @end