Home | History | Annotate | Download | only in android
      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)
   1477