OSDN Git Service

Merge "Don't deep copy animations, prepare animations on both trees" into ics-mr1
[android-x86/external-webkit.git] / Source / 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 "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:
49     OpacityDrawFilter(int opacity) : m_opacity(opacity) { }
50     virtual void filter(SkPaint* paint, Type)
51     {
52         paint->setAlpha(m_opacity);
53     }
54 private:
55     int m_opacity;
56 };
57
58 class HasTextBounder : public SkBounder {
59     virtual bool onIRect(const SkIRect& rect)
60     {
61         return false;
62     }
63 };
64
65 class HasTextCanvas : public SkCanvas {
66 public:
67     HasTextCanvas(SkBounder* bounder, SkPicture* picture)
68         : m_picture(picture)
69         , m_hasText(false)
70     {
71         setBounder(bounder);
72     }
73
74     void setHasText()
75     {
76         m_hasText = true;
77         m_picture->abortPlayback();
78     }
79
80     bool hasText()
81     {
82         return m_hasText;
83     }
84
85     virtual bool clipPath(const SkPath&, SkRegion::Op) {
86         return true;
87     }
88
89     virtual void commonDrawBitmap(const SkBitmap& bitmap,
90                                   const SkIRect* rect,
91                                   const SkMatrix&,
92                                   const SkPaint&) {}
93
94     virtual void drawPaint(const SkPaint& paint) {}
95     virtual void drawPath(const SkPath&, const SkPaint& paint) {}
96     virtual void drawPoints(PointMode, size_t,
97                             const SkPoint [], const SkPaint& paint) {}
98
99     virtual void drawRect(const SkRect& , const SkPaint& paint) {}
100     virtual void drawSprite(const SkBitmap& , int , int ,
101                             const SkPaint* paint = NULL) {}
102
103     virtual void drawText(const void*, size_t byteLength, SkScalar,
104                           SkScalar, const SkPaint& paint)
105     {
106         setHasText();
107     }
108
109     virtual void drawPosText(const void* , size_t byteLength,
110                              const SkPoint [], const SkPaint& paint)
111     {
112         setHasText();
113     }
114
115     virtual void drawPosTextH(const void*, size_t byteLength,
116                               const SkScalar [], SkScalar,
117                               const SkPaint& paint)
118     {
119         setHasText();
120     }
121
122     virtual void drawTextOnPath(const void*, size_t byteLength,
123                                 const SkPath&, const SkMatrix*,
124                                 const SkPaint& paint)
125     {
126         setHasText();
127     }
128
129     virtual void drawPicture(SkPicture& picture) {
130         SkCanvas::drawPicture(picture);
131     }
132
133 private:
134
135     SkPicture* m_picture;
136     bool m_hasText;
137 };
138
139 ///////////////////////////////////////////////////////////////////////////////
140
141 LayerAndroid::LayerAndroid(RenderLayer* owner) : Layer(),
142     m_haveClip(false),
143     m_isFixed(false),
144     m_isIframe(false),
145     m_backfaceVisibility(true),
146     m_visible(true),
147     m_preserves3D(false),
148     m_anchorPointZ(0),
149     m_recordingPicture(0),
150     m_uniqueId(++gUniqueId),
151     m_texture(0),
152     m_imageCRC(0),
153     m_pictureUsed(0),
154     m_scale(1),
155     m_lastComputeTextureSize(0),
156     m_owningLayer(owner),
157     m_type(LayerAndroid::WebCoreLayer),
158     m_hasText(true)
159 {
160     m_backgroundColor = 0;
161
162     m_preserves3D = false;
163     m_iframeOffset.set(0,0);
164     m_dirtyRegion.setEmpty();
165 #ifdef DEBUG_COUNT
166     ClassTracker::instance()->increment("LayerAndroid");
167     ClassTracker::instance()->add(this);
168 #endif
169 }
170
171 LayerAndroid::LayerAndroid(const LayerAndroid& layer) : Layer(layer),
172     m_haveClip(layer.m_haveClip),
173     m_isIframe(layer.m_isIframe),
174     m_uniqueId(layer.m_uniqueId),
175     m_texture(0),
176     m_owningLayer(layer.m_owningLayer),
177     m_type(LayerAndroid::UILayer),
178     m_hasText(true)
179 {
180     m_isFixed = layer.m_isFixed;
181     m_imageCRC = layer.m_imageCRC;
182     if (m_imageCRC)
183         ImagesManager::instance()->retainImage(m_imageCRC);
184
185     m_renderLayerPos = layer.m_renderLayerPos;
186     m_transform = layer.m_transform;
187     m_backfaceVisibility = layer.m_backfaceVisibility;
188     m_visible = layer.m_visible;
189     m_backgroundColor = layer.m_backgroundColor;
190
191     m_fixedLeft = layer.m_fixedLeft;
192     m_fixedTop = layer.m_fixedTop;
193     m_fixedRight = layer.m_fixedRight;
194     m_fixedBottom = layer.m_fixedBottom;
195     m_fixedMarginLeft = layer.m_fixedMarginLeft;
196     m_fixedMarginTop = layer.m_fixedMarginTop;
197     m_fixedMarginRight = layer.m_fixedMarginRight;
198     m_fixedMarginBottom = layer.m_fixedMarginBottom;
199     m_fixedRect = layer.m_fixedRect;
200     m_iframeOffset = layer.m_iframeOffset;
201     m_recordingPicture = layer.m_recordingPicture;
202     SkSafeRef(m_recordingPicture);
203
204     m_preserves3D = layer.m_preserves3D;
205     m_anchorPointZ = layer.m_anchorPointZ;
206     m_drawTransform = layer.m_drawTransform;
207     m_childrenTransform = layer.m_childrenTransform;
208     m_pictureUsed = layer.m_pictureUsed;
209     m_dirtyRegion = layer.m_dirtyRegion;
210     m_scale = layer.m_scale;
211     m_lastComputeTextureSize = 0;
212
213     for (int i = 0; i < layer.countChildren(); i++)
214         addChild(layer.getChild(i)->copy())->unref();
215
216     KeyframesMap::const_iterator end = layer.m_animations.end();
217     for (KeyframesMap::const_iterator it = layer.m_animations.begin(); it != end; ++it) {
218         m_animations.add(it->first, it->second);
219     }
220
221     m_hasText = layer.m_hasText;
222
223 #ifdef DEBUG_COUNT
224     ClassTracker::instance()->increment("LayerAndroid - recopy (UI)");
225     ClassTracker::instance()->add(this);
226 #endif
227 }
228
229 void LayerAndroid::checkTextPresence()
230 {
231     if (m_recordingPicture) {
232         // Let's check if we have text or not. If we don't, we can limit
233         // ourselves to scale 1!
234         HasTextBounder hasTextBounder;
235         HasTextCanvas checker(&hasTextBounder, m_recordingPicture);
236         SkBitmap bitmap;
237         bitmap.setConfig(SkBitmap::kARGB_8888_Config,
238                          m_recordingPicture->width(),
239                          m_recordingPicture->height());
240         checker.setBitmapDevice(bitmap);
241         checker.drawPicture(*m_recordingPicture);
242         m_hasText = checker.hasText();
243     }
244 }
245
246 LayerAndroid::LayerAndroid(SkPicture* picture) : Layer(),
247     m_haveClip(false),
248     m_isFixed(false),
249     m_isIframe(false),
250     m_recordingPicture(picture),
251     m_uniqueId(++gUniqueId),
252     m_texture(0),
253     m_imageCRC(0),
254     m_scale(1),
255     m_lastComputeTextureSize(0),
256     m_owningLayer(0),
257     m_type(LayerAndroid::NavCacheLayer),
258     m_hasText(true)
259 {
260     m_backgroundColor = 0;
261     SkSafeRef(m_recordingPicture);
262     m_iframeOffset.set(0,0);
263     m_dirtyRegion.setEmpty();
264 #ifdef DEBUG_COUNT
265     ClassTracker::instance()->increment("LayerAndroid - from picture");
266     ClassTracker::instance()->add(this);
267 #endif
268 }
269
270 LayerAndroid::~LayerAndroid()
271 {
272     if (m_imageCRC)
273         ImagesManager::instance()->releaseImage(m_imageCRC);
274
275     SkSafeUnref(m_recordingPicture);
276     m_animations.clear();
277 #ifdef DEBUG_COUNT
278     ClassTracker::instance()->remove(this);
279     if (m_type == LayerAndroid::WebCoreLayer)
280         ClassTracker::instance()->decrement("LayerAndroid");
281     else if (m_type == LayerAndroid::UILayer)
282         ClassTracker::instance()->decrement("LayerAndroid - recopy (UI)");
283     else if (m_type == LayerAndroid::NavCacheLayer)
284         ClassTracker::instance()->decrement("LayerAndroid - from picture");
285 #endif
286 }
287
288 static int gDebugNbAnims = 0;
289
290 bool LayerAndroid::evaluateAnimations()
291 {
292     double time = WTF::currentTime();
293     gDebugNbAnims = 0;
294     return evaluateAnimations(time);
295 }
296
297 bool LayerAndroid::hasAnimations() const
298 {
299     for (int i = 0; i < countChildren(); i++) {
300         if (getChild(i)->hasAnimations())
301             return true;
302     }
303     return !!m_animations.size();
304 }
305
306 bool LayerAndroid::evaluateAnimations(double time)
307 {
308     bool hasRunningAnimations = false;
309     for (int i = 0; i < countChildren(); i++) {
310         if (getChild(i)->evaluateAnimations(time))
311             hasRunningAnimations = true;
312     }
313
314     m_hasRunningAnimations = false;
315     int nbAnims = 0;
316     KeyframesMap::const_iterator end = m_animations.end();
317     for (KeyframesMap::const_iterator it = m_animations.begin(); it != end; ++it) {
318         gDebugNbAnims++;
319         nbAnims++;
320         LayerAndroid* currentLayer = const_cast<LayerAndroid*>(this);
321         m_hasRunningAnimations |= (it->second)->evaluate(currentLayer, time);
322     }
323
324     return hasRunningAnimations || m_hasRunningAnimations;
325 }
326
327 void LayerAndroid::initAnimations() {
328     // tell auto-initializing animations to start now
329     for (int i = 0; i < countChildren(); i++)
330         getChild(i)->initAnimations();
331
332     KeyframesMap::const_iterator localBegin = m_animations.begin();
333     KeyframesMap::const_iterator localEnd = m_animations.end();
334     for (KeyframesMap::const_iterator localIt = localBegin; localIt != localEnd; ++localIt)
335         (localIt->second)->suggestBeginTime(WTF::currentTime());
336 }
337
338 void LayerAndroid::addDirtyArea()
339 {
340     IntSize layerSize(getSize().width(), getSize().height());
341
342     FloatRect area = TilesManager::instance()->shader()->rectInInvScreenCoord(m_drawTransform, layerSize);
343     FloatRect clippingRect = TilesManager::instance()->shader()->rectInScreenCoord(m_clippingRect);
344     FloatRect clip = TilesManager::instance()->shader()->convertScreenCoordToInvScreenCoord(clippingRect);
345
346     area.intersect(clip);
347     IntRect dirtyArea(area.x(), area.y(), area.width(), area.height());
348     m_state->addDirtyArea(dirtyArea);
349 }
350
351 void LayerAndroid::addAnimation(PassRefPtr<AndroidAnimation> prpAnim)
352 {
353     RefPtr<AndroidAnimation> anim = prpAnim;
354     pair<String, int> key(anim->name(), anim->type());
355     removeAnimationsForProperty(anim->type());
356     m_animations.add(key, anim);
357 }
358
359 void LayerAndroid::removeAnimationsForProperty(AnimatedPropertyID property)
360 {
361     KeyframesMap::const_iterator end = m_animations.end();
362     Vector<pair<String, int> > toDelete;
363     for (KeyframesMap::const_iterator it = m_animations.begin(); it != end; ++it) {
364         if ((it->second)->type() == property)
365             toDelete.append(it->first);
366     }
367
368     for (unsigned int i = 0; i < toDelete.size(); i++)
369         m_animations.remove(toDelete[i]);
370 }
371
372 void LayerAndroid::removeAnimationsForKeyframes(const String& name)
373 {
374     KeyframesMap::const_iterator end = m_animations.end();
375     Vector<pair<String, int> > toDelete;
376     for (KeyframesMap::const_iterator it = m_animations.begin(); it != end; ++it) {
377         if ((it->second)->name() == name)
378             toDelete.append(it->first);
379     }
380
381     for (unsigned int i = 0; i < toDelete.size(); i++)
382         m_animations.remove(toDelete[i]);
383 }
384
385 // We only use the bounding rect of the layer as mask...
386 // FIXME: use a real mask?
387 void LayerAndroid::setMaskLayer(LayerAndroid* layer)
388 {
389     if (layer)
390         m_haveClip = true;
391 }
392
393 void LayerAndroid::setBackgroundColor(SkColor color)
394 {
395     m_backgroundColor = color;
396 }
397
398 static int gDebugChildLevel;
399
400 FloatPoint LayerAndroid::translation() const
401 {
402     TransformationMatrix::DecomposedType tDecomp;
403     m_transform.decompose(tDecomp);
404     FloatPoint p(tDecomp.translateX, tDecomp.translateY);
405     return p;
406 }
407
408 SkRect LayerAndroid::bounds() const
409 {
410     SkRect rect;
411     bounds(&rect);
412     return rect;
413 }
414
415 void LayerAndroid::bounds(SkRect* rect) const
416 {
417     const SkPoint& pos = this->getPosition();
418     const SkSize& size = this->getSize();
419
420     // The returned rect has the translation applied
421     // FIXME: apply the full transform to the rect,
422     // and fix the text selection accordingly
423     FloatPoint p(pos.fX, pos.fY);
424     p = m_transform.mapPoint(p);
425     rect->fLeft = p.x();
426     rect->fTop = p.y();
427     rect->fRight = p.x() + size.width();
428     rect->fBottom = p.y() + size.height();
429 }
430
431 static bool boundsIsUnique(const SkTDArray<SkRect>& region,
432                            const SkRect& local)
433 {
434     for (int i = 0; i < region.count(); i++) {
435         if (region[i].contains(local))
436             return false;
437     }
438     return true;
439 }
440
441 void LayerAndroid::clipArea(SkTDArray<SkRect>* region) const
442 {
443     SkRect local;
444     local.set(0, 0, std::numeric_limits<float>::max(),
445         std::numeric_limits<float>::max());
446     clipInner(region, local);
447 }
448
449 void LayerAndroid::clipInner(SkTDArray<SkRect>* region,
450                              const SkRect& local) const
451 {
452     SkRect localBounds;
453     bounds(&localBounds);
454     localBounds.intersect(local);
455     if (localBounds.isEmpty())
456         return;
457     if (m_recordingPicture && boundsIsUnique(*region, localBounds))
458         *region->append() = localBounds;
459     for (int i = 0; i < countChildren(); i++)
460         getChild(i)->clipInner(region, m_haveClip ? localBounds : local);
461 }
462
463 class FindCheck : public SkBounder {
464 public:
465     FindCheck()
466         : m_drew(false)
467         , m_drewText(false)
468     {
469     }
470
471     bool drew() const { return m_drew; }
472     bool drewText() const { return m_drewText; }
473     void reset() { m_drew = m_drewText = false; }
474
475 protected:
476     virtual bool onIRect(const SkIRect& )
477     {
478         m_drew = true;
479         return false;
480     }
481
482     virtual bool onIRectGlyph(const SkIRect& , const SkBounder::GlyphRec& )
483     {
484         m_drew = m_drewText = true;
485         return false;
486     }
487
488     bool m_drew;
489     bool m_drewText;
490 };
491
492 class FindCanvas : public ParseCanvas {
493 public:
494     void draw(SkPicture* picture, SkScalar offsetX, SkScalar offsetY)
495     {
496         save();
497         translate(-offsetX, -offsetY);
498         picture->draw(this);
499         restore();
500     }
501 };
502
503 class LayerAndroid::FindState {
504 public:
505     static const int TOUCH_SLOP = 10;
506
507     FindState(int x, int y)
508         : m_x(x)
509         , m_y(y)
510         , m_bestX(x)
511         , m_bestY(y)
512         , m_best(0)
513     {
514         m_bitmap.setConfig(SkBitmap::kARGB_8888_Config, TOUCH_SLOP * 2,
515              TOUCH_SLOP * 2);
516         m_checker.setBounder(&m_findCheck);
517         m_checker.setBitmapDevice(m_bitmap);
518     }
519
520     const LayerAndroid* best() const { return m_best; }
521     int bestX() const { return m_bestX; }
522     int bestY() const { return m_bestY; }
523
524     bool drew(SkPicture* picture, const SkRect& localBounds)
525     {
526         m_findCheck.reset();
527         SkScalar localX = SkIntToScalar(m_x - TOUCH_SLOP) - localBounds.fLeft;
528         SkScalar localY = SkIntToScalar(m_y - TOUCH_SLOP) - localBounds.fTop;
529         m_checker.draw(picture, localX, localY);
530         return m_findCheck.drew();
531     }
532
533     bool drewText() { return m_findCheck.drewText(); }
534
535     void setBest(const LayerAndroid* best, int x, int y)
536     {
537         m_best = best;
538         m_bestX = x;
539         m_bestY = y;
540     }
541     int x() const { return m_x; }
542     int y() const { return m_y; }
543
544     void setLocation(int x, int y)
545     {
546         m_x = x;
547         m_y = y;
548     }
549
550 protected:
551     int m_x;
552     int m_y;
553     int m_bestX;
554     int m_bestY;
555     const LayerAndroid* m_best;
556     FindCheck m_findCheck;
557     SkBitmap m_bitmap;
558     FindCanvas m_checker;
559 };
560
561 void LayerAndroid::findInner(LayerAndroid::FindState& state) const
562 {
563     int x = state.x();
564     int y = state.y();
565     SkRect localBounds;
566     bounds(&localBounds);
567     if (!localBounds.contains(x, y))
568         return;
569     // Move into local coordinates.
570     state.setLocation(x - localBounds.fLeft, y - localBounds.fTop);
571     for (int i = 0; i < countChildren(); i++)
572         getChild(i)->findInner(state);
573     // Move back into the parent coordinates.
574     int testX = state.x();
575     int testY = state.y();
576     state.setLocation(x + localBounds.fLeft, y + localBounds.fTop);
577     if (!m_recordingPicture)
578         return;
579     if (!contentIsScrollable() && !state.drew(m_recordingPicture, localBounds))
580         return;
581     state.setBest(this, testX, testY); // set last match (presumably on top)
582 }
583
584 const LayerAndroid* LayerAndroid::find(int* xPtr, int* yPtr, SkPicture* root) const
585 {
586     FindState state(*xPtr, *yPtr);
587     SkRect rootBounds;
588     rootBounds.setEmpty();
589     if (root && state.drew(root, rootBounds) && state.drewText())
590         return 0; // use the root picture only if it contains the text
591     findInner(state);
592     *xPtr = state.bestX();
593     *yPtr = state.bestY();
594     return state.best();
595 }
596
597 ///////////////////////////////////////////////////////////////////////////////
598
599 bool LayerAndroid::updateFixedLayersPositions(SkRect viewport, LayerAndroid* parentIframeLayer)
600 {
601     bool hasFixedElements = false;
602     XLOG("updating fixed positions, using viewport %fx%f - %fx%f",
603          viewport.fLeft, viewport.fTop,
604          viewport.width(), viewport.height());
605     // If this is an iframe, accumulate the offset from the parent with
606     // current position, and change the parent pointer.
607     if (m_isIframe) {
608         // If this is the top level, take the current position
609         SkPoint parentOffset;
610         parentOffset.set(0,0);
611         if (parentIframeLayer)
612             parentOffset = parentIframeLayer->getPosition();
613
614         m_iframeOffset = parentOffset + getPosition();
615
616         parentIframeLayer = this;
617     }
618
619     if (m_isFixed) {
620         hasFixedElements = true;
621         // So if this is a fixed layer inside a iframe, use the iframe offset
622         // and the iframe's size as the viewport and pass to the children
623         if (parentIframeLayer) {
624             viewport = SkRect::MakeXYWH(parentIframeLayer->m_iframeOffset.fX,
625                                  parentIframeLayer->m_iframeOffset.fY,
626                                  parentIframeLayer->getSize().width(),
627                                  parentIframeLayer->getSize().height());
628         }
629         float w = viewport.width();
630         float h = viewport.height();
631         float dx = viewport.fLeft;
632         float dy = viewport.fTop;
633         float x = dx;
634         float y = dy;
635
636         // It turns out that when it is 'auto', we should use the webkit value
637         // from the original render layer's X,Y, that will take care of alignment
638         // with the parent's layer and fix Margin etc.
639         if (!(m_fixedLeft.defined() || m_fixedRight.defined()))
640             x += m_renderLayerPos.x();
641         else if (m_fixedLeft.defined() || !m_fixedRight.defined())
642             x += m_fixedMarginLeft.calcFloatValue(w) + m_fixedLeft.calcFloatValue(w) - m_fixedRect.fLeft;
643         else
644             x += w - m_fixedMarginRight.calcFloatValue(w) - m_fixedRight.calcFloatValue(w) - m_fixedRect.fRight;
645
646         if (!(m_fixedTop.defined() || m_fixedBottom.defined()))
647             y += m_renderLayerPos.y();
648         else if (m_fixedTop.defined() || !m_fixedBottom.defined())
649             y += m_fixedMarginTop.calcFloatValue(h) + m_fixedTop.calcFloatValue(h) - m_fixedRect.fTop;
650         else
651             y += h - m_fixedMarginBottom.calcFloatValue(h) - m_fixedBottom.calcFloatValue(h) - m_fixedRect.fBottom;
652
653         this->setPosition(x, y);
654     }
655
656     int count = this->countChildren();
657     for (int i = 0; i < count; i++)
658         hasFixedElements |= this->getChild(i)->updateFixedLayersPositions(viewport, parentIframeLayer);
659
660     return hasFixedElements;
661 }
662
663 void LayerAndroid::updatePositions()
664 {
665     // apply the viewport to us
666     if (!m_isFixed) {
667         // turn our fields into a matrix.
668         //
669         // FIXME: this should happen in the caller, and we should remove these
670         // fields from our subclass
671         SkMatrix matrix;
672         GLUtils::toSkMatrix(matrix, m_transform);
673         this->setMatrix(matrix);
674     }
675
676     // now apply it to our children
677     int count = this->countChildren();
678     for (int i = 0; i < count; i++)
679         this->getChild(i)->updatePositions();
680 }
681
682 void LayerAndroid::updateGLPositionsAndScale(const TransformationMatrix& parentMatrix,
683                                              const FloatRect& clipping, float opacity, float scale)
684 {
685     m_atomicSync.lock();
686     IntSize layerSize(getSize().width(), getSize().height());
687     FloatPoint anchorPoint(getAnchorPoint().fX, getAnchorPoint().fY);
688     FloatPoint position(getPosition().fX, getPosition().fY);
689     float centerOffsetX = (0.5f - anchorPoint.x()) * layerSize.width();
690     float centerOffsetY = (0.5f - anchorPoint.y()) * layerSize.height();
691     float originX = anchorPoint.x() * layerSize.width();
692     float originY = anchorPoint.y() * layerSize.height();
693     TransformationMatrix localMatrix;
694     if (!m_isFixed)
695         localMatrix = parentMatrix;
696     localMatrix.translate3d(originX + position.x(),
697                             originY + position.y(),
698                             anchorPointZ());
699     localMatrix.multiply(m_transform);
700     localMatrix.translate3d(-originX,
701                             -originY,
702                             -anchorPointZ());
703
704     m_atomicSync.unlock();
705     setDrawTransform(localMatrix);
706     if (m_drawTransform.isIdentityOrTranslation()) {
707         // adjust the translation coordinates of the draw transform matrix so
708         // that layers (defined in content coordinates) will align to display/view pixels
709         float desiredContentX = round(m_drawTransform.m41() * scale) / scale;
710         float desiredContentY = round(m_drawTransform.m42() * scale) / scale;
711         XLOG("fudging translation from %f, %f to %f, %f",
712              m_drawTransform.m41(), m_drawTransform.m42(),
713              desiredContentX, desiredContentY);
714         m_drawTransform.setM41(desiredContentX);
715         m_drawTransform.setM42(desiredContentY);
716     }
717
718     m_zValue = TilesManager::instance()->shader()->zValue(m_drawTransform, getSize().width(), getSize().height());
719
720     m_atomicSync.lock();
721     m_scale = scale;
722     m_atomicSync.unlock();
723
724     opacity *= getOpacity();
725     setDrawOpacity(opacity);
726
727     if (m_haveClip) {
728         // The clipping rect calculation and intersetion will be done in documents coordinates.
729         FloatRect rect(0, 0, layerSize.width(), layerSize.height());
730         FloatRect clip = m_drawTransform.mapRect(rect);
731         clip.intersect(clipping);
732         setDrawClip(clip);
733     } else {
734         setDrawClip(clipping);
735     }
736
737     if (!m_backfaceVisibility
738          && m_drawTransform.inverse().m33() < 0) {
739          setVisible(false);
740          return;
741     } else {
742          setVisible(true);
743     }
744
745     int count = this->countChildren();
746     if (!count)
747         return;
748
749     // Flatten to 2D if the layer doesn't preserve 3D.
750     if (!preserves3D()) {
751         localMatrix.setM13(0);
752         localMatrix.setM23(0);
753         localMatrix.setM31(0);
754         localMatrix.setM32(0);
755         localMatrix.setM33(1);
756         localMatrix.setM34(0);
757         localMatrix.setM43(0);
758     }
759
760     // now apply it to our children
761
762     if (!m_childrenTransform.isIdentity()) {
763         localMatrix.translate(getSize().width() * 0.5f, getSize().height() * 0.5f);
764         localMatrix.multiply(m_childrenTransform);
765         localMatrix.translate(-getSize().width() * 0.5f, -getSize().height() * 0.5f);
766     }
767     for (int i = 0; i < count; i++)
768         this->getChild(i)->updateGLPositionsAndScale(localMatrix, drawClip(), opacity, scale);
769 }
770
771 void LayerAndroid::setContentsImage(SkBitmapRef* img)
772 {
773     ImageTexture* image = ImagesManager::instance()->setImage(img);
774     ImagesManager::instance()->releaseImage(m_imageCRC);
775     m_imageCRC = image ? image->imageCRC() : 0;
776 }
777
778 bool LayerAndroid::needsTexture()
779 {
780     return m_imageCRC || (m_recordingPicture
781         && m_recordingPicture->width() && m_recordingPicture->height());
782 }
783
784 void LayerAndroid::removeTexture(PaintedSurface* texture)
785 {
786     if (texture == m_texture)
787         m_texture = 0;
788 }
789
790 IntRect LayerAndroid::clippedRect() const
791 {
792     IntRect r(0, 0, getWidth(), getHeight());
793     IntRect tr = m_drawTransform.mapRect(r);
794     IntRect cr = TilesManager::instance()->shader()->clippedRectWithViewport(tr);
795     IntRect rect = m_drawTransform.inverse().mapRect(cr);
796     return rect;
797 }
798
799 int LayerAndroid::nbLayers()
800 {
801     int nb = 0;
802     int count = this->countChildren();
803     for (int i = 0; i < count; i++)
804         nb += this->getChild(i)->nbLayers();
805     return nb+1;
806 }
807
808 int LayerAndroid::nbTexturedLayers()
809 {
810     int nb = 0;
811     int count = this->countChildren();
812     for (int i = 0; i < count; i++)
813         nb += this->getChild(i)->nbTexturedLayers();
814     if (needsTexture())
815         nb++;
816     return nb;
817 }
818
819 void LayerAndroid::computeTexturesAmount(TexturesResult* result)
820 {
821     if (!result)
822         return;
823
824     int count = this->countChildren();
825     for (int i = 0; i < count; i++)
826         this->getChild(i)->computeTexturesAmount(result);
827     if (m_texture && m_visible)
828         m_texture->computeTexturesAmount(result);
829 }
830
831 void LayerAndroid::showLayer(int indent)
832 {
833     char spaces[256];
834     memset(spaces, 0, 256);
835     for (int i = 0; i < indent; i++)
836         spaces[i] = ' ';
837
838     if (!indent) {
839         XLOGC("\n\n--- LAYERS TREE ---");
840         IntRect documentViewport(TilesManager::instance()->shader()->documentViewport());
841         XLOGC("documentViewport(%d, %d, %d, %d)",
842               documentViewport.x(), documentViewport.y(),
843               documentViewport.width(), documentViewport.height());
844     }
845
846     IntRect r(0, 0, getWidth(), getHeight());
847     IntRect tr = m_drawTransform.mapRect(r);
848     IntRect visible = visibleArea();
849     IntRect clip(m_clippingRect.x(), m_clippingRect.y(),
850                  m_clippingRect.width(), m_clippingRect.height());
851     XLOGC("%s [%d:0x%x] - %s %s - area (%d, %d, %d, %d) - visible (%d, %d, %d, %d) "
852           "clip (%d, %d, %d, %d) %s %s prepareContext(%x), pic w: %d h: %d",
853           spaces, uniqueId(), m_owningLayer,
854           needsTexture() ? "needs a texture" : "no texture",
855           m_imageCRC ? "has an image" : "no image",
856           tr.x(), tr.y(), tr.width(), tr.height(),
857           visible.x(), visible.y(), visible.width(), visible.height(),
858           clip.x(), clip.y(), clip.width(), clip.height(),
859           contentIsScrollable() ? "SCROLLABLE" : "",
860           isFixed() ? "FIXED" : "",
861           m_recordingPicture,
862           m_recordingPicture ? m_recordingPicture->width() : -1,
863           m_recordingPicture ? m_recordingPicture->height() : -1);
864
865     int count = this->countChildren();
866     for (int i = 0; i < count; i++)
867         this->getChild(i)->showLayer(indent + 1);
868 }
869
870 void LayerAndroid::swapTiles()
871 {
872     int count = this->countChildren();
873     for (int i = 0; i < count; i++)
874         this->getChild(i)->swapTiles();
875
876     if (m_texture)
877         m_texture->swapTiles();
878 }
879
880 void LayerAndroid::setIsDrawing(bool isDrawing)
881 {
882     int count = this->countChildren();
883     for (int i = 0; i < count; i++)
884         this->getChild(i)->setIsDrawing(isDrawing);
885
886     if (m_texture) {
887         m_texture->setDrawingLayer(isDrawing ? this : 0);
888         m_texture->clearPaintingLayer();
889     }
890 }
891
892 void LayerAndroid::setIsPainting(Layer* drawingTree)
893 {
894     XLOG("setting layer %p as painting, needs texture %d, drawing tree %p",
895          this, needsTexture(), drawingTree);
896     int count = this->countChildren();
897     for (int i = 0; i < count; i++)
898         this->getChild(i)->setIsPainting(drawingTree);
899
900
901     LayerAndroid* drawingLayer = 0;
902     if (drawingTree)
903         drawingLayer = static_cast<LayerAndroid*>(drawingTree)->findById(uniqueId());
904
905     obtainTextureForPainting(drawingLayer);
906 }
907
908 void LayerAndroid::mergeInvalsInto(Layer* replacementTree)
909 {
910     int count = this->countChildren();
911     for (int i = 0; i < count; i++)
912         this->getChild(i)->mergeInvalsInto(replacementTree);
913
914     LayerAndroid* replacementLayer = static_cast<LayerAndroid*>(replacementTree)->findById(uniqueId());
915     if (replacementLayer)
916         replacementLayer->markAsDirty(m_dirtyRegion);
917 }
918
919 bool LayerAndroid::isReady()
920 {
921     int count = countChildren();
922     for (int i = 0; i < count; i++)
923         if (!getChild(i)->isReady())
924             return false;
925
926     if (m_texture)
927         return m_texture->isReady();
928     // TODO: image, check if uploaded?
929     return true;
930 }
931
932 bool LayerAndroid::updateWithTree(LayerAndroid* newTree)
933 {
934 // Disable fast update for now
935 #if (0)
936     bool needsRepaint = false;
937     int count = this->countChildren();
938     for (int i = 0; i < count; i++)
939         needsRepaint |= this->getChild(i)->updateWithTree(newTree);
940
941     if (newTree) {
942         LayerAndroid* newLayer = newTree->findById(uniqueId());
943         needsRepaint |= updateWithLayer(newLayer);
944     }
945     return needsRepaint;
946 #else
947     return true;
948 #endif
949 }
950
951 // Return true to indicate to WebViewCore that the updates
952 // are too complicated to be fully handled and we need a full
953 // call to webkit (e.g. handle repaints)
954 bool LayerAndroid::updateWithLayer(LayerAndroid* layer)
955 {
956     if (!layer)
957         return true;
958
959     android::AutoMutex lock(m_atomicSync);
960     m_position = layer->m_position;
961     m_anchorPoint = layer->m_anchorPoint;
962     m_size = layer->m_size;
963     m_opacity = layer->m_opacity;
964     m_transform = layer->m_transform;
965
966     if (m_imageCRC != layer->m_imageCRC)
967         m_visible = false;
968
969     if ((m_recordingPicture != layer->m_recordingPicture)
970         || (m_imageCRC != layer->m_imageCRC))
971         return true;
972
973     return false;
974 }
975
976 void LayerAndroid::obtainTextureForPainting(LayerAndroid* drawingLayer)
977 {
978     if (!needsTexture())
979         return;
980
981     if (m_imageCRC) {
982         if (m_texture) {
983             m_texture->setDrawingLayer(0);
984             m_texture->clearPaintingLayer();
985             m_texture = 0;
986         }
987     } else {
988         if (drawingLayer) {
989             // if a previous tree had the same layer, paint with that painted surface
990             m_texture = drawingLayer->m_texture;
991         }
992
993         if (!m_texture)
994             m_texture = new PaintedSurface();
995
996         // pass the invalidated regions to the PaintedSurface
997         m_texture->setPaintingLayer(this, m_dirtyRegion);
998     }
999     m_dirtyRegion.setEmpty();
1000 }
1001
1002
1003 static inline bool compareLayerZ(const LayerAndroid* a, const LayerAndroid* b)
1004 {
1005     return a->zValue() > b->zValue();
1006 }
1007
1008 // We call this in WebViewCore, when copying the tree of layers.
1009 // As we construct a new tree that will be passed on the UI,
1010 // we mark the webkit-side tree as having no more dirty region
1011 // (otherwise we would continuously have those dirty region UI-side)
1012 void LayerAndroid::clearDirtyRegion()
1013 {
1014     int count = this->countChildren();
1015     for (int i = 0; i < count; i++)
1016         this->getChild(i)->clearDirtyRegion();
1017
1018     m_dirtyRegion.setEmpty();
1019 }
1020
1021 void LayerAndroid::prepare()
1022 {
1023     XLOG("LA %p preparing, m_texture %p", this, m_texture);
1024
1025     int count = this->countChildren();
1026     if (count > 0) {
1027         Vector <LayerAndroid*> sublayers;
1028         for (int i = 0; i < count; i++)
1029             sublayers.append(this->getChild(i));
1030
1031         // now we sort for the transparency
1032         std::stable_sort(sublayers.begin(), sublayers.end(), compareLayerZ);
1033
1034         // iterate in reverse so top layers get textures first
1035         for (int i = count-1; i >= 0; i--)
1036             sublayers[i]->prepare();
1037     }
1038
1039     if (m_texture)
1040         m_texture->prepare(m_state);
1041 }
1042
1043 IntRect LayerAndroid::unclippedArea()
1044 {
1045     IntRect area;
1046     area.setX(0);
1047     area.setY(0);
1048     area.setWidth(getSize().width());
1049     area.setHeight(getSize().height());
1050     return area;
1051 }
1052
1053 IntRect LayerAndroid::visibleArea()
1054 {
1055     IntRect area = unclippedArea();
1056     // First, we get the transformed area of the layer,
1057     // in document coordinates
1058     IntRect rect = m_drawTransform.mapRect(area);
1059     int dx = rect.x();
1060     int dy = rect.y();
1061
1062     // Then we apply the clipping
1063     IntRect clip(m_clippingRect);
1064     rect.intersect(clip);
1065
1066     // Now clip with the viewport in documents coordinate
1067     IntRect documentViewport(TilesManager::instance()->shader()->documentViewport());
1068     rect.intersect(documentViewport);
1069
1070     // Finally, let's return the visible area, in layers coordinate
1071     rect.move(-dx, -dy);
1072     return rect;
1073 }
1074
1075 bool LayerAndroid::drawCanvas(SkCanvas* canvas)
1076 {
1077     if (!m_visible)
1078         return false;
1079
1080     bool askScreenUpdate = false;
1081
1082     {
1083         SkAutoCanvasRestore acr(canvas, true);
1084         SkRect r;
1085         r.set(m_clippingRect.x(), m_clippingRect.y(),
1086               m_clippingRect.x() + m_clippingRect.width(),
1087               m_clippingRect.y() + m_clippingRect.height());
1088         canvas->clipRect(r);
1089         SkMatrix matrix;
1090         GLUtils::toSkMatrix(matrix, m_drawTransform);
1091         SkMatrix canvasMatrix = canvas->getTotalMatrix();
1092         matrix.postConcat(canvasMatrix);
1093         canvas->setMatrix(matrix);
1094         SkRect layerRect;
1095         layerRect.fLeft = 0;
1096         layerRect.fTop = 0;
1097         layerRect.fRight = getWidth();
1098         layerRect.fBottom = getHeight();
1099         onDraw(canvas, m_drawOpacity);
1100     }
1101
1102     // When the layer is dirty, the UI thread should be notified to redraw.
1103     askScreenUpdate |= drawChildrenCanvas(canvas);
1104     m_atomicSync.lock();
1105     if (askScreenUpdate || m_hasRunningAnimations || m_drawTransform.hasPerspective())
1106         addDirtyArea();
1107
1108     m_atomicSync.unlock();
1109     return askScreenUpdate;
1110 }
1111
1112 bool LayerAndroid::drawGL()
1113 {
1114     FloatRect clippingRect = TilesManager::instance()->shader()->rectInScreenCoord(m_clippingRect);
1115     TilesManager::instance()->shader()->clip(clippingRect);
1116     if (!m_visible)
1117         return false;
1118
1119     bool askScreenUpdate = false;
1120
1121     if (m_state->layersRenderingMode() < GLWebViewState::kScrollableAndFixedLayers) {
1122         if (m_texture)
1123             askScreenUpdate |= m_texture->draw();
1124         if (m_imageCRC) {
1125             ImageTexture* imageTexture = ImagesManager::instance()->retainImage(m_imageCRC);
1126             if (imageTexture)
1127                 imageTexture->drawGL(this);
1128             ImagesManager::instance()->releaseImage(m_imageCRC);
1129         }
1130     }
1131
1132     // When the layer is dirty, the UI thread should be notified to redraw.
1133     askScreenUpdate |= drawChildrenGL();
1134     m_atomicSync.lock();
1135     if (askScreenUpdate || m_hasRunningAnimations || m_drawTransform.hasPerspective())
1136         addDirtyArea();
1137
1138     m_atomicSync.unlock();
1139     return askScreenUpdate;
1140 }
1141
1142 bool LayerAndroid::drawChildrenCanvas(SkCanvas* canvas)
1143 {
1144     bool askScreenUpdate = false;
1145     int count = this->countChildren();
1146     if (count > 0) {
1147         Vector <LayerAndroid*> sublayers;
1148         for (int i = 0; i < count; i++)
1149             sublayers.append(this->getChild(i));
1150
1151         // now we sort for the transparency
1152         std::stable_sort(sublayers.begin(), sublayers.end(), compareLayerZ);
1153         for (int i = 0; i < count; i++) {
1154             LayerAndroid* layer = sublayers[i];
1155             askScreenUpdate |= layer->drawCanvas(canvas);
1156         }
1157     }
1158
1159     return askScreenUpdate;
1160 }
1161
1162 bool LayerAndroid::drawChildrenGL()
1163 {
1164     bool askScreenUpdate = false;
1165     int count = this->countChildren();
1166     if (count > 0) {
1167         Vector <LayerAndroid*> sublayers;
1168         for (int i = 0; i < count; i++)
1169             sublayers.append(this->getChild(i));
1170
1171         // now we sort for the transparency
1172         std::stable_sort(sublayers.begin(), sublayers.end(), compareLayerZ);
1173         for (int i = 0; i < count; i++) {
1174             LayerAndroid* layer = sublayers[i];
1175             askScreenUpdate |= layer->drawGL();
1176         }
1177     }
1178
1179     return askScreenUpdate;
1180 }
1181
1182 void LayerAndroid::contentDraw(SkCanvas* canvas)
1183 {
1184     if (m_recordingPicture)
1185       canvas->drawPicture(*m_recordingPicture);
1186
1187     if (TilesManager::instance()->getShowVisualIndicator()) {
1188         float w = getSize().width();
1189         float h = getSize().height();
1190         SkPaint paint;
1191         paint.setARGB(128, 255, 0, 0);
1192         canvas->drawLine(0, 0, w, h, paint);
1193         canvas->drawLine(0, h, w, 0, paint);
1194         paint.setARGB(128, 0, 255, 0);
1195         canvas->drawLine(0, 0, 0, h, paint);
1196         canvas->drawLine(0, h, w, h, paint);
1197         canvas->drawLine(w, h, w, 0, paint);
1198         canvas->drawLine(w, 0, 0, 0, paint);
1199
1200         if (m_isFixed) {
1201           SkPaint paint;
1202           paint.setARGB(80, 255, 0, 0);
1203           canvas->drawRect(m_fixedRect, paint);
1204         }
1205     }
1206 }
1207
1208 void LayerAndroid::onDraw(SkCanvas* canvas, SkScalar opacity)
1209 {
1210     if (m_haveClip) {
1211         SkRect r;
1212         r.set(0, 0, getSize().width(), getSize().height());
1213         canvas->clipRect(r);
1214         return;
1215     }
1216
1217     if (!prepareContext())
1218         return;
1219
1220     // we just have this save/restore for opacity...
1221     SkAutoCanvasRestore restore(canvas, true);
1222
1223     int canvasOpacity = SkScalarRound(opacity * 255);
1224     if (canvasOpacity < 255)
1225         canvas->setDrawFilter(new OpacityDrawFilter(canvasOpacity));
1226
1227     if (m_imageCRC) {
1228         ImageTexture* imageTexture = ImagesManager::instance()->retainImage(m_imageCRC);
1229         m_dirtyRegion.setEmpty();
1230         if (imageTexture) {
1231             SkRect dest;
1232             dest.set(0, 0, getSize().width(), getSize().height());
1233             imageTexture->drawCanvas(canvas, dest);
1234         }
1235         ImagesManager::instance()->releaseImage(m_imageCRC);
1236     }
1237     contentDraw(canvas);
1238 }
1239
1240 SkPicture* LayerAndroid::recordContext()
1241 {
1242     if (prepareContext(true))
1243         return m_recordingPicture;
1244     return 0;
1245 }
1246
1247 bool LayerAndroid::prepareContext(bool force)
1248 {
1249     if (masksToBounds())
1250         return false;
1251
1252     if (force || !m_recordingPicture ||
1253         (m_recordingPicture &&
1254          ((m_recordingPicture->width() != (int) getSize().width()) ||
1255           (m_recordingPicture->height() != (int) getSize().height())))) {
1256         SkSafeUnref(m_recordingPicture);
1257         m_recordingPicture = new SkPicture();
1258     }
1259
1260     return m_recordingPicture;
1261 }
1262
1263 SkRect LayerAndroid::subtractLayers(const SkRect& visibleRect) const
1264 {
1265     SkRect result;
1266     if (m_recordingPicture) {
1267         // FIXME: This seems wrong. localToGlobal() applies the full local transform,
1268         // se surely we should operate globalMatrix on size(), not bounds() with
1269         // the position removed? Perhaps we never noticed the bug because most
1270         // layers don't use a local transform?
1271         // See http://b/5338388
1272         SkRect globalRect = bounds();
1273         globalRect.offset(-getPosition()); // localToGlobal adds in position
1274         SkMatrix globalMatrix;
1275         localToGlobal(&globalMatrix);
1276         globalMatrix.mapRect(&globalRect);
1277         SkIRect roundedGlobal;
1278         globalRect.round(&roundedGlobal);
1279         SkIRect iVisibleRect;
1280         visibleRect.round(&iVisibleRect);
1281         SkRegion visRegion(iVisibleRect);
1282         visRegion.op(roundedGlobal, SkRegion::kDifference_Op);
1283         result.set(visRegion.getBounds());
1284 #if DEBUG_NAV_UI
1285         SkDebugf("%s visibleRect=(%g,%g,r=%g,b=%g) globalRect=(%g,%g,r=%g,b=%g)"
1286             "result=(%g,%g,r=%g,b=%g)", __FUNCTION__,
1287             visibleRect.fLeft, visibleRect.fTop,
1288             visibleRect.fRight, visibleRect.fBottom,
1289             globalRect.fLeft, globalRect.fTop,
1290             globalRect.fRight, globalRect.fBottom,
1291             result.fLeft, result.fTop, result.fRight, result.fBottom);
1292 #endif
1293     } else
1294         result = visibleRect;
1295     for (int i = 0; i < countChildren(); i++)
1296         result = getChild(i)->subtractLayers(result);
1297     return result;
1298 }
1299
1300 // Debug tools : dump the layers tree in a file.
1301 // The format is simple:
1302 // properties have the form: key = value;
1303 // all statements are finished with a semi-colon.
1304 // value can be:
1305 // - int
1306 // - float
1307 // - array of elements
1308 // - composed type
1309 // a composed type enclose properties in { and }
1310 // an array enclose composed types in { }, separated with a comma.
1311 // exemple:
1312 // {
1313 //   x = 3;
1314 //   y = 4;
1315 //   value = {
1316 //     x = 3;
1317 //     y = 4;
1318 //   };
1319 //   anarray = [
1320 //     { x = 3; },
1321 //     { y = 4; }
1322 //   ];
1323 // }
1324
1325 void lwrite(FILE* file, const char* str)
1326 {
1327     fwrite(str, sizeof(char), strlen(str), file);
1328 }
1329
1330 void writeIndent(FILE* file, int indentLevel)
1331 {
1332     if (indentLevel)
1333         fprintf(file, "%*s", indentLevel*2, " ");
1334 }
1335
1336 void writeln(FILE* file, int indentLevel, const char* str)
1337 {
1338     writeIndent(file, indentLevel);
1339     lwrite(file, str);
1340     lwrite(file, "\n");
1341 }
1342
1343 void writeIntVal(FILE* file, int indentLevel, const char* str, int value)
1344 {
1345     writeIndent(file, indentLevel);
1346     fprintf(file, "%s = %d;\n", str, value);
1347 }
1348
1349 void writeHexVal(FILE* file, int indentLevel, const char* str, int value)
1350 {
1351     writeIndent(file, indentLevel);
1352     fprintf(file, "%s = %x;\n", str, value);
1353 }
1354
1355 void writeFloatVal(FILE* file, int indentLevel, const char* str, float value)
1356 {
1357     writeIndent(file, indentLevel);
1358     fprintf(file, "%s = %.3f;\n", str, value);
1359 }
1360
1361 void writePoint(FILE* file, int indentLevel, const char* str, SkPoint point)
1362 {
1363     writeIndent(file, indentLevel);
1364     fprintf(file, "%s = { x = %.3f; y = %.3f; };\n", str, point.fX, point.fY);
1365 }
1366
1367 void writeSize(FILE* file, int indentLevel, const char* str, SkSize size)
1368 {
1369     writeIndent(file, indentLevel);
1370     fprintf(file, "%s = { w = %.3f; h = %.3f; };\n", str, size.width(), size.height());
1371 }
1372
1373 void writeRect(FILE* file, int indentLevel, const char* str, SkRect rect)
1374 {
1375     writeIndent(file, indentLevel);
1376     fprintf(file, "%s = { x = %.3f; y = %.3f; w = %.3f; h = %.3f; };\n",
1377             str, rect.fLeft, rect.fTop, rect.width(), rect.height());
1378 }
1379
1380 void writeLength(FILE* file, int indentLevel, const char* str, SkLength length)
1381 {
1382     if (!length.defined())
1383         return;
1384     writeIndent(file, indentLevel);
1385     fprintf(file, "%s = { type = %d; value = %.2f; };\n", str, length.type, length.value);
1386 }
1387
1388 void writeMatrix(FILE* file, int indentLevel, const char* str, const TransformationMatrix& matrix)
1389 {
1390     writeIndent(file, indentLevel);
1391     fprintf(file, "%s = { (%.2f,%.2f,%.2f,%.2f),(%.2f,%.2f,%.2f,%.2f),"
1392             "(%.2f,%.2f,%.2f,%.2f),(%.2f,%.2f,%.2f,%.2f) };\n",
1393             str,
1394             matrix.m11(), matrix.m12(), matrix.m13(), matrix.m14(),
1395             matrix.m21(), matrix.m22(), matrix.m23(), matrix.m24(),
1396             matrix.m31(), matrix.m32(), matrix.m33(), matrix.m34(),
1397             matrix.m41(), matrix.m42(), matrix.m43(), matrix.m44());
1398 }
1399
1400 void LayerAndroid::dumpLayers(FILE* file, int indentLevel) const
1401 {
1402     writeln(file, indentLevel, "{");
1403
1404     writeHexVal(file, indentLevel + 1, "layer", (int)this);
1405     writeIntVal(file, indentLevel + 1, "layerId", m_uniqueId);
1406     writeIntVal(file, indentLevel + 1, "haveClip", m_haveClip);
1407     writeIntVal(file, indentLevel + 1, "isFixed", m_isFixed);
1408     writeIntVal(file, indentLevel + 1, "m_isIframe", m_isIframe);
1409     writePoint(file, indentLevel + 1, "m_iframeOffset", m_iframeOffset);
1410
1411     writeFloatVal(file, indentLevel + 1, "opacity", getOpacity());
1412     writeSize(file, indentLevel + 1, "size", getSize());
1413     writePoint(file, indentLevel + 1, "position", getPosition());
1414     writePoint(file, indentLevel + 1, "anchor", getAnchorPoint());
1415
1416     writeMatrix(file, indentLevel + 1, "drawMatrix", m_drawTransform);
1417     writeMatrix(file, indentLevel + 1, "transformMatrix", m_transform);
1418     writeRect(file, indentLevel + 1, "clippingRect", SkRect(m_clippingRect));
1419
1420     if (m_isFixed) {
1421         writeLength(file, indentLevel + 1, "fixedLeft", m_fixedLeft);
1422         writeLength(file, indentLevel + 1, "fixedTop", m_fixedTop);
1423         writeLength(file, indentLevel + 1, "fixedRight", m_fixedRight);
1424         writeLength(file, indentLevel + 1, "fixedBottom", m_fixedBottom);
1425         writeLength(file, indentLevel + 1, "fixedMarginLeft", m_fixedMarginLeft);
1426         writeLength(file, indentLevel + 1, "fixedMarginTop", m_fixedMarginTop);
1427         writeLength(file, indentLevel + 1, "fixedMarginRight", m_fixedMarginRight);
1428         writeLength(file, indentLevel + 1, "fixedMarginBottom", m_fixedMarginBottom);
1429         writeRect(file, indentLevel + 1, "fixedRect", m_fixedRect);
1430     }
1431
1432     if (m_recordingPicture) {
1433         writeIntVal(file, indentLevel + 1, "m_recordingPicture.width", m_recordingPicture->width());
1434         writeIntVal(file, indentLevel + 1, "m_recordingPicture.height", m_recordingPicture->height());
1435     }
1436
1437     if (countChildren()) {
1438         writeln(file, indentLevel + 1, "children = [");
1439         for (int i = 0; i < countChildren(); i++) {
1440             if (i > 0)
1441                 writeln(file, indentLevel + 1, ", ");
1442             getChild(i)->dumpLayers(file, indentLevel + 1);
1443         }
1444         writeln(file, indentLevel + 1, "];");
1445     }
1446     writeln(file, indentLevel, "}");
1447 }
1448
1449 void LayerAndroid::dumpToLog() const
1450 {
1451     FILE* file = fopen("/data/data/com.android.browser/layertmp", "w");
1452     dumpLayers(file, 0);
1453     fclose(file);
1454     file = fopen("/data/data/com.android.browser/layertmp", "r");
1455     char buffer[512];
1456     bzero(buffer, sizeof(buffer));
1457     while (fgets(buffer, sizeof(buffer), file))
1458         SkDebugf("%s", buffer);
1459     fclose(file);
1460 }
1461
1462 LayerAndroid* LayerAndroid::findById(int match)
1463 {
1464     if (m_uniqueId == match)
1465         return this;
1466     for (int i = 0; i < countChildren(); i++) {
1467         LayerAndroid* result = getChild(i)->findById(match);
1468         if (result)
1469             return result;
1470     }
1471     return 0;
1472 }
1473
1474 } // namespace WebCore
1475
1476 #endif // USE(ACCELERATED_COMPOSITING)