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