• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "config.h"
2 #include "LayerAndroid.h"
3 
4 #if USE(ACCELERATED_COMPOSITING)
5 
6 #include "AndroidAnimation.h"
7 #include "ClassTracker.h"
8 #include "DrawExtra.h"
9 #include "GLUtils.h"
10 #include "ImagesManager.h"
11 #include "MediaLayer.h"
12 #include "PaintedSurface.h"
13 #include "ParseCanvas.h"
14 #include "SkBitmapRef.h"
15 #include "SkBounder.h"
16 #include "SkDrawFilter.h"
17 #include "SkPaint.h"
18 #include "SkPicture.h"
19 #include "TilesManager.h"
20 
21 #include <wtf/CurrentTime.h>
22 #include <math.h>
23 
24 #define LAYER_DEBUG // Add diagonals for debugging
25 #undef LAYER_DEBUG
26 
27 #include <cutils/log.h>
28 #include <wtf/text/CString.h>
29 #define XLOGC(...) android_printLog(ANDROID_LOG_DEBUG, "LayerAndroid", __VA_ARGS__)
30 
31 #ifdef DEBUG
32 
33 #undef XLOG
34 #define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "LayerAndroid", __VA_ARGS__)
35 
36 #else
37 
38 #undef XLOG
39 #define XLOG(...)
40 
41 #endif // DEBUG
42 
43 namespace WebCore {
44 
45 static int gUniqueId;
46 
47 class OpacityDrawFilter : public SkDrawFilter {
48 public:
OpacityDrawFilter(int opacity)49     OpacityDrawFilter(int opacity) : m_opacity(opacity) { }
filter(SkPaint * paint,Type)50     virtual void filter(SkPaint* paint, Type)
51     {
52         paint->setAlpha(m_opacity);
53     }
54 private:
55     int m_opacity;
56 };
57 
58 ///////////////////////////////////////////////////////////////////////////////
59 
LayerAndroid(RenderLayer * owner)60 LayerAndroid::LayerAndroid(RenderLayer* owner) : Layer(),
61     m_haveClip(false),
62     m_isFixed(false),
63     m_isIframe(false),
64     m_backfaceVisibility(true),
65     m_visible(true),
66     m_preserves3D(false),
67     m_anchorPointZ(0),
68     m_recordingPicture(0),
69     m_extra(0),
70     m_uniqueId(++gUniqueId),
71     m_texture(0),
72     m_imageRef(0),
73     m_imageTexture(0),
74     m_pictureUsed(0),
75     m_requestSent(false),
76     m_scale(1),
77     m_lastComputeTextureSize(0),
78     m_owningLayer(owner),
79     m_type(LayerAndroid::WebCoreLayer)
80 {
81     m_backgroundColor = 0;
82 
83     m_preserves3D = false;
84     m_dirty = false;
85     m_iframeOffset.set(0,0);
86     m_dirtyRegion.setEmpty();
87 #ifdef DEBUG_COUNT
88     ClassTracker::instance()->increment("LayerAndroid");
89     ClassTracker::instance()->add(this);
90 #endif
91 }
92 
LayerAndroid(const LayerAndroid & layer)93 LayerAndroid::LayerAndroid(const LayerAndroid& layer) : Layer(layer),
94     m_haveClip(layer.m_haveClip),
95     m_isIframe(layer.m_isIframe),
96     m_extra(0), // deliberately not copied
97     m_uniqueId(layer.m_uniqueId),
98     m_texture(0),
99     m_imageTexture(0),
100     m_requestSent(false),
101     m_owningLayer(layer.m_owningLayer),
102     m_type(LayerAndroid::UILayer)
103 {
104     m_isFixed = layer.m_isFixed;
105     m_imageRef = layer.m_imageRef;
106     if (m_imageRef)
107         ImagesManager::instance()->addImage(m_imageRef);
108     m_renderLayerPos = layer.m_renderLayerPos;
109     m_transform = layer.m_transform;
110     m_backfaceVisibility = layer.m_backfaceVisibility;
111     m_visible = layer.m_visible;
112     m_backgroundColor = layer.m_backgroundColor;
113 
114     m_fixedLeft = layer.m_fixedLeft;
115     m_fixedTop = layer.m_fixedTop;
116     m_fixedRight = layer.m_fixedRight;
117     m_fixedBottom = layer.m_fixedBottom;
118     m_fixedMarginLeft = layer.m_fixedMarginLeft;
119     m_fixedMarginTop = layer.m_fixedMarginTop;
120     m_fixedMarginRight = layer.m_fixedMarginRight;
121     m_fixedMarginBottom = layer.m_fixedMarginBottom;
122     m_fixedRect = layer.m_fixedRect;
123     m_iframeOffset = layer.m_iframeOffset;
124     m_recordingPicture = layer.m_recordingPicture;
125     SkSafeRef(m_recordingPicture);
126 
127     m_preserves3D = layer.m_preserves3D;
128     m_anchorPointZ = layer.m_anchorPointZ;
129     m_drawTransform = layer.m_drawTransform;
130     m_childrenTransform = layer.m_childrenTransform;
131     m_dirty = layer.m_dirty;
132     m_pictureUsed = layer.m_pictureUsed;
133     m_dirtyRegion = layer.m_dirtyRegion;
134     m_scale = layer.m_scale;
135     m_lastComputeTextureSize = 0;
136 
137     for (int i = 0; i < layer.countChildren(); i++)
138         addChild(layer.getChild(i)->copy())->unref();
139 
140     KeyframesMap::const_iterator end = layer.m_animations.end();
141     for (KeyframesMap::const_iterator it = layer.m_animations.begin(); it != end; ++it) {
142         pair<String, int> key((it->second)->name(), (it->second)->type());
143         m_animations.add(key, (it->second)->copy());
144     }
145 
146 #ifdef DEBUG_COUNT
147     ClassTracker::instance()->increment("LayerAndroid - recopy (UI?)");
148     ClassTracker::instance()->add(this);
149 #endif
150 }
151 
LayerAndroid(SkPicture * picture)152 LayerAndroid::LayerAndroid(SkPicture* picture) : Layer(),
153     m_haveClip(false),
154     m_isFixed(false),
155     m_isIframe(false),
156     m_recordingPicture(picture),
157     m_extra(0),
158     m_uniqueId(-1),
159     m_texture(0),
160     m_imageRef(0),
161     m_imageTexture(0),
162     m_requestSent(false),
163     m_scale(1),
164     m_lastComputeTextureSize(0),
165     m_owningLayer(0),
166     m_type(LayerAndroid::NavCacheLayer)
167 {
168     m_backgroundColor = 0;
169     m_dirty = false;
170     SkSafeRef(m_recordingPicture);
171     m_iframeOffset.set(0,0);
172     m_dirtyRegion.setEmpty();
173 #ifdef DEBUG_COUNT
174     ClassTracker::instance()->increment("LayerAndroid - from picture");
175     ClassTracker::instance()->add(this);
176 #endif
177 }
178 
~LayerAndroid()179 LayerAndroid::~LayerAndroid()
180 {
181     if (m_imageTexture)
182         ImagesManager::instance()->removeImage(m_imageTexture->imageRef());
183     delete m_extra;
184     SkSafeUnref(m_recordingPicture);
185     m_animations.clear();
186 #ifdef DEBUG_COUNT
187     ClassTracker::instance()->remove(this);
188     if (m_type == LayerAndroid::WebCoreLayer)
189         ClassTracker::instance()->decrement("LayerAndroid");
190     else if (m_type == LayerAndroid::UILayer)
191         ClassTracker::instance()->decrement("LayerAndroid - recopy (UI)");
192     else if (m_type == LayerAndroid::NavCacheLayer)
193         ClassTracker::instance()->decrement("LayerAndroid - from picture");
194 #endif
195 }
196 
197 static int gDebugNbAnims = 0;
198 
evaluateAnimations()199 bool LayerAndroid::evaluateAnimations()
200 {
201     double time = WTF::currentTime();
202     gDebugNbAnims = 0;
203     return evaluateAnimations(time);
204 }
205 
hasAnimations() const206 bool LayerAndroid::hasAnimations() const
207 {
208     for (int i = 0; i < countChildren(); i++) {
209         if (getChild(i)->hasAnimations())
210             return true;
211     }
212     return !!m_animations.size();
213 }
214 
evaluateAnimations(double time)215 bool LayerAndroid::evaluateAnimations(double time)
216 {
217     bool hasRunningAnimations = false;
218     for (int i = 0; i < countChildren(); i++) {
219         if (getChild(i)->evaluateAnimations(time))
220             hasRunningAnimations = true;
221     }
222 
223     m_hasRunningAnimations = false;
224     int nbAnims = 0;
225     KeyframesMap::const_iterator end = m_animations.end();
226     for (KeyframesMap::const_iterator it = m_animations.begin(); it != end; ++it) {
227         gDebugNbAnims++;
228         nbAnims++;
229         LayerAndroid* currentLayer = const_cast<LayerAndroid*>(this);
230         m_hasRunningAnimations |= (it->second)->evaluate(currentLayer, time);
231     }
232 
233     return hasRunningAnimations || m_hasRunningAnimations;
234 }
235 
addDirtyArea(GLWebViewState * glWebViewState)236 void LayerAndroid::addDirtyArea(GLWebViewState* glWebViewState)
237 {
238     IntSize layerSize(getSize().width(), getSize().height());
239 
240     FloatRect area = TilesManager::instance()->shader()->rectInInvScreenCoord(m_drawTransform, layerSize);
241     FloatRect clip = TilesManager::instance()->shader()->convertScreenCoordToInvScreenCoord(m_clippingRect);
242 
243     area.intersect(clip);
244     IntRect dirtyArea(area.x(), area.y(), area.width(), area.height());
245     glWebViewState->addDirtyArea(dirtyArea);
246 }
247 
addAnimation(PassRefPtr<AndroidAnimation> prpAnim)248 void LayerAndroid::addAnimation(PassRefPtr<AndroidAnimation> prpAnim)
249 {
250     RefPtr<AndroidAnimation> anim = prpAnim;
251     pair<String, int> key(anim->name(), anim->type());
252     removeAnimationsForProperty(anim->type());
253     m_animations.add(key, anim);
254 }
255 
removeAnimationsForProperty(AnimatedPropertyID property)256 void LayerAndroid::removeAnimationsForProperty(AnimatedPropertyID property)
257 {
258     KeyframesMap::const_iterator end = m_animations.end();
259     Vector<pair<String, int> > toDelete;
260     for (KeyframesMap::const_iterator it = m_animations.begin(); it != end; ++it) {
261         if ((it->second)->type() == property)
262             toDelete.append(it->first);
263     }
264 
265     for (unsigned int i = 0; i < toDelete.size(); i++)
266         m_animations.remove(toDelete[i]);
267 }
268 
removeAnimationsForKeyframes(const String & name)269 void LayerAndroid::removeAnimationsForKeyframes(const String& name)
270 {
271     KeyframesMap::const_iterator end = m_animations.end();
272     Vector<pair<String, int> > toDelete;
273     for (KeyframesMap::const_iterator it = m_animations.begin(); it != end; ++it) {
274         if ((it->second)->name() == name)
275             toDelete.append(it->first);
276     }
277 
278     for (unsigned int i = 0; i < toDelete.size(); i++)
279             m_animations.remove(toDelete[i]);
280 }
281 
282 // We only use the bounding rect of the layer as mask...
283 // FIXME: use a real mask?
setMaskLayer(LayerAndroid * layer)284 void LayerAndroid::setMaskLayer(LayerAndroid* layer)
285 {
286     if (layer)
287         m_haveClip = true;
288 }
289 
setBackgroundColor(SkColor color)290 void LayerAndroid::setBackgroundColor(SkColor color)
291 {
292     m_backgroundColor = color;
293 }
294 
295 static int gDebugChildLevel;
296 
translation() const297 FloatPoint LayerAndroid::translation() const
298 {
299     TransformationMatrix::DecomposedType tDecomp;
300     m_transform.decompose(tDecomp);
301     FloatPoint p(tDecomp.translateX, tDecomp.translateY);
302     return p;
303 }
304 
bounds() const305 SkRect LayerAndroid::bounds() const
306 {
307     SkRect rect;
308     bounds(&rect);
309     return rect;
310 }
311 
bounds(SkRect * rect) const312 void LayerAndroid::bounds(SkRect* rect) const
313 {
314     const SkPoint& pos = this->getPosition();
315     const SkSize& size = this->getSize();
316 
317     // The returned rect has the translation applied
318     // FIXME: apply the full transform to the rect,
319     // and fix the text selection accordingly
320     FloatPoint p(pos.fX, pos.fY);
321     p = m_transform.mapPoint(p);
322     rect->fLeft = p.x();
323     rect->fTop = p.y();
324     rect->fRight = p.x() + size.width();
325     rect->fBottom = p.y() + size.height();
326 }
327 
boundsIsUnique(const SkTDArray<SkRect> & region,const SkRect & local)328 static bool boundsIsUnique(const SkTDArray<SkRect>& region,
329                            const SkRect& local)
330 {
331     for (int i = 0; i < region.count(); i++) {
332         if (region[i].contains(local))
333             return false;
334     }
335     return true;
336 }
337 
clipArea(SkTDArray<SkRect> * region) const338 void LayerAndroid::clipArea(SkTDArray<SkRect>* region) const
339 {
340     SkRect local;
341     local.set(0, 0, std::numeric_limits<float>::max(),
342         std::numeric_limits<float>::max());
343     clipInner(region, local);
344 }
345 
clipInner(SkTDArray<SkRect> * region,const SkRect & local) const346 void LayerAndroid::clipInner(SkTDArray<SkRect>* region,
347                              const SkRect& local) const
348 {
349     SkRect localBounds;
350     bounds(&localBounds);
351     localBounds.intersect(local);
352     if (localBounds.isEmpty())
353         return;
354     if (m_recordingPicture && boundsIsUnique(*region, localBounds))
355         *region->append() = localBounds;
356     for (int i = 0; i < countChildren(); i++)
357         getChild(i)->clipInner(region, m_haveClip ? localBounds : local);
358 }
359 
360 class FindCheck : public SkBounder {
361 public:
FindCheck()362     FindCheck()
363         : m_drew(false)
364         , m_drewText(false)
365     {
366     }
367 
drew() const368     bool drew() const { return m_drew; }
drewText() const369     bool drewText() const { return m_drewText; }
reset()370     void reset() { m_drew = m_drewText = false; }
371 
372 protected:
onIRect(const SkIRect &)373     virtual bool onIRect(const SkIRect& )
374     {
375         m_drew = true;
376         return false;
377     }
378 
onIRectGlyph(const SkIRect &,const SkBounder::GlyphRec &)379     virtual bool onIRectGlyph(const SkIRect& , const SkBounder::GlyphRec& )
380     {
381         m_drew = m_drewText = true;
382         return false;
383     }
384 
385     bool m_drew;
386     bool m_drewText;
387 };
388 
389 class FindCanvas : public ParseCanvas {
390 public:
draw(SkPicture * picture,SkScalar offsetX,SkScalar offsetY)391     void draw(SkPicture* picture, SkScalar offsetX, SkScalar offsetY)
392     {
393         save();
394         translate(-offsetX, -offsetY);
395         picture->draw(this);
396         restore();
397     }
398 };
399 
400 class LayerAndroid::FindState {
401 public:
402     static const int TOUCH_SLOP = 10;
403 
FindState(int x,int y)404     FindState(int x, int y)
405         : m_x(x)
406         , m_y(y)
407         , m_bestX(x)
408         , m_bestY(y)
409         , m_best(0)
410     {
411         m_bitmap.setConfig(SkBitmap::kARGB_8888_Config, TOUCH_SLOP * 2,
412              TOUCH_SLOP * 2);
413         m_checker.setBounder(&m_findCheck);
414         m_checker.setBitmapDevice(m_bitmap);
415     }
416 
best() const417     const LayerAndroid* best() const { return m_best; }
bestX() const418     int bestX() const { return m_bestX; }
bestY() const419     int bestY() const { return m_bestY; }
420 
drew(SkPicture * picture,const SkRect & localBounds)421     bool drew(SkPicture* picture, const SkRect& localBounds)
422     {
423         m_findCheck.reset();
424         SkScalar localX = SkIntToScalar(m_x - TOUCH_SLOP) - localBounds.fLeft;
425         SkScalar localY = SkIntToScalar(m_y - TOUCH_SLOP) - localBounds.fTop;
426         m_checker.draw(picture, localX, localY);
427         return m_findCheck.drew();
428     }
429 
drewText()430     bool drewText() { return m_findCheck.drewText(); }
431 
setBest(const LayerAndroid * best,int x,int y)432     void setBest(const LayerAndroid* best, int x, int y)
433     {
434         m_best = best;
435         m_bestX = x;
436         m_bestY = y;
437     }
x() const438     int x() const { return m_x; }
y() const439     int y() const { return m_y; }
440 
setLocation(int x,int y)441     void setLocation(int x, int y)
442     {
443         m_x = x;
444         m_y = y;
445     }
446 
447 protected:
448     int m_x;
449     int m_y;
450     int m_bestX;
451     int m_bestY;
452     const LayerAndroid* m_best;
453     FindCheck m_findCheck;
454     SkBitmap m_bitmap;
455     FindCanvas m_checker;
456 };
457 
findInner(LayerAndroid::FindState & state) const458 void LayerAndroid::findInner(LayerAndroid::FindState& state) const
459 {
460     int x = state.x();
461     int y = state.y();
462     SkRect localBounds;
463     bounds(&localBounds);
464     if (!localBounds.contains(x, y))
465         return;
466     // Move into local coordinates.
467     state.setLocation(x - localBounds.fLeft, y - localBounds.fTop);
468     for (int i = 0; i < countChildren(); i++)
469         getChild(i)->findInner(state);
470     // Move back into the parent coordinates.
471     int testX = state.x();
472     int testY = state.y();
473     state.setLocation(x + localBounds.fLeft, y + localBounds.fTop);
474     if (!m_recordingPicture)
475         return;
476     if (!contentIsScrollable() && !state.drew(m_recordingPicture, localBounds))
477         return;
478     state.setBest(this, testX, testY); // set last match (presumably on top)
479 }
480 
find(int * xPtr,int * yPtr,SkPicture * root) const481 const LayerAndroid* LayerAndroid::find(int* xPtr, int* yPtr, SkPicture* root) const
482 {
483     FindState state(*xPtr, *yPtr);
484     SkRect rootBounds;
485     rootBounds.setEmpty();
486     if (root && state.drew(root, rootBounds) && state.drewText())
487         return 0; // use the root picture only if it contains the text
488     findInner(state);
489     *xPtr = state.bestX();
490     *yPtr = state.bestY();
491     return state.best();
492 }
493 
494 ///////////////////////////////////////////////////////////////////////////////
495 
updateFixedLayersPositions(SkRect viewport,LayerAndroid * parentIframeLayer)496 void LayerAndroid::updateFixedLayersPositions(SkRect viewport, LayerAndroid* parentIframeLayer)
497 {
498     XLOG("updating fixed positions, using viewport %fx%f - %fx%f",
499          viewport.fLeft, viewport.fTop,
500          viewport.width(), viewport.height());
501     // If this is an iframe, accumulate the offset from the parent with
502     // current position, and change the parent pointer.
503     if (m_isIframe) {
504         // If this is the top level, take the current position
505         SkPoint parentOffset;
506         parentOffset.set(0,0);
507         if (parentIframeLayer)
508             parentOffset = parentIframeLayer->getPosition();
509 
510         m_iframeOffset = parentOffset + getPosition();
511 
512         parentIframeLayer = this;
513     }
514 
515     if (m_isFixed) {
516         // So if this is a fixed layer inside a iframe, use the iframe offset
517         // and the iframe's size as the viewport and pass to the children
518         if (parentIframeLayer) {
519             viewport = SkRect::MakeXYWH(parentIframeLayer->m_iframeOffset.fX,
520                                  parentIframeLayer->m_iframeOffset.fY,
521                                  parentIframeLayer->getSize().width(),
522                                  parentIframeLayer->getSize().height());
523         }
524         float w = viewport.width();
525         float h = viewport.height();
526         float dx = viewport.fLeft;
527         float dy = viewport.fTop;
528         float x = dx;
529         float y = dy;
530 
531         // It turns out that when it is 'auto', we should use the webkit value
532         // from the original render layer's X,Y, that will take care of alignment
533         // with the parent's layer and fix Margin etc.
534         if (!(m_fixedLeft.defined() || m_fixedRight.defined()))
535             x += m_renderLayerPos.x();
536         else if (m_fixedLeft.defined() || !m_fixedRight.defined())
537             x += m_fixedMarginLeft.calcFloatValue(w) + m_fixedLeft.calcFloatValue(w) - m_fixedRect.fLeft;
538         else
539             x += w - m_fixedMarginRight.calcFloatValue(w) - m_fixedRight.calcFloatValue(w) - m_fixedRect.fRight;
540 
541         if (!(m_fixedTop.defined() || m_fixedBottom.defined()))
542             y += m_renderLayerPos.y();
543         else if (m_fixedTop.defined() || !m_fixedBottom.defined())
544             y += m_fixedMarginTop.calcFloatValue(h) + m_fixedTop.calcFloatValue(h) - m_fixedRect.fTop;
545         else
546             y += h - m_fixedMarginBottom.calcFloatValue(h) - m_fixedBottom.calcFloatValue(h) - m_fixedRect.fBottom;
547 
548         this->setPosition(x, y);
549     }
550 
551     int count = this->countChildren();
552     for (int i = 0; i < count; i++)
553         this->getChild(i)->updateFixedLayersPositions(viewport, parentIframeLayer);
554 }
555 
updatePositions()556 void LayerAndroid::updatePositions()
557 {
558     // apply the viewport to us
559     if (!m_isFixed) {
560         // turn our fields into a matrix.
561         //
562         // FIXME: this should happen in the caller, and we should remove these
563         // fields from our subclass
564         SkMatrix matrix;
565         GLUtils::toSkMatrix(matrix, m_transform);
566         this->setMatrix(matrix);
567     }
568 
569     // now apply it to our children
570     int count = this->countChildren();
571     for (int i = 0; i < count; i++)
572         this->getChild(i)->updatePositions();
573 }
574 
updateGLPositionsAndScale(const TransformationMatrix & parentMatrix,const FloatRect & clipping,float opacity,float scale)575 void LayerAndroid::updateGLPositionsAndScale(const TransformationMatrix& parentMatrix,
576                                              const FloatRect& clipping, float opacity, float scale)
577 {
578     m_atomicSync.lock();
579     IntSize layerSize(getSize().width(), getSize().height());
580     FloatPoint anchorPoint(getAnchorPoint().fX, getAnchorPoint().fY);
581     FloatPoint position(getPosition().fX, getPosition().fY);
582     float centerOffsetX = (0.5f - anchorPoint.x()) * layerSize.width();
583     float centerOffsetY = (0.5f - anchorPoint.y()) * layerSize.height();
584     float originX = anchorPoint.x() * layerSize.width();
585     float originY = anchorPoint.y() * layerSize.height();
586     TransformationMatrix localMatrix;
587     if (!m_isFixed)
588         localMatrix = parentMatrix;
589     localMatrix.translate3d(originX + position.x(),
590                             originY + position.y(),
591                             anchorPointZ());
592     localMatrix.multiply(m_transform);
593     localMatrix.translate3d(-originX,
594                             -originY,
595                             -anchorPointZ());
596 
597     m_atomicSync.unlock();
598     setDrawTransform(localMatrix);
599     if (m_drawTransform.isIdentityOrTranslation()) {
600         // adjust the translation coordinates of the draw transform matrix so
601         // that layers (defined in content coordinates) will align to display/view pixels
602         float desiredContentX = round(m_drawTransform.m41() * scale) / scale;
603         float desiredContentY = round(m_drawTransform.m42() * scale) / scale;
604         XLOG("fudging translation from %f, %f to %f, %f",
605              m_drawTransform.m41(), m_drawTransform.m42(),
606              desiredContentX, desiredContentY);
607         m_drawTransform.setM41(desiredContentX);
608         m_drawTransform.setM42(desiredContentY);
609     }
610 
611     m_zValue = TilesManager::instance()->shader()->zValue(m_drawTransform, getSize().width(), getSize().height());
612 
613     m_atomicSync.lock();
614     m_scale = scale;
615     m_atomicSync.unlock();
616 
617     opacity *= getOpacity();
618     setDrawOpacity(opacity);
619 
620     if (m_haveClip) {
621         // The clipping rect calculation and intersetion will be done in Screen Coord now.
622         FloatRect clip =
623             TilesManager::instance()->shader()->rectInScreenCoord(m_drawTransform, layerSize);
624         clip.intersect(clipping);
625         setDrawClip(clip);
626     } else {
627         setDrawClip(clipping);
628     }
629 
630     if (!m_backfaceVisibility
631          && m_drawTransform.inverse().m33() < 0) {
632          setVisible(false);
633          return;
634     } else {
635          setVisible(true);
636     }
637 
638     int count = this->countChildren();
639     if (!count)
640         return;
641 
642     // Flatten to 2D if the layer doesn't preserve 3D.
643     if (!preserves3D()) {
644         localMatrix.setM13(0);
645         localMatrix.setM23(0);
646         localMatrix.setM31(0);
647         localMatrix.setM32(0);
648         localMatrix.setM33(1);
649         localMatrix.setM34(0);
650         localMatrix.setM43(0);
651     }
652 
653     // now apply it to our children
654 
655     if (!m_childrenTransform.isIdentity()) {
656         localMatrix.translate(getSize().width() * 0.5f, getSize().height() * 0.5f);
657         localMatrix.multiply(m_childrenTransform);
658         localMatrix.translate(-getSize().width() * 0.5f, -getSize().height() * 0.5f);
659     }
660     for (int i = 0; i < count; i++)
661         this->getChild(i)->updateGLPositionsAndScale(localMatrix, drawClip(), opacity, scale);
662 }
663 
setContentsImage(SkBitmapRef * img)664 void LayerAndroid::setContentsImage(SkBitmapRef* img)
665 {
666     m_imageRef = img;
667     if (!img)
668         return;
669 
670     ImagesManager::instance()->addImage(img);
671 }
672 
needsTexture()673 bool LayerAndroid::needsTexture()
674 {
675     return m_imageRef || (prepareContext()
676         && m_recordingPicture->width() && m_recordingPicture->height());
677 }
678 
removeTexture(PaintedSurface * texture)679 void LayerAndroid::removeTexture(PaintedSurface* texture)
680 {
681     if (texture == m_texture)
682         m_texture = 0;
683 }
684 
clippedRect() const685 IntRect LayerAndroid::clippedRect() const
686 {
687     IntRect r(0, 0, getWidth(), getHeight());
688     IntRect tr = m_drawTransform.mapRect(r);
689     IntRect cr = TilesManager::instance()->shader()->clippedRectWithViewport(tr);
690     IntRect rect = m_drawTransform.inverse().mapRect(cr);
691     return rect;
692 }
693 
nbLayers()694 int LayerAndroid::nbLayers()
695 {
696     int nb = 0;
697     int count = this->countChildren();
698     for (int i = 0; i < count; i++)
699         nb += this->getChild(i)->nbLayers();
700     return nb+1;
701 }
702 
nbTexturedLayers()703 int LayerAndroid::nbTexturedLayers()
704 {
705     int nb = 0;
706     int count = this->countChildren();
707     for (int i = 0; i < count; i++)
708         nb += this->getChild(i)->nbTexturedLayers();
709     if (needsTexture())
710         nb++;
711     return nb;
712 }
713 
showLayer(int indent)714 void LayerAndroid::showLayer(int indent)
715 {
716     char spaces[256];
717     memset(spaces, 0, 256);
718     for (int i = 0; i < indent; i++)
719         spaces[i] = ' ';
720 
721     if (!indent)
722         XLOGC("\n\n--- LAYERS TREE ---");
723 
724     IntRect r(0, 0, getWidth(), getHeight());
725     IntRect tr = m_drawTransform.mapRect(r);
726     XLOGC("%s [%d:0x%x] - %s - (%d, %d, %d, %d) %s prepareContext(%d), pic w: %d h: %d",
727           spaces, uniqueId(), m_owningLayer,
728           needsTexture() ? "needs a texture" : "no texture",
729           tr.x(), tr.y(), tr.width(), tr.height(),
730           contentIsScrollable() ? "SCROLLABLE" : "",
731           prepareContext(),
732           m_recordingPicture ? m_recordingPicture->width() : -1,
733           m_recordingPicture ? m_recordingPicture->height() : -1);
734 
735     int count = this->countChildren();
736     for (int i = 0; i < count; i++)
737         this->getChild(i)->showLayer(indent + 1);
738 }
739 
740 // We go through our tree, and if we have layer in the new
741 // tree that is similar, we transfer our texture to it.
742 // Otherwise, we remove ourselves from the texture so
743 // that TilesManager::swapLayersTextures() have a chance
744 // at deallocating the textures (PaintedSurfaces)
assignTextureTo(LayerAndroid * newTree)745 void LayerAndroid::assignTextureTo(LayerAndroid* newTree)
746 {
747     int count = this->countChildren();
748     for (int i = 0; i < count; i++)
749         this->getChild(i)->assignTextureTo(newTree);
750 
751     if (newTree) {
752         LayerAndroid* newLayer = newTree->findById(uniqueId());
753         if (newLayer == this)
754             return;
755         if (newLayer && m_texture) {
756             m_texture->replaceLayer(newLayer);
757             newLayer->m_texture = m_texture;
758             m_texture = 0;
759         }
760         if (!newLayer && m_texture) {
761             m_texture->removeLayer(this);
762             m_texture = 0;
763         }
764     }
765 }
766 
updateWithTree(LayerAndroid * newTree)767 bool LayerAndroid::updateWithTree(LayerAndroid* newTree)
768 {
769 // Disable fast update for now
770 #if (0)
771     bool needsRepaint = false;
772     int count = this->countChildren();
773     for (int i = 0; i < count; i++)
774         needsRepaint |= this->getChild(i)->updateWithTree(newTree);
775 
776     if (newTree) {
777         LayerAndroid* newLayer = newTree->findById(uniqueId());
778         needsRepaint |= updateWithLayer(newLayer);
779     }
780     return needsRepaint;
781 #else
782     return true;
783 #endif
784 }
785 
786 // Return true to indicate to WebViewCore that the updates
787 // are too complicated to be fully handled and we need a full
788 // call to webkit (e.g. handle repaints)
updateWithLayer(LayerAndroid * layer)789 bool LayerAndroid::updateWithLayer(LayerAndroid* layer)
790 {
791     if (!layer)
792         return true;
793 
794     android::AutoMutex lock(m_atomicSync);
795     m_position = layer->m_position;
796     m_anchorPoint = layer->m_anchorPoint;
797     m_size = layer->m_size;
798     m_opacity = layer->m_opacity;
799     m_transform = layer->m_transform;
800 
801     if (m_imageRef != layer->m_imageRef)
802         m_visible = false;
803 
804     if ((m_recordingPicture != layer->m_recordingPicture)
805         || (m_imageRef != layer->m_imageRef))
806         return true;
807 
808     return false;
809 }
810 
createTexture()811 void LayerAndroid::createTexture()
812 {
813     int count = this->countChildren();
814     for (int i = 0; i < count; i++)
815         this->getChild(i)->createTexture();
816 
817     if (!needsTexture())
818         return;
819 
820     if (m_imageRef) {
821         if (!m_imageTexture) {
822             m_imageTexture = ImagesManager::instance()->getTextureForImage(m_imageRef);
823             m_dirtyRegion.setEmpty();
824         }
825         if (m_texture) {
826             m_texture->removeLayer(this);
827             m_texture = 0;
828         }
829     } else {
830         if (!m_texture)
831             m_texture = new PaintedSurface(this);
832 
833         // pass the invalidated regions to the PaintedSurface
834         m_texture->markAsDirty(m_dirtyRegion);
835         m_dirtyRegion.setEmpty();
836     }
837 }
838 
compareLayerZ(const LayerAndroid * a,const LayerAndroid * b)839 static inline bool compareLayerZ(const LayerAndroid* a, const LayerAndroid* b)
840 {
841     return a->zValue() > b->zValue();
842 }
843 
markAsDirty(const SkRegion & dirtyArea)844 void LayerAndroid::markAsDirty(const SkRegion& dirtyArea)
845 {
846     m_dirtyRegion.op(dirtyArea, SkRegion::kUnion_Op);
847 }
848 
849 // We call this in WebViewCore, when copying the tree of layers.
850 // As we construct a new tree that will be passed on the UI,
851 // we mark the webkit-side tree as having no more dirty region
852 // (otherwise we would continuously have those dirty region UI-side)
clearDirtyRegion()853 void LayerAndroid::clearDirtyRegion()
854 {
855     int count = this->countChildren();
856     for (int i = 0; i < count; i++)
857         this->getChild(i)->clearDirtyRegion();
858 
859     m_dirtyRegion.setEmpty();
860 }
861 
prepare(GLWebViewState * glWebViewState)862 void LayerAndroid::prepare(GLWebViewState* glWebViewState)
863 {
864     m_state = glWebViewState;
865 
866     int count = this->countChildren();
867     if (count > 0) {
868         Vector <LayerAndroid*> sublayers;
869         for (int i = 0; i < count; i++)
870             sublayers.append(this->getChild(i));
871 
872         // now we sort for the transparency
873         std::stable_sort(sublayers.begin(), sublayers.end(), compareLayerZ);
874 
875         // iterate in reverse so top layers get textures first
876         for (int i = count-1; i >= 0; i--)
877             sublayers[i]->prepare(glWebViewState);
878     }
879 
880     if (m_texture)
881         m_texture->prepare(glWebViewState);
882 
883     if (m_imageTexture)
884         m_imageTexture->prepareGL();
885 }
886 
drawGL(GLWebViewState * glWebViewState,SkMatrix & matrix)887 bool LayerAndroid::drawGL(GLWebViewState* glWebViewState, SkMatrix& matrix)
888 {
889     TilesManager::instance()->shader()->clip(m_clippingRect);
890     if (!m_visible)
891         return false;
892 
893     bool askScreenUpdate = false;
894 
895     if (m_texture)
896         askScreenUpdate |= m_texture->draw();
897 
898     if (m_imageTexture)
899         m_imageTexture->drawGL(this);
900 
901     // When the layer is dirty, the UI thread should be notified to redraw.
902     askScreenUpdate |= drawChildrenGL(glWebViewState, matrix);
903     m_atomicSync.lock();
904     askScreenUpdate |= m_dirty;
905     if (askScreenUpdate || m_hasRunningAnimations || m_drawTransform.hasPerspective())
906         addDirtyArea(glWebViewState);
907 
908     m_atomicSync.unlock();
909     return askScreenUpdate;
910 }
911 
drawChildrenGL(GLWebViewState * glWebViewState,SkMatrix & matrix)912 bool LayerAndroid::drawChildrenGL(GLWebViewState* glWebViewState, SkMatrix& matrix)
913 {
914     bool askScreenUpdate = false;
915     int count = this->countChildren();
916     if (count > 0) {
917         Vector <LayerAndroid*> sublayers;
918         for (int i = 0; i < count; i++)
919             sublayers.append(this->getChild(i));
920 
921         // now we sort for the transparency
922         std::stable_sort(sublayers.begin(), sublayers.end(), compareLayerZ);
923         for (int i = 0; i < count; i++) {
924             LayerAndroid* layer = sublayers[i];
925             askScreenUpdate |= layer->drawGL(glWebViewState, matrix);
926         }
927     }
928 
929     return askScreenUpdate;
930 }
931 
extraDraw(SkCanvas * canvas)932 void LayerAndroid::extraDraw(SkCanvas* canvas)
933 {
934     m_atomicSync.lock();
935     if (m_extra)
936         canvas->drawPicture(*m_extra);
937     m_atomicSync.unlock();
938 }
939 
contentDraw(SkCanvas * canvas)940 void LayerAndroid::contentDraw(SkCanvas* canvas)
941 {
942     if (m_recordingPicture)
943       canvas->drawPicture(*m_recordingPicture);
944 
945     if (TilesManager::instance()->getShowVisualIndicator()) {
946         float w = getSize().width();
947         float h = getSize().height();
948         SkPaint paint;
949         paint.setARGB(128, 255, 0, 0);
950         canvas->drawLine(0, 0, w, h, paint);
951         canvas->drawLine(0, h, w, 0, paint);
952         paint.setARGB(128, 0, 255, 0);
953         canvas->drawLine(0, 0, 0, h, paint);
954         canvas->drawLine(0, h, w, h, paint);
955         canvas->drawLine(w, h, w, 0, paint);
956         canvas->drawLine(w, 0, 0, 0, paint);
957 
958         if (m_isFixed) {
959           SkPaint paint;
960           paint.setARGB(80, 255, 0, 0);
961           canvas->drawRect(m_fixedRect, paint);
962         }
963     }
964 }
965 
onDraw(SkCanvas * canvas,SkScalar opacity)966 void LayerAndroid::onDraw(SkCanvas* canvas, SkScalar opacity)
967 {
968     if (m_haveClip) {
969         SkRect r;
970         r.set(0, 0, getSize().width(), getSize().height());
971         canvas->clipRect(r);
972         return;
973     }
974 
975     if (!prepareContext())
976         return;
977 
978     // we just have this save/restore for opacity...
979     SkAutoCanvasRestore restore(canvas, true);
980 
981     int canvasOpacity = SkScalarRound(opacity * 255);
982     if (canvasOpacity < 255)
983         canvas->setDrawFilter(new OpacityDrawFilter(canvasOpacity));
984 
985     if (m_imageRef) {
986         if (!m_imageTexture) {
987             m_imageTexture = ImagesManager::instance()->getTextureForImage(m_imageRef);
988             m_dirtyRegion.setEmpty();
989         }
990         if (m_imageTexture) {
991             SkRect dest;
992             dest.set(0, 0, getSize().width(), getSize().height());
993             m_imageTexture->drawCanvas(canvas, dest);
994         }
995     }
996     contentDraw(canvas);
997 }
998 
recordContext()999 SkPicture* LayerAndroid::recordContext()
1000 {
1001     if (prepareContext(true))
1002         return m_recordingPicture;
1003     return 0;
1004 }
1005 
prepareContext(bool force)1006 bool LayerAndroid::prepareContext(bool force)
1007 {
1008     if (masksToBounds())
1009         return false;
1010 
1011     if (force || !m_recordingPicture ||
1012         (m_recordingPicture &&
1013          ((m_recordingPicture->width() != (int) getSize().width()) ||
1014           (m_recordingPicture->height() != (int) getSize().height())))) {
1015         SkSafeUnref(m_recordingPicture);
1016         m_recordingPicture = new SkPicture();
1017     }
1018 
1019     return m_recordingPicture;
1020 }
1021 
subtractLayers(const SkRect & visibleRect) const1022 SkRect LayerAndroid::subtractLayers(const SkRect& visibleRect) const
1023 {
1024     SkRect result;
1025     if (m_recordingPicture) {
1026         // FIXME: This seems wrong. localToGlobal() applies the full local transform,
1027         // se surely we should operate globalMatrix on size(), not bounds() with
1028         // the position removed? Perhaps we never noticed the bug because most
1029         // layers don't use a local transform?
1030         // See http://b/5338388
1031         SkRect globalRect = bounds();
1032         globalRect.offset(-getPosition()); // localToGlobal adds in position
1033         SkMatrix globalMatrix;
1034         localToGlobal(&globalMatrix);
1035         globalMatrix.mapRect(&globalRect);
1036         SkIRect roundedGlobal;
1037         globalRect.round(&roundedGlobal);
1038         SkIRect iVisibleRect;
1039         visibleRect.round(&iVisibleRect);
1040         SkRegion visRegion(iVisibleRect);
1041         visRegion.op(roundedGlobal, SkRegion::kDifference_Op);
1042         result.set(visRegion.getBounds());
1043 #if DEBUG_NAV_UI
1044         SkDebugf("%s visibleRect=(%g,%g,r=%g,b=%g) globalRect=(%g,%g,r=%g,b=%g)"
1045             "result=(%g,%g,r=%g,b=%g)", __FUNCTION__,
1046             visibleRect.fLeft, visibleRect.fTop,
1047             visibleRect.fRight, visibleRect.fBottom,
1048             globalRect.fLeft, globalRect.fTop,
1049             globalRect.fRight, globalRect.fBottom,
1050             result.fLeft, result.fTop, result.fRight, result.fBottom);
1051 #endif
1052     } else
1053         result = visibleRect;
1054     for (int i = 0; i < countChildren(); i++)
1055         result = getChild(i)->subtractLayers(result);
1056     return result;
1057 }
1058 
1059 // Debug tools : dump the layers tree in a file.
1060 // The format is simple:
1061 // properties have the form: key = value;
1062 // all statements are finished with a semi-colon.
1063 // value can be:
1064 // - int
1065 // - float
1066 // - array of elements
1067 // - composed type
1068 // a composed type enclose properties in { and }
1069 // an array enclose composed types in { }, separated with a comma.
1070 // exemple:
1071 // {
1072 //   x = 3;
1073 //   y = 4;
1074 //   value = {
1075 //     x = 3;
1076 //     y = 4;
1077 //   };
1078 //   anarray = [
1079 //     { x = 3; },
1080 //     { y = 4; }
1081 //   ];
1082 // }
1083 
lwrite(FILE * file,const char * str)1084 void lwrite(FILE* file, const char* str)
1085 {
1086     fwrite(str, sizeof(char), strlen(str), file);
1087 }
1088 
writeIndent(FILE * file,int indentLevel)1089 void writeIndent(FILE* file, int indentLevel)
1090 {
1091     if (indentLevel)
1092         fprintf(file, "%*s", indentLevel*2, " ");
1093 }
1094 
writeln(FILE * file,int indentLevel,const char * str)1095 void writeln(FILE* file, int indentLevel, const char* str)
1096 {
1097     writeIndent(file, indentLevel);
1098     lwrite(file, str);
1099     lwrite(file, "\n");
1100 }
1101 
writeIntVal(FILE * file,int indentLevel,const char * str,int value)1102 void writeIntVal(FILE* file, int indentLevel, const char* str, int value)
1103 {
1104     writeIndent(file, indentLevel);
1105     fprintf(file, "%s = %d;\n", str, value);
1106 }
1107 
writeHexVal(FILE * file,int indentLevel,const char * str,int value)1108 void writeHexVal(FILE* file, int indentLevel, const char* str, int value)
1109 {
1110     writeIndent(file, indentLevel);
1111     fprintf(file, "%s = %x;\n", str, value);
1112 }
1113 
writeFloatVal(FILE * file,int indentLevel,const char * str,float value)1114 void writeFloatVal(FILE* file, int indentLevel, const char* str, float value)
1115 {
1116     writeIndent(file, indentLevel);
1117     fprintf(file, "%s = %.3f;\n", str, value);
1118 }
1119 
writePoint(FILE * file,int indentLevel,const char * str,SkPoint point)1120 void writePoint(FILE* file, int indentLevel, const char* str, SkPoint point)
1121 {
1122     writeIndent(file, indentLevel);
1123     fprintf(file, "%s = { x = %.3f; y = %.3f; };\n", str, point.fX, point.fY);
1124 }
1125 
writeSize(FILE * file,int indentLevel,const char * str,SkSize size)1126 void writeSize(FILE* file, int indentLevel, const char* str, SkSize size)
1127 {
1128     writeIndent(file, indentLevel);
1129     fprintf(file, "%s = { w = %.3f; h = %.3f; };\n", str, size.width(), size.height());
1130 }
1131 
writeRect(FILE * file,int indentLevel,const char * str,SkRect rect)1132 void writeRect(FILE* file, int indentLevel, const char* str, SkRect rect)
1133 {
1134     writeIndent(file, indentLevel);
1135     fprintf(file, "%s = { x = %.3f; y = %.3f; w = %.3f; h = %.3f; };\n",
1136             str, rect.fLeft, rect.fTop, rect.width(), rect.height());
1137 }
1138 
writeLength(FILE * file,int indentLevel,const char * str,SkLength length)1139 void writeLength(FILE* file, int indentLevel, const char* str, SkLength length)
1140 {
1141     if (!length.defined())
1142         return;
1143     writeIndent(file, indentLevel);
1144     fprintf(file, "%s = { type = %d; value = %.2f; };\n", str, length.type, length.value);
1145 }
1146 
writeMatrix(FILE * file,int indentLevel,const char * str,const TransformationMatrix & matrix)1147 void writeMatrix(FILE* file, int indentLevel, const char* str, const TransformationMatrix& matrix)
1148 {
1149     writeIndent(file, indentLevel);
1150     fprintf(file, "%s = { (%.2f,%.2f,%.2f,%.2f),(%.2f,%.2f,%.2f,%.2f),"
1151             "(%.2f,%.2f,%.2f,%.2f),(%.2f,%.2f,%.2f,%.2f) };\n",
1152             str,
1153             matrix.m11(), matrix.m12(), matrix.m13(), matrix.m14(),
1154             matrix.m21(), matrix.m22(), matrix.m23(), matrix.m24(),
1155             matrix.m31(), matrix.m32(), matrix.m33(), matrix.m34(),
1156             matrix.m41(), matrix.m42(), matrix.m43(), matrix.m44());
1157 }
1158 
dumpLayers(FILE * file,int indentLevel) const1159 void LayerAndroid::dumpLayers(FILE* file, int indentLevel) const
1160 {
1161     writeln(file, indentLevel, "{");
1162 
1163     writeHexVal(file, indentLevel + 1, "layer", (int)this);
1164     writeIntVal(file, indentLevel + 1, "layerId", m_uniqueId);
1165     writeIntVal(file, indentLevel + 1, "haveClip", m_haveClip);
1166     writeIntVal(file, indentLevel + 1, "isFixed", m_isFixed);
1167     writeIntVal(file, indentLevel + 1, "m_isIframe", m_isIframe);
1168     writePoint(file, indentLevel + 1, "m_iframeOffset", m_iframeOffset);
1169 
1170     writeFloatVal(file, indentLevel + 1, "opacity", getOpacity());
1171     writeSize(file, indentLevel + 1, "size", getSize());
1172     writePoint(file, indentLevel + 1, "position", getPosition());
1173     writePoint(file, indentLevel + 1, "anchor", getAnchorPoint());
1174 
1175     writeMatrix(file, indentLevel + 1, "drawMatrix", m_drawTransform);
1176     writeMatrix(file, indentLevel + 1, "transformMatrix", m_transform);
1177     writeRect(file, indentLevel + 1, "clippingRect", SkRect(m_clippingRect));
1178 
1179     if (m_isFixed) {
1180         writeLength(file, indentLevel + 1, "fixedLeft", m_fixedLeft);
1181         writeLength(file, indentLevel + 1, "fixedTop", m_fixedTop);
1182         writeLength(file, indentLevel + 1, "fixedRight", m_fixedRight);
1183         writeLength(file, indentLevel + 1, "fixedBottom", m_fixedBottom);
1184         writeLength(file, indentLevel + 1, "fixedMarginLeft", m_fixedMarginLeft);
1185         writeLength(file, indentLevel + 1, "fixedMarginTop", m_fixedMarginTop);
1186         writeLength(file, indentLevel + 1, "fixedMarginRight", m_fixedMarginRight);
1187         writeLength(file, indentLevel + 1, "fixedMarginBottom", m_fixedMarginBottom);
1188         writeRect(file, indentLevel + 1, "fixedRect", m_fixedRect);
1189     }
1190 
1191     if (m_recordingPicture) {
1192         writeIntVal(file, indentLevel + 1, "m_recordingPicture.width", m_recordingPicture->width());
1193         writeIntVal(file, indentLevel + 1, "m_recordingPicture.height", m_recordingPicture->height());
1194     }
1195 
1196     if (countChildren()) {
1197         writeln(file, indentLevel + 1, "children = [");
1198         for (int i = 0; i < countChildren(); i++) {
1199             if (i > 0)
1200                 writeln(file, indentLevel + 1, ", ");
1201             getChild(i)->dumpLayers(file, indentLevel + 1);
1202         }
1203         writeln(file, indentLevel + 1, "];");
1204     }
1205     writeln(file, indentLevel, "}");
1206 }
1207 
dumpToLog() const1208 void LayerAndroid::dumpToLog() const
1209 {
1210     FILE* file = fopen("/data/data/com.android.browser/layertmp", "w");
1211     dumpLayers(file, 0);
1212     fclose(file);
1213     file = fopen("/data/data/com.android.browser/layertmp", "r");
1214     char buffer[512];
1215     bzero(buffer, sizeof(buffer));
1216     while (fgets(buffer, sizeof(buffer), file))
1217         SkDebugf("%s", buffer);
1218     fclose(file);
1219 }
1220 
findById(int match)1221 LayerAndroid* LayerAndroid::findById(int match)
1222 {
1223     if (m_uniqueId == match)
1224         return this;
1225     for (int i = 0; i < countChildren(); i++) {
1226         LayerAndroid* result = getChild(i)->findById(match);
1227         if (result)
1228             return result;
1229     }
1230     return 0;
1231 }
1232 
setExtra(DrawExtra * extra)1233 void LayerAndroid::setExtra(DrawExtra* extra)
1234 {
1235     for (int i = 0; i < countChildren(); i++)
1236         getChild(i)->setExtra(extra);
1237 
1238     android::AutoMutex lock(m_atomicSync);
1239     if (extra || (m_extra && !extra))
1240         m_dirty = true;
1241 
1242     delete m_extra;
1243     m_extra = 0;
1244 
1245     if (!extra)
1246         return;
1247 
1248     if (m_recordingPicture) {
1249         IntRect dummy; // inval area, unused for now
1250         m_extra = new SkPicture();
1251         SkCanvas* canvas = m_extra->beginRecording(m_recordingPicture->width(),
1252                                                    m_recordingPicture->height());
1253         extra->draw(canvas, this, &dummy);
1254         m_extra->endRecording();
1255         needsRepaint();
1256     }
1257 }
1258 
1259 } // namespace WebCore
1260 
1261 #endif // USE(ACCELERATED_COMPOSITING)
1262