API  0.9.8
 All Classes Files Functions Variables Typedefs Macros Groups Pages
CALayer.j
Go to the documentation of this file.
1 /*
2  * CALayer.j
3  * AppKit
4  *
5  * Created by Francisco Tolmasky.
6  * Copyright 2008, 280 North, Inc.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
23 
24 
25 
26 
27 #define DOM(aLayer) aLayer._DOMElement
28 
34 
35 var USE_BUFFER = NO;
36 
43 
45 
46 
47  A CALayer is similar to a CPView, but with the ability
48  to have a transform applied to it.
49 
50  @delegate -(void)drawLayer:(CALayer)layer inContext:(CGContextRef)ctx;
51  If the delegate implements this method, the CALayer will
52  call this in place of its \c -drawInContext:.
53  @param layer the layer to draw for
54  @param ctx the context to draw on
55 
56  @delegate -(void)displayLayer:(CALayer)layer;
57  The delegate can override the layer's \c -display method
58  by implementing this method.
59 */
60 @implementation CALayer : CPObject
61 {
62  // Modifying the Layer Geometry
63 
64  CGRect _frame;
65  CGRect _bounds;
66  CGPoint _position;
67  unsigned _zPosition;
68  CGPoint _anchorPoint;
69 
70  CGAffineTransform _affineTransform;
71  CGAffineTransform _sublayerTransform;
72  CGAffineTransform _sublayerTransformForSublayers;
73 
74  CGRect _backingStoreFrame;
75  CGRect _standardBackingStoreFrame;
76 
77  BOOL _hasSublayerTransform;
78  BOOL _hasCustomBackingStoreFrame;
79 
80  // Style Attributes
81 
82  float _opacity;
83  BOOL _isHidden;
84  BOOL _masksToBounds;
85  CPColor _backgroundColor;
86 
87  // Managing Layer Hierarchy
88 
89  CALayer _superlayer;
90  CPMutableArray _sublayers;
91 
92  // Updating Layer Display
93 
94  unsigned _runLoopUpdateMask;
95  BOOL _needsDisplayOnBoundsChange;
96 
97  // Modifying the Delegate
98 
99  id _delegate;
100 
101  BOOL _delegateRespondsToDisplayLayerSelector;
102  BOOL _delegateRespondsToDrawLayerInContextSelector;
103 
104  // DOM Implementation
105 
106  DOMElement _DOMElement;
107  DOMElement _DOMContentsElement;
108  id _contents;
109  CGContext _context;
110  CPView _owningView;
111 
112  CGAffineTransform _transformToLayer;
113  CGAffineTransform _transformFromLayer;
114 }
115 
120 {
121  return [[[self class] alloc] init];
122 }
123 
127 - (id)init
128 {
129  self = [super init];
130 
131  if (self)
132  {
133  _frame = CGRectMakeZero();
134 
135  _backingStoreFrame = CGRectMakeZero();
136  _standardBackingStoreFrame = CGRectMakeZero();
137 
138  _bounds = CGRectMakeZero();
139  _position = CGPointMakeZero();
140  _zPosition = 0.0;
141  _anchorPoint = CGPointMake(0.5, 0.5);
142  _affineTransform = CGAffineTransformMakeIdentity();
143  _sublayerTransform = CGAffineTransformMakeIdentity();
144 
145  _transformToLayer = CGAffineTransformMakeIdentity(); // FIXME? does it matter?
146  _transformFromLayer = CGAffineTransformMakeIdentity();
147 
148  _opacity = 1.0;
149  _isHidden = NO;
150  _masksToBounds = NO;
151 
152  _sublayers = [];
153 
154 #if PLATFORM(DOM)
155  _DOMElement = document.createElement("div");
156 
157  _DOMElement.style.overflow = "visible";
158  _DOMElement.style.position = "absolute";
159  _DOMElement.style.visibility = "visible";
160  _DOMElement.style.top = "0px";
161  _DOMElement.style.left = "0px";
162  _DOMElement.style.zIndex = 0;
163  _DOMElement.style.width = "0px";
164  _DOMElement.style.height = "0px";
165 #endif
166  }
167 
168  return self;
169 }
170 
171 // Modifying the Layer Geometry
176 - (void)setBounds:(CGRect)aBounds
177 {
178  if (CGRectEqualToRect(_bounds, aBounds))
179  return;
180 
181  var oldOrigin = _bounds.origin;
182 
183  _bounds = CGRectMakeCopy(aBounds);
184 
185  if (_hasSublayerTransform)
186  _CALayerUpdateSublayerTransformForSublayers(self);
187 
188  // _hasSublayerTransform == true will handle this for us.
189  /*else if (!CGPointEqualToPoint(_bounds.origin, oldOrigin))
190  {
191  var index = _sublayers.length;
192 
193  // FIXME: This should climb the layer tree down.
194  while (index--)
195  _CALayerRecalculateGeometry(_sublayers[index], CALayerGeometryPositionMask);
196  }*/
197 
198  _CALayerRecalculateGeometry(self, CALayerGeometryBoundsMask);
199 }
200 
204 - (CGRect)bounds
205 {
206  return _bounds;
207 }
208 
213 - (void)setPosition:(CGPoint)aPosition
214 {
215  if (CGPointEqualToPoint(_position, aPosition))
216  return;
217 
218  _position = CGPointMakeCopy(aPosition);
219 
220  _CALayerRecalculateGeometry(self, CALayerGeometryPositionMask);
221 }
222 
226 - (CGPoint)position
227 {
228  return _position;
229 }
230 
235 - (void)setZPosition:(int)aZPosition
236 {
237  if (_zPosition == aZPosition)
238  return;
239 
240  _zPosition = aZPosition;
241 
242  [self registerRunLoopUpdateWithMask:CALayerZPositionUpdateMask];
243 }
244 
249 - (void)setAnchorPoint:(CGPoint)anAnchorPoint
250 {
251  anAnchorPoint = CGPointMakeCopy(anAnchorPoint);
252  anAnchorPoint.x = MIN(1.0, MAX(0.0, anAnchorPoint.x));
253  anAnchorPoint.y = MIN(1.0, MAX(0.0, anAnchorPoint.y));
254 
255  if (CGPointEqualToPoint(_anchorPoint, anAnchorPoint))
256  return;
257 
258  _anchorPoint = anAnchorPoint;
259 
260  if (_hasSublayerTransform)
261  _CALayerUpdateSublayerTransformForSublayers(self);
262 
263  if (_owningView)
264  _position = CGPointMake(CGRectGetWidth(_bounds) * _anchorPoint.x, CGRectGetHeight(_bounds) * _anchorPoint.y);
265 
266  _CALayerRecalculateGeometry(self, CALayerGeometryAnchorPointMask);
267 }
268 
272 - (CGPoint)anchorPoint
273 {
274  return _anchorPoint;
275 }
276 
281 - (void)setAffineTransform:(CGAffineTransform)anAffineTransform
282 {
283  if (CGAffineTransformEqualToTransform(_affineTransform, anAffineTransform))
284  return;
285 
286  _affineTransform = CGAffineTransformMakeCopy(anAffineTransform);
287 
288  _CALayerRecalculateGeometry(self, CALayerGeometryAffineTransformMask);
289 }
290 
294 - (CGAffineTransform)affineTransform
295 {
296  return _affineTransform;
297 }
298 
303 - (void)setSublayerTransform:(CGAffineTransform)anAffineTransform
304 {
305  if (CGAffineTransformEqualToTransform(_sublayerTransform, anAffineTransform))
306  return;
307 
308  var hadSublayerTransform = _hasSublayerTransform;
309 
310  _sublayerTransform = CGAffineTransformMakeCopy(anAffineTransform);
311  _hasSublayerTransform = !CGAffineTransformIsIdentity(_sublayerTransform);
312 
313  if (_hasSublayerTransform)
314  {
315  _CALayerUpdateSublayerTransformForSublayers(self);
316 
317  var index = _sublayers.length;
318 
319  // FIXME: This should climb the layer tree down.
320  while (index--)
321  _CALayerRecalculateGeometry(_sublayers[index], CALayerGeometryParentSublayerTransformMask);
322  }
323 }
324 
328 - (CGAffineTransform)sublayerTransform
329 {
330  return _sublayerTransform;
331 }
332 
333 /*
334  Private
335  @ignore
336 */
337 - (CGAffineTransform)transformToLayer
338 {
339  return _transformToLayer;
340 }
341 
347 - (void)setFrame:(CGRect)aFrame
348 {
349  // FIXME: implement this
350 }
351 
359 - (CGRect)frame
360 {
361  if (!_frame)
362  _frame = [self convertRect:_bounds toLayer:_superlayer];
363 
364  return _frame;
365 }
366 
376 {
377  return _backingStoreFrame;
378 }
379 
384 - (void)setBackingStoreFrame:(CGRect)aFrame
385 {
386  _hasCustomBackingStoreFrame = (aFrame != nil);
387 
388  if (aFrame == nil)
389  aFrame = CGRectMakeCopy(_standardBackingStoreFrame);
390  else
391  {
392  if (_superlayer)
393  {
394  aFrame = [_superlayer convertRect:aFrame toLayer:nil];
395 
396  var bounds = [_superlayer bounds],
397  frame = [_superlayer convertRect:bounds toLayer:nil];
398 
399  aFrame.origin.x -= CGRectGetMinX(frame);
400  aFrame.origin.y -= CGRectGetMinY(frame);
401  }
402  else
403  aFrame = CGRectMakeCopy(aFrame);
404  }
405 
406  if (!CGPointEqualToPoint(_backingStoreFrame.origin, aFrame.origin))
407  [self registerRunLoopUpdateWithMask:CALayerFrameOriginUpdateMask];
408 
409  if (!CGSizeEqualToSize(_backingStoreFrame.size, aFrame.size))
410  [self registerRunLoopUpdateWithMask:CALayerFrameSizeUpdateMask];
411 
412  _backingStoreFrame = aFrame;
413 }
414 
415 // Providing Layer Content
420 - (CGImage)contents
421 {
422  return _contents;
423 }
424 
429 - (void)setContents:(CGImage)contents
430 {
431  if (_contents == contents)
432  return;
433 
434  _contents = contents;
435 
436  [self composite];
437 }
438 
439 /*
440  Composites this layer onto the super layer, and draws its contents as well.
441  @ignore
442 */
443 - (void)composite
444 {
445  if (USE_BUFFER && !_contents || !_context)
446  return;
447 
448  CGContextClearRect(_context, CGRectMake(0.0, 0.0, CGRectGetWidth(_backingStoreFrame), CGRectGetHeight(_backingStoreFrame)));
449 
450  // Recomposite
451  var transform;
452 
453  if (_superlayer)
454  {
455  var superlayerTransform = _CALayerGetTransform(_superlayer, nil),
456  superlayerOrigin = CGPointApplyAffineTransform(_superlayer._bounds.origin, superlayerTransform);
457 
458  transform = CGAffineTransformConcat(_transformFromLayer, superlayerTransform);
459 
460  transform.tx -= superlayerOrigin.x;
461  transform.ty -= superlayerOrigin.y;
462  }
463 
464  else
465  // Copy so we don't affect the original.
466  transform = CGAffineTransformCreateCopy(_transformFromLayer);
467 
468  transform.tx -= CGRectGetMinX(_backingStoreFrame);
469  transform.ty -= CGRectGetMinY(_backingStoreFrame);
470 
471  CGContextSaveGState(_context);
472 
473  CGContextConcatCTM(_context, transform);//_transformFromView);
474 
475  if (USE_BUFFER)
476  {
477 // CGContextDrawImage(_context, _bounds, _contents.context);
478  _context.drawImage(_contents.buffer, CGRectGetMinX(_bounds), CGRectGetMinY(_bounds));//, CGRectGetWidth(_standardBackingStoreFrame), CGRectGetHeight(_standardBackingStoreFrame));
479  }
480  else
481  [self drawInContext:_context];
482 
483  CGContextRestoreGState(_context);
484 }
485 
489 - (void)display
490 {
491  if (!_context)
492  {
493  _context = CGBitmapGraphicsContextCreate();
494 
495 #if PLATFORM(DOM)
496  _DOMContentsElement = _context.DOMElement;
497 
498  _DOMContentsElement.style.zIndex = -100;
499 
500  _DOMContentsElement.style.overflow = "hidden";
501  _DOMContentsElement.style.position = "absolute";
502  _DOMContentsElement.style.visibility = "visible";
503 
504  _DOMContentsElement.width = ROUND(CGRectGetWidth(_backingStoreFrame));
505  _DOMContentsElement.height = ROUND(CGRectGetHeight(_backingStoreFrame));
506 
507  _DOMContentsElement.style.top = "0px";
508  _DOMContentsElement.style.left = "0px";
509  _DOMContentsElement.style.width = ROUND(CGRectGetWidth(_backingStoreFrame)) + "px";
510  _DOMContentsElement.style.height = ROUND(CGRectGetHeight(_backingStoreFrame)) + "px";
511 
512  _DOMElement.appendChild(_DOMContentsElement);
513 #endif
514  }
515 
516  if (USE_BUFFER)
517  {
518  if (_delegateRespondsToDisplayLayerSelector)
519  return [_delegate displayInLayer:self];
520 
521  if (CGRectGetWidth(_backingStoreFrame) == 0.0 || CGRectGetHeight(_backingStoreFrame) == 0.0)
522  return;
523 
524  if (!_contents)
525  _contents = CABackingStoreCreate();
526 
527  CABackingStoreSetSize(_contents, _bounds.size);
528 
529  [self drawInContext:CABackingStoreGetContext(_contents)];
530  }
531 
532  [self composite];
533 }
534 
539 - (void)drawInContext:(CGContext)aContext
540 {
541  if (_backgroundColor)
542  {
543  CGContextSetFillColor(aContext, _backgroundColor);
544  CGContextFillRect(aContext, _bounds);
545  }
546 
547  if (_delegateRespondsToDrawLayerInContextSelector)
548  [_delegate drawLayer:self inContext:aContext];
549 }
550 
551 
552 // Style Attributes
557 - (float)opacity
558 {
559  return _opacity;
560 }
561 
566 - (void)setOpacity:(float)anOpacity
567 {
568  if (_opacity == anOpacity)
569  return;
570 
571  _opacity = anOpacity;
572 
573  _DOMElement.style.opacity = anOpacity;
574  _DOMElement.style.filter = "alpha(opacity=" + anOpacity * 100 + ")";
575 }
576 
581 - (void)setHidden:(BOOL)isHidden
582 {
583  _isHidden = isHidden;
584  _DOMElement.style.display = isHidden ? "none" : "block";
585 }
586 
590 - (BOOL)hidden
591 {
592  return _isHidden;
593 }
594 
598 - (BOOL)isHidden
599 {
600  return _isHidden;
601 }
602 
607 - (void)setMasksToBounds:(BOOL)masksToBounds
608 {
609  if (_masksToBounds == masksToBounds)
610  return;
611 
612  _masksToBounds = masksToBounds;
613  _DOMElement.style.overflow = _masksToBounds ? "hidden" : "visible";
614 }
615 
620 - (void)setBackgroundColor:(CPColor)aColor
621 {
622  _backgroundColor = aColor;
623 
624  [self setNeedsDisplay];
625 }
626 
631 {
632  return _backgroundColor;
633 }
634 
635 // Managing Layer Hierarchy
639 - (CPArray)sublayers
640 {
641  return _sublayers;
642 }
643 
648 {
649  return _superlayer;
650 }
651 
652 #define ADJUST_CONTENTS_ZINDEX(aLayer)\
653 if (_DOMContentsElement && aLayer._zPosition > _DOMContentsElement.style.zIndex)\
654  _DOMContentsElement.style.zIndex -= 100.0;\
655 
656 
659 - (void)addSublayer:(CALayer)aLayer
660 {
661  [self insertSublayer:aLayer atIndex:_sublayers.length];
662 }
663 
668 {
669  if (_owningView)
670  [_owningView setLayer:nil];
671 
672  if (!_superlayer)
673  return;
674 
675  _superlayer._DOMElement.removeChild(_DOMElement);
676  [_superlayer._sublayers removeObject:self];
677 
678  _superlayer = nil;
679 }
680 
686 - (void)insertSublayer:(CALayer)aLayer atIndex:(CPUInteger)anIndex
687 {
688  if (!aLayer)
689  return;
690 
691  var superlayer = [aLayer superlayer];
692 
693  if (superlayer == self)
694  {
695  var index = [_sublayers indexOfObjectIdenticalTo:aLayer];
696 
697  if (index == anIndex)
698  return;
699 
700  [_sublayers removeObjectAtIndex:index];
701 
702  if (index < anIndex)
703  --anIndex;
704  }
705  else if (superlayer != nil)
706  [aLayer removeFromSuperlayer];
707 
708  ADJUST_CONTENTS_ZINDEX(aLayer);
709 
710  [_sublayers insertObject:aLayer atIndex:anIndex];
711 
712 #if PLATFORM(DOM)
713  if (anIndex >= _sublayers.length - 1)
714  _DOMElement.appendChild(DOM(aLayer));
715  else
716  _DOMElement.insertBefore(DOM(aLayer), _sublayers[anIndex + 1]._DOMElement);
717 #endif
718 
719  aLayer._superlayer = self;
720 
721  if (self != superlayer)
722  _CALayerRecalculateGeometry(aLayer, 0xFFFFFFF);
723 }
724 
731 - (void)insertSublayer:(CALayer)aLayer below:(CALayer)aSublayer
732 {
733  var index = aSublayer ? [_sublayers indexOfObjectIdenticalTo:aSublayer] : 0;
734 
735  [self insertSublayer:aLayer atIndex:index == CPNotFound ? _sublayers.length : index];
736 }
737 
744 - (void)insertSublayer:(CALayer)aLayer above:(CALayer)aSublayer
745 {
746  var index = aSublayer ? [_sublayers indexOfObjectIdenticalTo:aSublayer] : _sublayers.length;
747 
748  if (index == CPNotFound)
749  [CPException raise:"CALayerNotFoundException" reason:"aSublayer is not a sublayer of this layer"];
750 
751  [_sublayers insertObject:aLayer atIndex:index == CPNotFound ? _sublayers.length : index + 1];
752 }
753 
759 - (void)replaceSublayer:(CALayer)aSublayer with:(CALayer)aLayer
760 {
761  if (aSublayer == aLayer)
762  return;
763 
764  if (aSublayer._superlayer != self)
765  {
766  CPLog.warn("Attempt to replace a sublayer (%s) which is not in the sublayers of the receiver (%s).", [aSublayer description], [self description]);
767  return;
768  }
769 
770  ADJUST_CONTENTS_ZINDEX(aLayer);
771 
772  [_sublayers replaceObjectAtIndex:[_sublayers indexOfObjectIdenticalTo:aSublayer] withObject:aLayer];
773  _DOMElement.replaceChild(DOM(aSublayer), DOM(aLayer));
774 }
775 
776 // Updating Layer Display
777 /*
778  Updates the layers on screen.
779  @ignore
780 */
782 {
784  {
785  var layer = CALayerRegisteredRunLoopUpdates[UID],
786  mask = layer._runLoopUpdateMask;
787 
788  if (mask & CALayerDOMUpdateMask)
789  _CALayerUpdateDOM(layer, mask);
790 
791  if (mask & CALayerDisplayUpdateMask)
792  [layer display];
793 
794  else if (mask & CALayerFrameSizeUpdateMask || mask & CALayerCompositeUpdateMask)
795  [layer composite];
796 
797  layer._runLoopUpdateMask = 0;
798  }
799 
800  window.loop = false;
801  CALayerRegisteredRunLoopUpdates = nil;
802 }
803 
804 /*
805  @ignore
806 */
807 - (void)registerRunLoopUpdateWithMask:(unsigned)anUpdateMask
808 {
810  {
812 
813  [[CPRunLoop currentRunLoop] performSelector:@selector(runLoopUpdateLayers)
814  target:CALayer argument:nil order:0 modes:[CPDefaultRunLoopMode]];
815  }
816 
817  _runLoopUpdateMask |= anUpdateMask;
818  CALayerRegisteredRunLoopUpdates[[self UID]] = self;
819 }
820 
821 /*
822  @ignore
823 */
825 {
826  [self registerRunLoopUpdateWithMask:CALayerCompositeUpdateMask];
827 }
828 
833 {
834  [self registerRunLoopUpdateWithMask:CALayerDisplayUpdateMask];
835 }
836 
841 - (void)setNeedsDisplayOnBoundsChange:(BOOL)needsDisplayOnBoundsChange
842 {
843  _needsDisplayOnBoundsChange = needsDisplayOnBoundsChange;
844 }
845 
850 {
851  return _needsDisplayOnBoundsChange;
852 }
853 
858 - (void)setNeedsDisplayInRect:(CGRect)aRect
859 {
860 // _dirtyRect = aRect;
861  [self display];
862 }
863 
864 // Mapping Between Coordinate and Time Spaces
871 - (CGPoint)convertPoint:(CGPoint)aPoint fromLayer:(CALayer)aLayer
872 {
873  return CGPointApplyAffineTransform(aPoint, _CALayerGetTransform(aLayer, self));
874 }
875 
882 - (CGPoint)convertPoint:(CGPoint)aPoint toLayer:(CALayer)aLayer
883 {
884  return CGPointApplyAffineTransform(aPoint, _CALayerGetTransform(self, aLayer));
885 }
886 
893 - (CGRect)convertRect:(CGRect)aRect fromLayer:(CALayer)aLayer
894 {
895  return CGRectApplyAffineTransform(aRect, _CALayerGetTransform(aLayer, self));
896 }
897 
904 - (CGRect)convertRect:(CGRect)aRect toLayer:(CALayer)aLayer
905 {
906  return CGRectApplyAffineTransform(aRect, _CALayerGetTransform(self, aLayer));
907 }
908 
909 // Hit Testing
914 - (BOOL)containsPoint:(CGPoint)aPoint
915 {
916  return CGRectContainsPoint(_bounds, aPoint);
917 }
918 
924 - (CALayer)hitTest:(CGPoint)aPoint
925 {
926  if (_isHidden)
927  return nil;
928 
929  var point = CGPointApplyAffineTransform(aPoint, _transformToLayer);
930 
931  if (!CGRectContainsPoint(_bounds, point))
932  return nil;
933 
934  var layer = nil,
935  index = _sublayers.length;
936 
937  // FIXME: this should take into account zPosition.
938  while (index--)
939  if (layer = [_sublayers[index] hitTest:point])
940  return layer;
941 
942  return self;
943 }
944 
945 // Modifying the Delegate
950 - (void)setDelegate:(id)aDelegate
951 {
952  if (_delegate == aDelegate)
953  return;
954 
955  _delegate = aDelegate;
956 
957  _delegateRespondsToDisplayLayerSelector = [_delegate respondsToSelector:@selector(displayLayer:)];
958  _delegateRespondsToDrawLayerInContextSelector = [_delegate respondsToSelector:@selector(drawLayer:inContext:)];
959 
960  if (_delegateRespondsToDisplayLayerSelector || _delegateRespondsToDrawLayerInContextSelector)
961  [self setNeedsDisplay];
962 }
963 
967 - (id)delegate
968 {
969  return _delegate;
970 }
971 
972 /* @ignore */
973 - (void)_setOwningView:(CPView)anOwningView
974 {
975  _owningView = anOwningView;
976 
977  if (_owningView)
978  {
979  _owningView = anOwningView;
980 
981  _bounds.size = CGSizeMakeCopy([_owningView bounds].size);
982  _position = CGPointMake(CGRectGetWidth(_bounds) * _anchorPoint.x, CGRectGetHeight(_bounds) * _anchorPoint.y);
983  }
984 
985  _CALayerRecalculateGeometry(self, CALayerGeometryPositionMask | CALayerGeometryBoundsMask);
986 }
987 
988 /* @ignore */
989 - (void)_owningViewBoundsChanged
990 {
991  _bounds.size = CGSizeMakeCopy([_owningView bounds].size);
992  _position = CGPointMake(CGRectGetWidth(_bounds) * _anchorPoint.x, CGRectGetHeight(_bounds) * _anchorPoint.y);
993 
994  _CALayerRecalculateGeometry(self, CALayerGeometryPositionMask | CALayerGeometryBoundsMask);
995 }
996 
997 /* @ignore */
998 - (void)_update
999 {
1000  window.loop = true;
1001 
1002  var mask = _runLoopUpdateMask;
1003 
1004  if (mask & CALayerDOMUpdateMask)
1005  _CALayerUpdateDOM(self, mask);
1006 
1007  if (mask & CALayerDisplayUpdateMask)
1008  [self display];
1009 
1010  else if (mask & CALayerFrameSizeUpdateMask || mask & CALayerCompositeUpdateMask)
1011  [self composite];
1012 
1013  _runLoopUpdateMask = 0;
1014 
1015  window.loop = false;
1016 }
1017 
1018 @end
1019 
1020 function _CALayerUpdateSublayerTransformForSublayers(aLayer)
1021 {
1022  var bounds = aLayer._bounds,
1023  anchorPoint = aLayer._anchorPoint,
1024  translateX = CGRectGetWidth(bounds) * anchorPoint.x,
1025  translateY = CGRectGetHeight(bounds) * anchorPoint.y;
1026 
1027  aLayer._sublayerTransformForSublayers = CGAffineTransformConcat(
1028  CGAffineTransformMakeTranslation(-translateX, -translateY),
1029  CGAffineTransformConcat(aLayer._sublayerTransform,
1030  CGAffineTransformMakeTranslation(translateX, translateY)));
1031 }
1032 
1033 function _CALayerUpdateDOM(aLayer, aMask)
1034 {
1035 #if PLATFORM(DOM)
1036  var DOMElementStyle = aLayer._DOMElement.style;
1037 
1038  if (aMask & CALayerZPositionUpdateMask)
1039  DOMElementStyle.zIndex = aLayer._zPosition;
1040 
1041  var frame = aLayer._backingStoreFrame;
1042 
1043  if (aMask & CALayerFrameOriginUpdateMask)
1044  {
1045  DOMElementStyle.top = ROUND(CGRectGetMinY(frame)) + "px";
1046  DOMElementStyle.left = ROUND(CGRectGetMinX(frame)) + "px";
1047  }
1048 
1049  if (aMask & CALayerFrameSizeUpdateMask)
1050  {
1051  var width = MAX(0.0, ROUND(CGRectGetWidth(frame))),
1052  height = MAX(0.0, ROUND(CGRectGetHeight(frame))),
1053  DOMContentsElement = aLayer._DOMContentsElement;
1054 
1055  DOMElementStyle.width = width + "px";
1056  DOMElementStyle.height = height + "px";
1057 
1058  if (DOMContentsElement)
1059  {
1060  DOMContentsElement.width = width;
1061  DOMContentsElement.height = height;
1062  DOMContentsElement.style.width = width + "px";
1063  DOMContentsElement.style.height = height + "px";
1064  }
1065  }
1066 #endif
1067 }
1068 
1069 function _CALayerRecalculateGeometry(aLayer, aGeometryChange)
1070 {
1071  var bounds = aLayer._bounds,
1072  superlayer = aLayer._superlayer,
1073  width = CGRectGetWidth(bounds),
1074  height = CGRectGetHeight(bounds),
1075  position = aLayer._position,
1076  anchorPoint = aLayer._anchorPoint,
1077  affineTransform = aLayer._affineTransform,
1078  backingStoreFrameSize = CGSizeMakeCopy(aLayer._backingStoreFrame),
1079  hasCustomBackingStoreFrame = aLayer._hasCustomBackingStoreFrame;
1080 
1081  // Go to anchor, transform, go back to bounds.
1082  aLayer._transformFromLayer = CGAffineTransformConcat(
1083  CGAffineTransformMakeTranslation(-width * anchorPoint.x - CGRectGetMinX(aLayer._bounds), -height * anchorPoint.y - CGRectGetMinY(aLayer._bounds)),
1086 
1087  if (superlayer && superlayer._hasSublayerTransform)
1088  {
1089  // aLayer._transformFromLayer = CGAffineTransformConcat(aLayer._transformFromLayer, superlayer._sublayerTransformForSublayers);
1090  CGAffineTransformConcatTo(aLayer._transformFromLayer, superlayer._sublayerTransformForSublayers, aLayer._transformFromLayer);
1091  }
1092 
1093  aLayer._transformToLayer = CGAffineTransformInvert(aLayer._transformFromLayer);
1094 
1095  //aLayer._transformFromLayer.tx = ROUND(aLayer._transformFromLayer.tx);
1096  //aLayer._transformFromLayer.ty = ROUND(aLayer._transformFromLayer.ty);
1097 
1098  aLayer._frame = nil;
1099  aLayer._standardBackingStoreFrame = [aLayer convertRect:bounds toLayer:nil];
1100 
1101  if (superlayer)
1102  {
1103  var bounds = [superlayer bounds],
1104  frame = [superlayer convertRect:bounds toLayer:nil];
1105 
1106  aLayer._standardBackingStoreFrame.origin.x -= CGRectGetMinX(frame);
1107  aLayer._standardBackingStoreFrame.origin.y -= CGRectGetMinY(frame);
1108  }
1109 
1110  // We used to use CGRectIntegral here, but what we actually want, is the largest integral
1111  // rect that would ever contain this box, since for any width/height, there are 2 (4)
1112  // possible integral rects for it depending on it's position. It's OK that this is sometimes
1113  // bigger than the "optimal" bounding integral rect since that doesn't change drawing.
1114 
1115  var origin = aLayer._standardBackingStoreFrame.origin,
1116  size = aLayer._standardBackingStoreFrame.size;
1117 
1118  origin.x = FLOOR(origin.x);
1119  origin.y = FLOOR(origin.y);
1120  size.width = CEIL(size.width) + 1.0;
1121  size.height = CEIL(size.height) + 1.0;
1122 
1123  // FIXME: This avoids the central issue that a position change is sometimes a display and sometimes
1124  // a div move, and sometimes both.
1125 
1126  // Only use this frame if we don't currently have a custom backing store frame.
1127  if (!hasCustomBackingStoreFrame)
1128  {
1129  var backingStoreFrame = CGRectMakeCopy(aLayer._standardBackingStoreFrame);
1130 
1131  // These values get rounded in the DOM, so don't both updating them if they're
1132  // not going to be different after rounding.
1133  if (ROUND(CGRectGetMinX(backingStoreFrame)) != ROUND(CGRectGetMinX(aLayer._backingStoreFrame)) ||
1134  ROUND(CGRectGetMinY(backingStoreFrame)) != ROUND(CGRectGetMinY(aLayer._backingStoreFrame)))
1135  [aLayer registerRunLoopUpdateWithMask:CALayerFrameOriginUpdateMask];
1136 
1137  // Any change in size due to a geometry change is purely due to rounding error.
1138  if ((CGRectGetWidth(backingStoreFrame) != ROUND(CGRectGetWidth(aLayer._backingStoreFrame)) ||
1139  CGRectGetHeight(backingStoreFrame) != ROUND(CGRectGetHeight(aLayer._backingStoreFrame))))
1140  [aLayer registerRunLoopUpdateWithMask:CALayerFrameSizeUpdateMask];
1141 
1142  aLayer._backingStoreFrame = backingStoreFrame;
1143  }
1144 
1145  if (aGeometryChange & CALayerGeometryBoundsMask && aLayer._needsDisplayOnBoundsChange)
1146  [aLayer setNeedsDisplay];
1147  // We need to recompose if we have a custom backing store frame, OR
1148  // If the change is not solely composed of position and anchor points changes.
1149  // Anchor point and position changes simply move the object, requiring
1150  // no re-rendering.
1151  else if (hasCustomBackingStoreFrame || (aGeometryChange & ~(CALayerGeometryPositionMask | CALayerGeometryAnchorPointMask)))
1152  [aLayer setNeedsComposite];
1153 
1154  var sublayers = aLayer._sublayers,
1155  index = 0,
1156  count = sublayers.length;
1157 
1158  for (; index < count; ++index)
1159  _CALayerRecalculateGeometry(sublayers[index], aGeometryChange);
1160 }
1161 
1162 function _CALayerGetTransform(fromLayer, toLayer)
1163 {
1164  var transform = CGAffineTransformMakeIdentity();
1165 
1166  if (fromLayer)
1167  {
1168  var layer = fromLayer;
1169 
1170  // If we have a fromLayer, "climb up" the layer tree until
1171  // we hit the root node or we hit the toLayer.
1172  while (layer && layer != toLayer)
1173  {
1174  var transformFromLayer = layer._transformFromLayer;
1175 
1176  //transform = CGAffineTransformConcat(transform, layer._transformFromLayer);
1177  CGAffineTransformConcatTo(transform, transformFromLayer, transform);
1178 
1179  layer = layer._superlayer;
1180  }
1181 
1182  // If we hit toLayer, then we're done.
1183  if (layer == toLayer)
1184  return transform;
1185  }
1186 
1187  var layers = [],
1188  layer = toLayer;
1189 
1190  while (layer)
1191  {
1192  layers.push(layer);
1193  layer = layer._superlayer;
1194  }
1195 
1196  var index = layers.length;
1197 
1198  while (index--)
1199  {
1200  var transformToLayer = layers[index]._transformToLayer;
1201 
1202  CGAffineTransformConcatTo(transform, transformToLayer, transform);
1203  }
1204 
1205  return transform;
1206 }