OSDN Git Service

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