diff options
Diffstat (limited to 'WebKit/android/nav')
| -rw-r--r-- | WebKit/android/nav/CacheBuilder.cpp | 115 | ||||
| -rw-r--r-- | WebKit/android/nav/CacheBuilder.h | 24 | ||||
| -rw-r--r-- | WebKit/android/nav/CachedDebug.h | 5 | ||||
| -rw-r--r-- | WebKit/android/nav/CachedFrame.cpp | 231 | ||||
| -rw-r--r-- | WebKit/android/nav/CachedFrame.h | 50 | ||||
| -rw-r--r-- | WebKit/android/nav/CachedHistory.cpp | 6 | ||||
| -rw-r--r-- | WebKit/android/nav/CachedHistory.h | 4 | ||||
| -rw-r--r-- | WebKit/android/nav/CachedLayer.cpp | 128 | ||||
| -rw-r--r-- | WebKit/android/nav/CachedLayer.h | 79 | ||||
| -rw-r--r-- | WebKit/android/nav/CachedNode.cpp | 59 | ||||
| -rw-r--r-- | WebKit/android/nav/CachedNode.h | 28 | ||||
| -rw-r--r-- | WebKit/android/nav/CachedRoot.cpp | 221 | ||||
| -rw-r--r-- | WebKit/android/nav/CachedRoot.h | 23 | ||||
| -rw-r--r-- | WebKit/android/nav/FindCanvas.cpp | 187 | ||||
| -rw-r--r-- | WebKit/android/nav/FindCanvas.h | 49 | ||||
| -rw-r--r-- | WebKit/android/nav/WebView.cpp | 413 |
16 files changed, 1171 insertions, 451 deletions
diff --git a/WebKit/android/nav/CacheBuilder.cpp b/WebKit/android/nav/CacheBuilder.cpp index c665887..62c2771 100644 --- a/WebKit/android/nav/CacheBuilder.cpp +++ b/WebKit/android/nav/CacheBuilder.cpp @@ -35,6 +35,7 @@ #include "FrameTree.h" #include "FrameView.h" //#include "GraphicsContext.h" +#include "GraphicsLayerAndroid.h" #include "HTMLAreaElement.h" #include "HTMLImageElement.h" #include "HTMLInputElement.h" @@ -49,6 +50,7 @@ #include "RegisteredEventListener.h" #include "RenderImage.h" #include "RenderInline.h" +#include "RenderLayerBacking.h" #include "RenderListBox.h" #include "RenderSkinCombo.h" #include "RenderTextControl.h" @@ -433,11 +435,17 @@ void CacheBuilder::Debug::groups() { print("\"\""); RenderObject* renderer = node->renderer(); int tabindex = node->isElementNode() ? node->tabIndex() : 0; + RenderLayer* layer = 0; if (renderer) { const IntRect& absB = renderer->absoluteBoundingBoxRect(); + bool hasLayer = renderer->hasLayer(); + layer = hasLayer ? toRenderBoxModelObject(renderer)->layer() : 0; snprintf(scratch, sizeof(scratch), ", {%d, %d, %d, %d}, %s" - ", %d},",absB.x(), absB.y(), absB.width(), absB.height(), - renderer->hasOverflowClip() ? "true" : "false", tabindex); + ", %d, %s, %s},", + absB.x(), absB.y(), absB.width(), absB.height(), + renderer->hasOverflowClip() ? "true" : "false", tabindex, + hasLayer ? "true" : "false", + hasLayer && layer->isComposited() ? "true" : "false"); // TODO: add renderer->style()->visibility() print(scratch); } else @@ -463,6 +471,20 @@ void CacheBuilder::Debug::groups() { } count++; newLine(); +#if USE(ACCELERATED_COMPOSITING) + if (renderer && layer) { + RenderLayerBacking* back = layer->backing(); + GraphicsLayerAndroid* grLayer = static_cast + <GraphicsLayerAndroid*>(back ? back->graphicsLayer() : 0); + LayerAndroid* aLayer = grLayer ? grLayer->contentLayer() : 0; + const SkPicture* pict = aLayer ? aLayer->picture() : 0; + snprintf(scratch, sizeof(scratch), "// layer:%p back:%p" + " gLayer:%p aLayer:%p pict:%p", layer, back, grLayer, + aLayer, pict); + print(scratch); + newLine(); + } +#endif } while ((node = node->traverseNextNode()) != NULL); DUMP_NAV_LOGD("}; // focusables = %d\n", count - 1); DUMP_NAV_LOGD("\n"); @@ -875,22 +897,18 @@ static bool checkForPluginViewThatWantsFocus(RenderObject* renderer) { void CacheBuilder::BuildFrame(Frame* root, Frame* frame, CachedRoot* cachedRoot, CachedFrame* cachedFrame) { - WTF::Vector<Tracker> tracker(1); + WTF::Vector<FocusTracker> tracker(1); // sentinel { - Tracker* baseTracker = tracker.data(); // sentinel - bzero(baseTracker, sizeof(Tracker)); + FocusTracker* baseTracker = tracker.data(); + bzero(baseTracker, sizeof(FocusTracker)); baseTracker->mCachedNodeIndex = -1; } - WTF::Vector<ClipColumnTracker> clipTracker(1); - { - ClipColumnTracker* baseTracker = clipTracker.data(); // sentinel - bzero(baseTracker, sizeof(ClipColumnTracker)); - } - WTF::Vector<TabIndexTracker> tabIndexTracker(1); - { - TabIndexTracker* baseTracker = tabIndexTracker.data(); // sentinel - bzero(baseTracker, sizeof(TabIndexTracker)); - } + WTF::Vector<LayerTracker> layerTracker(1); // sentinel + bzero(layerTracker.data(), sizeof(LayerTracker)); + WTF::Vector<ClipColumnTracker> clipTracker(1); // sentinel + bzero(clipTracker.data(), sizeof(ClipColumnTracker)); + WTF::Vector<TabIndexTracker> tabIndexTracker(1); // sentinel + bzero(tabIndexTracker.data(), sizeof(TabIndexTracker)); #if DUMP_NAV_CACHE char* frameNamePtr = cachedFrame->mDebug.mFrameName; Builder(frame)->mDebug.frameName(frameNamePtr, frameNamePtr + @@ -919,7 +937,7 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame, #if DUMP_NAV_CACHE nodeIndex++; #endif - Tracker* last = &tracker.last(); + FocusTracker* last = &tracker.last(); int lastChildIndex = cachedFrame->size() - 1; while (node == last->mLastChild) { if (CleanUpContainedNodes(cachedFrame, last, lastChildIndex)) @@ -935,6 +953,12 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame, clipTracker.removeLast(); } while (true); do { + const LayerTracker* lastLayer = &layerTracker.last(); + if (node != lastLayer->mLastChild) + break; + layerTracker.removeLast(); + } while (true); + do { const TabIndexTracker* lastTabIndex = &tabIndexTracker.last(); if (node != lastTabIndex->mLastChild) break; @@ -988,6 +1012,10 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame, #ifdef ANDROID_CSS_TAP_HIGHLIGHT_COLOR hasCursorRing = style->tapHighlightColor().alpha() > 0; #endif +#if USE(ACCELERATED_COMPOSITING) + if (nodeRenderer->hasLayer()) + TrackLayer(layerTracker, nodeRenderer, lastChild); +#endif } bool more = walk.mMore; walk.reset(); @@ -1084,7 +1112,7 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame, IntRect(0, 0, INT_MAX, INT_MAX); if (ConstructTextRects((WebCore::Text*) node, walk.mStart, (WebCore::Text*) walk.mFinalNode, walk.mEnd, globalOffsetX, - globalOffsetY, &bounds, clip, &cachedNode.cursorRings()) == false) + globalOffsetY, &bounds, clip, cachedNode.cursorRingsPtr()) == false) continue; absBounds = bounds; cachedNode.setBounds(bounds); @@ -1176,9 +1204,9 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame, cachedNode.init(node); if (computeCursorRings == false) { cachedNode.setBounds(bounds); - cachedNode.cursorRings().append(bounds); + cachedNode.cursorRingsPtr()->append(bounds); } else if (ConstructPartRects(node, bounds, cachedNode.boundsPtr(), - globalOffsetX, globalOffsetY, &cachedNode.cursorRings()) == false) + globalOffsetX, globalOffsetY, cachedNode.cursorRingsPtr()) == false) continue; keepTextNode: IntRect clip = hasClip ? bounds : absBounds; @@ -1204,6 +1232,21 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame, else if (cachedNode.clip(clip) == false) continue; // skip this node if outside of the clip } + bool isInLayer = false; +#if USE(ACCELERATED_COMPOSITING) + // FIXME: does not work for area rects + LayerAndroid* layer = layerTracker.last().mLayer; + if (layer) { + isInLayer = true; + isUnclipped = true; // FIXME: add clipping analysis before blindly setting this + CachedLayer cachedLayer; + cachedLayer.reset(); + cachedLayer.setCachedNodeIndex(cachedFrame->size()); + cachedLayer.setOffset(layerTracker.last().mPosition); + cachedLayer.setUniqueId(layer->uniqueId()); + cachedFrame->add(cachedLayer); + } +#endif cachedNode.setNavableRects(); cachedNode.setExport(exported); cachedNode.setHasCursorRing(hasCursorRing); @@ -1211,6 +1254,7 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame, cachedNode.setHitBounds(absBounds); cachedNode.setIndex(cacheIndex); cachedNode.setIsFocus(isFocus); + cachedNode.setIsInLayer(isInLayer); cachedNode.setIsTransparent(isTransparent); cachedNode.setIsUnclipped(isUnclipped); cachedNode.setOriginalAbsoluteBounds(originalAbsBounds); @@ -1238,7 +1282,7 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame, } if (lastChild != NULL) { tracker.grow(tracker.size() + 1); - Tracker& working = tracker.last(); + FocusTracker& working = tracker.last(); working.mCachedNodeIndex = lastIndex; working.mLastChild = OneAfter(lastChild); last = &tracker.at(tracker.size() - 2); @@ -1248,7 +1292,7 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame, cacheIndex++; } while (tracker.size() > 1) { - Tracker* last = &tracker.last(); + FocusTracker* last = &tracker.last(); int lastChildIndex = cachedFrame->size() - 1; if (CleanUpContainedNodes(cachedFrame, last, lastChildIndex)) cacheIndex--; @@ -1257,7 +1301,7 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame, } bool CacheBuilder::CleanUpContainedNodes(CachedFrame* cachedFrame, - const Tracker* last, int lastChildIndex) + const FocusTracker* last, int lastChildIndex) { // if outer is body, disable outer // or if there's more than one inner, disable outer @@ -1272,7 +1316,7 @@ bool CacheBuilder::CleanUpContainedNodes(CachedFrame* cachedFrame, lastNode->hasTagName(HTMLNames::bodyTag) || lastNode->hasTagName(HTMLNames::formTag)) { lastCached->setBounds(IntRect(0, 0, 0, 0)); - lastCached->cursorRings().clear(); + lastCached->cursorRingsPtr()->clear(); lastCached->setNavableRects(); return false; } @@ -2682,6 +2726,31 @@ bool CacheBuilder::setData(CachedFrame* cachedFrame) return true; } +#if USE(ACCELERATED_COMPOSITING) +void CacheBuilder::TrackLayer(WTF::Vector<LayerTracker>& layerTracker, + RenderObject* nodeRenderer, Node* lastChild) +{ + RenderLayer* layer = toRenderBoxModelObject(nodeRenderer)->layer(); + RenderLayerBacking* back = layer->backing(); + if (!back) + return; + GraphicsLayerAndroid* grLayer = static_cast + <GraphicsLayerAndroid*>(back->graphicsLayer()); + if (!grLayer) + return; + LayerAndroid* aLayer = grLayer->contentLayer(); + if (!aLayer) + return; + layerTracker.grow(layerTracker.size() + 1); + LayerTracker& indexTracker = layerTracker.last(); + indexTracker.mLayer = aLayer; + indexTracker.mPosition = nodeRenderer->absoluteBoundingBoxRect().location(); + indexTracker.mLastChild = OneAfter(lastChild); + DBG_NAV_LOGD("layer=%p [%d] pos=(%d,%d)", aLayer, aLayer->uniqueId(), + indexTracker.mPosition.x(), indexTracker.mPosition.y()); +} +#endif + bool CacheBuilder::validNode(Frame* startFrame, void* matchFrame, void* matchNode) { diff --git a/WebKit/android/nav/CacheBuilder.h b/WebKit/android/nav/CacheBuilder.h index ff395d3..9ce91a2 100644 --- a/WebKit/android/nav/CacheBuilder.h +++ b/WebKit/android/nav/CacheBuilder.h @@ -44,6 +44,7 @@ class Document; class Frame; class HTMLAreaElement; class InlineTextBox; +class LayerAndroid; class Node; class PlatformGraphicsContext; class RenderFlow; @@ -183,23 +184,26 @@ private: mStarts[mWordCount] = mCurrentStart; } }; - struct ClipColumnTracker { - IntRect mBounds; + struct Tracker { Node* mLastChild; + }; + struct ClipColumnTracker : Tracker { Node* mNode; + IntRect mBounds; WTF::Vector<IntRect>* mColumns; int mColumnGap; TextDirection mDirection; bool mHasClip; }; - struct TabIndexTracker { + struct LayerTracker : Tracker { + LayerAndroid* mLayer; + IntPoint mPosition; + }; + struct TabIndexTracker : Tracker { int mTabIndex; - Node* mLastChild; }; - struct Tracker { + struct FocusTracker : TabIndexTracker { int mCachedNodeIndex; - int mTabIndex; - Node* mLastChild; bool mSomeParentTakesFocus; }; void adjustForColumns(const ClipColumnTracker& track, @@ -212,7 +216,7 @@ private: void BuildFrame(Frame* root, Frame* frame, CachedRoot* cachedRoot, CachedFrame* cachedFrame); bool CleanUpContainedNodes(CachedFrame* cachedFrame, - const Tracker* last, int lastChildIndex); + const FocusTracker* last, int lastChildIndex); static bool ConstructTextRect(Text* textNode, InlineTextBox* textBox, int start, int relEnd, int x, int y, IntRect* focusBounds, const IntRect& clip, WTF::Vector<IntRect>* result); @@ -238,6 +242,10 @@ private: static bool IsRealNode(Frame* , Node* ); int overlap(int left, int right); // returns distance scale factor as 16.16 scalar bool setData(CachedFrame* ); +#if USE(ACCELERATED_COMPOSITING) + void TrackLayer(WTF::Vector<LayerTracker>& layerTracker, + RenderObject* nodeRenderer, Node* lastChild); +#endif Node* tryFocus(Direction direction); Node* trySegment(Direction direction, int mainStart, int mainEnd); CachedNodeBits mAllowableTypes; diff --git a/WebKit/android/nav/CachedDebug.h b/WebKit/android/nav/CachedDebug.h index 3dbe5ef..3d9e012 100644 --- a/WebKit/android/nav/CachedDebug.h +++ b/WebKit/android/nav/CachedDebug.h @@ -57,11 +57,16 @@ extern FILE* gNavCacheLogFile; #define NAV_CACHE_LOG_FILE "/data/data/com.android.browser/navlog" #define DUMP_NAV_LOGD(...) do { if (gNavCacheLogFile) \ fprintf(gNavCacheLogFile, __VA_ARGS__); else LOGD(__VA_ARGS__); } while (false) +#define DUMP_NAV_LOGX(format, ...) do { if (gNavCacheLogFile) \ + fprintf(gNavCacheLogFile, format, __VA_ARGS__); \ + else LOGD("%s " format, __FUNCTION__, __VA_ARGS__); } while (false) #else #define DUMP_NAV_LOGD(...) LOGD(__VA_ARGS__) +#define DUMP_NAV_LOGX(format, ...) LOGD("%s " format, __FUNCTION__, __VA_ARGS__) #endif #else #define DUMP_NAV_LOGD(...) ((void)0) +#define DUMP_NAV_LOGX(...) ((void)0) #endif #endif diff --git a/WebKit/android/nav/CachedFrame.cpp b/WebKit/android/nav/CachedFrame.cpp index 299dc53..de407c8 100644 --- a/WebKit/android/nav/CachedFrame.cpp +++ b/WebKit/android/nav/CachedFrame.cpp @@ -36,6 +36,18 @@ namespace android { +WebCore::IntRect CachedFrame::adjustBounds(const CachedNode* node, + const WebCore::IntRect& rect) const +{ + DBG_NAV_LOGD("node=%p [%d] rect=(%d,%d,w=%d,h=%d)", + node, node->index(), rect.x(), rect.y(), rect.width(), rect.height()); +#if USE(ACCELERATED_COMPOSITING) + return layer(node)->adjustBounds(mRoot->rootLayer(), rect); +#else + return rect; +#endif +} + bool CachedFrame::CheckBetween(Direction direction, const WebCore::IntRect& bestRect, const WebCore::IntRect& prior, WebCore::IntRect* result) { @@ -105,6 +117,13 @@ bool CachedFrame::checkBetween(BestData* best, Direction direction) return true; } +bool CachedFrame::checkRings(const CachedNode* node, + const WTF::Vector<WebCore::IntRect>& rings, + const WebCore::IntRect& bounds) const +{ + return mRoot->checkRings(picture(node), rings, bounds); +} + bool CachedFrame::checkVisited(const CachedNode* node, Direction direction) const { return history()->checkVisited(node, direction); @@ -121,12 +140,11 @@ void CachedFrame::clearCursor() } // returns 0 if test is preferable to best, 1 if not preferable, or -1 if unknown -int CachedFrame::compare(BestData& testData, const BestData& bestData, - const CachedNode* cursor) const +int CachedFrame::compare(BestData& testData, const BestData& bestData) const { if (testData.mNode->tabIndex() != bestData.mNode->tabIndex()) { if (testData.mNode->tabIndex() < bestData.mNode->tabIndex() - || (cursor && cursor->tabIndex() < bestData.mNode->tabIndex())) { + || (mRoot->cursor() && mRoot->cursor()->tabIndex() < bestData.mNode->tabIndex())) { testData.mNode->setCondition(CachedNode::HIGHER_TAB_INDEX); return REJECT_TEST; } @@ -297,7 +315,7 @@ const CachedNode* CachedFrame::currentCursor(const CachedFrame** framePtr) const const CachedFrame* frame = hasFrame(result); if (frame != NULL) return frame->currentCursor(framePtr); - (const_cast<CachedNode*>(result))->fixUpCursorRects(mRoot); + (const_cast<CachedNode*>(result))->fixUpCursorRects(this); return result; } @@ -351,15 +369,25 @@ const CachedNode* CachedFrame::findBestAt(const WebCore::IntRect& rect, size_t parts = test->navableRects(); BestData testData; testData.mNode = test; - testData.mMouseBounds = testData.mNodeBounds = test->getBounds(); + testData.mFrame = this; + WebCore::IntRect bounds = test->bounds(this); + testData.setMouseBounds(bounds); + testData.setNodeBounds(bounds); bool checkForHidden = checkForHiddenStart; for (size_t part = 0; part < parts; part++) { - if (test->cursorRings().at(part).intersects(rect)) { + WebCore::IntRect testRect = test->ring(this, part); + if (test->isInLayer()) { + DBG_NAV_LOGD("[%d] intersects=%ss testRect=(%d,%d,w=%d,h=%d)" + " rect=(%d,%d,w=%d,h=%d)", test->index(), + testRect.intersects(rect) ? "true" : "false", + testRect.x(), testRect.y(), testRect.width(), testRect.height(), + rect.x(), rect.y(), rect.width(), rect.height()); + } + if (testRect.intersects(rect)) { if (checkForHidden && mRoot->maskIfHidden(&testData) == true) break; checkForHidden = false; - WebCore::IntRect testRect = test->cursorRings().at(part); - testRect.intersect(testData.mMouseBounds); + testRect.intersect(testData.mouseBounds()); if (testRect.contains(center)) { // We have a direct hit. if (*directHit == NULL) { @@ -370,7 +398,7 @@ const CachedNode* CachedFrame::findBestAt(const WebCore::IntRect& rect, } else { // We have hit another one before const CachedNode* d = *directHit; - if (d->getBounds().contains(testRect)) { + if (d->bounds(this).contains(testRect)) { // This rectangle is inside the other one, so it is // the best one. *directHit = test; @@ -455,16 +483,18 @@ const CachedNode* CachedFrame::findBestHitAt(const WebCore::IntRect& rect, test != mCachedNodes.begin() - 1; test--) { if (test->disabled()) continue; - const WebCore::IntRect& testRect = test->hitBounds(); + WebCore::IntRect testRect = test->hitBounds(this); if (testRect.intersects(rect) == false) continue; BestData testData; testData.mNode = test; - testData.mMouseBounds = testData.mNodeBounds = testRect; + testData.mFrame = this; + testData.setMouseBounds(testRect); + testData.setNodeBounds(testRect); if (mRoot->maskIfHidden(&testData) == true) continue; - for (unsigned i = 0; i < test->cursorRings().size(); i++) { - const WebCore::IntRect& cursorRect = test->cursorRings().at(i); + for (int i = 0; i < test->navableRects(); i++) { + WebCore::IntRect cursorRect = test->ring(this, i); if (cursorRect.intersects(rect)) { WebCore::IntRect intersection(cursorRect); intersection.intersect(rect); @@ -492,13 +522,13 @@ void CachedFrame::findClosest(BestData* bestData, Direction originalDirection, } if (test->noSecondChance()) continue; - if (test->isNavable(*clip) == false) + if (test->isNavable(this, *clip) == false) continue; if (checkVisited(test, originalDirection) == false) continue; size_t partMax = test->navableRects(); for (size_t part = 0; part < partMax; part++) { - WebCore::IntRect testBounds = test->cursorRings().at(part); + WebCore::IntRect testBounds = test->ring(this, part); if (clip->intersects(testBounds) == false) continue; if (clip->contains(testBounds) == false) { @@ -538,8 +568,9 @@ void CachedFrame::findClosest(BestData* bestData, Direction originalDirection, bestData->mNode = test; bestData->mFrame = this; bestData->mDistance = distance; - bestData->mMouseBounds = bestData->mNodeBounds = - test->cursorRings().at(part); + WebCore::IntRect rect = test->ring(this, part); + bestData->setMouseBounds(rect); + bestData->setNodeBounds(rect); CachedHistory* cachedHistory = history(); switch (direction) { case LEFT: @@ -577,29 +608,29 @@ void CachedFrame::finishInit() frameParent->setFocusIndex(indexInParent()); } -const CachedNode* CachedFrame::frameDown(const CachedNode* test, const CachedNode* limit, BestData* bestData, - const CachedNode* cursor) const +const CachedNode* CachedFrame::frameDown(const CachedNode* test, + const CachedNode* limit, BestData* bestData) const { BestData originalData = *bestData; do { - if (moveInFrame(&CachedFrame::frameDown, test, bestData, cursor)) + if (moveInFrame(&CachedFrame::frameDown, test, bestData)) continue; BestData testData; - if (frameNodeCommon(testData, test, bestData, &originalData, cursor) == REJECT_TEST) + if (frameNodeCommon(testData, test, bestData, &originalData) == REJECT_TEST) continue; if (checkVisited(test, DOWN) == false) continue; size_t parts = test->navableRects(); for (size_t part = 0; part < parts; part++) { - testData.mNodeBounds = test->cursorRings().at(part); + testData.setNodeBounds(test->ring(this, part)); if (testData.setDownDirection(history())) continue; - int result = framePartCommon(testData, test, bestData, cursor); + int result = framePartCommon(testData, test, bestData); if (result == REJECT_TEST) continue; if (result == 0 && limit == NULL) { // retry all data up to this point, since smaller may have replaced node preferable to larger BestData innerData = testData; - frameDown(document(), test, &innerData, cursor); + frameDown(document(), test, &innerData); if (checkVisited(innerData.mNode, DOWN)) { *bestData = innerData; continue; @@ -609,7 +640,7 @@ const CachedNode* CachedFrame::frameDown(const CachedNode* test, const CachedNod *bestData = testData; } } while ((test = test->traverseNextNode()) != limit); - ASSERT(cursor == NULL || bestData->mNode != cursor); + ASSERT(mRoot->cursor() == NULL || bestData->mNode != mRoot->cursor()); // does the best contain something (or, is it contained by an area which is not the cursor?) // if so, is the conainer/containee should have been chosen, but wasn't -- so there's a better choice // in the doc list prior to this choice @@ -617,29 +648,29 @@ const CachedNode* CachedFrame::frameDown(const CachedNode* test, const CachedNod return bestData->mNode; } -const CachedNode* CachedFrame::frameLeft(const CachedNode* test, const CachedNode* limit, BestData* bestData, - const CachedNode* cursor) const +const CachedNode* CachedFrame::frameLeft(const CachedNode* test, + const CachedNode* limit, BestData* bestData) const { BestData originalData = *bestData; do { - if (moveInFrame(&CachedFrame::frameLeft, test, bestData, cursor)) + if (moveInFrame(&CachedFrame::frameLeft, test, bestData)) continue; BestData testData; - if (frameNodeCommon(testData, test, bestData, &originalData, cursor) == REJECT_TEST) + if (frameNodeCommon(testData, test, bestData, &originalData) == REJECT_TEST) continue; if (checkVisited(test, LEFT) == false) continue; size_t parts = test->navableRects(); for (size_t part = 0; part < parts; part++) { - testData.mNodeBounds = test->cursorRings().at(part); + testData.setNodeBounds(test->ring(this, part)); if (testData.setLeftDirection(history())) continue; - int result = framePartCommon(testData, test, bestData, cursor); + int result = framePartCommon(testData, test, bestData); if (result == REJECT_TEST) continue; if (result == 0 && limit == NULL) { // retry all data up to this point, since smaller may have replaced node preferable to larger BestData innerData = testData; - frameLeft(document(), test, &innerData, cursor); + frameLeft(document(), test, &innerData); if (checkVisited(innerData.mNode, LEFT)) { *bestData = innerData; continue; @@ -649,12 +680,12 @@ const CachedNode* CachedFrame::frameLeft(const CachedNode* test, const CachedNod *bestData = testData; } } while ((test = test->traverseNextNode()) != limit); // FIXME ??? left and up should use traversePreviousNode to choose reverse document order - ASSERT(cursor == NULL || bestData->mNode != cursor); + ASSERT(mRoot->cursor() == NULL || bestData->mNode != mRoot->cursor()); return bestData->mNode; } -int CachedFrame::frameNodeCommon(BestData& testData, const CachedNode* test, BestData* bestData, BestData* originalData, - const CachedNode* cursor) const +int CachedFrame::frameNodeCommon(BestData& testData, const CachedNode* test, + BestData* bestData, BestData* originalData) const { testData.mFrame = this; testData.mNode = test; @@ -663,16 +694,21 @@ int CachedFrame::frameNodeCommon(BestData& testData, const CachedNode* test, Bes testData.mNode->setCondition(CachedNode::DISABLED); return REJECT_TEST; } - if (mRoot->scrolledBounds().intersects(test->bounds()) == false) { + if (mRoot->scrolledBounds().intersects(test->bounds(this)) == false) { testData.mNode->setCondition(CachedNode::NAVABLE); return REJECT_TEST; } + if (mRoot->rootLayer() && !test->isInLayer() + && !mRoot->baseUncovered().intersects(test->bounds(this))) { + testData.mNode->setCondition(CachedNode::UNDER_LAYER); + return REJECT_TEST; + } // if (isNavable(test, &testData.mNodeBounds, walk) == false) { // testData.mNode->setCondition(CachedNode::NAVABLE); // return REJECT_TEST; // } // - if (test == cursor) { + if (test == mRoot->cursor()) { testData.mNode->setCondition(CachedNode::NOT_CURSOR_NODE); return REJECT_TEST; } @@ -680,36 +716,12 @@ int CachedFrame::frameNodeCommon(BestData& testData, const CachedNode* test, Bes // testData.mNode->setCondition(CachedNode::NOT_ENCLOSING_CURSOR); // return REJECT_TEST; // } - void* par = cursor ? cursor->parentGroup() : NULL; + void* par = mRoot->cursor() ? mRoot->cursor()->parentGroup() : NULL; testData.mCursorChild = par ? test->parentGroup() == par : false; -#if 0 // not debugged - if (cursor && cursor->hasMouseOver() && test->hasMouseOver() == false && - cursor->bounds().contains(test->bounds())) - return REJECT_TEST; -#endif if (bestData->mNode == NULL) return TEST_IS_BEST; -#if 0 // not debugged - if (cursor && cursor->hasMouseOver() && test->hasMouseOver() == false && - cursor->bounds().contains(test->bounds())) - return REJECT_TEST; - if (test->hasMouseOver() != bestData->mNode->hasMouseOver()) { - if (test->hasMouseOver()) { - if (test->bounds().contains(bestData->mNode->bounds())) { - const_cast<CachedNode*>(bestData->mNode)->setDisabled(true); - bestData->mNode = NULL; // force part tests to be ignored, yet still set up remaining test data for later comparison - return TEST_IS_BEST; - } - } else { - if (bestData->mNode->bounds().contains(test->bounds())) { - test->setCondition(CachedNode::ANCHOR_IN_ANCHOR); - return REJECT_TEST; - } - } - } -#endif - if (cursor && testData.mNode->parentIndex() != bestData->mNode->parentIndex()) { - int cursorParentIndex = cursor->parentIndex(); + if (mRoot->cursor() && testData.mNode->parentIndex() != bestData->mNode->parentIndex()) { + int cursorParentIndex = mRoot->cursor()->parentIndex(); if (cursorParentIndex >= 0) { if (bestData->mNode->parentIndex() == cursorParentIndex) return REJECT_TEST; @@ -745,15 +757,17 @@ int CachedFrame::frameNodeCommon(BestData& testData, const CachedNode* test, Bes } int CachedFrame::framePartCommon(BestData& testData, - const CachedNode* test, BestData* bestData, const CachedNode* cursor) const + const CachedNode* test, BestData* bestData) const { - if (cursor && testData.mNodeBounds.contains(cursor->bounds()) && !test->wantsKeyEvents()) { + if (mRoot->cursor() + && testData.bounds().contains(mRoot->cursorBounds()) + && !test->wantsKeyEvents()) { testData.mNode->setCondition(CachedNode::NOT_ENCLOSING_CURSOR); return REJECT_TEST; } testData.setDistances(); if (bestData->mNode != NULL) { - int compared = compare(testData, *bestData, cursor); + int compared = compare(testData, *bestData); if (compared == 0 && test->isArea() == false && bestData->mNode->isArea() == false) goto pickTest; if (compared >= 0) @@ -763,29 +777,29 @@ pickTest: return -1; // pick test } -const CachedNode* CachedFrame::frameRight(const CachedNode* test, const CachedNode* limit, BestData* bestData, - const CachedNode* cursor) const +const CachedNode* CachedFrame::frameRight(const CachedNode* test, + const CachedNode* limit, BestData* bestData) const { BestData originalData = *bestData; do { - if (moveInFrame(&CachedFrame::frameRight, test, bestData, cursor)) + if (moveInFrame(&CachedFrame::frameRight, test, bestData)) continue; BestData testData; - if (frameNodeCommon(testData, test, bestData, &originalData, cursor) == REJECT_TEST) + if (frameNodeCommon(testData, test, bestData, &originalData) == REJECT_TEST) continue; if (checkVisited(test, RIGHT) == false) continue; size_t parts = test->navableRects(); for (size_t part = 0; part < parts; part++) { - testData.mNodeBounds = test->cursorRings().at(part); + testData.setNodeBounds(test->ring(this, part)); if (testData.setRightDirection(history())) continue; - int result = framePartCommon(testData, test, bestData, cursor); + int result = framePartCommon(testData, test, bestData); if (result == REJECT_TEST) continue; if (result == 0 && limit == NULL) { // retry all data up to this point, since smaller may have replaced node preferable to larger BestData innerData = testData; - frameRight(document(), test, &innerData, cursor); + frameRight(document(), test, &innerData); if (checkVisited(innerData.mNode, RIGHT)) { *bestData = innerData; continue; @@ -795,33 +809,33 @@ const CachedNode* CachedFrame::frameRight(const CachedNode* test, const CachedNo *bestData = testData; } } while ((test = test->traverseNextNode()) != limit); - ASSERT(cursor == NULL || bestData->mNode != cursor); + ASSERT(mRoot->cursor() == NULL || bestData->mNode != mRoot->cursor()); return bestData->mNode; } -const CachedNode* CachedFrame::frameUp(const CachedNode* test, const CachedNode* limit, BestData* bestData, - const CachedNode* cursor) const +const CachedNode* CachedFrame::frameUp(const CachedNode* test, + const CachedNode* limit, BestData* bestData) const { BestData originalData = *bestData; do { - if (moveInFrame(&CachedFrame::frameUp, test, bestData, cursor)) + if (moveInFrame(&CachedFrame::frameUp, test, bestData)) continue; BestData testData; - if (frameNodeCommon(testData, test, bestData, &originalData, cursor) == REJECT_TEST) + if (frameNodeCommon(testData, test, bestData, &originalData) == REJECT_TEST) continue; if (checkVisited(test, UP) == false) continue; size_t parts = test->navableRects(); for (size_t part = 0; part < parts; part++) { - testData.mNodeBounds = test->cursorRings().at(part); + testData.setNodeBounds(test->ring(this, part)); if (testData.setUpDirection(history())) continue; - int result = framePartCommon(testData, test, bestData, cursor); + int result = framePartCommon(testData, test, bestData); if (result == REJECT_TEST) continue; if (result == 0 && limit == NULL) { // retry all data up to this point, since smaller may have replaced node preferable to larger BestData innerData = testData; - frameUp(document(), test, &innerData, cursor); + frameUp(document(), test, &innerData); if (checkVisited(innerData.mNode, UP)) { *bestData = innerData; continue; @@ -831,7 +845,7 @@ const CachedNode* CachedFrame::frameUp(const CachedNode* test, const CachedNode* *bestData = testData; } } while ((test = test->traverseNextNode()) != limit); // FIXME ??? left and up should use traversePreviousNode to choose reverse document order - ASSERT(cursor == NULL || bestData->mNode != cursor); + ASSERT(mRoot->cursor() == NULL || bestData->mNode != mRoot->cursor()); return bestData->mNode; } @@ -868,6 +882,17 @@ void CachedFrame::init(const CachedRoot* root, int childFrameIndex, mIndexInParent = childFrameIndex; } +#if USE(ACCELERATED_COMPOSITING) +const CachedLayer* CachedFrame::layer(const CachedNode* node) const +{ + if (!node->isInLayer()) + return 0; + CachedLayer test; + test.setCachedNodeIndex(node->index()); + return std::lower_bound(mCachedLayers.begin(), mCachedLayers.end(), test); +} +#endif + int CachedFrame::minWorkingHorizontal() const { return history()->minWorkingHorizontal(); @@ -917,8 +942,7 @@ const CachedNode* CachedFrame::nextTextField(const CachedNode* start, } bool CachedFrame::moveInFrame(MoveInDirection moveInDirection, - const CachedNode* test, BestData* bestData, - const CachedNode* cursor) const + const CachedNode* test, BestData* bestData) const { const CachedFrame* frame = hasFrame(test); if (frame == NULL) @@ -926,7 +950,7 @@ bool CachedFrame::moveInFrame(MoveInDirection moveInDirection, const CachedNode* childDoc = frame->validDocument(); if (childDoc == NULL) return true; - (frame->*moveInDirection)(childDoc, NULL, bestData, cursor); + (frame->*moveInDirection)(childDoc, NULL, bestData); return true; } @@ -935,6 +959,15 @@ const WebCore::IntRect& CachedFrame::_navBounds() const return history()->navBounds(); } +SkPicture* CachedFrame::picture(const CachedNode* node) const +{ +#if USE(ACCELERATED_COMPOSITING) + if (node->isInLayer()) + return layer(node)->picture(mRoot->rootLayer()); +#endif + return mRoot->getPicture(); +} + void CachedFrame::resetClippedOut() { for (CachedNode* test = mCachedNodes.begin(); test != mCachedNodes.end(); test++) @@ -950,6 +983,20 @@ void CachedFrame::resetClippedOut() } } +void CachedFrame::resetLayers() +{ +#if USE(ACCELERATED_COMPOSITING) + for (CachedLayer* test = mCachedLayers.begin(); test != mCachedLayers.end(); + test++) { + test->reset(); + } + for (CachedFrame* frame = mCachedFrames.begin(); frame != mCachedFrames.end(); + frame++) { + frame->resetLayers(); + } +#endif +} + bool CachedFrame::sameFrame(const CachedFrame* test) const { ASSERT(test); @@ -1005,9 +1052,8 @@ bool CachedFrame::setCursor(WebCore::Frame* frame, WebCore::Node* node, if (test->nodePointer() != node && first) continue; size_t partMax = test->navableRects(); - WTF::Vector<WebCore::IntRect>& cursorRings = test->cursorRings(); for (size_t part = 0; part < partMax; part++) { - const WebCore::IntRect& testBounds = cursorRings.at(part); + WebCore::IntRect testBounds = test->ring(this, part); if (testBounds.contains(x, y) == false) continue; if (test->isCursor()) { @@ -1324,6 +1370,7 @@ void CachedFrame::Debug::print() const DEBUG_PRINT_RECT("//", CONTENTS, mContents); DEBUG_PRINT_RECT("", BOUNDS, mLocalViewBounds); DEBUG_PRINT_RECT("//", VIEW, mViewBounds); + DUMP_NAV_LOGD("// CachedNode mCachedNodes={ // count=%d\n", b->mCachedNodes.size()); for (CachedNode* node = b->mCachedNodes.begin(); node != b->mCachedNodes.end(); node++) { @@ -1333,6 +1380,14 @@ void CachedFrame::Debug::print() const input->mDebug.print(); } DUMP_NAV_LOGD("// }; // end of nodes\n"); +#if USE(ACCELERATED_COMPOSITING) + DUMP_NAV_LOGD("// CachedLayer mCachedLayers={ // count=%d\n", b->mCachedLayers.size()); + for (CachedLayer* layer = b->mCachedLayers.begin(); + layer != b->mCachedLayers.end(); layer++) { + layer->mDebug.print(); + } + DUMP_NAV_LOGD("// }; // end of layers\n"); +#endif // USE(ACCELERATED_COMPOSITING) DUMP_NAV_LOGD("// CachedFrame mCachedFrames={ // count=%d\n", b->mCachedFrames.size()); for (CachedFrame* child = b->mCachedFrames.begin(); child != b->mCachedFrames.end(); child++) diff --git a/WebKit/android/nav/CachedFrame.h b/WebKit/android/nav/CachedFrame.h index 7a00539..613b2eb 100644 --- a/WebKit/android/nav/CachedFrame.h +++ b/WebKit/android/nav/CachedFrame.h @@ -27,11 +27,14 @@ #define CachedFrame_H #include "CachedInput.h" +#include "CachedLayer.h" #include "CachedNode.h" #include "IntRect.h" #include "SkFixed.h" #include "wtf/Vector.h" +class SkPicture; + namespace WebCore { class Frame; class Node; @@ -68,8 +71,16 @@ public: }; CachedFrame() {} void add(CachedInput& input) { mCachedTextInputs.append(input); } +#if USE(ACCELERATED_COMPOSITING) + void add(CachedLayer& layer) { mCachedLayers.append(layer); } +#endif void add(CachedNode& node) { mCachedNodes.append(node); } void addFrame(CachedFrame& child) { mCachedFrames.append(child); } + WebCore::IntRect adjustBounds(const CachedNode* , + const WebCore::IntRect& ) const; + bool checkRings(const CachedNode* node, + const WTF::Vector<WebCore::IntRect>& rings, + const WebCore::IntRect& bounds) const; bool checkVisited(const CachedNode* , CachedFrame::Direction ) const; size_t childCount() { return mCachedFrames.size(); } void clearCursor(); @@ -99,6 +110,9 @@ public: const CachedFrame* lastChild() const { return &mCachedFrames.last(); } CachedNode* lastNode() { return &mCachedNodes.last(); } CachedFrame* lastChild() { return &mCachedFrames.last(); } +#if USE(ACCELERATED_COMPOSITING) + const CachedLayer* layer(const CachedNode* ) const; +#endif /** * Find the next textfield/textarea * @param start Must be a CachedNode in this CachedFrame's tree, or @@ -113,6 +127,8 @@ public: const CachedFrame** framePtr, bool includeTextAreas) const; const CachedFrame* parent() const { return mParent; } CachedFrame* parent() { return mParent; } + SkPicture* picture(const CachedNode* ) const; + void resetLayers(); bool sameFrame(const CachedFrame* ) const; void removeLast() { mCachedNodes.removeLast(); } void resetClippedOut(); @@ -132,8 +148,6 @@ public: const CachedNode* validDocument() const; protected: struct BestData { - WebCore::IntRect mNodeBounds; - WebCore::IntRect mMouseBounds; int mDistance; int mSideDistance; int mMajorDelta; // difference of center of object @@ -160,9 +174,12 @@ protected: bool inOrSubsumesNav() const { return (mNavDelta ^ mNavDelta2) >= 0; } bool inOrSubsumesWorking() const { return (mWorkingDelta ^ mWorkingDelta2) >= 0; } int isContainer(BestData* ); + const WebCore::IntRect& mouseBounds() const { return mMouseBounds; } static SkFixed Overlap(int span, int left, int right); void reset() { mNode = NULL; } int right() const { return bounds().right(); } + void setMouseBounds(const WebCore::IntRect& b) { mMouseBounds = b; } + void setNodeBounds(const WebCore::IntRect& b) { mNodeBounds = b; } void setDistances(); bool setDownDirection(const CachedHistory* ); bool setLeftDirection(const CachedHistory* ); @@ -175,37 +192,37 @@ protected: int width() const { return bounds().width(); } int x() const { return bounds().x(); } int y() const { return bounds().y(); } +private: // since computing these is complicated, protect them so that the + // are only written by appropriate helpers + WebCore::IntRect mMouseBounds; + WebCore::IntRect mNodeBounds; }; typedef const CachedNode* (CachedFrame::*MoveInDirection)( - const CachedNode* test, const CachedNode* limit, BestData* bestData, - const CachedNode* focus) const; + const CachedNode* test, const CachedNode* limit, BestData* ) const; void adjustToTextColumn(int* delta) const; static bool CheckBetween(Direction , const WebCore::IntRect& bestRect, const WebCore::IntRect& prior, WebCore::IntRect* result); bool checkBetween(BestData* , Direction ); - int compare(BestData& testData, const BestData& bestData, const - CachedNode* focus) const; + int compare(BestData& testData, const BestData& bestData) const; void findClosest(BestData* , Direction original, Direction test, WebCore::IntRect* clip) const; int frameNodeCommon(BestData& testData, const CachedNode* test, - BestData* bestData, BestData* originalData, - const CachedNode* focus) const; + BestData* bestData, BestData* originalData) const; int framePartCommon(BestData& testData, const CachedNode* test, - BestData* bestData, const CachedNode* focus) const; + BestData* ) const; const CachedNode* frameDown(const CachedNode* test, const CachedNode* limit, - BestData* , const CachedNode* focus) const; + BestData* ) const; const CachedNode* frameLeft(const CachedNode* test, const CachedNode* limit, - BestData* , const CachedNode* focus) const; + BestData* ) const; const CachedNode* frameRight(const CachedNode* test, const CachedNode* limit, - BestData* , const CachedNode* focus) const; + BestData* ) const; const CachedNode* frameUp(const CachedNode* test, const CachedNode* limit, - BestData* , const CachedNode* focus) const; + BestData* ) const; int minWorkingHorizontal() const; int minWorkingVertical() const; int maxWorkingHorizontal() const; int maxWorkingVertical() const; - bool moveInFrame(MoveInDirection , const CachedNode* test, BestData* best, - const CachedNode* focus) const; + bool moveInFrame(MoveInDirection , const CachedNode* test, BestData* ) const; const WebCore::IntRect& _navBounds() const; WebCore::IntRect mContents; WebCore::IntRect mLocalViewBounds; @@ -213,6 +230,9 @@ protected: WTF::Vector<CachedNode> mCachedNodes; WTF::Vector<CachedFrame> mCachedFrames; WTF::Vector<CachedInput> mCachedTextInputs; +#if USE(ACCELERATED_COMPOSITING) + WTF::Vector<CachedLayer> mCachedLayers; +#endif void* mFrame; // WebCore::Frame*, used only to compare pointers CachedFrame* mParent; int mCursorIndex; diff --git a/WebKit/android/nav/CachedHistory.cpp b/WebKit/android/nav/CachedHistory.cpp index 47a560c..9066412 100644 --- a/WebKit/android/nav/CachedHistory.cpp +++ b/WebKit/android/nav/CachedHistory.cpp @@ -91,7 +91,8 @@ void CachedHistory::reset() } void CachedHistory::setWorking(CachedFrame::Direction newMove, - const CachedNode* cursor, const WebCore::IntRect& viewBounds) + const CachedFrame* cursorFrame, const CachedNode* cursor, + const WebCore::IntRect& viewBounds) { CachedFrame::Direction lastAxis = (CachedFrame::Direction) (mLastMove & ~CachedFrame::RIGHT_DOWN); // up, left or uninitialized CachedFrame::Direction newAxis = (CachedFrame::Direction) (newMove & ~CachedFrame::RIGHT_DOWN); @@ -103,8 +104,7 @@ void CachedHistory::setWorking(CachedFrame::Direction newMove, } const WebCore::IntRect* navBounds = &mNavBounds; if (cursor != NULL) { - WebCore::IntRect cursorBounds; - cursor->getBounds(&cursorBounds); + WebCore::IntRect cursorBounds = cursor->bounds(cursorFrame); if (cursorBounds.isEmpty() == false) mNavBounds = cursorBounds; } diff --git a/WebKit/android/nav/CachedHistory.h b/WebKit/android/nav/CachedHistory.h index 302da4e..e8c1ad9 100644 --- a/WebKit/android/nav/CachedHistory.h +++ b/WebKit/android/nav/CachedHistory.h @@ -52,8 +52,8 @@ public: void setDidFirstLayout(bool did) { mDidFirstLayout = did; } void setMouseBounds(const WebCore::IntRect& loc) { mMouseBounds = loc; } void setNavBounds(const WebCore::IntRect& loc) { mNavBounds = loc; } - void setWorking(CachedFrame::Direction , const CachedNode* focus, - const WebCore::IntRect& viewBounds); + void setWorking(CachedFrame::Direction , const CachedFrame* , + const CachedNode* , const WebCore::IntRect& viewBounds); void reset(); private: void pinMaxMin(const WebCore::IntRect& viewBounds); diff --git a/WebKit/android/nav/CachedLayer.cpp b/WebKit/android/nav/CachedLayer.cpp new file mode 100644 index 0000000..f28da2b --- /dev/null +++ b/WebKit/android/nav/CachedLayer.cpp @@ -0,0 +1,128 @@ +/* + * Copyright 2010, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "CachedPrefix.h" + +#include "CachedLayer.h" +#include "FloatRect.h" +#include "LayerAndroid.h" + +namespace android { + +#if USE(ACCELERATED_COMPOSITING) + +IntRect CachedLayer::adjustBounds(const LayerAndroid* root, + const IntRect& bounds) const +{ + const LayerAndroid* aLayer = layer(root); + if (!aLayer) { + DBG_NAV_LOGD("no layer in root=%p uniqueId=%d", root, mUniqueId); +#if DUMP_NAV_CACHE + if (root) + mDebug.printRootLayerAndroid(root); +#endif + return bounds; + } + FloatRect temp = bounds; + const FloatPoint& position = aLayer->position(); + temp.move(position.x(), position.y()); + const FloatPoint& translation = aLayer->translation(); + temp.move(translation.x(), translation.y()); + IntRect result = enclosingIntRect(temp); + DBG_NAV_LOGD("root=%p aLayer=%p [%d]" + " bounds=(%d,%d,w=%d,h=%d) pos=(%g,%g) trans=(%g,%g)" + " result=(%d,%d,w=%d,h=%d) offset=(%d,%d)", + root, aLayer, aLayer->uniqueId(), + bounds.x(), bounds.y(), bounds.width(), bounds.height(), + position.x(), position.y(), translation.x(), translation.y(), + result.x(), result.y(), result.width(), result.height(), + mOffset.x(), mOffset.y()); + result.move(-mOffset.x(), -mOffset.y()); + return result; +} + +const LayerAndroid* CachedLayer::layer(const LayerAndroid* root) const +{ + if (!root || mLayer) + return mLayer; + return mLayer = root->findById(mUniqueId); +} + +SkPicture* CachedLayer::picture(const LayerAndroid* root) const +{ + const LayerAndroid* aLayer = layer(root); + if (!aLayer) + return 0; + DBG_NAV_LOGD("root=%p aLayer=%p [%d] picture=%p", + root, aLayer, aLayer->uniqueId(), aLayer->picture()); + return aLayer->picture(); +} + +#if DUMP_NAV_CACHE + +CachedLayer* CachedLayer::Debug::base() const { + return (CachedLayer*) ((char*) this - OFFSETOF(CachedLayer, mDebug)); +} + +void CachedLayer::Debug::print() const +{ + CachedLayer* b = base(); + DUMP_NAV_LOGD(" // int mCachedNodeIndex=%d;", b->mCachedNodeIndex); + DUMP_NAV_LOGD(" LayerAndroid* mLayer=%p;", b->mLayer); + DUMP_NAV_LOGD(" int mOffset=(%d, %d);", b->mOffset.x(), b->mOffset.y()); + DUMP_NAV_LOGD(" int mUniqueId=%p;\n", b->mUniqueId); +} + +#endif + +#if DUMP_NAV_CACHE + +int CachedLayer::Debug::spaces; + +void CachedLayer::Debug::printLayerAndroid(const LayerAndroid* layer) +{ + ++spaces; + SkRect bounds; + layer->bounds(&bounds); + 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"); + for (int i = 0; i < layer->countChildren(); i++) + printLayerAndroid(layer->getChild(i)); + --spaces; +} + +void CachedLayer::Debug::printRootLayerAndroid(const LayerAndroid* layer) +{ + spaces = 0; + printLayerAndroid(layer); +} +#endif + +#endif // USE(ACCELERATED_COMPOSITING) + +} + diff --git a/WebKit/android/nav/CachedLayer.h b/WebKit/android/nav/CachedLayer.h new file mode 100644 index 0000000..d320b0c --- /dev/null +++ b/WebKit/android/nav/CachedLayer.h @@ -0,0 +1,79 @@ +/* + * Copyright 2010, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CachedLayer_H +#define CachedLayer_H + +#include "CachedDebug.h" +#include "IntRect.h" + +class SkPicture; + +namespace WebCore { + class LayerAndroid; +} + +using namespace WebCore; + +namespace android { + +class CachedLayer { +public: +#if USE(ACCELERATED_COMPOSITING) + bool operator<(const CachedLayer& l) const { + return mCachedNodeIndex < l.mCachedNodeIndex; + } + IntRect adjustBounds(const LayerAndroid* root, const IntRect& bounds) const; + int cachedNodeIndex() const { return mCachedNodeIndex; } + const LayerAndroid* layer(const LayerAndroid* root) const; + SkPicture* picture(const LayerAndroid* root) const; + void reset() { mLayer = 0; } + void setCachedNodeIndex(int index) { mCachedNodeIndex = index; } + void setOffset(const IntPoint& offset) { mOffset = offset; } + void setUniqueId(int uniqueId) { mUniqueId = uniqueId; } + int uniqueId() const { return mUniqueId; } +private: + int mCachedNodeIndex; + mutable const LayerAndroid* mLayer; + IntPoint mOffset; + int mUniqueId; + +#if DUMP_NAV_CACHE +public: + class Debug { +public: + CachedLayer* base() const; + void print() const; + static void printLayerAndroid(const LayerAndroid* ); + static void printRootLayerAndroid(const LayerAndroid* ); + static int spaces; + } mDebug; +#endif +#endif // USE(ACCELERATED_COMPOSITING) +}; + +} + +#endif diff --git a/WebKit/android/nav/CachedNode.cpp b/WebKit/android/nav/CachedNode.cpp index 58ada58..9406db1 100644 --- a/WebKit/android/nav/CachedNode.cpp +++ b/WebKit/android/nav/CachedNode.cpp @@ -24,16 +24,21 @@ */ #include "CachedPrefix.h" +#include "android_graphics.h" +#include "CachedFrame.h" #include "CachedHistory.h" -#include "CachedRoot.h" #include "Node.h" #include "PlatformString.h" -#include "android_graphics.h" #include "CachedNode.h" namespace android { +WebCore::IntRect CachedNode::bounds(const CachedFrame* frame) const +{ + return mIsInLayer ? frame->adjustBounds(this, mBounds) : mBounds; +} + void CachedNode::clearCursor(CachedFrame* parent) { if (isFrame()) { @@ -76,26 +81,36 @@ bool CachedNode::clip(const WebCore::IntRect& bounds) return Clip(bounds, &mBounds, &mCursorRing); } -void CachedNode::cursorRingBounds(WebCore::IntRect* bounds) const + +void CachedNode::cursorRings(const CachedFrame* frame, + WTF::Vector<WebCore::IntRect>* rings) const +{ + rings->clear(); + for (unsigned index = 0; index < mCursorRing.size(); index++) + rings->append(ring(frame, index)); +} + +WebCore::IntRect CachedNode::cursorRingBounds(const CachedFrame* frame) const { int partMax = mNavableRects; ASSERT(partMax > 0); - *bounds = mCursorRing[0]; + WebCore::IntRect bounds = mCursorRing[0]; for (int partIndex = 1; partIndex < partMax; partIndex++) - bounds->unite(mCursorRing[partIndex]); - bounds->inflate(CURSOR_RING_HIT_TEST_RADIUS); + bounds.unite(mCursorRing[partIndex]); + bounds.inflate(CURSOR_RING_HIT_TEST_RADIUS); + return mIsInLayer ? frame->adjustBounds(this, bounds) : bounds; } #define OVERLAP 3 -void CachedNode::fixUpCursorRects(const CachedRoot* root) +void CachedNode::fixUpCursorRects(const CachedFrame* frame) { if (mFixedUpCursorRects) return; mFixedUpCursorRects = true; // if the hit-test rect doesn't intersect any other rect, use it if (mHitBounds != mBounds && mHitBounds.contains(mBounds) && - root->checkRings(mCursorRing, mHitBounds)) { + frame->checkRings(this, mCursorRing, mHitBounds)) { DBG_NAV_LOGD("use mHitBounds (%d,%d,%d,%d)", mHitBounds.x(), mHitBounds.y(), mHitBounds.width(), mHitBounds.height()); mUseHitBounds = true; @@ -105,7 +120,7 @@ void CachedNode::fixUpCursorRects(const CachedRoot* root) return; // if there is more than 1 rect, and the bounds doesn't intersect // any other cursor ring bounds, use it - if (root->checkRings(mCursorRing, mBounds)) { + if (frame->checkRings(this, mCursorRing, mBounds)) { DBG_NAV_LOGD("use mBounds (%d,%d,%d,%d)", mBounds.x(), mBounds.y(), mBounds.width(), mBounds.height()); mUseBounds = true; @@ -204,6 +219,7 @@ tryAgain: } while (again); } + void CachedNode::hideCursor(CachedFrame* parent) { if (isFrame()) { @@ -213,6 +229,11 @@ void CachedNode::hideCursor(CachedFrame* parent) mIsHidden = true; } +WebCore::IntRect CachedNode::hitBounds(const CachedFrame* frame) const +{ + return mIsInLayer ? frame->adjustBounds(this, mHitBounds) : mHitBounds; +} + void CachedNode::init(WebCore::Node* node) { bzero(this, sizeof(CachedNode)); @@ -256,6 +277,12 @@ bool CachedNode::partRectsContains(const CachedNode* other) const return false; } +WebCore::IntRect CachedNode::ring(const CachedFrame* frame, size_t part) const +{ + const WebCore::IntRect& rect = mCursorRing.at(part); + return mIsInLayer ? frame->adjustBounds(this, rect) : rect; +} + #if DUMP_NAV_CACHE #define DEBUG_PRINT_BOOL(field) \ @@ -333,12 +360,15 @@ void CachedNode::Debug::print() const DUMP_NAV_LOGD("%.*s\"\n", index, scratch); DEBUG_PRINT_RECT(mBounds); DEBUG_PRINT_RECT(mHitBounds); - const WTF::Vector<WebCore::IntRect>& rects = b->cursorRings(); - size_t size = rects.size(); + DEBUG_PRINT_RECT(mOriginalAbsoluteBounds); + const WTF::Vector<WebCore::IntRect>* rects = b->cursorRingsPtr(); + size_t size = rects->size(); DUMP_NAV_LOGD("// IntRect cursorRings={ // size=%d\n", size); - for (size_t i = 0; i < size; i++) - DUMP_NAV_LOGD(" // {%d, %d, %d, %d}, // %d\n", rects[i].x(), rects[i].y(), - rects[i].width(), rects[i].height(), i); + for (size_t i = 0; i < size; i++) { + const WebCore::IntRect& rect = (*rects)[i]; + DUMP_NAV_LOGD(" // {%d, %d, %d, %d}, // %d\n", rect.x(), rect.y(), + rect.width(), rect.height(), i); + } DUMP_NAV_LOGD("// };\n"); DUMP_NAV_LOGD("// void* mNode=%p; // (%d) \n", b->mNode, mNodeIndex); DUMP_NAV_LOGD("// void* mParentGroup=%p; // (%d) \n", b->mParentGroup, mParentGroupIndex); @@ -357,6 +387,7 @@ void CachedNode::Debug::print() const DEBUG_PRINT_BOOL(mIsCursor); DEBUG_PRINT_BOOL(mIsFocus); DEBUG_PRINT_BOOL(mIsHidden); + DEBUG_PRINT_BOOL(mIsInLayer); DEBUG_PRINT_BOOL(mIsParentAnchor); DEBUG_PRINT_BOOL(mIsTransparent); DEBUG_PRINT_BOOL(mIsUnclipped); diff --git a/WebKit/android/nav/CachedNode.h b/WebKit/android/nav/CachedNode.h index a433a47..825eab7 100644 --- a/WebKit/android/nav/CachedNode.h +++ b/WebKit/android/nav/CachedNode.h @@ -33,6 +33,8 @@ #include "PlatformString.h" #include "wtf/Vector.h" +class SkPicture; + namespace WebCore { class Node; } @@ -77,6 +79,7 @@ public: NOT_CURSOR_NODE, OUTSIDE_OF_BEST, // containership OUTSIDE_OF_ORIGINAL, // containership + UNDER_LAYER, CONDITION_SIZE // FIXME: test that CONDITION_SIZE fits in mCondition }; CachedNode() { @@ -84,8 +87,8 @@ public: // constructor } - const WebCore::IntRect& bounds() const { return mBounds; } - WebCore::IntRect* boundsPtr() { return &mBounds; } + WebCore::IntRect bounds(const CachedFrame* ) const; + WebCore::IntRect* boundsPtr() { return &mBounds; } // CacheBuilder only int childFrameIndex() const { return isFrame() ? mDataIndex : -1; } void clearCondition() const { mCondition = NOT_REJECTED; } void clearCursor(CachedFrame* ); @@ -93,19 +96,18 @@ public: WTF::Vector<WebCore::IntRect>* rings); bool clip(const WebCore::IntRect& ); bool clippedOut() { return mClippedOut; } - void cursorRingBounds(WebCore::IntRect* ) const; - WTF::Vector<WebCore::IntRect>& cursorRings() { return mCursorRing; } - const WTF::Vector<WebCore::IntRect>& cursorRings() const { return mCursorRing; } + WebCore::IntRect cursorRingBounds(const CachedFrame* ) const; + // cursorRingsPtr() only for CacheBuilder since it points to raw data + WTF::Vector<WebCore::IntRect>* cursorRingsPtr() { return &mCursorRing; } + void cursorRings(const CachedFrame* , WTF::Vector<WebCore::IntRect>* ) const; bool disabled() const { return mDisabled; } const CachedNode* document() const { return &this[-mIndex]; } - void fixUpCursorRects(const CachedRoot* root); - const WebCore::IntRect& getBounds() const { return mBounds; } - void getBounds(WebCore::IntRect* bounds) const { *bounds = mBounds; } + void fixUpCursorRects(const CachedFrame* frame); const WebCore::String& getExport() const { return mExport; } bool hasCursorRing() const { return mHasCursorRing; } bool hasMouseOver() const { return mHasMouseOver; } void hideCursor(CachedFrame* ); - const WebCore::IntRect& hitBounds() const { return mHitBounds; } + WebCore::IntRect hitBounds(const CachedFrame* ) const; int index() const { return mIndex; } void init(WebCore::Node* node); bool isAnchor() const { return mType == ANCHOR_CACHEDNODETYPE; } @@ -114,8 +116,9 @@ public: bool isFocus() const { return mIsFocus; } bool isFrame() const { return mType == FRAME_CACHEDNODETYPE; } bool isHidden() const { return mIsHidden; } - bool isNavable(const WebCore::IntRect& clip) const { - return clip.intersects(mBounds); + bool isInLayer() const { return mIsInLayer; } + bool isNavable(const CachedFrame* frame, const WebCore::IntRect& clip) const { + return clip.intersects(bounds(frame)); } bool isPlugin() const { return mType == PLUGIN_CACHEDNODETYPE; } bool isSyntheticLink() const { @@ -136,6 +139,7 @@ public: int parentIndex() const { return mParentIndex; } bool partRectsContains(const CachedNode* other) const; void reset(); + WebCore::IntRect ring(const CachedFrame* , size_t part) const; void setBounds(const WebCore::IntRect& bounds) { mBounds = bounds; } void setClippedOut(bool clipped) { mClippedOut = clipped; } void setCondition(Condition condition) const { mCondition = condition; } @@ -150,6 +154,7 @@ public: void setIndex(int index) { mIndex = index; } void setIsCursor(bool isCursor) { mIsCursor = isCursor; } void setIsFocus(bool isFocus) { mIsFocus = isFocus; } + void setIsInLayer(bool isInLayer) { mIsInLayer = isInLayer; } void setIsParentAnchor(bool isAnchor) { mIsParentAnchor = isAnchor; } void setIsTransparent(bool isTransparent) { mIsTransparent = isTransparent; } void setIsUnclipped(bool unclipped) { mIsUnclipped = unclipped; } @@ -189,6 +194,7 @@ private: bool mIsCursor : 1; bool mIsFocus : 1; bool mIsHidden : 1; + bool mIsInLayer : 1; bool mIsParentAnchor : 1; bool mIsTransparent : 1; bool mIsUnclipped : 1; diff --git a/WebKit/android/nav/CachedRoot.cpp b/WebKit/android/nav/CachedRoot.cpp index 54e0c15..d81d764 100644 --- a/WebKit/android/nav/CachedRoot.cpp +++ b/WebKit/android/nav/CachedRoot.cpp @@ -28,14 +28,19 @@ #include "CachedHistory.h" #include "CachedInput.h" #include "CachedNode.h" +#include "FindCanvas.h" +#include "FloatRect.h" +#include "LayerAndroid.h" #include "SkBitmap.h" #include "SkBounder.h" -#include "SkCanvas.h" #include "SkPixelRef.h" #include "SkRegion.h" #include "CachedRoot.h" +using std::min; +using std::max; + #ifdef DUMP_NAV_CACHE_USING_PRINTF extern android::Mutex gWriteLogMutex; #endif @@ -693,7 +698,7 @@ bool CachedRoot::adjustForScroll(BestData* best, CachedFrame::Direction directio innerMove(document(), best, direction, scrollPtr, false); return true; } - newNode->cursorRingBounds(&newOutset); + newOutset = newNode->cursorRingBounds(best->mFrame); } int delta; bool newNodeInView = scrollDelta(newOutset, direction, &delta); @@ -717,7 +722,7 @@ int CachedRoot::checkForCenter(int x, int y) const checker.setBitmapDevice(bitmap); checker.translate(SkIntToScalar(width - mViewBounds.x()), SkIntToScalar(-mViewBounds.y())); - checker.drawPicture(*mPicture); + checker.drawPicture(*pictureAt(x, y)); return centerCheck.center(); } @@ -731,16 +736,18 @@ void CachedRoot::checkForJiggle(int* xDeltaPtr) const bitmap.setConfig(SkBitmap::kARGB_8888_Config, mViewBounds.width() + absDelta, mViewBounds.height()); checker.setBitmapDevice(bitmap); - checker.translate(SkIntToScalar(-mViewBounds.x() - - (xDelta < 0 ? xDelta : 0)), SkIntToScalar(-mViewBounds.y())); - checker.drawPicture(*mPicture); + int x = -mViewBounds.x() - (xDelta < 0 ? xDelta : 0); + int y = -mViewBounds.y(); + checker.translate(SkIntToScalar(x), SkIntToScalar(y)); + checker.drawPicture(*pictureAt(x, y)); *xDeltaPtr = jiggleCheck.jiggle(); } -bool CachedRoot::checkRings(const WTF::Vector<WebCore::IntRect>& rings, +bool CachedRoot::checkRings(SkPicture* picture, + const WTF::Vector<WebCore::IntRect>& rings, const WebCore::IntRect& bounds) const { - if (!mPicture) + if (!picture) return false; RingCheck ringCheck(rings, bounds.location()); BoundsCanvas checker(&ringCheck); @@ -749,13 +756,24 @@ bool CachedRoot::checkRings(const WTF::Vector<WebCore::IntRect>& rings, bounds.height()); checker.setBitmapDevice(bitmap); checker.translate(SkIntToScalar(-bounds.x()), SkIntToScalar(-bounds.y())); - checker.drawPicture(*mPicture); + checker.drawPicture(*picture); DBG_NAV_LOGD("bounds=(%d,%d,r=%d,b=%d) success=%s", bounds.x(), bounds.y(), bounds.right(), bounds.bottom(), ringCheck.success() ? "true" : "false"); return ringCheck.success(); } +void CachedRoot::draw(FindCanvas& canvas) const +{ + canvas.setLayerId(-1); // overlays change the ID as their pictures draw + canvas.drawPicture(*mPicture); +#if USE(ACCELERATED_COMPOSITING) + if (!mRootLayer) + return; + canvas.drawLayers(mRootLayer); +#endif +} + const CachedNode* CachedRoot::findAt(const WebCore::IntRect& rect, const CachedFrame** framePtr, int* x, int* y, bool checkForHidden) const { @@ -821,10 +839,13 @@ int CachedRoot::getBlockLeftEdge(int x, int y, float scale) const int fx, fy; const CachedNode* node = findAt(rect, &frame, &fx, &fy, true); if (node && node->wantsKeyEvents()) { - DBG_NAV_LOGD("x=%d (%s)", node->bounds().x(), + DBG_NAV_LOGD("x=%d (%s)", node->bounds(frame).x(), node->isTextInput() ? "text" : "plugin"); - return node->bounds().x(); + return node->bounds(frame).x(); } + SkPicture* picture = node ? frame->picture(node) : pictureAt(x, y); + if (!picture) + return x; int halfW = (int) (mViewBounds.width() * scale * 0.5f); int fullW = halfW << 1; int halfH = (int) (mViewBounds.height() * scale * 0.5f); @@ -835,7 +856,7 @@ int CachedRoot::getBlockLeftEdge(int x, int y, float scale) const bitmap.setConfig(SkBitmap::kARGB_8888_Config, fullW, fullH); checker.setBitmapDevice(bitmap); checker.translate(SkIntToScalar(fullW - x), SkIntToScalar(halfH - y)); - checker.drawPicture(*mPicture); + checker.drawPicture(*picture); int result = x + leftCheck.left() - fullW; DBG_NAV_LOGD("halfW=%d halfH=%d mMostLeft=%d x=%d", halfW, halfH, leftCheck.mMostLeft, result); @@ -893,7 +914,8 @@ bool CachedRoot::innerDown(const CachedNode* test, BestData* bestData) const mScrolledBounds.setY(navTop); } } - frameDown(test, NULL, bestData, currentCursor()); + setCursorCache(0, mMaxYScroll); + frameDown(test, NULL, bestData); return true; } @@ -916,7 +938,8 @@ bool CachedRoot::innerLeft(const CachedNode* test, BestData* bestData) const if (testRight > navRight && navRight > (scrollLeft = mScrolledBounds.x())) mScrolledBounds.setWidth(navRight - scrollLeft); } - frameLeft(test, NULL, bestData, currentCursor()); + setCursorCache(-mMaxXScroll, 0); + frameLeft(test, NULL, bestData); return true; } @@ -932,8 +955,9 @@ void CachedRoot::innerMove(const CachedNode* node, BestData* bestData, mHistory->reset(); outOfCursor = true; } - const CachedNode* cursor = currentCursor(); - mHistory->setWorking(direction, cursor, mViewBounds); + const CachedFrame* cursorFrame; + const CachedNode* cursor = currentCursor(&cursorFrame); + mHistory->setWorking(direction, cursorFrame, cursor, mViewBounds); bool findClosest = false; if (mScrollOnly == false) { switch (direction) { @@ -968,13 +992,13 @@ void CachedRoot::innerMove(const CachedNode* node, BestData* bestData, } if (firstCall) mHistory->mPriorBounds = mHistory->mNavBounds; // bounds always advances, even if new node is ultimately NULL - bestData->mMouseBounds = bestData->mNodeBounds; + bestData->setMouseBounds(bestData->bounds()); if (adjustForScroll(bestData, direction, scroll, findClosest)) return; if (bestData->mNode != NULL) { mHistory->addToVisited(bestData->mNode, direction); - mHistory->mNavBounds = bestData->mNodeBounds; - mHistory->mMouseBounds = bestData->mMouseBounds; + mHistory->mNavBounds = bestData->bounds(); + mHistory->mMouseBounds = bestData->mouseBounds(); } else if (scroll->x() != 0 || scroll->y() != 0) { WebCore::IntRect newBounds = mHistory->mNavBounds; int offsetX = scroll->x(); @@ -1014,7 +1038,8 @@ bool CachedRoot::innerRight(const CachedNode* test, BestData* bestData) const mScrolledBounds.setX(navLeft); } } - frameRight(test, NULL, bestData, currentCursor()); + setCursorCache(mMaxXScroll, 0); + frameRight(test, NULL, bestData); return true; } @@ -1037,7 +1062,8 @@ bool CachedRoot::innerUp(const CachedNode* test, BestData* bestData) const if (testBottom > navBottom && navBottom > (scrollTop = mScrolledBounds.y())) mScrolledBounds.setHeight(navBottom - scrollTop); } - frameUp(test, NULL, bestData, currentCursor()); + setCursorCache(0, -mMaxYScroll); + frameUp(test, NULL, bestData); return true; } @@ -1049,22 +1075,23 @@ WebCore::String CachedRoot::imageURI(int x, int y) const bitmap.setConfig(SkBitmap::kARGB_8888_Config, 1, 1); checker.setBitmapDevice(bitmap); checker.translate(SkIntToScalar(-x), SkIntToScalar(-y)); - checker.drawPicture(*mPicture); + checker.drawPicture(*pictureAt(x, y)); return WebCore::String(checker.mURI); } bool CachedRoot::maskIfHidden(BestData* best) const { - if (mPicture == NULL) { - DBG_NAV_LOG("missing picture"); - return false; - } const CachedNode* bestNode = best->mNode; if (bestNode->isUnclipped()) return false; + SkPicture* picture = best->mFrame->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->getBounds(); + const WebCore::IntRect& nodeBounds = bestNode->bounds(best->mFrame); WebCore::IntRect bounds = nodeBounds; bounds.intersect(mScrolledBounds); int leftMargin = bounds.x() == nodeBounds.x() ? kMargin : 0; @@ -1090,7 +1117,7 @@ bool CachedRoot::maskIfHidden(BestData* best) const // ? need to know (like imdb menu bar) to give up sometimes (when?) checker.translate(SkIntToScalar(leftMargin - bounds.x()), SkIntToScalar(topMargin - bounds.y())); - checker.drawPicture(*mPicture); + checker.drawPicture(*picture); boundsCheck.checkLast(); // was it not drawn or clipped out? CachedNode* node = const_cast<CachedNode*>(best->mNode); @@ -1149,9 +1176,9 @@ bool CachedRoot::maskIfHidden(BestData* best) const orig.fLeft, orig.fTop, orig.fRight, orig.fBottom, base.fLeft, base.fTop, base.fRight, base.fBottom); #endif - best->mMouseBounds = WebCore::IntRect(bounds.x() + base.fLeft - kMargin, - bounds.y() + base.fTop - kMargin, base.width(), base.height()); - node->clip(best->mMouseBounds); + best->setMouseBounds(WebCore::IntRect(bounds.x() + base.fLeft - kMargin, + bounds.y() + base.fTop - kMargin, base.width(), base.height())); + node->clip(best->mouseBounds()); return true; } return false; @@ -1173,10 +1200,87 @@ const CachedNode* CachedRoot::moveCursor(Direction direction, const CachedFrame* setData(); BestData bestData; innerMove(node, &bestData, direction, scroll, true); + // if node is partially or fully concealed by layer, scroll it into view + if (mRootLayer && bestData.mNode && !bestData.mNode->isInLayer()) { +#if USE(ACCELERATED_COMPOSITING) +#if DUMP_NAV_CACHE + CachedLayer::Debug::printRootLayerAndroid(mRootLayer); +#endif + SkIRect original = bestData.mNode->cursorRingBounds(bestData.mFrame); + DBG_NAV_LOGD("original=(%d,%d,w=%d,h=%d) scroll=(%d,%d)", + original.fLeft, original.fTop, original.width(), original.height(), + scroll->x(), scroll->y()); + original.offset(-scroll->x(), -scroll->y()); + SkRegion rings(original); + SkTDArray<SkRect> region; + mRootLayer->clipArea(®ion); + SkRegion layers; + for (int index = 0; index < region.count(); index++) { + SkIRect enclosing; + region[index].round(&enclosing); + rings.op(enclosing, SkRegion::kDifference_Op); + layers.op(enclosing, SkRegion::kUnion_Op); + } + SkIRect layerBounds(layers.getBounds()); + SkIRect ringBounds(rings.getBounds()); + int scrollX = scroll->x(); + int scrollY = scroll->y(); + if (rings.getBounds() != original) { + int topOverlap = layerBounds.fBottom - original.fTop; + int bottomOverlap = original.fBottom - layerBounds.fTop; + int leftOverlap = layerBounds.fRight - original.fLeft; + int rightOverlap = original.fRight - layerBounds.fLeft; + if (direction & UP_DOWN) { + if (layerBounds.fLeft < original.fLeft && leftOverlap < 0) + scroll->setX(leftOverlap); + if (original.fRight < layerBounds.fRight && rightOverlap > 0 + && -leftOverlap > rightOverlap) + scroll->setX(rightOverlap); + bool topSet = scrollY > topOverlap && (direction == UP + || !scrollY); + if (topSet) + scroll->setY(topOverlap); + if (scrollY < bottomOverlap && (direction == DOWN || (!scrollY + && (!topSet || -topOverlap > bottomOverlap)))) + scroll->setY(bottomOverlap); + } else { + if (layerBounds.fTop < original.fTop && topOverlap < 0) + scroll->setY(topOverlap); + if (original.fBottom < layerBounds.fBottom && bottomOverlap > 0 + && -topOverlap > bottomOverlap) + scroll->setY(bottomOverlap); + bool leftSet = scrollX > leftOverlap && (direction == LEFT + || !scrollX); + if (leftSet) + scroll->setX(leftOverlap); + if (scrollX < rightOverlap && (direction == RIGHT || (!scrollX + && (!leftSet || -leftOverlap > rightOverlap)))) + scroll->setX(rightOverlap); + } + DBG_NAV_LOGD("rings=(%d,%d,w=%d,h=%d) layers=(%d,%d,w=%d,h=%d)" + " scroll=(%d,%d)", + ringBounds.fLeft, ringBounds.fTop, ringBounds.width(), ringBounds.height(), + layerBounds.fLeft, layerBounds.fTop, layerBounds.width(), layerBounds.height(), + scroll->x(), scroll->y()); + } +#endif + } *framePtr = bestData.mFrame; return const_cast<CachedNode*>(bestData.mNode); } +SkPicture* CachedRoot::pictureAt(int x, int y) const +{ +#if USE(ACCELERATED_COMPOSITING) + if (mRootLayer) { + const LayerAndroid* layer = mRootLayer->find(FloatPoint(x, y)); + if (layer) + return layer->picture(); + } +#endif + return mPicture; +} + void CachedRoot::reset() { #ifndef NDEBUG @@ -1184,6 +1288,7 @@ void CachedRoot::reset() #endif mContents = mViewBounds = WebCore::IntRect(0, 0, 0, 0); mMaxXScroll = mMaxYScroll = 0; + mRootLayer = 0; mSelectionStart = mSelectionEnd = -1; mScrollOnly = false; } @@ -1216,7 +1321,7 @@ void CachedRoot::setCachedFocus(CachedFrame* frame, CachedNode* node) if (node == NULL) return; node->setIsFocus(true); - mFocusBounds = node->bounds(); + mFocusBounds = node->bounds(frame); frame->setFocusIndex(node - frame->document()); CachedFrame* parent; while ((parent = frame->parent()) != NULL) { @@ -1224,10 +1329,11 @@ void CachedRoot::setCachedFocus(CachedFrame* frame, CachedNode* node) frame = parent; } #if DEBUG_NAV_UI - const CachedNode* focus = frame->currentFocus(); + const CachedFrame* focusFrame; + const CachedNode* focus = currentFocus(&focusFrame); WebCore::IntRect bounds = WebCore::IntRect(0, 0, 0, 0); if (focus) - bounds = focus->bounds(); + bounds = focus->bounds(focusFrame); DBG_NAV_LOGD("new focus %d (nodePointer=%p) bounds={%d,%d,%d,%d}", focus ? focus->index() : 0, focus ? focus->nodePointer() : NULL, bounds.x(), bounds.y(), @@ -1238,10 +1344,11 @@ void CachedRoot::setCachedFocus(CachedFrame* frame, CachedNode* node) void CachedRoot::setCursor(CachedFrame* frame, CachedNode* node) { #if DEBUG_NAV_UI - const CachedNode* cursor = currentCursor(); + const CachedFrame* cursorFrame; + const CachedNode* cursor = currentCursor(&cursorFrame); WebCore::IntRect bounds; if (cursor) - bounds = cursor->bounds(); + bounds = cursor->bounds(cursorFrame); DBG_NAV_LOGD("old cursor %d (nodePointer=%p) bounds={%d,%d,%d,%d}", cursor ? cursor->index() : 0, cursor ? cursor->nodePointer() : NULL, bounds.x(), bounds.y(), @@ -1259,10 +1366,10 @@ void CachedRoot::setCursor(CachedFrame* frame, CachedNode* node) frame = parent; } #if DEBUG_NAV_UI - cursor = currentCursor(); + cursor = currentCursor(&cursorFrame); bounds = WebCore::IntRect(0, 0, 0, 0); if (cursor) - bounds = cursor->bounds(); + bounds = cursor->bounds(cursorFrame); DBG_NAV_LOGD("new cursor %d (nodePointer=%p) bounds={%d,%d,%d,%d}", cursor ? cursor->index() : 0, cursor ? cursor->nodePointer() : NULL, bounds.x(), bounds.y(), @@ -1270,6 +1377,44 @@ void CachedRoot::setCursor(CachedFrame* frame, CachedNode* node) #endif } +void CachedRoot::setCursorCache(int scrollX, int scrollY) const +{ + mCursor = currentCursor(); + if (mCursor) + mCursorBounds = mCursor->bounds(this); + if (!mRootLayer) + return; + SkRegion baseScrolled(mScrolledBounds); + mBaseUncovered = SkRegion(mScrolledBounds); +#if USE(ACCELERATED_COMPOSITING) +#if DUMP_NAV_CACHE + CachedLayer::Debug::printRootLayerAndroid(mRootLayer); +#endif + SkTDArray<SkRect> region; + mRootLayer->clipArea(®ion); + WebCore::IntSize offset( + copysign(min(max(0, mContents.width() - mScrolledBounds.width()), + abs(scrollX)), scrollX), + copysign(min(max(0, mContents.height() - mScrolledBounds.height()), + abs(scrollY)), scrollY)); + bool hasOffset = offset.width() || offset.height(); + // restrict scrollBounds to that which is not under layer + for (int index = 0; index < region.count(); index++) { + SkIRect less; + region[index].round(&less); + DBG_NAV_LOGD("less=(%d,%d,w=%d,h=%d)", less.fLeft, less.fTop, + less.width(), less.height()); + mBaseUncovered.op(less, SkRegion::kDifference_Op); + if (!hasOffset) + continue; + less.offset(offset.width(), offset.height()); + baseScrolled.op(less, SkRegion::kDifference_Op); + } + if (hasOffset) + mBaseUncovered.op(baseScrolled, SkRegion::kUnion_Op); +#endif +} + #if DUMP_NAV_CACHE #define DEBUG_PRINT_BOOL(field) \ diff --git a/WebKit/android/nav/CachedRoot.h b/WebKit/android/nav/CachedRoot.h index dc0cea8..e4461d1 100644 --- a/WebKit/android/nav/CachedRoot.h +++ b/WebKit/android/nav/CachedRoot.h @@ -29,10 +29,16 @@ #include "CachedFrame.h" #include "IntRect.h" #include "SkPicture.h" +#include "SkRegion.h" #include "wtf/Vector.h" +class FindCanvas; class SkRect; +namespace WebCore { + class LayerAndroid; +} + namespace android { class CachedHistory; @@ -42,18 +48,22 @@ class CachedRoot : public CachedFrame { public: bool adjustForScroll(BestData* , Direction , WebCore::IntPoint* scrollPtr, bool findClosest); + const SkRegion& baseUncovered() const { return mBaseUncovered; } int checkForCenter(int x, int y) const; void checkForJiggle(int* ) const; - bool checkRings(const WTF::Vector<WebCore::IntRect>& rings, + bool checkRings(SkPicture* , const WTF::Vector<WebCore::IntRect>& rings, const WebCore::IntRect& bounds) const; WebCore::IntPoint cursorLocation() const; + const WebCore::IntRect& cursorBounds() const { return mCursorBounds; } // should only be called by CachedFrame + const CachedNode* cursor() const { return mCursor; } // should only be called by CachedFrame int documentHeight() { return mContents.height(); } int documentWidth() { return mContents.width(); } + void draw(FindCanvas& ) const; const CachedNode* findAt(const WebCore::IntRect& , const CachedFrame** , int* x, int* y, bool checkForHidden) const; const WebCore::IntRect& focusBounds() const { return mFocusBounds; } WebCore::IntPoint focusLocation() const; - SkPicture* getPicture() { return mPicture; } + SkPicture* getPicture() const { return mPicture; } // should only be called by CachedFrame int getAndResetSelectionEnd(); int getAndResetSelectionStart(); int getBlockLeftEdge(int x, int y, float scale) const; @@ -68,16 +78,20 @@ public: WebCore::String imageURI(int x, int y) const; bool maskIfHidden(BestData* ) const; const CachedNode* moveCursor(Direction , const CachedFrame** , WebCore::IntPoint* scroll); + SkPicture* pictureAt(int x, int y) const; void reset(); CachedHistory* rootHistory() const { return mHistory; } + const WebCore::LayerAndroid* rootLayer() const { return mRootLayer; } bool scrollDelta(WebCore::IntRect& cursorRingBounds, Direction , int* delta); const WebCore::IntRect& scrolledBounds() const { return mScrolledBounds; } void setCursor(CachedFrame* , CachedNode* ); + void setCursorCache(int scrollX, int scrollY) const; // compute cached state used to find next cursor void setCachedFocus(CachedFrame* , CachedNode* ); void setFocusBounds(const WebCore::IntRect& r) { mFocusBounds = r; } void setTextGeneration(int textGeneration) { mTextGeneration = textGeneration; } void setMaxScroll(int x, int y) { mMaxXScroll = x; mMaxYScroll = y; } void setPicture(SkPicture* picture) { mPicture = picture; } + void setRootLayer(WebCore::LayerAndroid* layer) { mRootLayer = layer; } void setScrollOnly(bool state) { mScrollOnly = state; } void setSelection(int start, int end) { mSelectionStart = start; mSelectionEnd = end; } void setupScrolledBounds() const { mScrolledBounds = mViewBounds; } @@ -87,6 +101,7 @@ public: private: CachedHistory* mHistory; SkPicture* mPicture; + WebCore::LayerAndroid* mRootLayer; WebCore::IntRect mFocusBounds; // dom text input focus node bounds mutable WebCore::IntRect mScrolledBounds; // view bounds + amount visible as result of scroll int mTextGeneration; @@ -95,6 +110,10 @@ private: // These two are ONLY used when the tree is rebuilt and the focus is a textfield/area int mSelectionStart; int mSelectionEnd; + // these four set up as cache for use by frameDown/Up/Left/Right etc + mutable WebCore::IntRect mCursorBounds; + mutable const CachedNode* mCursor; + mutable SkRegion mBaseUncovered; bool mScrollOnly; #if DUMP_NAV_CACHE public: diff --git a/WebKit/android/nav/FindCanvas.cpp b/WebKit/android/nav/FindCanvas.cpp index 1465b91..15a8001 100644 --- a/WebKit/android/nav/FindCanvas.cpp +++ b/WebKit/android/nav/FindCanvas.cpp @@ -23,11 +23,18 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#define LOG_TAG "webviewglue" + #include "config.h" #include "FindCanvas.h" - +#include "LayerAndroid.h" +#include "IntRect.h" +#include "SkBlurMaskFilter.h" +#include "SkCornerPathEffect.h" #include "SkRect.h" +#include <utils/Log.h> + // MatchInfo methods //////////////////////////////////////////////////////////////////////////////// @@ -40,13 +47,15 @@ MatchInfo::~MatchInfo() { } MatchInfo::MatchInfo(const MatchInfo& src) { + m_layerId = src.m_layerId; m_location = src.m_location; m_picture = src.m_picture; m_picture->safeRef(); } -void MatchInfo::set(const SkRegion& region, SkPicture* pic) { +void MatchInfo::set(const SkRegion& region, SkPicture* pic, int layerId) { m_picture->safeUnref(); + m_layerId = layerId; m_location = region; m_picture = pic; SkASSERT(pic); @@ -218,6 +227,16 @@ SkRect FindCanvas::addMatchPosH(int index, return r; } +void FindCanvas::drawLayers(WebCore::LayerAndroid* layer) { + SkPicture* picture = layer->picture(); + if (picture) { + setLayerId(layer->uniqueId()); + drawPicture(*picture); + } + for (int i = 0; i < layer->countChildren(); i++) + drawLayers(layer->getChild(i)); +} + void FindCanvas::drawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, const SkPaint& paint) { findHelper(text, byteLength, paint, &x, y, &FindCanvas::addMatchNormal); @@ -456,7 +475,9 @@ void FindCanvas::insertMatchInfo(const SkRegion& region) { mWorkingPicture->endRecording(); MatchInfo matchInfo; mMatches->append(matchInfo); - mMatches->last().set(region, mWorkingPicture); + LOGD("%s region=%p pict=%p layer=%d", __FUNCTION__, + region, mWorkingPicture, mLayerId); + mMatches->last().set(region, mWorkingPicture, mLayerId); } void FindCanvas::resetWorkingCanvas() { @@ -465,3 +486,163 @@ void FindCanvas::resetWorkingCanvas() { // Do not need to reset mWorkingCanvas itself because we only access it via // getWorkingCanvas. } + +// This function sets up the paints that are used to draw the matches. +void FindOnPage::setUpFindPaint() { + // Set up the foreground paint + m_findPaint.setAntiAlias(true); + const SkScalar roundiness = SkIntToScalar(2); + SkCornerPathEffect* cornerEffect = new SkCornerPathEffect(roundiness); + m_findPaint.setPathEffect(cornerEffect); + m_findPaint.setARGB(255, 132, 190, 0); + + // Set up the background blur paint. + m_findBlurPaint.setAntiAlias(true); + m_findBlurPaint.setARGB(204, 0, 0, 0); + m_findBlurPaint.setPathEffect(cornerEffect); + cornerEffect->unref(); + SkMaskFilter* blurFilter = SkBlurMaskFilter::Create(SK_Scalar1, + SkBlurMaskFilter::kNormal_BlurStyle); + m_findBlurPaint.setMaskFilter(blurFilter)->unref(); + m_isFindPaintSetUp = true; +} + +WebCore::IntRect FindOnPage::currentMatchBounds() const { + if (!m_matches || !m_matches->size()) + return WebCore::IntRect(0, 0, 0, 0); + return (*m_matches)[m_findIndex].getLocation().getBounds(); +} + +// This function is only used by findNext and setMatches. In it, we store +// upper left corner of the match specified by m_findIndex in +// m_currentMatchLocation. +void FindOnPage::storeCurrentMatchLocation() { + SkASSERT(m_findIndex < m_matches->size()); + const SkIRect& bounds = (*m_matches)[m_findIndex].getLocation().getBounds(); + m_currentMatchLocation.set(bounds.fLeft, bounds.fTop); + m_hasCurrentLocation = true; +} + +// Put a cap on the number of matches to draw. If the current page has more +// matches than this, only draw the focused match. +#define MAX_NUMBER_OF_MATCHES_TO_DRAW 101 + +void FindOnPage::drawLayer(SkCanvas* canvas, const WebCore::IntRect* visRect, + int layerId) { + if (!m_matches || !m_matches->size()) + return; + if (m_findIndex >= m_matches->size()) + m_findIndex = 0; + const MatchInfo& matchInfo = (*m_matches)[m_findIndex]; + const SkRegion& currentMatchRegion = matchInfo.getLocation(); + + // Set up the paints used for drawing the matches + if (!m_isFindPaintSetUp) + setUpFindPaint(); + + // Draw the current match + if (matchInfo.layerId() == layerId) { + drawMatch(currentMatchRegion, canvas, true); + // Now draw the picture, so that it shows up on top of the rectangle + canvas->drawPicture(*matchInfo.getPicture()); + } + // Draw the rest + unsigned numberOfMatches = m_matches->size(); + if (numberOfMatches > 1 + && numberOfMatches < MAX_NUMBER_OF_MATCHES_TO_DRAW) { + for(unsigned i = 0; i < numberOfMatches; i++) { + // The current match has already been drawn + if (i == m_findIndex) + continue; + if ((*m_matches)[i].layerId() != layerId) + continue; + const SkRegion& region = (*m_matches)[i].getLocation(); + // Do not draw matches which intersect the current one, or if it is + // offscreen + if (currentMatchRegion.intersects(region) + || (visRect && !region.intersects(*visRect))) + continue; + drawMatch(region, canvas, false); + } + } +} + +// Draw the match specified by region to the canvas. +void FindOnPage::drawMatch(const SkRegion& region, SkCanvas* canvas, + bool focused) +{ + // For the match which has focus, use a filled paint. For the others, use + // a stroked paint. + if (focused) { + m_findPaint.setStyle(SkPaint::kFill_Style); + m_findBlurPaint.setStyle(SkPaint::kFill_Style); + } else { + m_findPaint.setStyle(SkPaint::kStroke_Style); + m_findPaint.setStrokeWidth(SK_Scalar1); + m_findBlurPaint.setStyle(SkPaint::kStroke_Style); + m_findBlurPaint.setStrokeWidth(SkIntToScalar(2)); + } + // Find the path for the current match + SkPath matchPath; + region.getBoundaryPath(&matchPath); + // Offset the path for a blurred shadow + SkPath blurPath; + matchPath.offset(SK_Scalar1, SkIntToScalar(2), &blurPath); + int saveCount = 0; + if (!focused) { + saveCount = canvas->save(); + canvas->clipPath(matchPath, SkRegion::kDifference_Op); + } + // Draw the blurred background + canvas->drawPath(blurPath, m_findBlurPaint); + if (!focused) + canvas->restoreToCount(saveCount); + // Draw the foreground + canvas->drawPath(matchPath, m_findPaint); +} + +void FindOnPage::findNext(bool forward) +{ + if (!m_matches || !m_matches->size()) + return; + if (forward) { + m_findIndex++; + if (m_findIndex == m_matches->size()) + m_findIndex = 0; + } else { + if (m_findIndex == 0) { + m_findIndex = m_matches->size() - 1; + } else { + m_findIndex--; + } + } + storeCurrentMatchLocation(); +} + +// With this call, WebView takes ownership of matches, and is responsible for +// deleting it. +void FindOnPage::setMatches(WTF::Vector<MatchInfo>* matches) +{ + if (m_matches) + delete m_matches; + m_matches = matches; + if (m_matches->size()) { + if (m_hasCurrentLocation) { + for (unsigned i = 0; i < m_matches->size(); i++) { + const SkIRect& rect = (*m_matches)[i].getLocation().getBounds(); + if (rect.fLeft == m_currentMatchLocation.fX + && rect.fTop == m_currentMatchLocation.fY) { + m_findIndex = i; + return; + } + } + } + // If we did not have a stored location, or if we were unable to restore + // it, store the new one. + m_findIndex = 0; + storeCurrentMatchLocation(); + } else { + m_hasCurrentLocation = false; + } +} + diff --git a/WebKit/android/nav/FindCanvas.h b/WebKit/android/nav/FindCanvas.h index d357a2a..fd04bd0 100644 --- a/WebKit/android/nav/FindCanvas.h +++ b/WebKit/android/nav/FindCanvas.h @@ -26,6 +26,7 @@ #ifndef Find_Canvas_h #define Find_Canvas_h +#include "IntRect.h" #include "SkBounder.h" #include "SkCanvas.h" #include "SkPicture.h" @@ -34,8 +35,13 @@ #include "icu/unicode/umachine.h" #include "wtf/Vector.h" -class SkRect; -class SkTypeface; +// class SkIRect; +// class SkRect; +// class SkTypeface; + +namespace WebCore { + class LayerAndroid; +} // Stores both region information and an SkPicture of the match, so that the // region can be drawn, followed by drawing the matching text on top of it. @@ -51,11 +57,14 @@ public: SkPicture* getPicture() const { return m_picture; } // This will make a copy of the region, and increase the ref count on the // SkPicture. If this MatchInfo already had one, unref it. - void set(const SkRegion& region, SkPicture* pic); + bool isInLayer() const { return m_layerId >= 0; } + int layerId() const { return m_layerId; } + void set(const SkRegion& region, SkPicture* pic, int layerId); private: MatchInfo& operator=(MatchInfo& src); SkRegion m_location; SkPicture* m_picture; + int m_layerId; }; // A class containing a typeface for reference, the length in glyphs, and @@ -135,7 +144,9 @@ public: const SkPaint& paint) { } + void drawLayers(WebCore::LayerAndroid* ); int found() const { return mNumFound; } + void setLayerId(int layerId) { mLayerId = layerId; } // This method detaches our array of matches and passes ownership to // the caller, who is then responsible for deleting them. @@ -201,6 +212,38 @@ private: SkCanvas* mWorkingCanvas; SkRegion mWorkingRegion; int mWorkingIndex; + int mLayerId; +}; + +class FindOnPage { +public: + FindOnPage() { + m_matches = 0; + m_hasCurrentLocation = false; + m_isFindPaintSetUp = false; + } + ~FindOnPage() { delete m_matches; } + void clearCurrentLocation() { m_hasCurrentLocation = false; } + WebCore::IntRect currentMatchBounds() const; + void drawLayer(SkCanvas* canvas, const WebCore::IntRect* vis, int layerId); + void findNext(bool forward); + void setMatches(WTF::Vector<MatchInfo>* matches); +private: + void drawMatch(const SkRegion& region, SkCanvas* canvas, bool focused); + void setUpFindPaint(); + void storeCurrentMatchLocation(); + WTF::Vector<MatchInfo>* m_matches; + // Stores the location of the current match. + SkIPoint m_currentMatchLocation; + // Tells whether the value in m_currentMatchLocation is valid. + bool m_hasCurrentLocation; + // Tells whether we have done the setup to draw the Find matches. + bool m_isFindPaintSetUp; + // Paint used to draw our Find matches. + SkPaint m_findPaint; + // Paint used for the background of our Find matches. + SkPaint m_findBlurPaint; + unsigned m_findIndex; }; #endif // Find_Canvas_h diff --git a/WebKit/android/nav/WebView.cpp b/WebKit/android/nav/WebView.cpp index d334589..04e9336 100644 --- a/WebKit/android/nav/WebView.cpp +++ b/WebKit/android/nav/WebView.cpp @@ -45,9 +45,7 @@ #include "PlatformGraphicsContext.h" #include "PlatformString.h" #include "SelectText.h" -#include "SkBlurMaskFilter.h" #include "SkCanvas.h" -#include "SkCornerPathEffect.h" #include "SkDumpCanvas.h" #include "SkPath.h" #include "SkPicture.h" @@ -110,6 +108,7 @@ struct JavaGlue { jmethodID m_getScaledMaxXScroll; jmethodID m_getScaledMaxYScroll; jmethodID m_getVisibleRect; + jmethodID m_getViewMetrics; jmethodID m_rebuildWebTextView; jmethodID m_viewInvalidate; jmethodID m_viewInvalidateRect; @@ -118,6 +117,11 @@ struct JavaGlue { jfieldID m_rectTop; jmethodID m_rectWidth; jmethodID m_rectHeight; + jfieldID m_metricsScrollX; + jfieldID m_metricsScrollY; + jfieldID m_metricsWidth; + jfieldID m_metricsHeight; + jfieldID m_metricsScale; AutoJObject object(JNIEnv* env) { return getRealObject(env, m_obj); } @@ -129,7 +133,7 @@ WebView(JNIEnv* env, jobject javaWebView, int viewImpl) // m_javaGlue = new JavaGlue; m_javaGlue.m_obj = env->NewWeakGlobalRef(javaWebView); m_javaGlue.m_scrollBy = GetJMethod(env, clazz, "setContentScrollBy", "(IIZ)Z"); - m_javaGlue.m_clearTextEntry = GetJMethod(env, clazz, "clearTextEntry", "()V"); + m_javaGlue.m_clearTextEntry = GetJMethod(env, clazz, "clearTextEntry", "(Z)V"); m_javaGlue.m_overrideLoading = GetJMethod(env, clazz, "overrideLoading", "(Ljava/lang/String;)V"); m_javaGlue.m_sendMoveFocus = GetJMethod(env, clazz, "sendMoveFocus", "(II)V"); m_javaGlue.m_sendMoveMouse = GetJMethod(env, clazz, "sendMoveMouse", "(IIII)V"); @@ -139,6 +143,7 @@ WebView(JNIEnv* env, jobject javaWebView, int viewImpl) m_javaGlue.m_getScaledMaxXScroll = GetJMethod(env, clazz, "getScaledMaxXScroll", "()I"); m_javaGlue.m_getScaledMaxYScroll = GetJMethod(env, clazz, "getScaledMaxYScroll", "()I"); m_javaGlue.m_getVisibleRect = GetJMethod(env, clazz, "sendOurVisibleRect", "()Landroid/graphics/Rect;"); + m_javaGlue.m_getViewMetrics = GetJMethod(env, clazz, "getViewMetrics", "()Landroid/webkit/WebView$Metrics;"); m_javaGlue.m_rebuildWebTextView = GetJMethod(env, clazz, "rebuildWebTextView", "()V"); m_javaGlue.m_viewInvalidate = GetJMethod(env, clazz, "viewInvalidate", "()V"); m_javaGlue.m_viewInvalidateRect = GetJMethod(env, clazz, "viewInvalidate", "(IIII)V"); @@ -150,6 +155,12 @@ WebView(JNIEnv* env, jobject javaWebView, int viewImpl) m_javaGlue.m_rectTop = env->GetFieldID(rectClass, "top", "I"); m_javaGlue.m_rectWidth = GetJMethod(env, rectClass, "width", "()I"); m_javaGlue.m_rectHeight = GetJMethod(env, rectClass, "height", "()I"); + jclass metricsClass = env->FindClass("android/webkit/WebView$Metrics"); + m_javaGlue.m_metricsScrollX = env->GetFieldID(metricsClass, "mScrollX", "I"); + m_javaGlue.m_metricsScrollY = env->GetFieldID(metricsClass, "mScrollY", "I"); + m_javaGlue.m_metricsWidth = env->GetFieldID(metricsClass, "mWidth", "I"); + m_javaGlue.m_metricsHeight = env->GetFieldID(metricsClass, "mHeight", "I"); + m_javaGlue.m_metricsScale = env->GetFieldID(metricsClass, "mScale", "F"); env->SetIntField(javaWebView, gWebViewField, (jint)this); m_viewImpl = (WebViewCore*) viewImpl; @@ -163,9 +174,7 @@ WebView(JNIEnv* env, jobject javaWebView, int viewImpl) m_ringAnimationEnd = 0; m_selStart.setEmpty(); m_selEnd.setEmpty(); - m_matches = 0; - m_hasCurrentLocation = false; - m_isFindPaintSetUp = false; + m_rootLayer = 0; } ~WebView() @@ -178,8 +187,6 @@ WebView(JNIEnv* env, jobject javaWebView, int viewImpl) } delete m_frameCacheUI; delete m_navPictureUI; - if (m_matches) - delete m_matches; } WebViewCore* getWebViewCore() const { @@ -214,7 +221,8 @@ void clearTextEntry() { DEBUG_NAV_UI_LOGD("%s", __FUNCTION__); JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_clearTextEntry); + env->CallVoidMethod(m_javaGlue.object(env).get(), + m_javaGlue.m_clearTextEntry, true); checkException(env); } @@ -236,6 +244,7 @@ void debugDump() void nativeRecordButtons(bool hasFocus, bool pressed, bool invalidate) { bool cursorIsOnButton = false; + const CachedFrame* cachedFrame; const CachedNode* cachedCursor = 0; // Lock the mutex, since we now share with the WebCore thread. m_viewImpl->gButtonMutex.lock(); @@ -246,7 +255,7 @@ void nativeRecordButtons(bool hasFocus, bool pressed, bool invalidate) WebCore::Node* cursor = 0; CachedRoot* root = getFrameCache(DontAllowNewer); if (root) { - cachedCursor = root->currentCursor(); + cachedCursor = root->currentCursor(&cachedFrame); if (cachedCursor) cursor = (WebCore::Node*) cachedCursor->nodePointer(); } @@ -276,68 +285,11 @@ void nativeRecordButtons(bool hasFocus, bool pressed, bool invalidate) } m_viewImpl->gButtonMutex.unlock(); if (invalidate && cachedCursor && cursorIsOnButton) { - const WebCore::IntRect& b = cachedCursor->getBounds(); + const WebCore::IntRect& b = cachedCursor->bounds(cachedFrame); viewInvalidateRect(b.x(), b.y(), b.right(), b.bottom()); } } -// These two functions separate out the particular look of the drawn find -// matches from the code that draws them. This function sets up the paints that -// are used to draw the matches. -void setUpFindPaint() -{ - // Set up the foreground paint - m_findPaint.setAntiAlias(true); - const SkScalar roundiness = SkIntToScalar(2); - SkCornerPathEffect* cornerEffect = new SkCornerPathEffect(roundiness); - m_findPaint.setPathEffect(cornerEffect); - m_findPaint.setARGB(255, 132, 190, 0); - - // Set up the background blur paint. - m_findBlurPaint.setAntiAlias(true); - m_findBlurPaint.setARGB(204, 0, 0, 0); - m_findBlurPaint.setPathEffect(cornerEffect); - cornerEffect->unref(); - SkMaskFilter* blurFilter = SkBlurMaskFilter::Create(SK_Scalar1, - SkBlurMaskFilter::kNormal_BlurStyle); - m_findBlurPaint.setMaskFilter(blurFilter)->unref(); - m_isFindPaintSetUp = true; -} - -// Draw the match specified by region to the canvas. -void drawMatch(const SkRegion& region, SkCanvas* canvas, bool focused) -{ - // For the match which has focus, use a filled paint. For the others, use - // a stroked paint. - if (focused) { - m_findPaint.setStyle(SkPaint::kFill_Style); - m_findBlurPaint.setStyle(SkPaint::kFill_Style); - } else { - m_findPaint.setStyle(SkPaint::kStroke_Style); - m_findPaint.setStrokeWidth(SK_Scalar1); - m_findBlurPaint.setStyle(SkPaint::kStroke_Style); - m_findBlurPaint.setStrokeWidth(SkIntToScalar(2)); - } - // Find the path for the current match - SkPath matchPath; - region.getBoundaryPath(&matchPath); - // Offset the path for a blurred shadow - SkPath blurPath; - matchPath.offset(SK_Scalar1, SkIntToScalar(2), &blurPath); - int saveCount = 0; - if (!focused) { - saveCount = canvas->save(); - canvas->clipPath(matchPath, SkRegion::kDifference_Op); - } - // Draw the blurred background - canvas->drawPath(blurPath, m_findBlurPaint); - if (!focused) { - canvas->restoreToCount(saveCount); - } - // Draw the foreground - canvas->drawPath(matchPath, m_findPaint); -} - bool scrollRectOnScreen(int left, int top, int right, int bottom) { WebCore::IntRect visible; @@ -362,52 +314,22 @@ bool scrollRectOnScreen(int left, int top, int right, int bottom) return true; } -// Put a cap on the number of matches to draw. If the current page has more -// matches than this, only draw the focused match. -#define MAX_NUMBER_OF_MATCHES_TO_DRAW 101 - +// draws the root matches only. Matches over layers are drawn by LayerAndroid void drawMatches(SkCanvas* canvas) { - if (!m_matches || !m_matches->size()) - return; - if (m_findIndex >= m_matches->size()) - m_findIndex = 0; - const MatchInfo& matchInfo = (*m_matches)[m_findIndex]; - const SkRegion& currentMatchRegion = matchInfo.getLocation(); - const SkIRect& currentMatchBounds = currentMatchRegion.getBounds(); - if (scrollRectOnScreen(currentMatchBounds.fLeft, currentMatchBounds.fTop, - currentMatchBounds.fRight, currentMatchBounds.fBottom)) + WebCore::IntRect visible; + getVisibleRect(&visible); + m_findOnPage.drawLayer(canvas, &visible, -1); + WebCore::IntRect currentMatchBounds = m_findOnPage.currentMatchBounds(); + if (currentMatchBounds.isEmpty()) return; + scrollRectOnScreen(currentMatchBounds.x(), currentMatchBounds.y(), + currentMatchBounds.right(), currentMatchBounds.bottom()); +} - // Set up the paints used for drawing the matches - if (!m_isFindPaintSetUp) - setUpFindPaint(); - - // Draw the current match - drawMatch(currentMatchRegion, canvas, true); - // Now draw the picture, so that it shows up on top of the rectangle - canvas->drawPicture(*matchInfo.getPicture()); - - // Draw the rest - unsigned numberOfMatches = m_matches->size(); - if (numberOfMatches > 1 - && numberOfMatches < MAX_NUMBER_OF_MATCHES_TO_DRAW) { - WebCore::IntRect visible; - getVisibleRect(&visible); - SkIRect visibleIRect(visible); - for(unsigned i = 0; i < numberOfMatches; i++) { - // The current match has already been drawn - if (i == m_findIndex) - continue; - const SkRegion& region = (*m_matches)[i].getLocation(); - // Do not draw matches which intersect the current one, or if it is - // offscreen - if (currentMatchRegion.intersects(region) - || !region.intersects(visibleIRect)) - continue; - drawMatch(region, canvas, false); - } - } +FindOnPage* findOnPage() +{ + return m_viewImpl->m_findIsUp ? &m_findOnPage : 0; } void resetCursorRing() @@ -418,7 +340,7 @@ void resetCursorRing() void drawCursorRing(SkCanvas* canvas) { - const CachedRoot* root = getFrameCache(AllowNewer); + CachedRoot* root = getFrameCache(AllowNewer); if (!root) { DBG_NAV_LOG("!root"); resetCursorRing(); @@ -436,9 +358,11 @@ void drawCursorRing(SkCanvas* canvas) m_viewImpl->m_hasCursorBounds = false; return; } - const WTF::Vector<WebCore::IntRect>* rings = &node->cursorRings(); - if (!rings->size()) { - DBG_NAV_LOG("!rings->size()"); + setVisibleRect(root); + WTF::Vector<WebCore::IntRect> rings; + node->cursorRings(frame, &rings); + if (!rings.size()) { + DBG_NAV_LOG("!rings.size()"); m_viewImpl->m_hasCursorBounds = false; return; } @@ -459,17 +383,16 @@ void drawCursorRing(SkCanvas* canvas) } } m_viewImpl->gButtonMutex.unlock(); - WebCore::IntRect bounds = node->bounds(); + WebCore::IntRect bounds = node->bounds(frame); updateCursorBounds(root, frame, node); - WTF::Vector<WebCore::IntRect> oneRing; bool useHitBounds = node->useHitBounds(); if (useHitBounds) { - bounds = node->hitBounds(); + bounds = node->hitBounds(frame); } if (useHitBounds || node->useBounds()) { - oneRing.append(bounds); - rings = &oneRing; + rings.clear(); + rings.append(bounds); } bounds.inflate(SkScalarCeil(CURSOR_RING_OUTER_DIAMETER)); if (canvas->quickReject(bounds, SkCanvas::kAA_EdgeType)) { @@ -490,14 +413,14 @@ void drawCursorRing(SkCanvas* canvas) (flavor + CursorRing::NORMAL_ANIMATING); } #if DEBUG_NAV_UI - const WebCore::IntRect& ring = (*rings)[0]; + const WebCore::IntRect& ring = rings[0]; DBG_NAV_LOGD("cursorNode=%d (nodePointer=%p) flavor=%s rings=%d" " (%d, %d, %d, %d) isPlugin=%s", node->index(), node->nodePointer(), flavor == CursorRing::FAKE_FLAVOR ? "FAKE_FLAVOR" : flavor == CursorRing::NORMAL_ANIMATING ? "NORMAL_ANIMATING" : flavor == CursorRing::FAKE_ANIMATING ? "FAKE_ANIMATING" : "NORMAL_FLAVOR", - rings->size(), ring.x(), ring.y(), ring.width(), ring.height(), + rings.size(), ring.x(), ring.y(), ring.width(), ring.height(), node->isPlugin() ? "true" : "false"); #endif } @@ -516,7 +439,7 @@ void drawCursorRing(SkCanvas* canvas) } } if (!isButton) - CursorRing::DrawRing(canvas, *rings, flavor); + CursorRing::DrawRing(canvas, rings, flavor); } bool cursorIsTextInput(FrameCachePermission allowNewer) @@ -540,9 +463,10 @@ void cursorRingBounds(WebCore::IntRect* bounds) DBG_NAV_LOGD("%s", ""); CachedRoot* root = getFrameCache(DontAllowNewer); if (root) { - const CachedNode* cachedNode = root->currentCursor(); + const CachedFrame* cachedFrame; + const CachedNode* cachedNode = root->currentCursor(&cachedFrame); if (cachedNode) { - cachedNode->cursorRingBounds(bounds); + *bounds = cachedNode->cursorRingBounds(cachedFrame); DBG_NAV_LOGD("bounds={%d,%d,%d,%d}", bounds->x(), bounds->y(), bounds->width(), bounds->height()); return; @@ -568,7 +492,7 @@ void fixCursor() // center (+/- 2) IntPoint oldCenter = IntPoint(bounds.x() + (bounds.width() >> 1), bounds.y() + (bounds.height() >> 1)); - IntRect newBounds = node->bounds(); + IntRect newBounds = node->bounds(frame); IntPoint newCenter = IntPoint(newBounds.x() + (newBounds.width() >> 1), newBounds.y() + (newBounds.height() >> 1)); DBG_NAV_LOGD("oldCenter=(%d,%d) newCenter=(%d,%d)" @@ -607,7 +531,15 @@ CachedRoot* getFrameCache(FrameCachePermission allowNewer) return m_frameCacheUI; } DBG_NAV_LOGD("%s", "m_viewImpl->m_updatedFrameCache == true"); - bool hadCursor = m_frameCacheUI && m_frameCacheUI->currentCursor(); + const CachedFrame* oldCursorFrame; + const CachedNode* oldCursorNode = m_frameCacheUI ? + m_frameCacheUI->currentCursor(&oldCursorFrame) : 0; +#if USE(ACCELERATED_COMPOSITING) + int layerId = oldCursorNode && oldCursorNode->isInLayer() ? + oldCursorFrame->layer(oldCursorNode)->layer( + m_frameCacheUI->rootLayer())->uniqueId() : -1; +#endif + // get id from old layer and use to find new layer const CachedNode* oldFocus = m_frameCacheUI ? m_frameCacheUI->currentFocus() : 0; m_viewImpl->gFrameCacheMutex.lock(); delete m_frameCacheUI; @@ -618,6 +550,17 @@ CachedRoot* getFrameCache(FrameCachePermission allowNewer) m_viewImpl->m_frameCacheKit = 0; m_viewImpl->m_navPictureKit = 0; m_viewImpl->gFrameCacheMutex.unlock(); + if (m_frameCacheUI) + m_frameCacheUI->setRootLayer(m_rootLayer); +#if USE(ACCELERATED_COMPOSITING) + if (layerId >= 0) { + SkRect viewMetrics; + getViewMetrics(&viewMetrics); + LayerAndroid* layer = const_cast<LayerAndroid*>( + m_frameCacheUI->rootLayer()->findById(layerId)); + layer->calcPosition(&viewMetrics, 0); + } +#endif fixCursor(); if (oldFocus && m_frameCacheUI) { const CachedNode* newFocus = m_frameCacheUI->currentFocus(); @@ -632,7 +575,7 @@ CachedRoot* getFrameCache(FrameCachePermission allowNewer) checkException(env); } } - if (hadCursor && (!m_frameCacheUI || !m_frameCacheUI->currentCursor())) + if (oldCursorNode && (!m_frameCacheUI || !m_frameCacheUI->currentCursor())) viewInvalidate(); // redraw in case cursor ring is still visible return m_frameCacheUI; } @@ -677,6 +620,23 @@ void getVisibleRect(WebCore::IntRect* rect) checkException(env); } +void getViewMetrics(SkRect* viewMetrics) +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + jobject jMetrics = env->CallObjectMethod(m_javaGlue.object(env).get(), + m_javaGlue.m_getViewMetrics); + checkException(env); + int scrollX = env->GetIntField(jMetrics, m_javaGlue.m_metricsScrollX); + int scrollY = env->GetIntField(jMetrics, m_javaGlue.m_metricsScrollY); + int width = env->GetIntField(jMetrics, m_javaGlue.m_metricsWidth); + int height = env->GetIntField(jMetrics, m_javaGlue.m_metricsHeight); + int scale = env->GetFloatField(jMetrics, m_javaGlue.m_metricsScale); + *viewMetrics = IntRect(scrollX / scale, scrollY / scale, + width / scale, height / scale); + env->DeleteLocalRef(jMetrics); + checkException(env); +} + static CachedFrame::Direction KeyToDirection(KeyCode keyCode) { switch (keyCode) { @@ -730,12 +690,12 @@ void updateCursorBounds(const CachedRoot* root, const CachedFrame* cachedFrame, // If m_viewImpl->m_hasCursorBounds is false, we never look at the other // values, so do not bother setting them. if (m_viewImpl->m_hasCursorBounds) { - WebCore::IntRect bounds = cachedNode->bounds(); + WebCore::IntRect bounds = cachedNode->bounds(cachedFrame); if (m_viewImpl->m_cursorBounds != bounds) DBG_NAV_LOGD("new cursor bounds=(%d,%d,w=%d,h=%d)", bounds.x(), bounds.y(), bounds.width(), bounds.height()); - m_viewImpl->m_cursorBounds = cachedNode->bounds(); - m_viewImpl->m_cursorHitBounds = cachedNode->hitBounds(); + m_viewImpl->m_cursorBounds = bounds; + m_viewImpl->m_cursorHitBounds = cachedNode->hitBounds(cachedFrame); m_viewImpl->m_cursorFrame = cachedFrame->framePointer(); root->getSimulatedMousePosition(&m_viewImpl->m_cursorLocation); m_viewImpl->m_cursorNode = cachedNode->nodePointer(); @@ -760,11 +720,7 @@ bool moveCursor(int keyCode, int count, bool ignoreScroll) DBG_NAV_LOGD("old cursor %d (nativeNode=%p) cursorLocation={%d, %d}", cursor ? cursor->index() : 0, cursor ? cursor->nodePointer() : 0, cursorLocation.x(), cursorLocation.y()); - WebCore::IntRect visibleRect; - getVisibleRect(&visibleRect); - DBG_NAV_LOGD("getVisibleRect %d,%d,%d,%d", - visibleRect.x(), visibleRect.y(), visibleRect.width(), visibleRect.height()); - root->setVisibleRect(visibleRect); + WebCore::IntRect visibleRect = setVisibleRect(root); int xMax = getScaledMaxXScroll(); int yMax = getScaledMaxYScroll(); root->setMaxScroll(xMax, yMax); @@ -784,10 +740,10 @@ bool moveCursor(int keyCode, int count, bool ignoreScroll) "bounds={%d,%d,w=%d,h=%d}", cachedNode ? cachedNode->index() : 0, cachedNode ? cachedNode->nodePointer() : 0, root->cursorLocation().x(), root->cursorLocation().y(), - cachedNode ? cachedNode->bounds().x() : 0, - cachedNode ? cachedNode->bounds().y() : 0, - cachedNode ? cachedNode->bounds().width() : 0, - cachedNode ? cachedNode->bounds().height() : 0); + cachedNode ? cachedNode->bounds(cachedFrame).x() : 0, + cachedNode ? cachedNode->bounds(cachedFrame).y() : 0, + cachedNode ? cachedNode->bounds(cachedFrame).width() : 0, + cachedNode ? cachedNode->bounds(cachedFrame).height() : 0); // If !m_heightCanMeasure (such as in the browser), we want to scroll no // matter what if (!ignoreScroll && (!m_heightCanMeasure || @@ -852,37 +808,40 @@ const CachedNode* findAt(CachedRoot* root, const WebCore::IntRect& rect, *framePtr = 0; if (!root) return 0; - WebCore::IntRect visibleRect; + setVisibleRect(root); + return root->findAt(rect, framePtr, rxPtr, ryPtr, true); +} + +IntRect setVisibleRect(CachedRoot* root) +{ + IntRect visibleRect; getVisibleRect(&visibleRect); + DBG_NAV_LOGD("getVisibleRect %d,%d,%d,%d", + visibleRect.x(), visibleRect.y(), visibleRect.width(), visibleRect.height()); root->setVisibleRect(visibleRect); - return root->findAt(rect, framePtr, rxPtr, ryPtr, true); + return visibleRect; } void selectBestAt(const WebCore::IntRect& rect) { const CachedFrame* frame; int rx, ry; - bool disableFocusController = false; CachedRoot* root = getFrameCache(DontAllowNewer); const CachedNode* node = findAt(root, rect, &frame, &rx, &ry); if (!node) { DBG_NAV_LOGD("no nodes found root=%p", root); - disableFocusController = true; m_viewImpl->m_hasCursorBounds = false; if (root) root->setCursor(0, 0); } else { DBG_NAV_LOGD("CachedNode:%p (%d)", node, node->index()); - root->rootHistory()->setMouseBounds(node->bounds()); + root->rootHistory()->setMouseBounds(node->bounds(frame)); updateCursorBounds(root, frame, node); root->setCursor(const_cast<CachedFrame*>(frame), const_cast<CachedNode*>(node)); - if (!node->wantsKeyEvents()) { - disableFocusController = true; - } } - sendMoveMouseIfLatest(disableFocusController); + sendMoveMouseIfLatest(false); viewInvalidate(); } @@ -988,7 +947,7 @@ void setFindIsUp(bool up) { m_viewImpl->m_findIsUp = up; if (!up) - m_hasCurrentLocation = false; + m_findOnPage.clearCurrentLocation(); } void setFollowedLink(bool followed) @@ -1148,33 +1107,9 @@ void sendMotionUp( checkException(env); } -// This function is only used by findNext and setMatches. In it, we store -// upper left corner of the match specified by m_findIndex in -// m_currentMatchLocation. -void inline storeCurrentMatchLocation() -{ - SkASSERT(m_findIndex < m_matches->size()); - const SkIRect& bounds = (*m_matches)[m_findIndex].getLocation().getBounds(); - m_currentMatchLocation.set(bounds.fLeft, bounds.fTop); - m_hasCurrentLocation = true; -} - void findNext(bool forward) { - if (!m_matches || !m_matches->size()) - return; - if (forward) { - m_findIndex++; - if (m_findIndex == m_matches->size()) - m_findIndex = 0; - } else { - if (m_findIndex == 0) { - m_findIndex = m_matches->size() - 1; - } else { - m_findIndex--; - } - } - storeCurrentMatchLocation(); + m_findOnPage.findNext(forward); viewInvalidate(); } @@ -1182,28 +1117,7 @@ void findNext(bool forward) // deleting it. void setMatches(WTF::Vector<MatchInfo>* matches) { - if (m_matches) - delete m_matches; - m_matches = matches; - if (m_matches->size()) { - if (m_hasCurrentLocation) { - for (unsigned i = 0; i < m_matches->size(); i++) { - const SkIRect& rect = (*m_matches)[i].getLocation().getBounds(); - if (rect.fLeft == m_currentMatchLocation.fX - && rect.fTop == m_currentMatchLocation.fY) { - m_findIndex = i; - viewInvalidate(); - return; - } - } - } - // If we did not have a stored location, or if we were unable to restore - // it, store the new one. - m_findIndex = 0; - storeCurrentMatchLocation(); - } else { - m_hasCurrentLocation = false; - } + m_findOnPage.setMatches(matches); viewInvalidate(); } @@ -1281,6 +1195,21 @@ int moveGeneration() return m_viewImpl->m_moveGeneration; } +const LayerAndroid* rootLayer() const +{ + return m_rootLayer; +} + +void setRootLayer(LayerAndroid* layer) +{ + m_rootLayer = layer; + CachedRoot* root = getFrameCache(DontAllowNewer); + if (!root) + return; + root->resetLayers(); + root->setRootLayer(m_rootLayer); +} + private: // local state for WebView // private to getFrameCache(); other functions operate in a different thread CachedRoot* m_frameCacheUI; // navigation data ready for use @@ -1293,18 +1222,8 @@ private: // local state for WebView bool m_heightCanMeasure; int m_lastDx; SkMSec m_lastDxTime; - WTF::Vector<MatchInfo>* m_matches; - // Stores the location of the current match. - SkIPoint m_currentMatchLocation; - // Tells whether the value in m_currentMatchLocation is valid. - bool m_hasCurrentLocation; - // Tells whether we have done the setup to draw the Find matches. - bool m_isFindPaintSetUp; - // Paint used to draw our Find matches. - SkPaint m_findPaint; - // Paint used for the background of our Find matches. - SkPaint m_findBlurPaint; - unsigned m_findIndex; + FindOnPage m_findOnPage; + LayerAndroid* m_rootLayer; }; // end of WebView class /* @@ -1383,13 +1302,14 @@ static const CachedNode* getCursorNode(JNIEnv *env, jobject obj, return root ? root->currentCursor(frame) : 0; } -static const CachedNode* getFocusCandidate(JNIEnv *env, jobject obj) +static const CachedNode* getFocusCandidate(JNIEnv *env, jobject obj, + const CachedFrame** frame) { WebView* view = GET_NATIVE_VIEW(env, obj); CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); if (!root) return 0; - const CachedNode* cursor = root->currentCursor(); + const CachedNode* cursor = root->currentCursor(frame); if (cursor && cursor->wantsKeyEvents()) return cursor; return root->currentFocus(); @@ -1424,8 +1344,9 @@ static jboolean nativeCursorMatchesFocus(JNIEnv *env, jobject obj) static jobject nativeCursorNodeBounds(JNIEnv *env, jobject obj) { - const CachedNode* node = getCursorNode(env, obj); - WebCore::IntRect bounds = node ? node->getBounds() + const CachedFrame* frame; + const CachedNode* node = getCursorNode(env, obj, &frame); + WebCore::IntRect bounds = node ? node->bounds(frame) : WebCore::IntRect(0, 0, 0, 0); jclass rectClass = env->FindClass("android/graphics/Rect"); jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V"); @@ -1462,9 +1383,10 @@ static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj) static bool nativeCursorIntersects(JNIEnv *env, jobject obj, jobject visRect) { - const CachedNode* node = getCursorNode(env, obj); - return node ? node->getBounds().intersects(jrect_to_webrect(env, visRect)) - : false; + const CachedFrame* frame; + const CachedNode* node = getCursorNode(env, obj, &frame); + return node ? node->bounds(frame).intersects( + jrect_to_webrect(env, visRect)) : false; } static bool nativeCursorIsAnchor(JNIEnv *env, jobject obj) @@ -1473,6 +1395,12 @@ static bool nativeCursorIsAnchor(JNIEnv *env, jobject obj) return node ? node->isAnchor() : false; } +static bool nativeCursorIsInLayer(JNIEnv *env, jobject obj) +{ + const CachedNode* node = getCursorNode(env, obj); + return node ? node->isInLayer() : false; +} + static bool nativeCursorIsTextInput(JNIEnv *env, jobject obj) { const CachedNode* node = getCursorNode(env, obj); @@ -1513,14 +1441,7 @@ static void nativeDrawMatches(JNIEnv *env, jobject obj, jobject canv) view->drawMatches(canvas); } -static void setXYWH(SkRect* r, SkScalar x, SkScalar y, SkScalar w, SkScalar h) { - r->set(x, y, x + w, y + h); -} - -static void nativeDrawLayers(JNIEnv *env, jobject obj, - jint layer, jint scrollX, jint scrollY, - jint width, jint height, - jfloat scale, jobject canv) +static void nativeDrawLayers(JNIEnv *env, jobject obj, jint layer, jobject canv) { if (!env) return; @@ -1532,13 +1453,11 @@ static void nativeDrawLayers(JNIEnv *env, jobject obj, #if USE(ACCELERATED_COMPOSITING) LayerAndroid* layerImpl = reinterpret_cast<LayerAndroid*>(layer); SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv); - if (canvas) { - SkRect viewPort; - setXYWH(&viewPort, - scrollX / scale, scrollY / scale, - width / scale, height / scale); - layerImpl->draw(canvas, &viewPort); - } + WebView* view = GET_NATIVE_VIEW(env, obj); + SkRect viewMetrics; + view->getViewMetrics(&viewMetrics); + layerImpl->setFindOnPage(view->findOnPage()); + layerImpl->draw(canvas, &viewMetrics); #endif } @@ -1568,6 +1487,14 @@ static void nativeDestroyLayer(JNIEnv *env, jobject obj, jint layer) #endif } +static void nativeSetRootLayer(JNIEnv *env, jobject obj, jint layer) +{ +#if USE(ACCELERATED_COMPOSITING) + LayerAndroid* layerImpl = reinterpret_cast<LayerAndroid*>(layer); + GET_NATIVE_VIEW(env, obj)->setRootLayer(layerImpl); +#endif +} + static void nativeDrawCursorRing(JNIEnv *env, jobject obj, jobject canv) { SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv); @@ -1655,7 +1582,7 @@ static bool nativeFocusCandidateIsRtlText(JNIEnv *env, jobject obj) static bool nativeFocusCandidateIsTextInput(JNIEnv *env, jobject obj) { - const CachedNode* node = getFocusCandidate(env, obj); + const CachedNode* node = getFocusCandidate(env, obj, 0); return node ? node->isTextInput() : false; } @@ -1676,8 +1603,9 @@ static jobject nativeFocusCandidateName(JNIEnv *env, jobject obj) static jobject nativeFocusCandidateNodeBounds(JNIEnv *env, jobject obj) { - const CachedNode* node = getFocusCandidate(env, obj); - WebCore::IntRect bounds = node ? node->getBounds() + const CachedFrame* frame; + const CachedNode* node = getFocusCandidate(env, obj, &frame); + WebCore::IntRect bounds = node ? node->bounds(frame) : WebCore::IntRect(0, 0, 0, 0); jclass rectClass = env->FindClass("android/graphics/Rect"); jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V"); @@ -1688,13 +1616,13 @@ static jobject nativeFocusCandidateNodeBounds(JNIEnv *env, jobject obj) static jint nativeFocusCandidatePointer(JNIEnv *env, jobject obj) { - const CachedNode* node = getFocusCandidate(env, obj); + const CachedNode* node = getFocusCandidate(env, obj, 0); return reinterpret_cast<int>(node ? node->nodePointer() : 0); } static jobject nativeFocusCandidateText(JNIEnv *env, jobject obj) { - const CachedNode* node = getFocusCandidate(env, obj); + const CachedNode* node = getFocusCandidate(env, obj, 0); if (!node) return 0; WebCore::String value = node->getExport(); @@ -1914,7 +1842,7 @@ static int nativeFindAll(JNIEnv *env, jobject obj, jstring findLower, SkBitmap bitmap; bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height); canvas.setBitmapDevice(bitmap); - canvas.drawPicture(*(root->getPicture())); + root->draw(canvas); WTF::Vector<MatchInfo>* matches = canvas.detachMatches(); // With setMatches, the WebView takes ownership of matches view->setMatches(matches); @@ -1983,7 +1911,7 @@ static void nativeMoveCursorToNextTextInput(JNIEnv *env, jobject obj) true); if (!next) return; - const WebCore::IntRect& bounds = next->bounds(); + const WebCore::IntRect& bounds = next->bounds(frame); root->rootHistory()->setMouseBounds(bounds); view->updateCursorBounds(root, frame, next); root->setCursor(const_cast<CachedFrame*>(frame), @@ -2052,9 +1980,8 @@ static void nativeDumpDisplayTree(JNIEnv* env, jobject jwebview, jstring jurl) fclose(file); } #if USE(ACCELERATED_COMPOSITING) - int pRootLayer = view->getWebViewCore()->rootLayer(); - if (pRootLayer) { - LayerAndroid* rootLayer = reinterpret_cast<LayerAndroid*>(pRootLayer); + const LayerAndroid* rootLayer = view->rootLayer(); + if (rootLayer) { FILE* file = fopen(LAYERS_TREE_LOG_FILE,"w"); if (file) { rootLayer->dumpLayers(file, 0); @@ -2092,6 +2019,8 @@ static JNINativeMethod gJavaWebViewMethods[] = { (void*) nativeCursorIntersects }, { "nativeCursorIsAnchor", "()Z", (void*) nativeCursorIsAnchor }, + { "nativeCursorIsInLayer", "()Z", + (void*) nativeCursorIsInLayer }, { "nativeCursorIsTextInput", "()Z", (void*) nativeCursorIsTextInput }, { "nativeCursorPosition", "()Landroid/graphics/Point;", @@ -2108,7 +2037,7 @@ static JNINativeMethod gJavaWebViewMethods[] = { (void*) nativeDrawCursorRing }, { "nativeDestroyLayer", "(I)V", (void*) nativeDestroyLayer }, - { "nativeDrawLayers", "(IIIIIFLandroid/graphics/Canvas;)V", + { "nativeDrawLayers", "(ILandroid/graphics/Canvas;)V", (void*) nativeDrawLayers }, { "nativeEvaluateLayersAnimations", "(I)Z", (void*) nativeEvaluateLayersAnimations }, @@ -2186,6 +2115,8 @@ static JNINativeMethod gJavaWebViewMethods[] = { (void*) nativeSetFollowedLink }, { "nativeSetHeightCanMeasure", "(Z)V", (void*) nativeSetHeightCanMeasure }, + { "nativeSetRootLayer", "(I)V", + (void*) nativeSetRootLayer }, { "nativeTextGeneration", "()I", (void*) nativeTextGeneration }, { "nativeUpdateCachedTextfield", "(Ljava/lang/String;I)V", |
