API  0.9.6
 All Classes Files Functions Variables 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 var USE_BUFFER = NO;
35 
42 
44 
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  CPColor _backgroundColor;
85 
86  // Managing Layer Hierarchy
87 
88  CALayer _superlayer;
89  CPMutableArray _sublayers;
90 
91  // Updating Layer Display
92 
93  unsigned _runLoopUpdateMask;
94  BOOL _needsDisplayOnBoundsChange;
95 
96  // Modifying the Delegate
97 
98  id _delegate;
99 
100  BOOL _delegateRespondsToDisplayLayerSelector;
101  BOOL _delegateRespondsToDrawLayerInContextSelector;
102 
103  // DOM Implementation
104 
105  DOMElement _DOMElement;
106  DOMElement _DOMContentsElement;
107  id _contents;
108  CGContext _context;
109  CPView _owningView;
110 
111  CGAffineTransform _transformToLayer;
112  CGAffineTransform _transformFromLayer;
113 }
114 
118 + (CALayer)layer
119 {
120  return [[[self class] alloc] init];
121 }
122 
126 - (id)init
127 {
128  self = [super init];
129 
130  if (self)
131  {
132  _frame = CGRectMakeZero();
133 
134  _backingStoreFrame = CGRectMakeZero();
135  _standardBackingStoreFrame = CGRectMakeZero();
136 
137  _bounds = CGRectMakeZero();
138  _position = CGPointMakeZero();
139  _zPosition = 0.0;
140  _anchorPoint = CGPointMake(0.5, 0.5);
141  _affineTransform = CGAffineTransformMakeIdentity();
142  _sublayerTransform = CGAffineTransformMakeIdentity();
143 
144  _transformToLayer = CGAffineTransformMakeIdentity(); // FIXME? does it matter?
145  _transformFromLayer = CGAffineTransformMakeIdentity();
146 
147  _opacity = 1.0;
148  _isHidden = NO;
149  _masksToBounds = NO;
150 
151  _sublayers = [];
152 
153  _DOMElement = document.createElement("div");
154 
155  _DOMElement.style.overflow = "visible";
156  _DOMElement.style.position = "absolute";
157  _DOMElement.style.visibility = "visible";
158  _DOMElement.style.top = "0px";
159  _DOMElement.style.left = "0px";
160  _DOMElement.style.zIndex = 0;
161  _DOMElement.style.width = "0px";
162  _DOMElement.style.height = "0px";
163  }
164 
165  return self;
166 }
167 
168 // Modifying the Layer Geometry
173 - (void)setBounds:(CGRect)aBounds
174 {
175  if (CGRectEqualToRect(_bounds, aBounds))
176  return;
177 
178  var oldOrigin = _bounds.origin;
179 
180  _bounds = _CGRectMakeCopy(aBounds);
181 
182  if (_hasSublayerTransform)
183  _CALayerUpdateSublayerTransformForSublayers(self);
184 
185  // _hasSublayerTransform == true will handle this for us.
186  /*else if (!CGPointEqualToPoint(_bounds.origin, oldOrigin))
187  {
188  var index = _sublayers.length;
189 
190  // FIXME: This should climb the layer tree down.
191  while (index--)
192  _CALayerRecalculateGeometry(_sublayers[index], CALayerGeometryPositionMask);
193  }*/
194 
195  _CALayerRecalculateGeometry(self, CALayerGeometryBoundsMask);
196 }
197 
201 - (CGRect)bounds
202 {
203  return _bounds;
204 }
205 
210 - (void)setPosition:(CGPoint)aPosition
211 {
212  if (CGPointEqualToPoint(_position, aPosition))
213  return;
214 
215  _position = _CGPointMakeCopy(aPosition);
216 
217  _CALayerRecalculateGeometry(self, CALayerGeometryPositionMask);
218 }
219 
223 - (CGPoint)position
224 {
225  return _position;
226 }
227 
232 - (void)setZPosition:(int)aZPosition
233 {
234  if (_zPosition == aZPosition)
235  return;
236 
237  _zPosition = aZPosition;
238 
239  [self registerRunLoopUpdateWithMask:CALayerZPositionUpdateMask];
240 }
241 
246 - (void)setAnchorPoint:(CGPoint)anAnchorPoint
247 {
248  anAnchorPoint = _CGPointMakeCopy(anAnchorPoint);
249  anAnchorPoint.x = MIN(1.0, MAX(0.0, anAnchorPoint.x));
250  anAnchorPoint.y = MIN(1.0, MAX(0.0, anAnchorPoint.y));
251 
252  if (CGPointEqualToPoint(_anchorPoint, anAnchorPoint))
253  return;
254 
255  _anchorPoint = anAnchorPoint;
256 
257  if (_hasSublayerTransform)
258  _CALayerUpdateSublayerTransformForSublayers(self);
259 
260  if (_owningView)
261  _position = CGPointMake(_CGRectGetWidth(_bounds) * _anchorPoint.x, _CGRectGetHeight(_bounds) * _anchorPoint.y);
262 
263  _CALayerRecalculateGeometry(self, CALayerGeometryAnchorPointMask);
264 }
265 
269 - (CGPoint)anchorPoint
270 {
271  return _anchorPoint;
272 }
273 
278 - (void)setAffineTransform:(CGAffineTransform)anAffineTransform
279 {
280  if (CGAffineTransformEqualToTransform(_affineTransform, anAffineTransform))
281  return;
282 
283  _affineTransform = _CGAffineTransformMakeCopy(anAffineTransform);
284 
285  _CALayerRecalculateGeometry(self, CALayerGeometryAffineTransformMask);
286 }
287 
291 - (CGAffineTransform)affineTransform
292 {
293  return _affineTransform;
294 }
295 
300 - (void)setSublayerTransform:(CGAffineTransform)anAffineTransform
301 {
302  if (CGAffineTransformEqualToTransform(_sublayerTransform, anAffineTransform))
303  return;
304 
305  var hadSublayerTransform = _hasSublayerTransform;
306 
307  _sublayerTransform = _CGAffineTransformMakeCopy(anAffineTransform);
308  _hasSublayerTransform = !_CGAffineTransformIsIdentity(_sublayerTransform);
309 
310  if (_hasSublayerTransform)
311  {
312  _CALayerUpdateSublayerTransformForSublayers(self);
313 
314  var index = _sublayers.length;
315 
316  // FIXME: This should climb the layer tree down.
317  while (index--)
318  _CALayerRecalculateGeometry(_sublayers[index], CALayerGeometryParentSublayerTransformMask);
319  }
320 }
321 
325 - (CGAffineTransform)sublayerTransform
326 {
327  return _sublayerTransform;
328 }
329 
330 /*
331  Private
332  @ignore
333 */
334 - (CGAffineTransform)transformToLayer
335 {
336  return _transformToLayer;
337 }
338 
344 - (void)setFrame:(CGRect)aFrame
345 {
346  alert("FIXME IMPLEMENT");
347 }
348 
356 - (CGRect)frame
357 {
358  if (!_frame)
359  _frame = [self convertRect:_bounds toLayer:_superlayer];
360 
361  return _frame;
362 }
363 
372 - (CGRect)backingStoreFrame
373 {
374  return _backingStoreFrame;
375 }
376 
381 - (void)setBackingStoreFrame:(CGRect)aFrame
382 {
383  _hasCustomBackingStoreFrame = (aFrame != nil);
384 
385  if (aFrame == nil)
386  aFrame = CGRectMakeCopy(_standardBackingStoreFrame);
387  else
388  {
389  if (_superlayer)
390  {
391  aFrame = [_superlayer convertRect:aFrame toLayer:nil];
392 
393  var bounds = [_superlayer bounds],
394  frame = [_superlayer convertRect:bounds toLayer:nil];
395 
396  aFrame.origin.x -= _CGRectGetMinX(frame);
397  aFrame.origin.y -= _CGRectGetMinY(frame);
398  }
399  else
400  aFrame = CGRectMakeCopy(aFrame);
401  }
402 
403  if (!CGPointEqualToPoint(_backingStoreFrame.origin, aFrame.origin))
404  [self registerRunLoopUpdateWithMask:CALayerFrameOriginUpdateMask];
405 
406  if (!CGSizeEqualToSize(_backingStoreFrame.size, aFrame.size))
407  [self registerRunLoopUpdateWithMask:CALayerFrameSizeUpdateMask];
408 
409  _backingStoreFrame = aFrame;
410 }
411 
412 // Providing Layer Content
417 - (CGImage)contents
418 {
419  return _contents;
420 }
421 
426 - (void)setContents:(CGImage)contents
427 {
428  if (_contents == contents)
429  return;
430 
431  _contents = contents;
432 
433  [self composite];
434 }
435 
436 /*
437  Composites this layer onto the super layer, and draws its contents as well.
438  @ignore
439 */
440 - (void)composite
441 {
442  if (USE_BUFFER && !_contents || !_context)
443  return;
444 
445  CGContextClearRect(_context, _CGRectMake(0.0, 0.0, _CGRectGetWidth(_backingStoreFrame), _CGRectGetHeight(_backingStoreFrame)));
446 
447  // Recomposite
448  var transform;
449 
450  if (_superlayer)
451  {
452  var superlayerTransform = _CALayerGetTransform(_superlayer, nil),
453  superlayerOrigin = CGPointApplyAffineTransform(_superlayer._bounds.origin, superlayerTransform);
454 
455  transform = CGAffineTransformConcat(_transformFromLayer, superlayerTransform);
456 
457  transform.tx -= superlayerOrigin.x;
458  transform.ty -= superlayerOrigin.y;
459  }
460 
461  else
462  // Copy so we don't affect the original.
463  transform = CGAffineTransformCreateCopy(_transformFromLayer);
464 
465  transform.tx -= _CGRectGetMinX(_backingStoreFrame);
466  transform.ty -= _CGRectGetMinY(_backingStoreFrame);
467 
468  CGContextSaveGState(_context);
469 
470  CGContextConcatCTM(_context, transform);//_transformFromView);
471  if (USE_BUFFER)
472  {
473 // CGContextDrawImage(_context, _bounds, _contents.context);
474  _context.drawImage(_contents.buffer, _CGRectGetMinX(_bounds), _CGRectGetMinY(_bounds));//, _CGRectGetWidth(_standardBackingStoreFrame), _CGRectGetHeight(_standardBackingStoreFrame));
475  }
476  else
477  [self drawInContext:_context];
478  CGContextRestoreGState(_context);
479 }
480 
484 - (void)display
485 {
486  if (!_context)
487  {
488  _context = CGBitmapGraphicsContextCreate();
489 
490  _DOMContentsElement = _context.DOMElement;
491 
492  _DOMContentsElement.style.zIndex = -100;
493 
494  _DOMContentsElement.style.overflow = "hidden";
495  _DOMContentsElement.style.position = "absolute";
496  _DOMContentsElement.style.visibility = "visible";
497 
498  _DOMContentsElement.width = ROUND(_CGRectGetWidth(_backingStoreFrame));
499  _DOMContentsElement.height = ROUND(_CGRectGetHeight(_backingStoreFrame));
500 
501  _DOMContentsElement.style.top = "0px";
502  _DOMContentsElement.style.left = "0px";
503  _DOMContentsElement.style.width = ROUND(_CGRectGetWidth(_backingStoreFrame)) + "px";
504  _DOMContentsElement.style.height = ROUND(_CGRectGetHeight(_backingStoreFrame)) + "px";
505 
506  _DOMElement.appendChild(_DOMContentsElement);
507  }
508 
509  if (USE_BUFFER)
510  {
511  if (_delegateRespondsToDisplayLayerSelector)
512  return [_delegate displayInLayer:self];
513 
514  if (_CGRectGetWidth(_backingStoreFrame) == 0.0 || _CGRectGetHeight(_backingStoreFrame) == 0.0)
515  return;
516 
517  if (!_contents)
518  _contents = CABackingStoreCreate();
519 
520  CABackingStoreSetSize(_contents, _bounds.size);
521 
522  [self drawInContext:CABackingStoreGetContext(_contents)];
523  }
524 
525  [self composite];
526 }
527 
532 - (void)drawInContext:(CGContext)aContext
533 { //if (!window.loop || window.nodisplay) CPLog.error("htiasd");
534  if (_backgroundColor)
535  {
536  CGContextSetFillColor(aContext, _backgroundColor);
537  CGContextFillRect(aContext, _bounds);
538  }
539 
540  if (_delegateRespondsToDrawLayerInContextSelector)
541  [_delegate drawLayer:self inContext:aContext];
542 }
543 
544 
545 // Style Attributes
550 - (float)opacity
551 {
552  return _opacity;
553 }
554 
559 - (void)setOpacity:(float)anOpacity
560 {
561  if (_opacity == anOpacity)
562  return;
563 
564  _opacity = anOpacity;
565 
566  _DOMElement.style.opacity = anOpacity;
567  _DOMElement.style.filter = "alpha(opacity=" + anOpacity * 100 + ")";
568 }
569 
574 - (void)setHidden:(BOOL)isHidden
575 {
576  _isHidden = isHidden;
577  _DOMElement.style.display = isHidden ? "none" : "block";
578 }
579 
583 - (BOOL)hidden
584 {
585  return _isHidden;
586 }
587 
591 - (BOOL)isHidden
592 {
593  return _isHidden;
594 }
595 
600 - (void)setMasksToBounds:(BOOL)masksToBounds
601 {
602  if (_masksToBounds == masksToBounds)
603  return;
604 
605  _masksToBounds = masksToBounds;
606  _DOMElement.style.overflow = _masksToBounds ? "hidden" : "visible";
607 }
608 
613 - (void)setBackgroundColor:(CPColor)aColor
614 {
615  _backgroundColor = aColor;
616 
617  [self setNeedsDisplay];
618 }
619 
623 - (CPColor)backgroundColor
624 {
625  return _backgroundColor;
626 }
627 
628 // Managing Layer Hierarchy
632 - (CPArray)sublayers
633 {
634  return _sublayers;
635 }
636 
640 - (CALayer)superlayer
641 {
642  return _superlayer;
643 }
644 
645 #define ADJUST_CONTENTS_ZINDEX(aLayer)\
646 if (_DOMContentsElement && aLayer._zPosition > _DOMContentsElement.style.zIndex)\
647  _DOMContentsElement.style.zIndex -= 100.0;\
648 
649 
652 - (void)addSublayer:(CALayer)aLayer
653 {
654  [self insertSublayer:aLayer atIndex:_sublayers.length];
655  return;
656  ADJUST_CONTENTS_ZINDEX(aLayer);
657 
658  [_sublayers addObject:aLayer];
659  _DOMElement.appendChild(DOM(aLayer));
660 }
661 
665 - (void)removeFromSuperlayer
666 {
667  if (_owningView)
668  [_owningView setLayer:nil];
669 
670  if (!_superlayer)
671  return;
672 
673  _superlayer._DOMElement.removeChild(_DOMElement);
674  [_superlayer._sublayers removeObject:self];
675 
676  _superlayer = nil;
677 }
678 
684 - (void)insertSublayer:(CALayer)aLayer atIndex:(unsigned)anIndex
685 {
686  if (!aLayer)
687  return;
688 
689  var superlayer = [aLayer superlayer];
690 
691  if (superlayer == self)
692  {
693  var index = [_sublayers indexOfObjectIdenticalTo:aLayer];
694 
695  if (index == anIndex)
696  return;
697 
698  [_sublayers removeObjectAtIndex:index];
699 
700  if (index < anIndex)
701  --anIndex;
702  }
703  else if (superlayer != nil)
704  [aLayer removeFromSuperlayer];
705 
706  ADJUST_CONTENTS_ZINDEX(aLayer);
707 
708  [_sublayers insertObject:aLayer atIndex:anIndex];
709 
710  if (anIndex >= _sublayers.length - 1)
711  _DOMElement.appendChild(DOM(aLayer));
712  else
713  _DOMElement.insertBefore(DOM(aLayer), _sublayers[anIndex + 1]._DOMElement);
714 
715  aLayer._superlayer = self;
716 
717  if (self != superlayer)
718  _CALayerRecalculateGeometry(aLayer, 0xFFFFFFF);
719 }
720 
727 - (void)insertSublayer:(CALayer)aLayer below:(CALayer)aSublayer
728 {
729  var index = aSublayer ? [_sublayers indexOfObjectIdenticalTo:aSublayer] : 0;
730 
731  [self insertSublayer:aLayer atIndex:index == CPNotFound ? _sublayers.length : index];
732 }
733 
740 - (void)insertSublayer:(CALayer)aLayer above:(CALayer)aSublayer
741 {
742  var index = aSublayer ? [_sublayers indexOfObjectIdenticalTo:aSublayer] : _sublayers.length;
743  if (index == CPNotFound)
744  [CPException raise:"CALayerNotFoundException" reason:"aSublayer is not a sublayer of this layer"];
745 
746  [_sublayers insertObject:aLayer atIndex:index == CPNotFound ? _sublayers.length : index + 1];
747 }
748 
754 - (void)replaceSublayer:(CALayer)aSublayer with:(CALayer)aLayer
755 {
756  if (aSublayer == aLayer)
757  return;
758 
759  // FIXME: EXCEPTION
760  if (aSublayer._superlayer != self)
761  {
762  alert("EXCEPTION");
763  return;
764  }
765 
766  ADJUST_CONTENTS_ZINDEX(aLayer);
767 
768  [_sublayers replaceObjectAtIndex:[_sublayers indexOfObjectIdenticalTo:aSublayer] withObject:aLayer];
769  _DOMElement.replaceChild(DOM(aSublayer), DOM(aLayer));
770 }
771 
772 // Updating Layer Display
773 /*
774  Updates the layers on screen.
775  @ignore
776 */
777 + (void)runLoopUpdateLayers
778 {
780  {
781  var layer = CALayerRegisteredRunLoopUpdates[UID],
782  mask = layer._runLoopUpdateMask;
783 
784  if (mask & CALayerDOMUpdateMask)
785  _CALayerUpdateDOM(layer, mask);
786 
787  if (mask & CALayerDisplayUpdateMask)
788  [layer display];
789 
790  else if (mask & CALayerFrameSizeUpdateMask || mask & CALayerCompositeUpdateMask)
791  [layer composite];
792 
793  layer._runLoopUpdateMask = 0;
794  }
795  window.loop = false;
797 }
798 
799 /*
800  @ignore
801 */
802 - (void)registerRunLoopUpdateWithMask:(unsigned)anUpdateMask
803 {
805  {
807 
808  [[CPRunLoop currentRunLoop] performSelector:@selector(runLoopUpdateLayers)
809  target:CALayer argument:nil order:0 modes:[CPDefaultRunLoopMode]];
810  }
811 
812  _runLoopUpdateMask |= anUpdateMask;
813  CALayerRegisteredRunLoopUpdates[[self UID]] = self;
814 }
815 
816 /*
817  @ignore
818 */
819 - (void)setNeedsComposite
820 {
821  [self registerRunLoopUpdateWithMask:CALayerCompositeUpdateMask];
822 }
823 
827 - (void)setNeedsDisplay
828 {
829  [self registerRunLoopUpdateWithMask:CALayerDisplayUpdateMask];
830 }
831 
836 - (void)setNeedsDisplayOnBoundsChange:(BOOL)needsDisplayOnBoundsChange
837 {
838  _needsDisplayOnBoundsChange = needsDisplayOnBoundsChange;
839 }
840 
844 - (BOOL)needsDisplayOnBoundsChange
845 {
846  return _needsDisplayOnBoundsChange;
847 }
848 
853 - (void)setNeedsDisplayInRect:(CGRect)aRect
854 {
855  _dirtyRect = aRect;
856  [self display];
857 }
858 
859 // Mapping Between Coordinate and Time Spaces
866 - (CGPoint)convertPoint:(CGPoint)aPoint fromLayer:(CALayer)aLayer
867 {
868  return CGPointApplyAffineTransform(aPoint, _CALayerGetTransform(aLayer, self));
869 }
870 
877 - (CGPoint)convertPoint:(CGPoint)aPoint toLayer:(CALayer)aLayer
878 {
879  return CGPointApplyAffineTransform(aPoint, _CALayerGetTransform(self, aLayer));
880 }
881 
888 - (CGRect)convertRect:(CGRect)aRect fromLayer:(CALayer)aLayer
889 {
890  return CGRectApplyAffineTransform(aRect, _CALayerGetTransform(aLayer, self));
891 }
892 
899 - (CGRect)convertRect:(CGRect)aRect toLayer:(CALayer)aLayer
900 {
901  return CGRectApplyAffineTransform(aRect, _CALayerGetTransform(self, aLayer));
902 }
903 
904 // Hit Testing
909 - (BOOL)containsPoint:(CGPoint)aPoint
910 {
911  return _CGRectContainsPoint(_bounds, aPoint);
912 }
913 
919 - (CALayer)hitTest:(CGPoint)aPoint
920 {
921  if (_isHidden)
922  return nil;
923 
924  var point = CGPointApplyAffineTransform(aPoint, _transformToLayer);
925  //alert(point.x + " " + point.y);
926 
927  if (!_CGRectContainsPoint(_bounds, point))
928  return nil;
929 
930  var layer = nil,
931  index = _sublayers.length;
932 
933  // FIXME: this should take into account zPosition.
934  while (index--)
935  if (layer = [_sublayers[index] hitTest:point])
936  return layer;
937 
938  return self;
939 }
940 
941 // Modifying the Delegate
946 - (void)setDelegate:(id)aDelegate
947 {
948  if (_delegate == aDelegate)
949  return;
950 
951  _delegate = aDelegate;
952 
953  _delegateRespondsToDisplayLayerSelector = [_delegate respondsToSelector:@selector(displayLayer:)];
954  _delegateRespondsToDrawLayerInContextSelector = [_delegate respondsToSelector:@selector(drawLayer:inContext:)];
955 
956  if (_delegateRespondsToDisplayLayerSelector || _delegateRespondsToDrawLayerInContextSelector)
957  [self setNeedsDisplay];
958 }
959 
963 - (id)delegate
964 {
965  return _delegate;
966 }
967 
968 /* @ignore */
969 - (void)_setOwningView:(CPView)anOwningView
970 {
971  _owningView = anOwningView;
972 
973  if (_owningView)
974  {
975  _owningView = anOwningView;
976 
977  _bounds.size = CGSizeMakeCopy([_owningView bounds].size);
978  _position = CGPointMake(_CGRectGetWidth(_bounds) * _anchorPoint.x, _CGRectGetHeight(_bounds) * _anchorPoint.y);
979  }
980 
981  _CALayerRecalculateGeometry(self, CALayerGeometryPositionMask | CALayerGeometryBoundsMask);
982 }
983 
984 /* @ignore */
985 - (void)_owningViewBoundsChanged
986 {
987  _bounds.size = CGSizeMakeCopy([_owningView bounds].size);
988  _position = CGPointMake(_CGRectGetWidth(_bounds) * _anchorPoint.x, _CGRectGetHeight(_bounds) * _anchorPoint.y);
989 
990  _CALayerRecalculateGeometry(self, CALayerGeometryPositionMask | CALayerGeometryBoundsMask);
991 }
992 
993 /* @ignore */
994 - (void)_update
995 {
996  window.loop = true;
997 
998  var mask = _runLoopUpdateMask;
999 
1000  if (mask & CALayerDOMUpdateMask)
1001  _CALayerUpdateDOM(self, mask);
1002 
1003  if (mask & CALayerDisplayUpdateMask)
1004  [self display];
1005 
1006  else if (mask & CALayerFrameSizeUpdateMask || mask & CALayerCompositeUpdateMask)
1007  [self composite];
1008 
1009  _runLoopUpdateMask = 0;
1010 
1011  window.loop = false;
1012 }
1013 
1014 @end
1015 
1016 function _CALayerUpdateSublayerTransformForSublayers(aLayer)
1017 {
1018  var bounds = aLayer._bounds,
1019  anchorPoint = aLayer._anchorPoint,
1020  translateX = _CGRectGetWidth(bounds) * anchorPoint.x,
1021  translateY = _CGRectGetHeight(bounds) * anchorPoint.y;
1022 
1023  aLayer._sublayerTransformForSublayers = CGAffineTransformConcat(
1024  CGAffineTransformMakeTranslation(-translateX, -translateY),
1025  CGAffineTransformConcat(aLayer._sublayerTransform,
1026  CGAffineTransformMakeTranslation(translateX, translateY)));
1027 }
1028 
1029 function _CALayerUpdateDOM(aLayer, aMask)
1030 {
1031  var DOMElementStyle = aLayer._DOMElement.style;
1032 
1033  if (aMask & CALayerZPositionUpdateMask)
1034  DOMElementStyle.zIndex = aLayer._zPosition;
1035 
1036  var frame = aLayer._backingStoreFrame;
1037 
1038  if (aMask & CALayerFrameOriginUpdateMask)
1039  {
1040  DOMElementStyle.top = ROUND(_CGRectGetMinY(frame)) + "px";
1041  DOMElementStyle.left = ROUND(_CGRectGetMinX(frame)) + "px";
1042  }
1043 
1044  if (aMask & CALayerFrameSizeUpdateMask)
1045  {
1046  var width = MAX(0.0, ROUND(_CGRectGetWidth(frame))),
1047  height = MAX(0.0, ROUND(_CGRectGetHeight(frame))),
1048  DOMContentsElement = aLayer._DOMContentsElement;
1049 
1050  DOMElementStyle.width = width + "px";
1051  DOMElementStyle.height = height + "px";
1052 
1053  if (DOMContentsElement)
1054  {
1055  DOMContentsElement.width = width;
1056  DOMContentsElement.height = height;
1057  DOMContentsElement.style.width = width + "px";
1058  DOMContentsElement.style.height = height + "px";
1059  }
1060  }
1061 }
1062 
1063 function _CALayerRecalculateGeometry(aLayer, aGeometryChange)
1064 {
1065  var bounds = aLayer._bounds,
1066  superlayer = aLayer._superlayer,
1067  width = _CGRectGetWidth(bounds),
1068  height = _CGRectGetHeight(bounds),
1069  position = aLayer._position,
1070  anchorPoint = aLayer._anchorPoint,
1071  affineTransform = aLayer._affineTransform,
1072  backingStoreFrameSize = _CGSizeMakeCopy(aLayer._backingStoreFrame),
1073  hasCustomBackingStoreFrame = aLayer._hasCustomBackingStoreFrame;
1074 
1075  // Go to anchor, transform, go back to bounds.
1076  aLayer._transformFromLayer = CGAffineTransformConcat(
1077  CGAffineTransformMakeTranslation(-width * anchorPoint.x - _CGRectGetMinX(aLayer._bounds), -height * anchorPoint.y - _CGRectGetMinY(aLayer._bounds)),
1078  CGAffineTransformConcat(affineTransform,
1079  CGAffineTransformMakeTranslation(position.x, position.y)));
1080 
1081  if (superlayer && superlayer._hasSublayerTransform)
1082  {
1083  // aLayer._transformFromLayer = CGAffineTransformConcat(aLayer._transformFromLayer, superlayer._sublayerTransformForSublayers);
1084  _CGAffineTransformConcatTo(aLayer._transformFromLayer, superlayer._sublayerTransformForSublayers, aLayer._transformFromLayer);
1085  }
1086 
1087  aLayer._transformToLayer = CGAffineTransformInvert(aLayer._transformFromLayer);
1088 
1089  //aLayer._transformFromLayer.tx = ROUND(aLayer._transformFromLayer.tx);
1090  //aLayer._transformFromLayer.ty = ROUND(aLayer._transformFromLayer.ty);
1091 
1092  aLayer._frame = nil;
1093  aLayer._standardBackingStoreFrame = [aLayer convertRect:bounds toLayer:nil];
1094 
1095  if (superlayer)
1096  {
1097  var bounds = [superlayer bounds],
1098  frame = [superlayer convertRect:bounds toLayer:nil];
1099 
1100  aLayer._standardBackingStoreFrame.origin.x -= _CGRectGetMinX(frame);
1101  aLayer._standardBackingStoreFrame.origin.y -= _CGRectGetMinY(frame);
1102  }
1103 
1104  // We used to use CGRectIntegral here, but what we actually want, is the largest integral
1105  // rect that would ever contain this box, since for any width/height, there are 2 (4)
1106  // possible integral rects for it depending on it's position. It's OK that this is sometimes
1107  // bigger than the "optimal" bounding integral rect since that doesn't change drawing.
1108 
1109  var origin = aLayer._standardBackingStoreFrame.origin,
1110  size = aLayer._standardBackingStoreFrame.size;
1111 
1112  origin.x = FLOOR(origin.x);
1113  origin.y = FLOOR(origin.y);
1114  size.width = CEIL(size.width) + 1.0;
1115  size.height = CEIL(size.height) + 1.0;
1116 
1117  // FIXME: This avoids the central issue that a position change is sometimes a display and sometimes
1118  // a div move, and sometimes both.
1119 
1120  // Only use this frame if we don't currently have a custom backing store frame.
1121  if (!hasCustomBackingStoreFrame)
1122  {
1123  var backingStoreFrame = CGRectMakeCopy(aLayer._standardBackingStoreFrame);
1124 
1125  // These values get rounded in the DOM, so don't both updating them if they're
1126  // not going to be different after rounding.
1127  if (ROUND(_CGRectGetMinX(backingStoreFrame)) != ROUND(_CGRectGetMinX(aLayer._backingStoreFrame)) ||
1128  ROUND(_CGRectGetMinY(backingStoreFrame)) != ROUND(_CGRectGetMinY(aLayer._backingStoreFrame)))
1129  [aLayer registerRunLoopUpdateWithMask:CALayerFrameOriginUpdateMask];
1130 
1131  // Any change in size due to a geometry change is purely due to rounding error.
1132  if ((_CGRectGetWidth(backingStoreFrame) != ROUND(_CGRectGetWidth(aLayer._backingStoreFrame)) ||
1133  _CGRectGetHeight(backingStoreFrame) != ROUND(_CGRectGetHeight(aLayer._backingStoreFrame))))
1134  [aLayer registerRunLoopUpdateWithMask:CALayerFrameSizeUpdateMask];
1135 
1136  aLayer._backingStoreFrame = backingStoreFrame;
1137  }
1138 
1139  if (aGeometryChange & CALayerGeometryBoundsMask && aLayer._needsDisplayOnBoundsChange)
1140  [aLayer setNeedsDisplay];
1141  // We need to recompose if we have a custom backing store frame, OR
1142  // If the change is not solely composed of position and anchor points changes.
1143  // Anchor point and position changes simply move the object, requiring
1144  // no re-rendering.
1145  else if (hasCustomBackingStoreFrame || (aGeometryChange & ~(CALayerGeometryPositionMask | CALayerGeometryAnchorPointMask)))
1146  [aLayer setNeedsComposite];
1147 
1148  var sublayers = aLayer._sublayers,
1149  index = 0,
1150  count = sublayers.length;
1151 
1152  for (; index < count; ++index)
1153  _CALayerRecalculateGeometry(sublayers[index], aGeometryChange);
1154 }
1155 
1156 function _CALayerGetTransform(fromLayer, toLayer)
1157 {
1158  var transform = CGAffineTransformMakeIdentity();
1159 
1160  if (fromLayer)
1161  {
1162  var layer = fromLayer;
1163 
1164  // If we have a fromLayer, "climb up" the layer tree until
1165  // we hit the root node or we hit the toLayer.
1166  while (layer && layer != toLayer)
1167  {
1168  var transformFromLayer = layer._transformFromLayer;
1169 
1170  //transform = CGAffineTransformConcat(transform, layer._transformFromLayer);
1171  _CGAffineTransformConcatTo(transform, transformFromLayer, transform);
1172 
1173  layer = layer._superlayer;
1174  }
1175 
1176  // If we hit toLayer, then we're done.
1177  if (layer == toLayer)
1178  return transform;
1179  }
1180 
1181  var layers = [],
1182  layer = toLayer;
1183 
1184  while (layer)
1185  {
1186  layers.push(layer);
1187  layer = layer._superlayer;
1188  }
1189 
1190  var index = layers.length;
1191 
1192  while (index--)
1193  {
1194  var transformToLayer = layers[index]._transformToLayer;
1195 
1196  _CGAffineTransformConcatTo(transform, transformToLayer, transform);
1197  }
1198 
1199  return transform;
1200 }