SVGClipPathElement.m 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. #import "SVGClipPathElement.h"
  2. #import "CALayerWithChildHitTest.h"
  3. #import "SVGHelperUtilities.h"
  4. @implementation SVGClipPathElement
  5. @synthesize clipPathUnits;
  6. @synthesize transform; // each SVGElement subclass that conforms to protocol "SVGTransformable" has to re-synthesize this to work around bugs in Apple's Objective-C 2.0 design that don't allow @properties to be extended by categories / protocols
  7. - (void)postProcessAttributesAddingErrorsTo:(SVGKParseResult *)parseResult {
  8. [super postProcessAttributesAddingErrorsTo:parseResult];
  9. NSError *error = [NSError errorWithDomain:@"SVGKit" code:1 userInfo:[NSDictionary dictionaryWithObjectsAndKeys:
  10. @"<clipPath> found in SVG. May render incorrectly with SVGKFastImageView due to Apple bug in CALayer .mask rendering.", NSLocalizedDescriptionKey,
  11. nil]];
  12. [parseResult addParseErrorRecoverable:error];
  13. clipPathUnits = SVG_UNIT_TYPE_USERSPACEONUSE;
  14. NSString *units = [self getAttribute:@"clipPathUnits"];
  15. if( units != nil && units.length > 0 ) {
  16. if( [units isEqualToString:@"userSpaceOnUse"] )
  17. clipPathUnits = SVG_UNIT_TYPE_USERSPACEONUSE;
  18. else if( [units isEqualToString:@"objectBoundingBox"] )
  19. clipPathUnits = SVG_UNIT_TYPE_OBJECTBOUNDINGBOX;
  20. else {
  21. SVGKitLogWarn(@"Unknown clipPathUnits value %@", units);
  22. NSError *error = [NSError errorWithDomain:@"SVGKit" code:1 userInfo:[NSDictionary dictionaryWithObjectsAndKeys:
  23. [NSString stringWithFormat:@"Unknown clipPathUnits value %@", units], NSLocalizedDescriptionKey,
  24. nil]];
  25. [parseResult addParseErrorRecoverable:error];
  26. }
  27. }
  28. }
  29. - (CALayer *) newLayer
  30. {
  31. CALayer* _layer = [CALayerWithChildHitTest layer];
  32. [SVGHelperUtilities configureCALayer:_layer usingElement:self];
  33. return _layer;
  34. }
  35. - (void)layoutLayer:(CALayer *)layer toMaskLayer:(CALayer *)maskThis
  36. {
  37. // null rect union any other rect will return the other rect
  38. CGRect mainRect = CGRectNull;
  39. /** make mainrect the UNION of all sublayer's frames (i.e. their individual "bounds" inside THIS layer's space) */
  40. for ( CALayer *currentLayer in [layer sublayers] )
  41. {
  42. mainRect = CGRectUnion(mainRect, currentLayer.frame);
  43. }
  44. /** Changing THIS layer's frame now means all DIRECT sublayers are offset by too much (because when we change the offset
  45. of the parent frame (this.frame), Apple *does not* shift the sublayers around to keep them in same place.
  46. NB: there are bugs in some Apple code in Interface Builder where it attempts to do exactly that (incorrectly, as the API
  47. is specifically designed NOT to do this), and ... Fails. But in code, thankfully, Apple *almost* never does this (there are a few method
  48. calls where it appears someone at Apple forgot how their API works, and tried to do the offsetting automatically. "Paved
  49. with good intentions...".
  50. */
  51. if (CGRectIsNull(mainRect))
  52. {
  53. // TODO what to do when mainRect is null rect? i.e. no sublayer or all sublayers have null rect frame
  54. } else {
  55. for (CALayer *currentLayer in [layer sublayers])
  56. currentLayer.frame = CGRectOffset(currentLayer.frame, -mainRect.origin.x, -mainRect.origin.y);
  57. }
  58. // unless we're working in bounding box coords, subtract the owning layer's origin
  59. if( self.clipPathUnits == SVG_UNIT_TYPE_USERSPACEONUSE )
  60. mainRect = CGRectOffset(mainRect, -maskThis.frame.origin.x, -maskThis.frame.origin.y);
  61. layer.frame = mainRect;
  62. }
  63. @end