allow anchor containing layer to be mapped to navable layer

A layer may be inside or outside of an anchor. If it is inside,
the corresponding CachedNode has already been created, but is
being tracked. These tracked nodes need their layer and unclipped
bits set. For now, node in layers are assumed to draw last in
their layer, and aren't obscured by other drawing.

We may allow nodes in layers to be obscured one day. Preparing
for that, translate the layer picture by its global position
when testing to see if the node is hidden.

Fix debugging by allowing CachedLayer to see inside LayerAndroid.

http://b/2453974
diff --git a/WebCore/platform/graphics/android/LayerAndroid.h b/WebCore/platform/graphics/android/LayerAndroid.h
index 940c4d6..4faf27d 100644
--- a/WebCore/platform/graphics/android/LayerAndroid.h
+++ b/WebCore/platform/graphics/android/LayerAndroid.h
@@ -143,6 +143,9 @@
     virtual void onDraw(SkCanvas*, SkScalar opacity);
 
 private:
+#if DUMP_NAV_CACHE
+    friend class CachedLayer::Debug; // debugging access only
+#endif
     void bounds(SkRect* ) const;
     bool prepareContext(bool force = false);
     void clipInner(SkTDArray<SkRect>* region, const SkRect& local) const;
diff --git a/WebKit/android/nav/CacheBuilder.cpp b/WebKit/android/nav/CacheBuilder.cpp
index 9643e68..e34a628 100644
--- a/WebKit/android/nav/CacheBuilder.cpp
+++ b/WebKit/android/nav/CacheBuilder.cpp
@@ -887,6 +887,21 @@
     return false;
 }
 
+#if USE(ACCELERATED_COMPOSITING)
+static void AddLayer(CachedFrame* frame, size_t index, const IntPoint& location,
+    int id)
+{
+    DBG_NAV_LOGD("frame=%p index=%d loc=(%d,%d) id=%d", frame, index,
+        location.x(), location.y(), id);
+    CachedLayer cachedLayer;
+    cachedLayer.reset();
+    cachedLayer.setCachedNodeIndex(index);
+    cachedLayer.setOffset(location);
+    cachedLayer.setUniqueId(id);
+    frame->add(cachedLayer);
+}
+#endif
+
 // when new focus is found, push it's parent on a stack
     // as long as more focii are found with the same (grand) parent, note it
     // (which only requires retrieving the last parent on the stack)
@@ -1018,8 +1033,26 @@
             hasCursorRing = style->tapHighlightColor().alpha() > 0;
 #endif
 #if USE(ACCELERATED_COMPOSITING)
-            if (nodeRenderer->hasLayer())
+            if (nodeRenderer->hasLayer()) {
                 TrackLayer(layerTracker, nodeRenderer, lastChild);
+                size_t size = tracker.size();
+                const LayerAndroid* layer = layerTracker.last().mLayer;
+                if (layer) {
+                    int id = layer->uniqueId();
+                    const IntPoint& loc = nodeRenderer->
+                        absoluteBoundingBoxRect().location();
+                    // if this is a child of a CachedNode, add a layer
+                    for (size_t index = 1; index < tracker.size(); index++) {
+                        const FocusTracker& cursorNode = tracker.at(index);
+                        DBG_NAV_LOGD("call add layer %d", id);
+                        size_t index = cursorNode.mCachedNodeIndex;
+                        CachedNode* trackedNode = cachedFrame->getIndex(index);
+                        trackedNode->setIsInLayer(true);
+                        trackedNode->setIsUnclipped(true);
+                        AddLayer(cachedFrame, index, loc, id);
+                    }
+                }
+            }
 #endif
         }
         bool more = walk.mMore;
@@ -1248,13 +1281,9 @@
                 continue; // skip this node if outside of the clip
             }
             isInLayer = true;
-            isUnclipped = true; // FIXME: add clipping analysis before blindly setting this
-            CachedLayer cachedLayer;
-            cachedLayer.reset();
-            cachedLayer.setCachedNodeIndex(cachedFrame->size());
-            cachedLayer.setOffset(layerClip.location());
-            cachedLayer.setUniqueId(layer->uniqueId());
-            cachedFrame->add(cachedLayer);
+            isUnclipped = true; // assume that layers do not have occluded nodes
+            AddLayer(cachedFrame, cachedFrame->size(), layerClip.location(),
+                layer->uniqueId());
         }
 #endif
         cachedNode.setNavableRects();
diff --git a/WebKit/android/nav/CachedLayer.cpp b/WebKit/android/nav/CachedLayer.cpp
index 12096c7..2f6e20a 100644
--- a/WebKit/android/nav/CachedLayer.cpp
+++ b/WebKit/android/nav/CachedLayer.cpp
@@ -117,7 +117,7 @@
     DUMP_NAV_LOGX("%.*s layer=%p [%d] (%g,%g,%g,%g) picture=%p clipped=%s",
         spaces, "                   ", layer, layer->uniqueId(),
         bounds.fLeft, bounds.fTop, bounds.width(), bounds.height(),
-        layer->picture(), layer->haveClip() ? "true" : "false");
+        layer->picture(), layer->m_haveClip ? "true" : "false");
     for (int i = 0; i < layer->countChildren(); i++)
         printLayerAndroid(layer->getChild(i));
     --spaces;
diff --git a/WebKit/android/nav/CachedRoot.cpp b/WebKit/android/nav/CachedRoot.cpp
index 60b151d..daacbab 100644
--- a/WebKit/android/nav/CachedRoot.cpp
+++ b/WebKit/android/nav/CachedRoot.cpp
@@ -1084,14 +1084,15 @@
     const CachedNode* bestNode = best->mNode;
     if (bestNode->isUnclipped())
         return false;
-    SkPicture* picture = best->mFrame->picture(bestNode);
+    const CachedFrame* frame = best->mFrame;
+    SkPicture* picture = frame->picture(bestNode);
     if (picture == NULL) {
         DBG_NAV_LOG("missing picture");
         return false;
     }
     // given the picture matching this nav cache
         // create an SkBitmap with dimensions of the cursor intersected w/ extended view
-    const WebCore::IntRect& nodeBounds = bestNode->bounds(best->mFrame);
+    const WebCore::IntRect& nodeBounds = bestNode->bounds(frame);
     WebCore::IntRect bounds = nodeBounds;
     bounds.intersect(mScrolledBounds);
     int leftMargin = bounds.x() == nodeBounds.x() ? kMargin : 0;
@@ -1102,6 +1103,25 @@
     WebCore::IntRect marginBounds = nodeBounds;
     marginBounds.inflate(kMargin);
     marginBounds.intersect(mScrolledBounds);
+    SkScalar offsetX = SkIntToScalar(leftMargin - bounds.x());
+    SkScalar offsetY = SkIntToScalar(topMargin - bounds.y());
+#if USE(ACCELERATED_COMPOSITING)
+    // When cached nodes are constructed in CacheBuilder.cpp, their
+    // unclipped attribute is set so this condition won't be reached.
+    // In the future, layers may contain nodes that can be clipped.
+    // So to be safe, adjust the layer picture by its offset.
+    if (bestNode->isInLayer()) {
+        const CachedLayer* cachedLayer = frame->layer(bestNode);
+        const LayerAndroid* layer = cachedLayer->layer(mRootLayer);
+        SkMatrix pictMatrix;
+        layer->localToGlobal(&pictMatrix);
+        // FIXME: ignore scale, rotation for now
+        offsetX += pictMatrix.getTranslateX();
+        offsetY += pictMatrix.getTranslateY();
+        DBG_NAV_LOGD("layer picture=%p (%g,%g)", picture,
+            pictMatrix.getTranslateX(), pictMatrix.getTranslateY());
+    }
+#endif
     BoundsCheck boundsCheck;
     BoundsCanvas checker(&boundsCheck);
     boundsCheck.mBounds.set(leftMargin, topMargin,
@@ -1115,8 +1135,7 @@
     // insert probes to be called when the data corresponding to this ring is drawn
         // need to know if ring was generated by text, image, or parent (like div)
         // ? need to know (like imdb menu bar) to give up sometimes (when?)
-    checker.translate(SkIntToScalar(leftMargin - bounds.x()),
-        SkIntToScalar(topMargin - bounds.y()));
+    checker.translate(offsetX, offsetY);
     checker.drawPicture(*picture);
     boundsCheck.checkLast();
     // was it not drawn or clipped out?