summaryrefslogtreecommitdiffstats
path: root/WebKit/android/nav
diff options
context:
space:
mode:
Diffstat (limited to 'WebKit/android/nav')
-rw-r--r--WebKit/android/nav/CacheBuilder.cpp3072
-rw-r--r--WebKit/android/nav/CacheBuilder.h272
-rw-r--r--WebKit/android/nav/CachedDebug.h74
-rw-r--r--WebKit/android/nav/CachedFrame.cpp1318
-rw-r--r--WebKit/android/nav/CachedFrame.h228
-rw-r--r--WebKit/android/nav/CachedHistory.cpp203
-rw-r--r--WebKit/android/nav/CachedHistory.h90
-rw-r--r--WebKit/android/nav/CachedNode.cpp346
-rw-r--r--WebKit/android/nav/CachedNode.h235
-rw-r--r--WebKit/android/nav/CachedNodeType.h41
-rw-r--r--WebKit/android/nav/CachedPrefix.h46
-rw-r--r--WebKit/android/nav/CachedRoot.cpp1087
-rw-r--r--WebKit/android/nav/CachedRoot.h115
-rw-r--r--WebKit/android/nav/FindCanvas.cpp458
-rw-r--r--WebKit/android/nav/FindCanvas.h207
-rw-r--r--WebKit/android/nav/SelectText.cpp263
-rw-r--r--WebKit/android/nav/SelectText.h42
-rw-r--r--WebKit/android/nav/WebView.cpp2322
18 files changed, 0 insertions, 10419 deletions
diff --git a/WebKit/android/nav/CacheBuilder.cpp b/WebKit/android/nav/CacheBuilder.cpp
deleted file mode 100644
index 8b31de6..0000000
--- a/WebKit/android/nav/CacheBuilder.cpp
+++ /dev/null
@@ -1,3072 +0,0 @@
-/*
- * Copyright 2006, 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 APPLE COMPUTER, INC. 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 "CachedNode.h"
-#include "CachedRoot.h"
-#include "Document.h"
-#include "EventNames.h"
-#include "EventTargetNode.h"
-#include "Frame.h"
-#include "FrameLoader.h"
-#include "FrameLoaderClientAndroid.h"
-#include "FrameTree.h"
-#include "FrameView.h"
-//#include "GraphicsContext.h"
-#include "HTMLAreaElement.h"
-#include "HTMLImageElement.h"
-#include "HTMLInputElement.h"
-#include "HTMLMapElement.h"
-#include "HTMLNames.h"
-#include "HTMLOptionElement.h"
-#include "HTMLSelectElement.h"
-#include "InlineTextBox.h"
-#include "KURL.h"
-#include "PluginView.h"
-#include "RenderImage.h"
-#include "RenderInline.h"
-#include "RenderListBox.h"
-#include "RenderSkinCombo.h"
-#include "RenderTextControl.h"
-#include "RenderWidget.h"
-#include "SkCanvas.h"
-#include "SkPoint.h"
-#include "Text.h"
-#include "WebCoreFrameBridge.h"
-#include "WebCoreViewBridge.h"
-#include "Widget.h"
-#include <wtf/unicode/Unicode.h>
-
-#ifdef DUMP_NAV_CACHE_USING_PRINTF
- FILE* gNavCacheLogFile = NULL;
- android::Mutex gWriteLogMutex;
-#endif
-
-#include "CacheBuilder.h"
-
-#define MINIMUM_FOCUSABLE_WIDTH 3
-#define MINIMUM_FOCUSABLE_HEIGHT 3
-#define MAXIMUM_FOCUS_RING_COUNT 32
-
-namespace android {
-
-CacheBuilder* CacheBuilder::Builder(Frame* frame) {
- return &((FrameLoaderClientAndroid*) frame->loader()->client())->getCacheBuilder();
-}
-
-Frame* CacheBuilder::FrameAnd(CacheBuilder* cacheBuilder) {
- FrameLoaderClientAndroid* loader = (FrameLoaderClientAndroid*)
- ((char*) cacheBuilder - OFFSETOF(FrameLoaderClientAndroid, m_cacheBuilder));
- return loader->getFrame();
-}
-
-Frame* CacheBuilder::FrameAnd(const CacheBuilder* cacheBuilder) {
- FrameLoaderClientAndroid* loader = (FrameLoaderClientAndroid*)
- ((char*) cacheBuilder - OFFSETOF(FrameLoaderClientAndroid, m_cacheBuilder));
- return loader->getFrame();
-}
-
-#if DUMP_NAV_CACHE
-
-#define DEBUG_BUFFER_SIZE 256
-#define DEBUG_WRAP_SIZE 150
-#define DEBUG_WRAP_MAX 170
-
-Frame* CacheBuilder::Debug::frameAnd() const {
- CacheBuilder* nav = (CacheBuilder*) ((char*) this - OFFSETOF(CacheBuilder, mDebug));
- return CacheBuilder::FrameAnd(nav);
-}
-
-void CacheBuilder::Debug::attr(const AtomicString& name, const AtomicString& value) {
- if (name.isNull() || name.isEmpty() || value.isNull() || value.isEmpty())
- return;
- uChar(name.characters(), name.length(), false);
- print("=");
- wideString(value.characters(), value.length(), false);
- print(" ");
-}
-
-void CacheBuilder::Debug::comma(const char* str) {
- print(str);
- print(", ");
-}
-
-int CacheBuilder::Debug::flowBoxes(RenderFlow* flow, int ifIndex, int indent) {
- char scratch[256];
- const InlineFlowBox* box = flow->firstLineBox();
- if (box == NULL)
- return ifIndex;
- do {
- newLine();
- int i = snprintf(scratch, sizeof(scratch), "// render flow:%p"
- " box:%p%.*s", flow, box, indent, " ");
- for (; box; box = box->nextFlowBox()) {
- i += snprintf(&scratch[i], sizeof(scratch) - i,
- " [%d]:{%d, %d, %d, %d}", ++ifIndex,
- box->xPos(), box->yPos(), box->width(), box->height());
- if (ifIndex % 4 == 0)
- break;
- }
- print(scratch);
- } while (box);
- RenderObject const * const end = flow->lastChild();
- if (end == NULL)
- return ifIndex;
- indent += 2;
- if (indent > 8)
- indent = 8;
- for (const RenderObject* renderer = flow->firstChild(); renderer != end;
- renderer = renderer->nextSibling())
- {
- if (renderer->isInlineFlow())
- ifIndex = flowBoxes((RenderFlow*) renderer, ifIndex, indent);
- }
- return ifIndex;
-}
-
-void CacheBuilder::Debug::flush() {
- int len;
- do {
- int limit = mIndex;
- if (limit < DEBUG_WRAP_SIZE)
- return;
- if (limit < DEBUG_WRAP_MAX)
- len = limit;
- else {
- limit = DEBUG_WRAP_MAX;
- len = DEBUG_WRAP_SIZE;
- while (len < limit) {
- char test = mBuffer[len];
- if (test < '/' || (test > '9' && test < 'A') || (test > 'Z' && test < 'a') || test > 'z')
- break;
- len++;
- }
- while (mBuffer[len] == '\\' || mBuffer[len] == '"')
- len++;
- }
- const char* prefix = mPrefix;
- if (prefix[0] == '\"') {
- // see if we're inside a quote
- int quoteCount = 0;
- for (int index = 0; index < len; index++) {
- if (mBuffer[index] == '\\') {
- index++;
- continue;
- }
- if (mBuffer[index] == '\n') {
- quoteCount = 0;
- continue;
- }
- if (mBuffer[index] == '"')
- quoteCount++;
- }
- if ((quoteCount & 1) == 0)
- prefix = "\n";
- }
- DUMP_NAV_LOGD("%.*s", len, mBuffer);
- int copy = mIndex - len;
- strcpy(mBuffer, prefix);
- memcpy(&mBuffer[strlen(prefix)], &mBuffer[len], copy);
- mIndex = strlen(prefix) + copy;
- } while (true);
-}
-
-void CacheBuilder::Debug::frameName(char*& namePtr, const char* max) const {
- if (namePtr >= max)
- return;
- Frame* frame = frameAnd();
- Frame* parent = frame->tree()->parent();
- if (parent)
- Builder(parent)->mDebug.frameName(namePtr, max);
- const AtomicString& name = frame->tree()->name();
- if (name.length() == 0)
- return;
- unsigned index = 0;
- if (name.startsWith(AtomicString("opener")))
- index = 6;
- for (; index < name.length(); index++) {
- char ch = name[index];
- if (ch <= ' ')
- ch = '_';
- if (WTF::isASCIIAlphanumeric(ch) || ch == '_')
- *namePtr++ = ch;
- }
-}
-
-void CacheBuilder::Debug::frames() {
- Frame* frame = frameAnd();
- Document* doc = frame->document();
- if (doc == NULL)
- return;
- bool top = frame->tree()->parent() == NULL;
- if (top) {
-#ifdef DUMP_NAV_CACHE_USING_PRINTF
- gWriteLogMutex.lock();
- ASSERT(gNavCacheLogFile == NULL);
- gNavCacheLogFile = fopen(NAV_CACHE_LOG_FILE, "a");
-#endif
- groups();
- }
- Frame* child = frame->tree()->firstChild();
- bool hasChild = child != NULL;
- if (top && hasChild)
- DUMP_NAV_LOGD("\nnamespace TEST_SPACE {\n\n");
- while (child) {
- Builder(child)->mDebug.frames();
- child = child->tree()->nextSibling();
- }
- if (hasChild) {
- child = frame->tree()->firstChild();
- while (child) {
- char childName[256];
- char* childNamePtr = childName;
- Builder(child)->mDebug.frameName(childNamePtr, childNamePtr + sizeof(childName) - 1);
- *childNamePtr = '\0';
- if (child == frame->tree()->firstChild())
- DUMP_NAV_LOGD("DebugTestFrameGroup TEST%s_GROUP[] = {\n", childName);
- Frame* next = child->tree()->nextSibling();
- Document* doc = child->document();
- if (doc != NULL) {
- RenderObject* renderer = doc->renderer();
- if (renderer != NULL) {
- RenderLayer* layer = renderer->enclosingLayer();
- if (layer != NULL) {
- DUMP_NAV_LOGD("{ ");
- DUMP_NAV_LOGD("TEST%s_RECTS, ", childName);
- DUMP_NAV_LOGD("TEST%s_RECT_COUNT, ", childName);
- DUMP_NAV_LOGD("TEST%s_RECTPARTS, ", childName);
- DUMP_NAV_LOGD("TEST%s_BOUNDS,\n", childName);
- DUMP_NAV_LOGD("TEST%s_WIDTH, ", childName);
- DUMP_NAV_LOGD("TEST%s_HEIGHT,\n", childName);
- DUMP_NAV_LOGD("0, 0, 0, 0,\n");
- DUMP_NAV_LOGD("TEST%s_FOCUS, ", childName);
- Frame* grandChild = child->tree()->firstChild();
- if (grandChild) {
- char grandChildName[256];
- char* grandChildNamePtr = grandChildName;
- Builder(grandChild)->mDebug.frameName(grandChildNamePtr,
- grandChildNamePtr + sizeof(grandChildName) - 1);
- *grandChildNamePtr = '\0';
- DUMP_NAV_LOGD("TEST%s_GROUP, ", grandChildName);
- DUMP_NAV_LOGD("sizeof(TEST%s_GROUP) / sizeof(DebugTestFrameGroup), ", grandChildName);
- } else
- DUMP_NAV_LOGD("NULL, 0, ");
- DUMP_NAV_LOGD("\"%s\"\n", childName);
- DUMP_NAV_LOGD("}%c\n", next ? ',' : ' ');
- }
- }
- }
- child = next;
- }
- DUMP_NAV_LOGD("};\n");
- }
- if (top) {
- if (hasChild)
- DUMP_NAV_LOGD("\n} // end of namespace\n\n");
- char name[256];
- char* frameNamePtr = name;
- frameName(frameNamePtr, frameNamePtr + sizeof(name) - 1);
- *frameNamePtr = '\0';
- DUMP_NAV_LOGD("DebugTestFrameGroup TEST%s_GROUP = {\n", name);
- DUMP_NAV_LOGD("TEST%s_RECTS, ", name);
- DUMP_NAV_LOGD("TEST%s_RECT_COUNT, ", name);
- DUMP_NAV_LOGD("TEST%s_RECTPARTS, ", name);
- DUMP_NAV_LOGD("TEST%s_BOUNDS,\n", name);
- DUMP_NAV_LOGD("TEST%s_WIDTH, ", name);
- DUMP_NAV_LOGD("TEST%s_HEIGHT,\n", name);
- DUMP_NAV_LOGD("TEST%s_MAX_H, ", name);
- DUMP_NAV_LOGD("TEST%s_MIN_H, ", name);
- DUMP_NAV_LOGD("TEST%s_MAX_V, ", name);
- DUMP_NAV_LOGD("TEST%s_MIN_V,\n", name);
- DUMP_NAV_LOGD("TEST%s_FOCUS, ", name);
- if (hasChild) {
- child = frame->tree()->firstChild();
- char childName[256];
- char* childNamePtr = childName;
- Builder(child)->mDebug.frameName(childNamePtr, childNamePtr + sizeof(childName) - 1);
- *childNamePtr = '\0';
- DUMP_NAV_LOGD("TEST_SPACE::TEST%s_GROUP, ", childName);
- DUMP_NAV_LOGD("sizeof(TEST_SPACE::TEST%s_GROUP) / sizeof(DebugTestFrameGroup), \n" ,childName);
- } else
- DUMP_NAV_LOGD("NULL, 0, ");
- DUMP_NAV_LOGD("\"%s\"\n", name);
- DUMP_NAV_LOGD("};\n");
-#ifdef DUMP_NAV_CACHE_USING_PRINTF
- if (gNavCacheLogFile)
- fclose(gNavCacheLogFile);
- gNavCacheLogFile = NULL;
- gWriteLogMutex.unlock();
-#endif
- }
-}
-
-void CacheBuilder::Debug::init(char* buffer, size_t size) {
- mBuffer = buffer;
- mBufferSize = size;
- mIndex = 0;
- mPrefix = "";
-}
-
-void CacheBuilder::Debug::groups() {
- Frame* frame = frameAnd();
- Frame* child = frame->tree()->firstChild();
- bool hasChild = child != NULL;
- if (frame->tree()->parent() == NULL && hasChild)
- DUMP_NAV_LOGD("namespace TEST_SPACE {\n\n");
- while (child) {
- Builder(child)->mDebug.groups();
- child = child->tree()->nextSibling();
- }
- if (frame->tree()->parent() == NULL && hasChild)
- DUMP_NAV_LOGD("\n} // end of namespace\n\n");
- Document* doc = frame->document();
- char name[256];
- char* frameNamePtr = name;
- frameName(frameNamePtr, frameNamePtr + sizeof(name) - 1);
- *frameNamePtr = '\0';
- if (doc == NULL) {
- DUMP_NAV_LOGD("// %s has no document\n", name);
- return;
- }
- RenderObject* renderer = doc->renderer();
- if (renderer == NULL) {
- DUMP_NAV_LOGD("// %s has no renderer\n", name);
- return;
- }
- RenderLayer* layer = renderer->enclosingLayer();
- if (layer == NULL) {
- DUMP_NAV_LOGD("// %s has no enclosingLayer\n", name);
- return;
- }
- Node* node = doc;
- Node* focus = doc->focusedNode();
- bool atLeastOne = false;
- do {
- if ((atLeastOne |= isFocusable(node)) != false)
- break;
- } while ((node = node->traverseNextNode()) != NULL);
- int focusIndex = -1;
- if (atLeastOne == false) {
- DUMP_NAV_LOGD("#define TEST%s_RECTS NULL\n", name);
- DUMP_NAV_LOGD("static int TEST%s_RECT_COUNT = 0; // no focusable nodes\n", name);
- DUMP_NAV_LOGD("#define TEST%s_RECTPARTS NULL\n", name);
- } else {
- node = doc;
- int count = 1;
- DUMP_NAV_LOGD("static DebugTestNode TEST%s_RECTS[] = {\n", name);
- do {
- String properties;
- EventTargetNode* elementTarget = node->isEventTargetNode() ?
- (EventTargetNode*) node : NULL;
- if (elementTarget) {
- if (elementTarget->getEventListener(eventNames().clickEvent))
- properties.append("ONCLICK | ");
- if (elementTarget->getEventListener(eventNames().mousedownEvent))
- properties.append("MOUSEDOWN | ");
- if (elementTarget->getEventListener(eventNames().mouseupEvent))
- properties.append("MOUSEUP | ");
- if (elementTarget->getEventListener(eventNames().mouseoverEvent))
- properties.append("MOUSEOVER | ");
- if (elementTarget->getEventListener(eventNames().mouseoutEvent))
- properties.append("MOUSEOUT | ");
- if (elementTarget->getEventListener(eventNames().keydownEvent))
- properties.append("KEYDOWN | ");
- if (elementTarget->getEventListener(eventNames().keyupEvent))
- properties.append("KEYUP | ");
- }
- if (CacheBuilder::HasFrame(node))
- properties.append("FRAME | ");
- if (focus == node) {
- properties.append("FOCUS | ");
- focusIndex = count;
- }
- if (node->isKeyboardFocusable(NULL))
- properties.append("KEYBOARD_FOCUSABLE | ");
- if (node->isMouseFocusable())
- properties.append("MOUSE_FOCUSABLE | ");
- if (node->isFocusable())
- properties.append("SIMPLE_FOCUSABLE | ");
- if (properties.isEmpty())
- properties.append("0");
- else
- properties.truncate(properties.length() - 3);
- IntRect rect = node->getRect();
- if (node->hasTagName(HTMLNames::areaTag))
- rect = Builder(frame)->getAreaRect(static_cast<HTMLAreaElement*>(node));
- char buffer[DEBUG_BUFFER_SIZE];
- memset(buffer, 0, sizeof(buffer));
- mBuffer = buffer;
- mBufferSize = sizeof(buffer);
- mPrefix = "\"\n\"";
- mIndex = snprintf(buffer, sizeof(buffer), "{{%d, %d, %d, %d}, ", rect.x(), rect.y(),
- rect.width(), rect.height());
- localName(node);
- uChar(properties.characters(), properties.length(), false);
- print(", ");
- int parentIndex = ParentIndex(node, count, node->parentNode());
- char scratch[256];
- snprintf(scratch, sizeof(scratch), "%d", parentIndex);
- comma(scratch);
- Element* element = static_cast<Element*>(node);
- if (node->isElementNode() && element->hasID())
- wideString(element->getIDAttribute());
- else if (node->isTextNode()) {
- #if 01 // set to one to abbreviate text that can be omitted from the address detection code
- if (rect.isEmpty() && node->textContent().length() > 100) {
- wideString(node->textContent().characters(), 100, false);
- snprintf(scratch, sizeof(scratch), "/* + %d bytes */",
- node->textContent().length() - 100);
- print(scratch);
- } else
- #endif
- wideString(node->textContent().characters(), node->textContent().length(), true);
- } else if (node->hasTagName(HTMLNames::aTag) ||
- node->hasTagName(HTMLNames::areaTag))
- {
- HTMLAnchorElement* anchor = static_cast<HTMLAnchorElement*>(node);
- wideString(anchor->href());
- } else if (node->hasTagName(HTMLNames::imgTag)) {
- HTMLImageElement* image = static_cast<HTMLImageElement*>(node);
- wideString(image->src());
- } else
- print("\"\"");
- RenderObject* renderer = node->renderer();
- int tabindex = node->isElementNode() ? node->tabIndex() : 0;
- if (renderer) {
- const IntRect& absB = renderer->absoluteBoundingBoxRect();
- snprintf(scratch, sizeof(scratch), ", {%d, %d, %d, %d}, %s"
- ", %d},",absB.x(), absB.y(), absB.width(), absB.height(),
- renderer->hasOverflowClip() ? "true" : "false", tabindex);
- print(scratch);
- } else
- print(", {0, 0, 0, 0}, false, 0},");
-
- flush();
- snprintf(scratch, sizeof(scratch), "// %d: ", count);
- mPrefix = "\n// ";
- print(scratch);
- //print(renderer ? renderer->information().ascii() : "NO_RENDER_INFO");
- if (node->isElementNode()) {
- Element* element = static_cast<Element*>(node);
- NamedAttrMap* attrs = element->attributes();
- unsigned length = attrs->length();
- if (length > 0) {
- newLine();
- print("// attr: ");
- for (unsigned i = 0; i < length; i++) {
- Attribute* a = attrs->attributeItem(i);
- attr(a->localName(), a->value());
- }
- }
- }
- if (renderer)
- renderTree(renderer, 0, node, count);
- count++;
- newLine();
- } while ((node = node->traverseNextNode()) != NULL);
- DUMP_NAV_LOGD("}; // focusables = %d\n", count - 1);
- DUMP_NAV_LOGD("\n");
- DUMP_NAV_LOGD("static int TEST%s_RECT_COUNT = %d;\n\n", name, count - 1);
- // look for rects with multiple parts
- node = doc;
- count = 1;
- bool hasRectParts = false;
- int globalOffsetX, globalOffsetY;
- GetGlobalOffset(frame, &globalOffsetX, &globalOffsetY);
- do {
- IntRect rect;
- bool _isFocusable = isFocusable(node) || (node->isTextNode()
- && node->getRect().isEmpty() == false
- );
- int nodeIndex = count++;
- if (_isFocusable == false)
- continue;
- RenderObject* renderer = node->renderer();
- if (renderer == NULL)
- continue;
- WTF::Vector<IntRect> rects;
- IntRect clipBounds = IntRect(0, 0, INT_MAX, INT_MAX);
- IntRect focusBounds = IntRect(0, 0, INT_MAX, INT_MAX);
- IntRect* rectPtr = &focusBounds;
- if (node->isTextNode()) {
- Text* textNode = (Text*) node;
- if (CacheBuilder::ConstructTextRects(textNode, 0, textNode,
- INT_MAX, globalOffsetX, globalOffsetY, rectPtr,
- clipBounds, &rects) == false)
- continue;
- } else {
- IntRect nodeBounds = node->getRect();
- if (CacheBuilder::ConstructPartRects(node, nodeBounds, rectPtr,
- globalOffsetX, globalOffsetY, &rects) == false)
- continue;
- }
- unsigned arraySize = rects.size();
- if (arraySize > 1 || (arraySize == 1 && (rectPtr->width() != rect.width())) ||
- rectPtr->height() != rect.height()) {
- if (hasRectParts == false) {
- DUMP_NAV_LOGD("static DebugTestRectPart TEST%s_RECTPARTS[] = {\n", name);
- hasRectParts = true;
- }
- if (node->isTextNode() == false) {
- unsigned rectIndex = 0;
- for (; rectIndex < arraySize; rectIndex++) {
- rectPtr = &rects.at(rectIndex);
- DUMP_NAV_LOGD("{ %d, %d, %d, %d, %d }, // %d\n", nodeIndex,
- rectPtr->x(), rectPtr->y(), rectPtr->width(),
- rectPtr->height(), rectIndex + 1);
- }
- } else {
- RenderText* renderText = (RenderText*) node->renderer();
- InlineTextBox* textBox = renderText->firstTextBox();
- unsigned rectIndex = 0;
- while (textBox) {
- int renderX, renderY;
- renderText->absolutePosition(renderX, renderY);
- IntRect rect = textBox->selectionRect(renderX, renderY, 0, INT_MAX);
- mIndex = 0;
- mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex, "{ %d, %d, %d, %d, %d",
- nodeIndex, rect.x(), rect.y(), rect.width(), rect.height());
- mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex, ", %d, %d, %d",
- textBox->len(), textBox->selectionHeight(), textBox->selectionTop());
- mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex, ", %d, %d, %d",
- textBox->spaceAdd(), textBox->start(), textBox->textPos());
- mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex, ", %d, %d, %d, %d",
- textBox->xPos(), textBox->yPos(), textBox->width(), textBox->height());
- mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex, ", %d }, // %d ",
- textBox->baseline(), ++rectIndex);
- wideString(node->textContent().characters() + textBox->start(), textBox->len(), true);
- DUMP_NAV_LOGD("%.*s\n", mIndex, mBuffer);
- textBox = textBox->nextTextBox();
- }
- }
- }
- } while ((node = node->traverseNextNode()) != NULL);
- if (hasRectParts)
- DUMP_NAV_LOGD("{0}\n};\n\n");
- else
- DUMP_NAV_LOGD("static DebugTestRectPart* TEST%s_RECTPARTS = NULL;\n", name);
- }
- int contentsWidth = layer->width();
- int contentsHeight = layer->height();
- DUMP_NAV_LOGD("static int TEST%s_FOCUS = %d;\n", name, focusIndex);
- DUMP_NAV_LOGD("static int TEST%s_WIDTH = %d;\n", name, contentsWidth);
- DUMP_NAV_LOGD("static int TEST%s_HEIGHT = %d;\n", name, contentsHeight);
-}
-
-bool CacheBuilder::Debug::isFocusable(Node* node) {
- if (node->hasTagName(HTMLNames::areaTag))
- return true;
- if (node->renderer() == false)
- return false;
- if (node->isKeyboardFocusable(NULL))
- return true;
- if (node->isMouseFocusable())
- return true;
- if (node->isFocusable())
- return true;
- if (node->isEventTargetNode())
- return true;
- if (CacheBuilder::AnyIsClick(node))
- return false;
- if (CacheBuilder::HasTriggerEvent(node))
- return true;
- return false;
-}
-
-void CacheBuilder::Debug::localName(Node* node) {
- const AtomicString& local = node->localName();
- if (node->isTextNode())
- print("\"#text\"");
- else
- wideString(local.characters(), local.length(), false);
- print(", ");
-}
-
-void CacheBuilder::Debug::newLine(int indent) {
- if (mPrefix[0] != '\n')
- print(&mPrefix[0], 1);
- flush();
- int lastnewline = mIndex - 1;
- while (lastnewline >= 0 && mBuffer[lastnewline] != '\n')
- lastnewline--;
- lastnewline++;
- char* buffer = mBuffer;
- if (lastnewline > 0) {
- DUMP_NAV_LOGD("%.*s", lastnewline, buffer);
- mIndex -= lastnewline;
- buffer += lastnewline;
- }
- size_t prefixLen = strlen(mPrefix);
- int minPrefix = prefixLen - 1;
- while (minPrefix >= 0 && mPrefix[minPrefix] != '\n')
- minPrefix--;
- minPrefix = prefixLen - minPrefix - 1;
- if (mIndex > minPrefix)
- DUMP_NAV_LOGD("%.*s\n", mIndex, buffer);
- mIndex = 0;
- setIndent(indent);
-}
-
-int CacheBuilder::Debug::ParentIndex(Node* node, int count, Node* parent)
-{
- if (parent == NULL)
- return -1;
- ASSERT(node != parent);
- int result = count;
- Node* previous = node;
- do {
- result--;
- previous = previous->traversePreviousNode();
- } while (previous && previous != parent);
- if (previous != NULL)
- return result;
- result = count;
- do {
- result++;
- } while ((node = node->traverseNextNode()) != NULL && node != parent);
- if (node != NULL)
- return result;
- ASSERT(0);
- return -1;
-}
-
-void CacheBuilder::Debug::print(const char* name) {
- print(name, strlen(name));
-}
-
-void CacheBuilder::Debug::print(const char* name, unsigned len) {
- do {
- if (mIndex + len >= DEBUG_BUFFER_SIZE)
- flush();
- int copyLen = mIndex + len < DEBUG_BUFFER_SIZE ?
- len : DEBUG_BUFFER_SIZE - mIndex;
- memcpy(&mBuffer[mIndex], name, copyLen);
- mIndex += copyLen;
- name += copyLen;
- len -= copyLen;
- } while (len > 0);
- mBuffer[mIndex] = '\0';
-}
-
-void CacheBuilder::Debug::setIndent(int indent)
-{
- char scratch[64];
- snprintf(scratch, sizeof(scratch), "%.*s", indent,
- " ");
- print(scratch);
-}
-
-void CacheBuilder::Debug::renderTree(RenderObject* renderer, int indent,
- Node* child, int count)
-{
- char scratch[256];
- Node* node = renderer->node();
- if (node != child) {
- count = ParentIndex(child, count, node);
- if (renderer->isRenderBlock() == false)
- goto tryParent;
- RenderBlock* renderBlock = (RenderBlock*) renderer;
- if (renderBlock->hasColumns() == false)
- goto tryParent;
- Vector<IntRect>* rects = renderBlock->columnRects();
- newLine(indent);
- snprintf(scratch, sizeof(scratch), "// render parent=%d", count);
- print(scratch);
- for (size_t x = 0; x < rects->size(); x++) {
- const IntRect& rect = rects->at(x);
- snprintf(scratch, sizeof(scratch), "(%d,%d,%d,%d) ", rect.x(),
- rect.y(), rect.width(), rect.height());
- print(scratch);
- }
- }
- {
- newLine(indent);
- RenderStyle* style = renderer->style();
- EVisibility vis = style->visibility();
- ASSERT(vis == VISIBLE || vis == HIDDEN || vis == COLLAPSE);
- snprintf(scratch, sizeof(scratch),
- "// render style visible:%s opacity:%g width:%d height:%d"
- " hasBackground:%s isInlineFlow:%s isBlockFlow:%s"
- " textOverflow:%s",
- vis == VISIBLE ? "visible" : vis == HIDDEN ? "hidden" : "collapse",
- style->opacity(), renderer->width(), renderer->height(),
- style->hasBackground() ? "true" : "false",
- renderer->isInlineFlow() ? "true" : "false",
- renderer->isBlockFlow() ? "true" : "false",
- style->textOverflow() ? "true" : "false"
- );
- print(scratch);
- newLine(indent);
- const IntRect& oRect = renderer->overflowRect(true);
- const IntRect& cRect = renderer->getOverflowClipRect(0,0);
- snprintf(scratch, sizeof(scratch),
- "// render xPos:%d yPos:%d overflowRect:{%d, %d, %d, %d} "
- " getOverflowClipRect:{%d, %d, %d, %d} ",
- renderer->xPos(), renderer->yPos(),
- oRect.x(), oRect.y(), oRect.width(), oRect.height(),
- cRect.x(), cRect.y(), cRect.width(), cRect.height()
- );
- print(scratch);
- if (renderer->isInlineFlow()) {
- RenderFlow* renderFlow = (RenderFlow*) renderer;
- int ifIndex = 0;
- flowBoxes(renderFlow, ifIndex, 0);
- }
- }
-tryParent:
- RenderObject* parent = renderer->parent();
- if (parent)
- renderTree(parent, indent + 2, node, count);
-}
-
-void CacheBuilder::Debug::uChar(const UChar* name, unsigned len, bool hex) {
- const UChar* end = name + len;
- bool wroteHex = false;
- while (name < end) {
- unsigned ch = *name++;
- if (ch == '\t' || ch == '\n' || ch == '\r' || ch == 0xa0)
- ch = ' ';
- if (ch < ' ' || ch == 0x7f) {
- if (hex) {
- mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex, "\\x%02x", ch);
- wroteHex = true;
- } else
- mBuffer[mIndex++] = '?';
- } else if (ch >= 0x80) {
- if (hex) {
- if (ch < 0x800)
- mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex,
- "\\x%02x\\x%02x", ch >> 6 | 0xc0, (ch & 0x3f) | 0x80);
- else
- mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex,
- "\\x%02x\\x%02x\\x%02x", ch >> 12 | 0xe0,
- (ch >> 6 & 0x3f) | 0x80, (ch & 0x3f) | 0x80);
- wroteHex = true;
- } else
- mBuffer[mIndex++] = '?';
- } else {
- if (wroteHex && WTF::isASCIIHexDigit((UChar) ch))
- mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex,
- "\" \"");
- else if (ch == '"' || ch == '\\')
- mBuffer[mIndex++] = '\\';
- mBuffer[mIndex++] = ch;
- wroteHex = false;
- }
- if (mIndex + 1 >= DEBUG_BUFFER_SIZE)
- flush();
- }
- flush();
-}
-
-void CacheBuilder::Debug::validateFrame() {
- Frame* frame = frameAnd();
- Page* page = frame->page();
- ASSERT(page);
- ASSERT((int) page > 0x10000);
- Frame* child = frame->tree()->firstChild();
- while (child) {
- Builder(child)->mDebug.validateFrame();
- child = child->tree()->nextSibling();
- }
-}
-
-void CacheBuilder::Debug::wideString(const UChar* chars, int length, bool hex) {
- if (length == 0)
- print("\"\"");
- else {
- print("\"");
- uChar(chars, length, hex);
- print("\"");
- }
-}
-
-void CacheBuilder::Debug::wideString(const String& str) {
- wideString(str.characters(), str.length(), false);
-}
-
-#endif // DUMP_NAV_CACHE
-
-CacheBuilder::CacheBuilder()
-{
- mLastKnownFocus = NULL;
- mAllowableTypes = ALL_CACHEDNODETYPES;
-#ifdef DUMP_NAV_CACHE_USING_PRINTF
- gNavCacheLogFile = NULL;
-#endif
-}
-
-void CacheBuilder::adjustForColumns(const ClipColumnTracker& track,
- CachedNode* node, IntRect* bounds)
-{
- int x = 0;
- int y = 0;
- int tx = track.mBounds.x();
- int ty = track.mBounds.y();
- int columnGap = track.mColumnGap;
- size_t limit = track.mColumns->size();
- for (size_t index = 0; index < limit; index++) {
- IntRect column = track.mColumns->at(index);
- column.move(tx, ty);
- IntRect test = *bounds;
- test.move(x, y);
- if (column.contains(test)) {
- if ((x | y) == 0)
- return;
- *bounds = test;
- node->move(x, y);
- return;
- }
- int xOffset = column.width() + columnGap;
- x += track.mDirection == LTR ? xOffset : -xOffset;
- y -= column.height();
- }
-}
-
-bool CacheBuilder::AnyChildIsClick(Node* node)
-{
- Node* child = node->firstChild();
- while (child != NULL) {
- if (child->isEventTargetNode()) {
- EventTargetNode* target = (EventTargetNode*) child;
- if (target->isFocusable() ||
- target->getEventListener(eventNames().clickEvent) ||
- target->getEventListener(eventNames().mousedownEvent) ||
- target->getEventListener(eventNames().mouseupEvent) ||
- target->getEventListener(eventNames().keydownEvent) ||
- target->getEventListener(eventNames().keyupEvent))
- return true;
- }
- if (AnyChildIsClick(child))
- return true;
- child = child->nextSibling();
- }
- return false;
-}
-
-bool CacheBuilder::AnyIsClick(Node* node)
-{
- if (node->hasTagName(HTMLNames::bodyTag))
- return AnyChildIsClick(node);
- EventTargetNode* target = (EventTargetNode*) node;
- if (target->getEventListener(eventNames().mouseoverEvent) == NULL &&
- target->getEventListener(eventNames().mouseoutEvent) == NULL &&
- target->getEventListener(eventNames().keydownEvent) == NULL &&
- target->getEventListener(eventNames().keyupEvent) == NULL)
- return false;
- if (target->getEventListener(eventNames().clickEvent))
- return false;
- if (target->getEventListener(eventNames().mousedownEvent))
- return false;
- if (target->getEventListener(eventNames().mouseupEvent))
- return false;
- return AnyChildIsClick(node);
-}
-
-void CacheBuilder::buildCache(CachedRoot* root)
-{
- Frame* frame = FrameAnd(this);
- mLastKnownFocus = NULL;
- m_areaBoundsMap.clear();
- BuildFrame(frame, frame, root, (CachedFrame*) root);
- root->finishInit(); // set up frame parent pointers, child pointers
- setData((CachedFrame*) root);
-}
-
-static Node* OneAfter(Node* node)
-{
- Node* parent = node;
- Node* sibling = NULL;
- while ((parent = parent->parentNode()) != NULL) {
- sibling = parent->nextSibling();
- if (sibling != NULL)
- break;
- }
- return sibling;
-}
-
-// return true if this renderer is really a pluinview, and it wants
-// key-events (i.e. focus)
-static bool checkForPluginViewThatWantsFocus(RenderObject* renderer) {
- if (renderer->isWidget()) {
- Widget* widget = static_cast<RenderWidget*>(renderer)->widget();
- if (widget && widget->isPluginView()) {
- PluginView* pv = static_cast<PluginView*>(widget);
- // check if this plugin really wants key events (TODO)
- return true;
- }
- }
- return false;
-}
-
-// when new focus is found, push it's parent on a stack
- // as long as more focii are found with the same (grand) parent, note it
- // (which only requires retrieving the last parent on the stack)
-// when the parent's last child is found, pop the stack
-// different from Tracker in that Tracker only pushes focii with children
-
-// making this work with focus - child focus - grandchild focus is tricky
-// if I keep the generation number, I may be able to more quickly determine that
-// a node is a grandchild of the focus's parent
-// this additionally requires being able to find the grandchild's parent
-
-// keep nodes that are focusable
-void CacheBuilder::BuildFrame(Frame* root, Frame* frame,
- CachedRoot* cachedRoot, CachedFrame* cachedFrame)
-{
- WTF::Vector<Tracker> tracker(1);
- {
- Tracker* baseTracker = tracker.data(); // sentinel
- bzero(baseTracker, sizeof(Tracker));
- 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));
- }
-#if DUMP_NAV_CACHE
- char* frameNamePtr = cachedFrame->mDebug.mFrameName;
- Builder(frame)->mDebug.frameName(frameNamePtr, frameNamePtr +
- sizeof(cachedFrame->mDebug.mFrameName) - 1);
- *frameNamePtr = '\0';
- int nodeIndex = 1;
-#endif
- NodeWalk walk;
- Document* doc = frame->document();
- Node* parent = doc;
- CachedNode cachedParentNode;
- cachedParentNode.init(parent);
-#if DUMP_NAV_CACHE
- cachedParentNode.mDebug.mNodeIndex = nodeIndex;
-#endif
- cachedFrame->add(cachedParentNode);
- Node* node = parent;
- int cacheIndex = 1;
- Node* focused = doc->focusedNode();
- if (focused) {
- setLastFocus(focused);
- cachedRoot->setFocusBounds(mLastKnownFocusBounds);
- }
- int globalOffsetX, globalOffsetY;
- GetGlobalOffset(frame, &globalOffsetX, &globalOffsetY);
- while (walk.mMore || (node = node->traverseNextNode()) != NULL) {
-#if DUMP_NAV_CACHE
- nodeIndex++;
-#endif
- Tracker* last = &tracker.last();
- int lastChildIndex = cachedFrame->size() - 1;
- while (node == last->mLastChild) {
- if (CleanUpContainedNodes(cachedFrame, last, lastChildIndex))
- cacheIndex--;
- tracker.removeLast();
- lastChildIndex = last->mCachedNodeIndex;
- last = &tracker.last();
- }
- if (node == last->mParentLastChild)
- last->mParentLastChild = NULL;
- do {
- const ClipColumnTracker* lastClip = &clipTracker.last();
- if (node != lastClip->mLastChild)
- break;
- clipTracker.removeLast();
- } while (true);
- do {
- const TabIndexTracker* lastTabIndex = &tabIndexTracker.last();
- if (node != lastTabIndex->mLastChild)
- break;
- tabIndexTracker.removeLast();
- } while (true);
- Frame* child = HasFrame(node);
- CachedNode cachedNode;
- if (child != NULL) {
- if (child->document() == NULL)
- continue;
- RenderObject* nodeRenderer = node->renderer();
- if (nodeRenderer != NULL && nodeRenderer->style()->visibility() == HIDDEN)
- continue;
- CachedFrame cachedChild;
- cachedChild.init(cachedRoot, cacheIndex, child);
- int childFrameIndex = cachedFrame->childCount();
- cachedFrame->addFrame(cachedChild);
- cachedNode.init(node);
- cachedNode.setIndex(cacheIndex++);
- cachedNode.setChildFrameIndex(childFrameIndex);
-#if DUMP_NAV_CACHE
- cachedNode.mDebug.mNodeIndex = nodeIndex;
- cachedNode.mDebug.mParentGroupIndex = Debug::ParentIndex(
- node, nodeIndex, NULL);
-#endif
- cachedFrame->add(cachedNode);
- CachedFrame* childPtr = cachedFrame->lastChild();
- BuildFrame(root, child, cachedRoot, childPtr);
- continue;
- }
- int tabIndex = node->tabIndex();
- Node* lastChild = node->lastChild();
- if (tabIndex <= 0)
- tabIndex = tabIndexTracker.last().mTabIndex;
- else if (tabIndex > 0 && lastChild) {
- DBG_NAV_LOGD("tabIndex=%d node=%p", tabIndex, node);
- tabIndexTracker.grow(tabIndexTracker.size() + 1);
- TabIndexTracker& indexTracker = tabIndexTracker.last();
- indexTracker.mTabIndex = tabIndex;
- indexTracker.mLastChild = OneAfter(lastChild);
- }
- RenderObject* nodeRenderer = node->renderer();
- bool isTransparent = false;
- bool hasFocusRing = true;
- if (nodeRenderer != NULL) {
- RenderStyle* style = nodeRenderer->style();
- if (style->visibility() == HIDDEN)
- continue;
- if (nodeRenderer->isImage()) { // set all the area elements to have a link to their images
- RenderImage* image = static_cast<RenderImage*>(nodeRenderer);
- HTMLMapElement* map = image->imageMap();
- if (map) {
- Node* node;
- for (node = map->firstChild(); node;
- node = node->traverseNextNode(map)) {
- if (!node->hasTagName(HTMLNames::areaTag))
- continue;
- HTMLAreaElement* area = static_cast<HTMLAreaElement*>(node);
- m_areaBoundsMap.set(area, image);
- }
- }
- }
- isTransparent = style->hasBackground() == false;
-#ifdef ANDROID_CSS_TAP_HIGHLIGHT_COLOR
- hasFocusRing = style->tapHighlightColor().alpha() > 0;
-#endif
- }
- bool more = walk.mMore;
- walk.reset();
- // GetGlobalBounds(node, &bounds, false);
- bool computeFocusRings = false;
- bool hasClip = false;
- bool hasMouseOver = false;
- bool isAnchor = false;
- bool isArea = node->hasTagName(HTMLNames::areaTag);
- bool isInput = false;
- bool isPassword = false;
- bool isTextArea = false;
- bool isTextField = false;
- bool isRtlText = false;
- bool isUnclipped = false;
- bool isFocus = node == focused;
- bool takesFocus = false;
- bool wantsKeyEvents = false;
- int maxLength = -1;
- int textSize = 12;
- int columnGap = 0;
- TextDirection direction = LTR;
- String name;
- String exported;
- CachedNodeType type = NORMAL_CACHEDNODETYPE;
- IntRect bounds;
- IntRect absBounds;
- WTF::Vector<IntRect>* columns = NULL;
- if (isArea) {
- HTMLAreaElement* area = static_cast<HTMLAreaElement*>(node);
- bounds = getAreaRect(area);
- bounds.move(globalOffsetX, globalOffsetY);
- absBounds = bounds;
- isUnclipped = true; // FIXME: areamaps require more effort to detect
- // assume areamaps are always visible for now
- takesFocus = true;
- goto keepNode;
- }
- if (nodeRenderer == NULL)
- continue;
-
- // some common setup
- absBounds = nodeRenderer->absoluteBoundingBoxRect();
- absBounds.move(globalOffsetX, globalOffsetY);
- hasClip = nodeRenderer->hasOverflowClip();
-
- if (checkForPluginViewThatWantsFocus(nodeRenderer)) {
- bounds = absBounds;
- isUnclipped = true;
- takesFocus = true;
- wantsKeyEvents = true;
- goto keepNode;
- }
- if (nodeRenderer->isRenderBlock()) {
- RenderBlock* renderBlock = (RenderBlock*) nodeRenderer;
- if (renderBlock->hasColumns()) {
- columns = renderBlock->columnRects();
-#ifdef ANDROID_EXPOSE_COLUMN_GAP
- columnGap = renderBlock->columnGap();
-#endif
- direction = renderBlock->style()->direction();
- }
- }
- if ((hasClip != false || columns != NULL) && lastChild) {
- clipTracker.grow(clipTracker.size() + 1);
- ClipColumnTracker& clip = clipTracker.last();
- clip.mBounds = absBounds;
- clip.mLastChild = OneAfter(lastChild);
- clip.mNode = node;
- clip.mColumns = columns;
- clip.mColumnGap = columnGap;
- clip.mHasClip = hasClip;
- clip.mDirection = direction;
- if (columns != NULL) {
- const IntRect& oRect = nodeRenderer->overflowRect(true);
- clip.mBounds.move(oRect.x(), oRect.y());
- }
- }
- if (node->isTextNode() && mAllowableTypes != NORMAL_CACHEDNODETYPE) {
- if (last->mSomeParentTakesFocus) // don't look at text inside focusable node
- continue;
- CachedNodeType checkType;
- if (isFocusableText(&walk, more, node, &checkType,
- &exported) == false)
- continue;
- #if DUMP_NAV_CACHE
- {
- char buffer[DEBUG_BUFFER_SIZE];
- mDebug.init(buffer, sizeof(buffer));
- mDebug.print("text link found: ");
- mDebug.wideString(exported);
- DUMP_NAV_LOGD("%s\n", buffer);
- }
- #endif
- type = (CachedNodeType) checkType;
- // !!! test ! is the following line correctly needed for frames to work?
- cachedNode.init(node);
- const ClipColumnTracker& clipTrack = clipTracker.last();
- const IntRect& clip = clipTrack.mHasClip ? clipTrack.mBounds :
- 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.focusRings()) == false)
- continue;
- absBounds = bounds;
- cachedNode.setBounds(bounds);
- if (bounds.width() < MINIMUM_FOCUSABLE_WIDTH)
- continue;
- if (bounds.height() < MINIMUM_FOCUSABLE_HEIGHT)
- continue;
- computeFocusRings = true;
- isUnclipped = true; // FIXME: to hide or partially occlude synthesized links, each
- // focus ring will also need the offset and length of characters
- // used to produce it
- goto keepTextNode;
- }
- if (node->hasTagName(WebCore::HTMLNames::inputTag)) {
- HTMLInputElement* input = (HTMLInputElement*) node;
- if (input->inputType() == HTMLInputElement::FILE)
- continue;
- isInput = true;
- isTextField = input->isTextField();
- isPassword = input->inputType() == HTMLInputElement::PASSWORD;
- maxLength = input->maxLength();
- name = String(input->name().string());
- isUnclipped = isTransparent; // can't detect if this is drawn on top (example: deviant.com login parts)
- } else if (node->hasTagName(HTMLNames::textareaTag))
- isTextArea = true;
- else if (node->hasTagName(HTMLNames::aTag)) {
- const HTMLAnchorElement* anchorNode =
- (const HTMLAnchorElement*) node;
- if (!anchorNode->isFocusable() && !HasTriggerEvent(node))
- continue;
- EventTargetNode* target = (EventTargetNode*) node;
- if (target->disabled())
- continue;
- hasMouseOver = target->getEventListener(eventNames().mouseoverEvent);
- isAnchor = true;
- KURL href = anchorNode->href();
- if (!href.isEmpty() && !href.protocolIs("javascript"))
- // Set the exported string for all non-javascript anchors.
- exported = href.string();
- }
- if (isTextField || isTextArea) {
- RenderTextControl* renderText =
- static_cast<RenderTextControl*>(nodeRenderer);
- if (isFocus)
- cachedRoot->setSelection(renderText->selectionStart(), renderText->selectionEnd());
- exported = String(renderText->text());
- // FIXME: Would it be better to use (float) size()?
- // FIXME: Are we sure there will always be a style and font, and it's correct?
- RenderStyle* style = nodeRenderer->style();
- if (style) {
- isUnclipped |= !style->hasAppearance();
- textSize = style->fontSize();
- isRtlText = style->direction() == RTL ||
- style->textAlign() == WebCore::RIGHT ||
- style->textAlign() == WebCore::WEBKIT_RIGHT;
- }
- }
- takesFocus = true;
- if (isAnchor) {
- bounds = absBounds;
- } else {
- bool isFocusable = node->isKeyboardFocusable(NULL) ||
- node->isMouseFocusable() || node->isFocusable();
- if (isFocusable == false) {
- if (node->isEventTargetNode() == false)
- continue;
- EventTargetNode* eventTargetNode = (EventTargetNode*) node;
- if (eventTargetNode->disabled())
- continue;
- bool overOrOut = HasOverOrOut(node);
- bool hasTrigger = HasTriggerEvent(node);
- if (overOrOut == false && hasTrigger == false)
- continue;
- takesFocus = hasTrigger;
- }
- bounds = node->getRect();
- // For Bank of America site
- if (isTextField && nodeRenderer->paddingLeft() > 100) {
- int paddingLeft = nodeRenderer->paddingLeft();
- int paddingTop = nodeRenderer->paddingTop();
- int x = bounds.x() + paddingLeft;
- int y = bounds.y() + paddingTop;
- int width = bounds.width() - paddingLeft - nodeRenderer->paddingRight();
- int height = bounds.height() - paddingTop - nodeRenderer->paddingBottom();
- bounds.setLocation(IntPoint(x, y));
- bounds.setSize(IntSize(width, height));
- }
- if (bounds.width() < MINIMUM_FOCUSABLE_WIDTH)
- continue;
- if (bounds.height() < MINIMUM_FOCUSABLE_HEIGHT)
- continue;
- bounds.move(globalOffsetX, globalOffsetY);
- }
- computeFocusRings = true;
- keepNode:
- cachedNode.init(node);
- if (computeFocusRings == false) {
- cachedNode.setBounds(bounds);
- cachedNode.focusRings().append(bounds);
- } else if (ConstructPartRects(node, bounds, cachedNode.boundsPtr(),
- globalOffsetX, globalOffsetY, &cachedNode.focusRings()) == false)
- continue;
- keepTextNode:
- IntRect clip = hasClip ? bounds : absBounds;
- size_t clipIndex = clipTracker.size();
- if (clipTracker.last().mNode == node)
- clipIndex -= 1;
- while (--clipIndex > 0) {
- const ClipColumnTracker& clipTrack = clipTracker.at(clipIndex);
- if (clipTrack.mHasClip == false) {
- adjustForColumns(clipTrack, &cachedNode, &absBounds);
- continue;
- }
- const IntRect& parentClip = clipTrack.mBounds;
- if (hasClip == false && isAnchor)
- clip = parentClip;
- else
- clip.intersect(parentClip);
- hasClip = true;
- }
- if (hasClip && cachedNode.clip(clip) == false) {
- cachedNode.setBounds(clip);
- cachedNode.focusRings().append(clip);
- isUnclipped = true;
- }
- cachedNode.setNavableRects();
- cachedNode.setChildFrameIndex(-1);
- cachedNode.setExport(exported);
- cachedNode.setHasFocusRing(hasFocusRing);
- cachedNode.setHasMouseOver(hasMouseOver);
- cachedNode.setHitBounds(absBounds);
- cachedNode.setIndex(cacheIndex);
- cachedNode.setIsAnchor(isAnchor);
- cachedNode.setIsArea(isArea);
- cachedNode.setIsFocus(isFocus);
- cachedNode.setIsInput(isInput);
- cachedNode.setIsPassword(isPassword);
- cachedNode.setIsRtlText(isRtlText);
- cachedNode.setIsTextArea(isTextArea);
- cachedNode.setIsTextField(isTextField);
- cachedNode.setIsTransparent(isTransparent);
- cachedNode.setIsUnclipped(isUnclipped);
- cachedNode.setMaxLength(maxLength);
- cachedNode.setName(name);
- cachedNode.setParentIndex(last->mCachedNodeIndex);
- if (last->mParentLastChild == NULL)
- last->mParentLastChild = OneAfter(node->parentNode()->lastChild());
- cachedNode.setParentGroup(last->mParentLastChild);
- cachedNode.setTabIndex(tabIndex);
- cachedNode.setTextSize(textSize);
- cachedNode.setType(type);
- cachedNode.setWantsKeyEvents(wantsKeyEvents);
-#if DUMP_NAV_CACHE
- cachedNode.mDebug.mNodeIndex = nodeIndex;
- cachedNode.mDebug.mParentGroupIndex = Debug::ParentIndex(
- node, nodeIndex, (Node*) cachedNode.parentGroup());
-#endif
- cachedFrame->add(cachedNode);
- {
- int lastIndex = cachedFrame->size() - 1;
- if (node == focused) {
- CachedNode* cachedNodePtr = cachedFrame->getIndex(lastIndex);
- cachedRoot->setCachedFocus(cachedFrame, cachedNodePtr);
- }
- if (lastChild != NULL) {
- tracker.grow(tracker.size() + 1);
- Tracker& working = tracker.last();
- working.mCachedNodeIndex = lastIndex;
- working.mLastChild = OneAfter(lastChild);
- working.mParentLastChild = OneAfter(node->parentNode()->lastChild());
- last = &tracker.at(tracker.size() - 2);
- working.mSomeParentTakesFocus = last->mSomeParentTakesFocus | takesFocus;
- }
- }
- cacheIndex++;
- }
- while (tracker.size() > 1) {
- Tracker* last = &tracker.last();
- int lastChildIndex = cachedFrame->size() - 1;
- if (CleanUpContainedNodes(cachedFrame, last, lastChildIndex))
- cacheIndex--;
- tracker.removeLast();
- }
-}
-
-bool CacheBuilder::CleanUpContainedNodes(CachedFrame* cachedFrame,
- const Tracker* last, int lastChildIndex)
-{
- // if outer is body, disable outer
- // or if there's more than one inner, disable outer
- // or if inner is keyboard focusable, disable outer
- // else disable inner by removing it
- int childCount = lastChildIndex - last->mCachedNodeIndex;
- if (childCount == 0)
- return false;
- CachedNode* lastCached = cachedFrame->getIndex(last->mCachedNodeIndex);
- Node* lastNode = (Node*) lastCached->nodePointer();
- if ((childCount > 1 && lastNode->hasTagName(HTMLNames::selectTag) == false) ||
- lastNode->hasTagName(HTMLNames::bodyTag) ||
- lastNode->hasTagName(HTMLNames::formTag)) {
- lastCached->setBounds(IntRect(0, 0, 0, 0));
- lastCached->focusRings().clear();
- lastCached->setNavableRects();
- return false;
- }
- CachedNode* onlyChildCached = cachedFrame->lastNode();
- Node* onlyChild = (Node*) onlyChildCached->nodePointer();
- bool outerIsMouseMoveOnly =
- lastNode->isKeyboardFocusable(NULL) == false &&
- lastNode->isMouseFocusable() == false &&
- lastNode->isFocusable() == false &&
- lastNode->isEventTargetNode() == true &&
- HasOverOrOut(lastNode) == true &&
- HasTriggerEvent(lastNode) == false;
- if (cachedFrame->focusIndex() == lastChildIndex)
- cachedFrame->setFocusIndex(last->mCachedNodeIndex);
- if (onlyChildCached->parent() == lastCached)
- onlyChildCached->setParentIndex(lastCached->parentIndex());
- if (outerIsMouseMoveOnly || onlyChild->isKeyboardFocusable(NULL))
- *lastCached = *onlyChildCached;
- cachedFrame->removeLast();
- return true;
-}
-
-Node* CacheBuilder::currentFocus() const
-{
- Frame* frame = FrameAnd(this);
- Document* doc = frame->document();
- if (doc != NULL) {
- Node* focus = doc->focusedNode();
- if (focus != NULL)
- return focus;
- }
- Frame* child = frame->tree()->firstChild();
- while (child) {
- CacheBuilder* cacheBuilder = Builder(child);
- Node* focus = cacheBuilder->currentFocus();
- if (focus)
- return focus;
- child = child->tree()->nextSibling();
- }
- return NULL;
-}
-
-static bool strCharCmp(const char* matches, const UChar* test, int wordLength,
- int wordCount)
-{
- for (int index = 0; index < wordCount; index++) {
- for (int inner = 0; inner < wordLength; inner++) {
- if (matches[inner] != test[inner]) {
- matches += wordLength;
- goto next;
- }
- }
- return true;
-next:
- ;
- }
- return false;
-}
-
-static const int stateTwoLetter[] = {
- 0x02060c00, // A followed by: [KLRSZ]
- 0x00000000, // B
- 0x00084001, // C followed by: [AOT]
- 0x00000014, // D followed by: [CE]
- 0x00000000, // E
- 0x00001800, // F followed by: [LM]
- 0x00100001, // G followed by: [AU]
- 0x00000100, // H followed by: [I]
- 0x00002809, // I followed by: [ADLN]
- 0x00000000, // J
- 0x01040000, // K followed by: [SY]
- 0x00000001, // L followed by: [A]
- 0x000ce199, // M followed by: [ADEHINOPST]
- 0x0120129c, // N followed by: [CDEHJMVY]
- 0x00020480, // O followed by: [HKR]
- 0x00420001, // P followed by: [ARW]
- 0x00000000, // Q
- 0x00000100, // R followed by: [I]
- 0x0000000c, // S followed by: [CD]
- 0x00802000, // T followed by: [NX]
- 0x00080000, // U followed by: [T]
- 0x00080101, // V followed by: [AIT]
- 0x01200101 // W followed by: [AIVY]
-};
-
-static const char firstIndex[] = {
- 0, 5, 5, 8, 10, 10, 12, 14,
- 15, 19, 19, 21, 22, 32, 40, 43,
- 46, 46, 47, 49, 51, 52, 55, 59
-};
-
-// from http://infolab.stanford.edu/~manku/bitcount/bitcount.html
-#define TWO(c) (0x1u << (c))
-#define MASK(c) (((unsigned int)(-1)) / (TWO(TWO(c)) + 1u))
-#define COUNT(x,c) ((x) & MASK(c)) + (((x) >> (TWO(c))) & MASK(c))
-
-int bitcount (unsigned int n)
-{
- n = COUNT(n, 0);
- n = COUNT(n, 1);
- n = COUNT(n, 2);
- n = COUNT(n, 3);
- return COUNT(n, 4);
-}
-
-#undef TWO
-#undef MASK
-#undef COUNT
-
-static bool isUnicodeSpace(UChar ch)
-{
- return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' || ch == 0xa0;
-}
-
-static bool validZip(int stateIndex, const UChar* zipPtr)
-{
- static const struct {
- char mLow;
- char mHigh;
- char mException1;
- char mException2;
- } zipRange[] = {
- { 99, 99, -1, -1 }, // AK Alaska
- { 35, 36, -1, -1 }, // AL Alabama
- { 71, 72, -1, -1 }, // AR Arkansas
- { 96, 96, -1, -1 }, // AS American Samoa
- { 85, 86, -1, -1 }, // AZ Arizona
- { 90, 96, -1, -1 }, // CA California
- { 80, 81, -1, -1 }, // CO Colorado
- { 6, 6, -1, -1 }, // CT Connecticut
- { 20, 20, -1, -1 }, // DC District of Columbia
- { 19, 19, -1, -1 }, // DE Delaware
- { 32, 34, -1, -1 }, // FL Florida
- { 96, 96, -1, -1 }, // FM Federated States of Micronesia
- { 30, 31, -1, -1 }, // GA Georgia
- { 96, 96, -1, -1 }, // GU Guam
- { 96, 96, -1, -1 }, // HI Hawaii
- { 50, 52, -1, -1 }, // IA Iowa
- { 83, 83, -1, -1 }, // ID Idaho
- { 60, 62, -1, -1 }, // IL Illinois
- { 46, 47, -1, -1 }, // IN Indiana
- { 66, 67, 73, -1 }, // KS Kansas
- { 40, 42, -1, -1 }, // KY Kentucky
- { 70, 71, -1, -1 }, // LA Louisiana
- { 1, 2, -1, -1 }, // MA Massachusetts
- { 20, 21, -1, -1 }, // MD Maryland
- { 3, 4, -1, -1 }, // ME Maine
- { 96, 96, -1, -1 }, // MH Marshall Islands
- { 48, 49, -1, -1 }, // MI Michigan
- { 55, 56, -1, -1 }, // MN Minnesota
- { 63, 65, -1, -1 }, // MO Missouri
- { 96, 96, -1, -1 }, // MP Northern Mariana Islands
- { 38, 39, -1, -1 }, // MS Mississippi
- { 55, 56, -1, -1 }, // MT Montana
- { 27, 28, -1, -1 }, // NC North Carolina
- { 58, 58, -1, -1 }, // ND North Dakota
- { 68, 69, -1, -1 }, // NE Nebraska
- { 3, 4, -1, -1 }, // NH New Hampshire
- { 7, 8, -1, -1 }, // NJ New Jersey
- { 87, 88, 86, -1 }, // NM New Mexico
- { 88, 89, 96, -1 }, // NV Nevada
- { 10, 14, 0, 6 }, // NY New York
- { 43, 45, -1, -1 }, // OH Ohio
- { 73, 74, -1, -1 }, // OK Oklahoma
- { 97, 97, -1, -1 }, // OR Oregon
- { 15, 19, -1, -1 }, // PA Pennsylvania
- { 6, 6, 0, 9 }, // PR Puerto Rico
- { 96, 96, -1, -1 }, // PW Palau
- { 2, 2, -1, -1 }, // RI Rhode Island
- { 29, 29, -1, -1 }, // SC South Carolina
- { 57, 57, -1, -1 }, // SD South Dakota
- { 37, 38, -1, -1 }, // TN Tennessee
- { 75, 79, 87, 88 }, // TX Texas
- { 84, 84, -1, -1 }, // UT Utah
- { 22, 24, 20, -1 }, // VA Virginia
- { 6, 9, -1, -1 }, // VI Virgin Islands
- { 5, 5, -1, -1 }, // VT Vermont
- { 98, 99, -1, -1 }, // WA Washington
- { 53, 54, -1, -1 }, // WI Wisconsin
- { 24, 26, -1, -1 }, // WV West Virginia
- { 82, 83, -1, -1 } // WY Wyoming
- };
-
- int zip = zipPtr[0] - '0';
- zip *= 10;
- zip += zipPtr[1] - '0';
- int low = zipRange[stateIndex].mLow;
- int high = zipRange[stateIndex].mHigh;
- if (zip >= low && zip <= high)
- return true;
- if (zip == zipRange[stateIndex].mException1)
- return true;
- if (zip == zipRange[stateIndex].mException2)
- return true;
- return false;
-}
-
-#define MAX_PLACE_NAME_LENGTH 25 // the longest allowable one word place name
-
-CacheBuilder::FoundState CacheBuilder::FindAddress(const UChar* chars, unsigned length, int* start, int* end)
-{
- FindState addressState;
- FindReset(&addressState);
- addressState.mWords[0] = addressState.mStarts[0] = chars;
- FoundState state = FindPartialAddress(chars, chars, length, &addressState);
- if (state == FOUND_PARTIAL && addressState.mProgress == ZIP_CODE &&
- addressState.mNumberCount == 0) {
- addressState.mProgress = FIND_STREET;
- state = FindPartialAddress(NULL, NULL, 0, &addressState);
- }
- *start = addressState.mStartResult;
- *end = addressState.mEndResult;
- return state;
-}
-
-CacheBuilder::FoundState CacheBuilder::FindPartialAddress(const UChar* baseChars,
- const UChar* chars, unsigned length, FindState* s)
-{
- // lower case letters are optional; trailing asterisk is optional 's'
- static char const* const longStreetNames[] = {
- "\x04" "LleY" "\x04" "NneX" "\x05" "RCade" "\x05" "VEnue" "\x06" "LAMEDA", // A
- "\x04" "aYoU" "\x04" "eaCH" "\x03" "eND" "\x05" "LuFf*" "\x05" "oTtoM"
- "\x08" "ouLeVarD" "\x05" "Ranch" "\x05" "RidGe" "\x05" "RooK*"
- "\x04" "urG*" "\x05" "YPass" "\x07" "roadWAY", // B
- "\x05" "AMINO"
- "\x03" "amP" "\x05" "anYoN" "\x03" "aPE" "\x07" "auSeWaY" "\x06" "enTeR*"
- "\x06" "IRcle*" "\x05" "LiFf*" "\x03" "LuB" "\x05" "oMmoN" "\x06" "ORner*"
- "\x05" "ouRSE" "\x05" "ourT*" "\x04" "oVe*" "\x04" "ReeK" "\x07" "REScent"
- "\x04" "ReST" "\x07" "ROSSING" "\x08" "ROSSROAD" "\x04" "URVe"
- "\x05" "AMINO" "\x06" "IRCULO" "\x07" "REScent", // C
- "\x03" "aLe" "\x02" "aM" "\x05" "iVide" "\x05" "Rive*", // D
- "\x06" "STate*" "\x09" "XPresswaY" "\x09" "XTension*", // E
- "\x04" "ALL*" "\x04" "eRrY" "\x05" "ieLD*" "\x04" "LaT*" "\x04" "oRD*"
- "\x05" "oReST" "\x05" "oRGe*" "\x04" "oRK*" "\x03" "orT" "\x06" "reeWaY", // F
- "\x06" "arDeN*" "\x06" "aTeWaY" "\x04" "LeN*" "\x05" "ReeN*" "\x05" "RoVe*", // G
- "\x06" "arBoR*" "\x04" "aVeN" "\x06" "eighTS" "\x06" "ighWaY" "\x04" "iLl*"
- "\x05" "OLloW", // H
- "\x04" "NLeT" "\x06" "Sland*" "\x03" "SLE", // I
- "\x08" "unCTion*", // J
- "\x03" "eY*" "\x05" "NoLl*", // K
- "\x04" "aKe*" "\x03" "AND" "\x06" "aNDinG" "\x03" "aNe" "\x05" "iGhT*"
- "\x03" "oaF" "\x04" "oCK*" "\x04" "oDGe" "\x03" "OOP", // L
- "\x03" "ALL" "\x05" "aNoR*" "\x06" "eaDoW*" "\x03" "EWS" "\x04" "iLl*"
- "\x06" "iSsioN" "\x07" "oTorWaY" "\x04" "ounT" "\x08" "ounTaiN*", // M
- "\x03" "eCK", // N
- "\x06" "RCHard" "\x03" "VAL" "\x07" "verPASs", // O
- "\x04" "ARK*" "\x07" "arKWaY*" "\x03" "ASS" "\x06" "aSsaGE" "\x03" "ATH"
- "\x03" "IKE" "\x04" "iNE*" "\x04" "Lace" "\x05" "LaiN*" "\x04" "LaZa"
- "\x05" "oinT*" "\x04" "oRT*" "\x06" "Rairie" "\x06" "RIVADA", // P
- NULL,
- "\x05" "ADiaL" "\x03" "AMP" "\x04" "aNCH" "\x05" "aPiD*"
- "\x03" "eST"
- "\x05" "iDGe*" "\x04" "IVer" "\x04" "oaD*" "\x04" "ouTE" "\x02" "OW"
- "\x02" "UE" "\x02" "UN", // R
- "\x05" "HoaL*" "\x05" "HoRe*" "\x05" "KyWaY" "\x06" "PrinG*" "\x04" "PUR*"
- "\x06" "Quare*" "\x06" "TAtion" "\x08" "TRAvenue" "\x05" "TReaM"
- "\x06" "Treet*" "\x05" "uMmiT" "\x07" "PeeDWaY", // S
- "\x06" "ERrace" "\x09" "hRoughWaY" "\x04" "RaCE" "\x04" "RAcK" "\x09" "RaFficwaY"
- "\x04" "RaiL" "\x05" "UNneL" "\x07" "urnPiKE", // T
- "\x08" "nderPASs" "\x05" "Nion*", // U
- "\x06" "aLleY*" "\x06" "IAduct" "\x04" "ieW*" "\x07" "iLlaGe*" "\x04" "iLle"
- "\x04" "ISta", // V
- "\x04" "ALK*" "\x03" "ALL" "\x03" "AY*" "\x04" "eLl*", // W
- "\x03" "ING" "\x02" "RD", // X
- };
-
- static char const* const longStateNames[] = {
- "\x8e" "la" "\x85" "bama" "\x02" "\x84" "ska" "\x01" "\x8f" "merican Samoa" "\x04"
- "\x91" "r" "\x86" "izona" "\x05" "\x87" "kansas" "\x03",
- NULL,
- "\x8b" "alifornia" "\x06" "\x95" "o" "\x87" "lorado" "\x07" "\x8a" "nnecticut" "\x08",
- "\x89" "elaware" "\x0a" "\x95" "istrict of Columbia" "\x09",
- NULL,
- "\x9f" "ederated States of Micronesia" "\x0c" "\x88" "lorida" "\x0b",
- "\x85" "uam" "\x0e" "\x88" "eorgia" "\x0d",
- "\x87" "awaii" "\x0f",
- "\x86" "daho" "\x11" "\x89" "llinois" "\x12" "\x88" "ndiana" "\x13" "\x85"
- "owa" "\x10",
- NULL,
- "\x87" "ansas" "\x14" "\x89" "entucky" "\x15",
- "\x8a" "ouisiana" "\x16",
- "\x86" "aine" "\x19" "\x99" "ar" "\x8e" "shall Islands" "\x1a" "\x86" "yland" "\x18"
- "\x8e" "assachusetts" "\x17" "\x93" "i" "\x87" "chigan" "\x1b"
- "\x88" "nnesota" "\x1c" "\x93" "iss" "\x88" "issippi" "\x1f" "\x85"
- "ouri" "\x1d" "\x88" "ontana" "\x20",
- "\x90" "e" "\x87" "braska" "\x23" "\x85" "vada" "\x27" "\xa5" "ew " "\x8a"
- "Hampshire" "\x24" "\x87" "Jersey" "\x25" "\x87" "Mexico" "\x26"
- "\x85" "York" "\x28" "\x98" "orth " "\x89" "Carolina" "\x21" "\x87"
- "Dakota" "\x22" "\x99" "orthern Mariana Islands" "\x1e",
- "\x85" "hio" "\x29" "\x89" "klahoma" "\x2a" "\x87" "regon" "\x2b",
- "\x86" "alau" "\x2e" "\x8d" "ennsylvania" "\x2c" "\x8c" "uerto Rico" "\x2d",
- NULL,
- "\x8d" "hode Island" "\x2f",
- "\x98" "outh " "\x89" "Carolina" "\x30" "\x87" "Dakota" "\x31",
- "\x90" "e" "\x88" "nnessee" "\x32" "\x84" "xas" "\x33",
- "\x85" "tah" "\x34",
- "\x88" "ermont" "\x37" "\x94" "irgin" "\x89" " Islands" "\x36" "\x83" "ia" "\x35",
- "\x8b" "ashington" "\x38" "\x8e" "est Virginia" "\x3a" "\x8a" "isconsin" "\x39"
- "\x88" "yoming" "\x3b"
- };
-
-#if 0 // DEBUG_NAV_UI
- static char const* const progressNames[] = {
- "NO_ADDRESS",
- "SKIP_TO_SPACE",
- "HOUSE_NUMBER",
- "NUMBER_TRAILING_SPACE",
- "ADDRESS_LINE",
- "STATE_NAME",
- "SECOND_HALF",
- "ZIP_CODE",
- "PLUS_4",
- "FIND_STREET"
- };
-#endif
- // strategy: US only support at first
- // look for a 1 - 5 digit number for a street number (no support for 'One Microsoft Way')
- // ignore if preceded by '#', Suite, Ste, Rm
- // look for two or more words (up to 5? North Frank Lloyd Wright Blvd)
- // note: "The Circle at North Hills St." has six words, and a lower 'at' -- allow at, by, of, in, the, and, ... ?
- // if a word starts with a lowercase letter, no match
- // allow: , . - # / (for 1/2) ' "
- // don't look for street name type yet
- // look for one or two delimiters to represent possible 2nd addr line and city name
- // look for either full state name, or state two letters, and/or zip code (5 or 9 digits)
- // now look for street suffix, either in full or abbreviated form, with optional 's' if there's an asterisk
-
- s->mCurrentStart = chars;
- s->mEnd = chars + length;
- int candIndex = 0;
- bool mustBeAllUpper = false;
- bool secondHalf = false;
- chars -= 1;
- UChar ch = s->mCurrent;
- while (++chars <= s->mEnd) {
- UChar prior = ch;
- ch = chars < s->mEnd ? *chars : ' ';
- switch (s->mProgress) {
- case NO_ADDRESS:
- if (WTF::isASCIIDigit(ch) == false) {
- if (ch != 'O') // letter 'O', not zero
- continue;
- if (s->mEnd - chars < 3)
- continue;
- prior = *++chars;
- ch = *++chars;
- if ((prior != 'n' || ch != 'e') && (prior != 'N' || ch != 'E'))
- continue;
- if (isUnicodeSpace(*++chars) == false)
- continue;
- s->mProgress = ADDRESS_LINE;
- s->mStartResult = chars - 3 - s->mCurrentStart;
- continue;
- }
- if (isUnicodeSpace(prior) == false) {
- s->mProgress = SKIP_TO_SPACE;
- continue;
- }
- s->mNumberCount = 1;
- s->mProgress = HOUSE_NUMBER;
- s->mStartResult = chars - s->mCurrentStart;
- continue;
- case SKIP_TO_SPACE:
- if (isUnicodeSpace(ch) == false)
- continue;
- break;
- case HOUSE_NUMBER:
- if (WTF::isASCIIDigit(ch)) {
- if (++s->mNumberCount >= 6)
- s->mProgress = SKIP_TO_SPACE;
- continue;
- }
- if (WTF::isASCIIUpper(ch)) { // allow one letter after house number, e.g. 12A SKOLFIELD PL, HARPSWELL, ME 04079
- if (WTF::isASCIIDigit(prior) == false)
- s->mProgress = SKIP_TO_SPACE;
- continue;
- }
- if (ch == '-') {
- if (s->mNumberCount > 0) { // permit 21-23 ELM ST
- ++s->mNumberCount;
- continue;
- }
- }
- s->mNumberCount = 0;
- s->mProgress = NUMBER_TRAILING_SPACE;
- case NUMBER_TRAILING_SPACE:
- if (isUnicodeSpace(ch))
- continue;
- if (0 && WTF::isASCIIDigit(ch)) {
- s->mNumberCount = 1;
- s->mProgress = HOUSE_NUMBER;
- s->mStartResult = chars - s->mCurrentStart;
- continue;
- }
- if (WTF::isASCIIDigit(ch) == false && WTF::isASCIIUpper(ch) == false)
- break;
- s->mProgress = ADDRESS_LINE;
- case ADDRESS_LINE:
- if (WTF::isASCIIAlpha(ch) || ch == '\'' || ch == '-' || ch == '&' || ch == '(' || ch == ')') {
- if (++s->mLetterCount > 1) {
- s->mNumberWords &= ~(1 << s->mWordCount);
- continue;
- }
- if (s->mNumberCount >= 5)
- break;
-// FIXME: the test below was added to give up on a non-address, but it
-// incorrectly discards addresses where the house number is in one node
-// and the street name is in the next; I don't recall what the failing case
-// is that suggested this fix.
-// if (s->mWordCount == 0 && s->mContinuationNode)
-// return FOUND_NONE;
- s->mBases[s->mWordCount] = baseChars;
- s->mWords[s->mWordCount] = chars - s->mNumberCount;
- s->mStarts[s->mWordCount] = s->mCurrentStart;
- if (WTF::isASCIILower(ch) && s->mNumberCount == 0)
- s->mFirstLower = chars;
- s->mNumberCount = 0;
- if (WTF::isASCIILower(ch) || (WTF::isASCIIAlpha(ch) == false && ch != '-'))
- s->mNumberWords &= ~(1 << s->mWordCount);
- s->mUnparsed = true;
- continue;
- } else if (s->mLetterCount >= MAX_PLACE_NAME_LENGTH) {
- break;
- } else if (s->mFirstLower != NULL) {
- size_t length = chars - s->mFirstLower;
- if (length > 3)
- break;
- if (length == 3 && strCharCmp("and" "the", s->mFirstLower, 3, 2) == false)
- break;
- if (length == 2 && strCharCmp("at" "by" "el" "in" "of", s->mFirstLower, 2, 5) == false)
- break;
- goto resetWord;
- }
- if (ch == ',' || ch == '*') { // delimits lines
- // asterisk as delimiter: http://www.sa.sc.edu/wellness/members.html
- if (++s->mLineCount > 5)
- break;
- goto lookForState;
- }
- if (isUnicodeSpace(ch) || prior == '-') {
- lookForState:
- if (s->mUnparsed == false)
- continue;
- const UChar* candidate = s->mWords[s->mWordCount];
- UChar firstLetter = candidate[0];
- if (WTF::isASCIIUpper(firstLetter) == false && WTF::isASCIIDigit(firstLetter) == false)
- goto resetWord;
- s->mWordCount++;
- if ((s->mWordCount == 2 && s->mNumberWords == 3 && WTF::isASCIIDigit(s->mWords[1][1])) || // choose second of 8888 333 Main
- (s->mWordCount >= sizeof(s->mWords) / sizeof(s->mWords[0]) - 1)) { // subtract 1 since state names may have two parts
- // search for simple number already stored since first potential house # didn't pan out
- if (s->mNumberWords == 0)
- break;
- int shift = 0;
- while ((s->mNumberWords & (1 << shift)) == 0)
- shift++;
- s->mNumberWords >>= ++shift;
- if (s->mBases[0] != s->mBases[shift]) // if we're past the original node, bail
- break;
- memmove(s->mBases, &s->mBases[shift], (sizeof(s->mBases) / sizeof(s->mBases[0]) - shift) * sizeof(s->mBases[0]));
- memmove(s->mWords, &s->mWords[shift], (sizeof(s->mWords) / sizeof(s->mWords[0]) - shift) * sizeof(s->mWords[0]));
- memmove(s->mStarts, &s->mStarts[shift], (sizeof(s->mStarts) / sizeof(s->mStarts[0]) - shift) * sizeof(s->mStarts[0]));
- s->mStartResult = s->mWords[0] - s->mStarts[0];
- s->mWordCount -= shift;
- // FIXME: need to adjust lineCount to account for discarded delimiters
- }
- if (s->mWordCount < 4)
- goto resetWord;
- firstLetter -= 'A';
- if (firstLetter > 'W' - 'A')
- goto resetWord;
- UChar secondLetter = candidate[1];
- if (prior == '-')
- s->mLetterCount--; // trim trailing dashes, to accept CA-94043
- if (s->mLetterCount == 2) {
- secondLetter -= 'A';
- if (secondLetter > 'Z' - 'A')
- goto resetWord;
- if ((stateTwoLetter[firstLetter] & 1 << secondLetter) != 0) {
- // special case to ignore 'et al'
- if (strCharCmp("ET", s->mWords[s->mWordCount - 2], 2, 1) == false) {
- s->mStateWord = s->mWordCount - 1;
- s->mZipHint = firstIndex[firstLetter] +
- bitcount(stateTwoLetter[firstLetter] & ((1 << secondLetter) - 1));
- goto foundStateName;
- }
- }
- goto resetWord;
- }
- s->mStates = longStateNames[firstLetter];
- if (s->mStates == NULL)
- goto resetWord;
- mustBeAllUpper = false;
- s->mProgress = STATE_NAME;
- unsigned char section = s->mStates[0];
- ASSERT(section > 0x80);
- s->mSectionLength = section & 0x7f;
- candIndex = 1;
- secondHalf = false;
- s->mStateWord = s->mWordCount - 1;
- goto stateName;
- }
- if (WTF::isASCIIDigit(ch)) {
- if (s->mLetterCount == 0) {
- if (++s->mNumberCount > 1)
- continue;
- if (s->mWordCount == 0 && s->mContinuationNode)
- return FOUND_NONE;
- s->mBases[s->mWordCount] = baseChars;
- s->mWords[s->mWordCount] = chars;
- s->mStarts[s->mWordCount] = s->mCurrentStart;
- s->mNumberWords |= 1 << s->mWordCount;
- s->mUnparsed = true;
- }
- continue;
- }
- if (ch == '.') { // optionally can follow letters
- if (s->mLetterCount == 0)
- break;
- if (s->mNumberCount > 0)
- break;
- continue;
- }
- if (ch == '/') // between numbers (1/2) between words (12 Main / Ste 4d)
- goto resetWord;
- if (ch == '#') // can precede numbers, allow it to appear randomly
- goto resetWord;
- if (ch == '"') // sometimes parts of addresses are quoted (FIXME: cite an example here)
- continue;
- break;
- case SECOND_HALF:
- if (WTF::isASCIIAlpha(ch)) {
- if (s->mLetterCount == 0) {
- s->mBases[s->mWordCount] = baseChars;
- s->mWords[s->mWordCount] = chars;
- s->mStarts[s->mWordCount] = s->mCurrentStart;
- s->mWordCount++;
- }
- s->mLetterCount++;
- continue;
- }
- if (WTF::isASCIIDigit(ch) == false) {
- if (s->mLetterCount > 0) {
- s->mProgress = STATE_NAME;
- candIndex = 0;
- secondHalf = true;
- goto stateName;
- }
- continue;
- }
- s->mProgress = ADDRESS_LINE;
- goto resetState;
- case STATE_NAME:
- stateName:
- // pick up length of first section
- do {
- int stateIndex = 1;
- int skip = 0;
- int prefix = 0;
- bool subStr = false;
- do {
- unsigned char match = s->mStates[stateIndex];
- if (match >= 0x80) {
- if (stateIndex == s->mSectionLength)
- break;
- subStr = true;
- // if (skip > 0)
- // goto foundStateName;
- prefix = candIndex;
- skip = match & 0x7f;
- match = s->mStates[++stateIndex];
- }
- UChar candChar = s->mWords[s->mWordCount - 1][candIndex];
- if (mustBeAllUpper && WTF::isASCIILower(candChar))
- goto skipToNext;
- if (match != candChar) {
- if (match != WTF::toASCIILower(candChar)) {
- skipToNext:
- if (subStr == false)
- break;
- if (stateIndex == s->mSectionLength) {
- if (secondHalf) {
- s->mProgress = ADDRESS_LINE;
- goto resetState;
- }
- break;
- }
- stateIndex += skip;
- skip = 0;
- candIndex = prefix;
- continue; // try next substring
- }
- mustBeAllUpper = true;
- }
- int nextindex = stateIndex + 1;
- if (++candIndex >= s->mLetterCount && s->mStates[nextindex] == ' ') {
- s->mProgress = SECOND_HALF;
- s->mStates += nextindex;
- s->mSectionLength -= nextindex;
- goto resetWord;
- }
- if (nextindex + 1 == s->mSectionLength || skip == 2) {
- s->mZipHint = s->mStates[nextindex] - 1;
- goto foundStateName;
- }
- stateIndex += 1;
- skip -= 1;
- } while (true);
- s->mStates += s->mSectionLength;
- ASSERT(s->mStates[0] == 0 || (unsigned) s->mStates[0] > 0x80);
- s->mSectionLength = s->mStates[0] & 0x7f;
- candIndex = 1;
- subStr = false;
- } while (s->mSectionLength != 0);
- s->mProgress = ADDRESS_LINE;
- goto resetState;
- foundStateName:
- s->mEndResult = chars - s->mCurrentStart;
- s->mEndWord = s->mWordCount - 1;
- s->mProgress = ZIP_CODE;
- // a couple of delimiters is an indication that the state name is good
- // or, a non-space / non-alpha-digit is also good
- s->mZipDelimiter = s->mLineCount > 2 || isUnicodeSpace(ch) == false;
- if (WTF::isASCIIDigit(ch))
- s->mZipStart = chars;
- goto resetState;
- case ZIP_CODE:
- if (WTF::isASCIIDigit(ch)) {
- int count = ++s->mNumberCount;
- if (count == 1) {
- if (WTF::isASCIIDigit(prior))
- ++s->mNumberCount;
- else
- s->mZipStart = chars;
- }
- if (count <= 9)
- continue;
- } else if (isUnicodeSpace(ch)) {
- if (s->mNumberCount == 0) {
- s->mZipDelimiter = true; // two spaces delimit state name
- continue;
- }
- } else if (ch == '-') {
- if (s->mNumberCount == 5 && validZip(s->mZipHint, s->mZipStart)) {
- s->mNumberCount = 0;
- s->mProgress = PLUS_4;
- continue;
- }
- if (s->mNumberCount == 0)
- s->mZipDelimiter = true;
- } else if (WTF::isASCIIAlpha(ch) == false)
- s->mZipDelimiter = true;
- if (s->mNumberCount == 5 || s->mNumberCount == 9) {
- if (validZip(s->mZipHint, s->mZipStart) == false)
- goto noZipMatch;
- s->mEndResult = chars - s->mCurrentStart;
- s->mEndWord = s->mWordCount - 1;
- } else if (s->mZipDelimiter == false) {
- noZipMatch:
- --chars;
- s->mProgress = ADDRESS_LINE;
- continue;
- }
- s->mProgress = FIND_STREET;
- goto findStreet;
- case PLUS_4:
- if (WTF::isASCIIDigit(ch)) {
- if (++s->mNumberCount <= 4)
- continue;
- }
- if (isUnicodeSpace(ch)) {
- if (s->mNumberCount == 0)
- continue;
- }
- if (s->mNumberCount == 4) {
- if (WTF::isASCIIAlpha(ch) == false) {
- s->mEndResult = chars - s->mCurrentStart;
- s->mEndWord = s->mWordCount - 1;
- }
- } else if (s->mNumberCount != 0)
- break;
- s->mProgress = FIND_STREET;
- case FIND_STREET:
- findStreet: // minus two below skips city before state
- for (int wordsIndex = s->mStateWord - 2; wordsIndex >= 0; --wordsIndex) {
- const UChar* test = s->mWords[wordsIndex];
- UChar letter = test[0];
- letter -= 'A';
- if (letter > 'X' - 'A')
- continue;
- const char* names = longStreetNames[letter];
- if (names == NULL)
- continue;
- int offset;
- while ((offset = *names++) != 0) {
- int testIndex = 1;
- bool abbr = false;
- for (int idx = 0; idx < offset; idx++) {
- char nameLetter = names[idx];
- char testUpper = WTF::toASCIIUpper(test[testIndex]);
- if (nameLetter == '*') {
- if (testUpper == 'S')
- testIndex++;
- break;
- }
- bool fullOnly = WTF::isASCIILower(nameLetter);
- nameLetter = WTF::toASCIIUpper(nameLetter);
- if (testUpper == nameLetter) {
- if (abbr && fullOnly)
- goto nextTest;
- testIndex++;
- continue;
- }
- if (fullOnly == false)
- goto nextTest;
- abbr = true;
- }
- letter = test[testIndex];
- if (WTF::isASCIIAlpha(letter) == false && WTF::isASCIIDigit(letter) == false) {
- if (s->mNumberWords != 0) {
- int shift = 0;
- int wordReduction = -1;
- do {
- while ((s->mNumberWords & (1 << shift)) == 0)
- shift++;
- if (shift > wordsIndex)
- break;
- wordReduction = shift;
- } while (s->mNumberWords >> ++shift != 0);
- if (wordReduction >= 0) {
- if (s->mContinuationNode)
- return FOUND_NONE;
- s->mStartResult = s->mWords[wordReduction] - s->mStarts[wordReduction];
- }
- }
- return FOUND_COMPLETE;
- }
- nextTest:
- names += offset;
- }
- }
- if (s->mNumberWords != 0) {
- unsigned shift = 0;
- while ((s->mNumberWords & (1 << shift)) == 0)
- shift++;
- s->mNumberWords >>= ++shift;
- if (s->mBases[0] != s->mBases[shift])
- return FOUND_NONE;
- memmove(s->mBases, &s->mBases[shift], (sizeof(s->mBases) / sizeof(s->mBases[0]) - shift) * sizeof(s->mBases[0]));
- memmove(s->mWords, &s->mWords[shift], (sizeof(s->mWords) / sizeof(s->mWords[0]) - shift) * sizeof(s->mWords[0]));
- memmove(s->mStarts, &s->mStarts[shift], (sizeof(s->mStarts) / sizeof(s->mStarts[0]) - shift) * sizeof(s->mStarts[0]));
- s->mStartResult = s->mWords[0] - s->mStarts[0];
- s->mWordCount -= shift;
- s->mProgress = ADDRESS_LINE;
- --chars;
- continue;
- }
- break;
- }
- if (s->mContinuationNode)
- return FOUND_NONE;
- s->mProgress = NO_ADDRESS;
- s->mWordCount = s->mLineCount = 0;
- s->mNumberWords = 0;
- resetState:
- s->mStates = NULL;
- resetWord:
- s->mNumberCount = s->mLetterCount = 0;
- s->mFirstLower = NULL;
- s->mUnparsed = false;
- }
- s->mCurrent = ch;
- return s->mProgress == NO_ADDRESS ? FOUND_NONE : FOUND_PARTIAL;
-}
-
-// Recogize common email patterns only. Currently has lots of state, walks text forwards and backwards -- will be
-// a real challenge to adapt to walk text across multiple nodes, I imagine
-// FIXME: it's too hard for the caller to call these incrementally -- it's probably best for this to
-// either walk the node tree directly or make a callout to get the next or previous node, if there is one
-// walking directly will avoid adding logic in caller to track the multiple partial or full nodes that compose this
-// text pattern.
-CacheBuilder::FoundState CacheBuilder::FindPartialEMail(const UChar* chars, unsigned length,
- FindState* s)
-{
- // the following tables were generated by tests/browser/focusNavigation/BrowserDebug.cpp
- // hand-edit at your own risk
- static const int domainTwoLetter[] = {
- 0x02df797c, // a followed by: [cdefgilmnoqrstuwxz]
- 0x036e73fb, // b followed by: [abdefghijmnorstvwyz]
- 0x03b67ded, // c followed by: [acdfghiklmnorsuvxyz]
- 0x02005610, // d followed by: [ejkmoz]
- 0x001e00d4, // e followed by: [ceghrstu]
- 0x00025700, // f followed by: [ijkmor]
- 0x015fb9fb, // g followed by: [abdefghilmnpqrstuwy]
- 0x001a3400, // h followed by: [kmnrtu]
- 0x000f7818, // i followed by: [delmnoqrst]
- 0x0000d010, // j followed by: [emop]
- 0x0342b1d0, // k followed by: [eghimnprwyz]
- 0x013e0507, // l followed by: [abcikrstuvy]
- 0x03fffccd, // m followed by: [acdghklmnopqrstuvwxyz]
- 0x0212c975, // n followed by: [acefgilopruz]
- 0x00001000, // o followed by: [m]
- 0x014e3cf1, // p followed by: [aefghklmnrstwy]
- 0x00000001, // q followed by: [a]
- 0x00504010, // r followed by: [eouw]
- 0x032a7fdf, // s followed by: [abcdeghijklmnortvyz]
- 0x026afeec, // t followed by: [cdfghjklmnoprtvwz]
- 0x03041441, // u followed by: [agkmsyz]
- 0x00102155, // v followed by: [aceginu]
- 0x00040020, // w followed by: [fs]
- 0x00000000, // x
- 0x00180010, // y followed by: [etu]
- 0x00401001, // z followed by: [amw]
- };
-
- static char const* const longDomainNames[] = {
- "\x03" "ero" "\x03" "rpa", // aero, arpa
- "\x02" "iz", // biz
- "\x02" "at" "\x02" "om" "\x03" "oop", // cat, com, coop
- NULL, // d
- "\x02" "du", // edu
- NULL, // f
- "\x02" "ov", // gov
- NULL, // h
- "\x03" "nfo" "\x02" "nt", // info, int
- "\x03" "obs", // jobs
- NULL, // k
- NULL, // l
- "\x02" "il" "\x03" "obi" "\x05" "useum", // mil, mobi, museum
- "\x03" "ame" "\x02" "et", // name, net
- "\x02" "rg", // , org
- "\x02" "ro", // pro
- NULL, // q
- NULL, // r
- NULL, // s
- "\x05" "ravel", // travel
- NULL, // u
- NULL, // v
- NULL, // w
- NULL, // x
- NULL, // y
- NULL, // z
- };
-
- const UChar* start = chars;
- const UChar* end = chars + length;
- while (chars < end) {
- UChar ch = *chars++;
- if (ch != '@')
- continue;
- const UChar* atLocation = chars - 1;
- // search for domain
- ch = *chars++ | 0x20; // convert uppercase to lower
- if (ch < 'a' || ch > 'z')
- continue;
- while (chars < end) {
- ch = *chars++;
- if (IsDomainChar(ch) == false)
- goto nextAt;
- if (ch != '.')
- continue;
- UChar firstLetter = *chars++ | 0x20; // first letter of the domain
- if (chars >= end)
- return FOUND_NONE; // only one letter; must be at least two
- firstLetter -= 'a';
- if (firstLetter > 'z' - 'a')
- continue; // non-letter followed '.'
- int secondLetterMask = domainTwoLetter[firstLetter];
- ch = *chars | 0x20; // second letter of the domain
- ch -= 'a';
- if (ch >= 'z' - 'a')
- continue;
- bool secondMatch = (secondLetterMask & 1 << ch) != 0;
- const char* wordMatch = longDomainNames[firstLetter];
- int wordIndex = 0;
- while (wordMatch != NULL) {
- int len = *wordMatch++;
- char match;
- do {
- match = wordMatch[wordIndex];
- if (match < 0x20)
- goto foundDomainStart;
- if (chars[wordIndex] != match)
- break;
- wordIndex++;
- } while (true);
- wordMatch += len;
- if (*wordMatch == '\0')
- break;
- wordIndex = 0;
- }
- if (secondMatch) {
- wordIndex = 1;
- foundDomainStart:
- chars += wordIndex;
- if (chars < end) {
- ch = *chars;
- if (ch != '.') {
- if (IsDomainChar(ch))
- goto nextDot;
- } else if (chars + 1 < end && IsDomainChar(chars[1]))
- goto nextDot;
- }
- // found domain. Search backwards from '@' for beginning of email address
- s->mEndResult = chars - start;
- chars = atLocation;
- if (chars <= start)
- goto nextAt;
- ch = *--chars;
- if (ch == '.')
- goto nextAt; // mailbox can't end in period
- do {
- if (IsMailboxChar(ch) == false) {
- chars++;
- break;
- }
- if (chars == start)
- break;
- ch = *--chars;
- } while (true);
- UChar firstChar = *chars;
- if (firstChar == '.' || firstChar == '@') // mailbox can't start with period or be empty
- goto nextAt;
- s->mStartResult = chars - start;
- return FOUND_COMPLETE;
- }
- nextDot:
- ;
- }
-nextAt:
- chars = atLocation + 1;
- }
- return FOUND_NONE;
-}
-
-#define PHONE_PATTERN "(200) /-.\\ 100 -. 0000" // poor man's regex: parens optional, any one of punct, digit smallest allowed
-
-CacheBuilder::FoundState CacheBuilder::FindPartialNumber(const UChar* chars, unsigned length,
- FindState* s)
-{
- char* pattern = s->mPattern;
- UChar* store = s->mStorePtr;
- const UChar* start = chars;
- const UChar* end = chars + length;
- const UChar* lastDigit = NULL;
- do {
- bool initialized = s->mInitialized;
- while (chars < end) {
- if (initialized == false) {
- s->mBackTwo = s->mBackOne;
- s->mBackOne = s->mCurrent;
- }
- UChar ch = s->mCurrent = *chars;
- do {
- char patternChar = *pattern;
- switch (patternChar) {
- case '2':
- if (initialized == false) {
- s->mStartResult = chars - start;
- initialized = true;
- }
- case '0':
- case '1':
- if (ch < patternChar || ch > '9')
- goto resetPattern;
- *store++ = ch;
- pattern++;
- lastDigit = chars;
- goto nextChar;
- case '\0':
- if (WTF::isASCIIDigit(ch) == false) {
- *store = '\0';
- goto checkMatch;
- }
- goto resetPattern;
- case ' ':
- if (ch == patternChar)
- goto nextChar;
- break;
- case '(':
- if (ch == patternChar) {
- s->mStartResult = chars - start;
- initialized = true;
- s->mOpenParen = true;
- }
- goto commonPunctuation;
- case ')':
- if ((ch == patternChar) ^ s->mOpenParen)
- goto resetPattern;
- default:
- commonPunctuation:
- if (ch == patternChar) {
- pattern++;
- goto nextChar;
- }
- }
- } while (++pattern); // never false
- nextChar:
- chars++;
- }
- break;
-resetPattern:
- if (s->mContinuationNode)
- return FOUND_NONE;
- FindResetNumber(s);
- pattern = s->mPattern;
- store = s->mStorePtr;
- } while (++chars < end);
-checkMatch:
- if (WTF::isASCIIDigit(s->mBackOne != '1' ? s->mBackOne : s->mBackTwo))
- return FOUND_NONE;
- *store = '\0';
- s->mStorePtr = store;
- s->mPattern = pattern;
- s->mEndResult = lastDigit - start + 1;
- char pState = pattern[0];
- return pState == '\0' ? FOUND_COMPLETE : pState == '(' || (WTF::isASCIIDigit(pState) && WTF::isASCIIDigit(pattern[-1])) ?
- FOUND_NONE : FOUND_PARTIAL;
-}
-
-CacheBuilder::FoundState CacheBuilder::FindPhoneNumber(const UChar* chars, unsigned length,
- int* start, int* end)
-{
- FindState state;
- FindReset(&state);
- FoundState result = FindPartialNumber(chars, length, &state);
- *start = state.mStartResult;
- *end = state.mEndResult;
- return result;
-}
-
-void CacheBuilder::FindReset(FindState* state)
-{
- memset(state, 0, sizeof(FindState));
- state->mCurrent = ' ';
- FindResetNumber(state);
-}
-
-void CacheBuilder::FindResetNumber(FindState* state)
-{
- state->mOpenParen = false;
- state->mPattern = (char*) PHONE_PATTERN;
- state->mStorePtr = state->mStore;
-}
-
-IntRect CacheBuilder::getAreaRect(const HTMLAreaElement* area) const
-{
- RenderImage* map = m_areaBoundsMap.get(area);
- if (!map)
- return IntRect();
- if (area->isDefault())
- return map->absoluteBoundingBoxRect();
- return area->getRect(map);
-}
-
-void CacheBuilder::GetGlobalOffset(Node* node, int* x, int * y)
-{
- GetGlobalOffset(node->document()->frame(), x, y);
-}
-
-void CacheBuilder::GetGlobalOffset(Frame* frame, int* x, int* y)
-{
-// TIMER_PROBE(__FUNCTION__);
- ASSERT(x);
- ASSERT(y);
- *x = 0;
- *y = 0;
- if (!frame->view())
- return;
- Frame* parent;
- while ((parent = frame->tree()->parent()) != NULL) {
- const WebCore::IntRect& rect = frame->view()->platformWidget()->getBounds();
- *x += rect.x();
- *y += rect.y();
- frame = parent;
- }
- // TIMER_PROBE_END();
-}
-
-Frame* CacheBuilder::HasFrame(Node* node)
-{
- RenderObject* renderer = node->renderer();
- if (renderer == NULL)
- return NULL;
- if (renderer->isWidget() == false)
- return NULL;
- Widget* widget = static_cast<RenderWidget*>(renderer)->widget();
- if (widget == NULL)
- return NULL;
- if (widget->isFrameView() == false)
- return NULL;
- return static_cast<FrameView*>(widget)->frame();
-}
-
-bool CacheBuilder::HasOverOrOut(Node* node)
-{
- EventTargetNode* target = (EventTargetNode*) node;
- return target->getEventListener(eventNames().mouseoverEvent) ||
- target->getEventListener(eventNames().mouseoutEvent);
-
-}
-
-bool CacheBuilder::HasTriggerEvent(Node* node)
-{
- EventTargetNode* target = (EventTargetNode*) node;
- return target->getEventListener(eventNames().clickEvent) ||
- target->getEventListener(eventNames().mousedownEvent) ||
- target->getEventListener(eventNames().mouseupEvent) ||
- target->getEventListener(eventNames().keydownEvent) ||
- target->getEventListener(eventNames().keyupEvent);
-}
-
-// #define EMAIL_PATTERN "x@y.d" // where 'x' is letters, numbers, and '-', '.', '_' ; 'y' is 'x' without the underscore, and 'd' is a valid domain
-// - 0x2D . 0x2E 0-9 0x30-39 A-Z 0x41-5A _ 0x5F a-z 0x61-7A
-
-bool CacheBuilder::IsDomainChar(UChar ch)
-{
- static const unsigned body[] = {0x03ff6000, 0x07fffffe, 0x07fffffe}; // 0-9 . - A-Z a-z
- ch -= 0x20;
- if (ch > 'z' - 0x20)
- return false;
- return (body[ch >> 5] & 1 << (ch & 0x1f)) != 0;
-}
-
-// does not find text to keep it fast
-// (this assume text nodes are more rarely moved than other nodes)
-Node* CacheBuilder::findByCenter(int x, int y) const
-{
- DBG_NAV_LOGD("x=%d y=%d\n", x, y);
- Frame* frame = FrameAnd(this);
- Node* node = frame->document();
- ASSERT(node != NULL);
- int globalOffsetX, globalOffsetY;
- GetGlobalOffset(frame, &globalOffsetX, &globalOffsetY);
- while ((node = node->traverseNextNode()) != NULL) {
- Frame* child = HasFrame(node);
- if (child != NULL) {
- if (child->document() == NULL)
- continue;
- CacheBuilder* cacheBuilder = Builder(child);
- // if (cacheBuilder->mViewBounds.isEmpty())
- // continue;
- Node* result = cacheBuilder->findByCenter(x, y);
- if (result != NULL)
- return result;
- }
- if (node->isTextNode())
- continue;
- IntRect bounds;
- if (node->hasTagName(HTMLNames::areaTag)) {
- HTMLAreaElement* area = static_cast<HTMLAreaElement*>(node);
- bounds = getAreaRect(area);
- bounds.move(globalOffsetX, globalOffsetY);
- } else
- bounds = node->getRect();
- if (bounds.isEmpty())
- continue;
- bounds.move(globalOffsetX, globalOffsetY);
- if (x != bounds.x() + (bounds.width() >> 1))
- continue;
- if (y != bounds.y() + (bounds.height() >> 1))
- continue;
- if (node->isKeyboardFocusable(NULL))
- return node;
- if (node->isMouseFocusable())
- return node;
- if (node->isFocusable())
- return node;
- if (node->isEventTargetNode() == false)
- continue;
- if (AnyIsClick(node))
- continue;
- if (HasTriggerEvent(node) == false)
- continue;
- return node;
- }
- return NULL;
-}
-
-bool CacheBuilder::isFocusableText(NodeWalk* walk, bool more, Node* node,
- CachedNodeType* type, String* exported) const
-{
- Text* textNode = static_cast<Text*>(node);
- StringImpl* string = textNode->string();
- const UChar* baseChars = string->characters();
-// const UChar* originalBase = baseChars;
- int length = string->length();
- int index = 0;
- while (index < length && isUnicodeSpace(baseChars[index]))
- index++;
- if (index >= length)
- return false;
- if (more == false) {
- walk->mStart = 0;
- walk->mEnd = 0;
- walk->mFinalNode = node;
- walk->mLastInline = NULL;
- }
- // starting with this node, search forward for email, phone number, and address
- // if any of the three is found, track it so that the remaining can be looked for later
- FoundState state = FOUND_NONE;
- RenderText* renderer = (RenderText*) node->renderer();
- bool foundBetter = false;
- InlineTextBox* baseInline = walk->mLastInline != NULL ? walk->mLastInline :
- renderer->firstTextBox();
- if (baseInline == NULL)
- return false;
- int start = walk->mEnd;
- InlineTextBox* saveInline;
- int baseStart, firstStart = start;
- saveInline = baseInline;
- baseStart = start;
- for (CachedNodeType checkType = ADDRESS_CACHEDNODETYPE;
- checkType <= PHONE_CACHEDNODETYPE;
- checkType = (CachedNodeType) (checkType << 1))
- {
- if ((checkType & mAllowableTypes) == 0)
- continue;
- InlineTextBox* inlineTextBox = baseInline;
- FindState findState;
- FindReset(&findState);
- start = baseStart;
- if (checkType == ADDRESS_CACHEDNODETYPE) {
- findState.mBases[0] = baseChars;
- findState.mWords[0] = baseChars + start;
- findState.mStarts[0] = baseChars + start;
- }
- Node* lastPartialNode = NULL;
- int lastPartialEnd = -1;
- bool lastPartialMore = false;
- bool firstPartial = true;
- InlineTextBox* lastPartialInline = NULL;
- do {
- do {
- const UChar* chars = baseChars + start;
- length = inlineTextBox == NULL ? 0 :
- inlineTextBox->end() - start + 1;
- bool wasInitialized = findState.mInitialized;
- switch (checkType) {
- case ADDRESS_CACHEDNODETYPE:
- state = FindPartialAddress(baseChars, chars, length, &findState);
- break;
- case EMAIL_CACHEDNODETYPE:
- state = FindPartialEMail(chars, length, &findState);
- break;
- case PHONE_CACHEDNODETYPE:
- state = FindPartialNumber(chars, length, &findState);
- break;
- default:
- ASSERT(0);
- }
- findState.mInitialized = state != FOUND_NONE;
- if (wasInitialized != findState.mInitialized)
- firstStart = start;
- if (state == FOUND_PARTIAL) {
- lastPartialNode = node;
- lastPartialEnd = findState.mEndResult + start;
- lastPartialMore = firstPartial &&
- lastPartialEnd < (int) string->length();
- firstPartial = false;
- lastPartialInline = inlineTextBox;
- findState.mContinuationNode = true;
- } else if (state == FOUND_COMPLETE) {
- if (foundBetter == false || walk->mStart > findState.mStartResult) {
- walk->mStart = findState.mStartResult + firstStart;
- if (findState.mEndResult > 0) {
- walk->mFinalNode = node;
- walk->mEnd = findState.mEndResult + start;
- walk->mMore = node == textNode &&
- walk->mEnd < (int) string->length();
- walk->mLastInline = inlineTextBox;
- } else {
- walk->mFinalNode = lastPartialNode;
- walk->mEnd = lastPartialEnd;
- walk->mMore = lastPartialMore;
- walk->mLastInline = lastPartialInline;
- }
- *type = checkType;
- if (checkType == PHONE_CACHEDNODETYPE) {
- const UChar* store = findState.mStore;
- *exported = String(store);
- } else {
- Node* temp = textNode;
- length = 1;
- start = walk->mStart;
- exported->truncate(0);
- do {
- Text* tempText = static_cast<Text*>(temp);
- StringImpl* string = tempText->string();
- int end = tempText == walk->mFinalNode ?
- walk->mEnd : string->length();
- exported->append(String(string->substring(
- start, end - start)));
- ASSERT(end > start);
- length += end - start + 1;
- if (temp == walk->mFinalNode)
- break;
- start = 0;
- do {
- temp = temp->traverseNextNode();
- ASSERT(temp);
- } while (temp->isTextNode() == false);
- // add a space in between text nodes to avoid
- // words collapsing together
- exported->append(" ");
- } while (true);
- }
- foundBetter = true;
- }
- goto tryNextCheckType;
- } else if (findState.mContinuationNode)
- break;
- if (inlineTextBox == NULL)
- break;
- inlineTextBox = inlineTextBox->nextTextBox();
- if (inlineTextBox == NULL)
- break;
- start = inlineTextBox->start();
- if (state == FOUND_PARTIAL && node == textNode)
- findState.mContinuationNode = false;
- } while (true);
- if (state == FOUND_NONE)
- break;
- // search for next text node, if any
- Text* nextNode;
- do {
- do {
- do {
- node = node->traverseNextNode();
- if (node == NULL || node->hasTagName(HTMLNames::aTag)) {
- if (state == FOUND_PARTIAL &&
- checkType == ADDRESS_CACHEDNODETYPE &&
- findState.mProgress == ZIP_CODE &&
- findState.mNumberCount == 0) {
- baseChars = NULL;
- inlineTextBox = NULL;
- start = 0;
- findState.mProgress = FIND_STREET;
- goto finalNode;
- }
- goto tryNextCheckType;
- }
- } while (node->isTextNode() == false);
- nextNode = static_cast<Text*>(node);
- renderer = (RenderText*) nextNode->renderer();
- } while (renderer == NULL);
- baseInline = renderer->firstTextBox();
- } while (baseInline == NULL);
- string = nextNode->string();
- baseChars = string->characters();
- inlineTextBox = baseInline;
- start = inlineTextBox->start();
- finalNode:
- findState.mEndResult = 0;
- } while (true);
-tryNextCheckType:
- node = textNode;
- baseInline = saveInline;
- string = textNode->string();
- baseChars = string->characters();
- }
- if (foundBetter) {
- CachedNodeType temp = *type;
- switch (temp) {
- case ADDRESS_CACHEDNODETYPE: {
- static const char geoString[] = "geo:0,0?q=";
- exported->insert(String(geoString), 0);
- int index = sizeof(geoString) - 1;
- String escapedComma("%2C");
- while ((index = exported->find(',', index)) >= 0)
- exported->replace(index, 1, escapedComma);
- } break;
- case EMAIL_CACHEDNODETYPE:
- exported->insert(WebCore::String("mailto:"), 0);
- break;
- case PHONE_CACHEDNODETYPE:
- exported->insert(WebCore::String("tel:"), 0);
- break;
- default:
- break;
- }
- return true;
- }
-noTextMatch:
- walk->reset();
- return false;
-}
-
-bool CacheBuilder::IsMailboxChar(UChar ch)
-{
- static const unsigned body[] = {0x03ff6000, 0x87fffffe, 0x07fffffe}; // 0-9 . - A-Z _ a-z
- ch -= 0x20;
- if (ch > 'z' - 0x20)
- return false;
- return (body[ch >> 5] & 1 << (ch & 0x1f)) != 0;
-}
-
-bool CacheBuilder::outOfDate()
-{
- Node* kitFocusNode = currentFocus();
- if (mLastKnownFocus != kitFocusNode) {
- DBG_NAV_LOGD("%s\n", "mLastKnownFocus != kitFocusNode");
- return true;
- }
- if (kitFocusNode == NULL)
- return false;
- IntRect kitBounds = kitFocusNode->getRect();
- bool result = kitBounds != mLastKnownFocusBounds;
- if (result == true)
- DBG_NAV_LOGD("%s\n", "kitBounds != mLastKnownFocusBounds");
- return result;
-}
-
-void CacheBuilder::setLastFocus(Node* node)
-{
- ASSERT(node);
- mLastKnownFocus = node;
- mLastKnownFocusBounds = node->getRect();
-}
-
-bool CacheBuilder::setData(CachedFrame* cachedFrame)
-{
- Frame* frame = FrameAnd(this);
- Document* doc = frame->document();
- if (doc == NULL)
- return false;
- RenderObject* renderer = doc->renderer();
- if (renderer == NULL)
- return false;
- RenderLayer* layer = renderer->enclosingLayer();
- if (layer == NULL)
- return false;
- if (layer->width() == 0 || layer->height() == 0)
- return false;
- if (!frame->view())
- return false;
- int x, y;
- GetGlobalOffset(frame, &x, &y);
- WebCore::IntRect viewBounds = frame->view()->platformWidget()->getBounds();
- if ((x | y) != 0)
- viewBounds.setLocation(WebCore::IntPoint(x, y));
- cachedFrame->setLocalViewBounds(viewBounds);
- cachedFrame->setContentsSize(layer->width(), layer->height());
- if (cachedFrame->childCount() == 0)
- return true;
- CachedFrame* lastCachedFrame = cachedFrame->lastChild();
- cachedFrame = cachedFrame->firstChild();
- do {
- CacheBuilder* cacheBuilder = Builder((Frame* )cachedFrame->framePointer());
- cacheBuilder->setData(cachedFrame);
- } while (cachedFrame++ != lastCachedFrame);
- return true;
-}
-
-bool CacheBuilder::validNode(void* matchFrame, void* matchNode) const
-{
- Frame* frame = FrameAnd(this);
- if (matchFrame == frame) {
- if (matchNode == NULL)
- return true;
- Node* node = frame->document();
- while (node != NULL) {
- if (node == matchNode) {
- const IntRect& rect = node->hasTagName(HTMLNames::areaTag) ?
- getAreaRect(static_cast<HTMLAreaElement*>(node)) : node->getRect();
- // Consider nodes with empty rects that are not at the origin
- // to be valid, since news.google.com has valid nodes like this
- if (rect.x() == 0 && rect.y() == 0 && rect.isEmpty())
- return false;
- return true;
- }
- node = node->traverseNextNode();
- }
- DBG_NAV_LOGD("frame=%p valid node=%p invalid\n", matchFrame, matchNode);
- return false;
- }
- Frame* child = frame->tree()->firstChild();
- while (child) {
- bool result = Builder(child)->validNode(matchFrame, matchNode);
- if (result)
- return result;
- child = child->tree()->nextSibling();
- }
-#if DEBUG_NAV_UI
- if (frame->tree()->parent() == NULL)
- DBG_NAV_LOGD("frame=%p node=%p false\n", matchFrame, matchNode);
-#endif
- return false;
-}
-
-static int Area(const IntRect& rect)
-{
- return rect.width() * rect.height();
-}
-
-bool CacheBuilder::AddPartRect(IntRect& bounds, int x, int y,
- WTF::Vector<IntRect>* result, IntRect* focusBounds)
-{
- if (bounds.isEmpty())
- return true;
- bounds.move(x, y);
- if (bounds.right() <= 0 || bounds.bottom() <= 0)
- return true;
- IntRect* work = result->begin() - 1;
- IntRect* end = result->end();
- while (++work < end) {
- if (work->contains(bounds))
- return true;
- if (bounds.contains(*work)) {
- *work = bounds;
- focusBounds->unite(bounds);
- return true;
- }
- if ((bounds.x() != work->x() || bounds.width() != work->width()) &&
- (bounds.y() != work->y() || bounds.height() != work->height()))
- continue;
- IntRect test = *work;
- test.unite(bounds);
- if (Area(test) > Area(*work) + Area(bounds))
- continue;
- *work = test;
- focusBounds->unite(bounds);
- return true;
- }
- if (result->size() >= MAXIMUM_FOCUS_RING_COUNT)
- return false;
- result->append(bounds);
- if (focusBounds->isEmpty())
- *focusBounds = bounds;
- else
- focusBounds->unite(bounds);
- return true;
-}
-
-bool CacheBuilder::ConstructPartRects(Node* node, const IntRect& bounds,
- IntRect* focusBounds, int x, int y, WTF::Vector<IntRect>* result)
-{
- WTF::Vector<ClipColumnTracker> clipTracker(1);
- ClipColumnTracker* baseTracker = clipTracker.data(); // sentinel
- bzero(baseTracker, sizeof(ClipColumnTracker));
- if (node->hasChildNodes() && node->hasTagName(HTMLNames::buttonTag) == false
- && node->hasTagName(HTMLNames::selectTag) == false) {
- // collect all text rects from first to last child
- Node* test = node->firstChild();
- Node* last = NULL;
- Node* prior = node;
- while ((prior = prior->lastChild()) != NULL)
- last = prior;
- ASSERT(last != NULL);
- bool nodeIsAnchor = node->hasTagName(HTMLNames::aTag);
- do {
- do {
- const ClipColumnTracker* lastClip = &clipTracker.last();
- if (test != lastClip->mLastChild)
- break;
- clipTracker.removeLast();
- } while (true);
- RenderObject* renderer = test->renderer();
- if (renderer == NULL)
- continue;
- EVisibility vis = renderer->style()->visibility();
- if (vis == HIDDEN)
- continue;
- if (test->isTextNode()) {
- RenderText* renderText = (RenderText*) renderer;
- InlineTextBox *textBox = renderText->firstTextBox();
- if (textBox == NULL)
- continue;
- bool hasClip = renderer->hasOverflowClip();
- size_t clipIndex = clipTracker.size();
- IntRect clipBounds = IntRect(0, 0, INT_MAX, INT_MAX);
- if (hasClip || --clipIndex > 0) {
- clipBounds = hasClip ? renderer->absoluteBoundingBoxRect() :
- clipTracker.at(clipIndex).mBounds; // x, y fixup done by ConstructTextRect
- }
- if (ConstructTextRect((Text*) test, textBox, 0, INT_MAX,
- x, y, focusBounds, clipBounds, result) == false) {
- return false;
- }
- continue;
- }
- if (test->hasTagName(HTMLNames::imgTag)) {
- IntRect bounds = test->getRect();
- if (AddPartRect(bounds, x, y, result, focusBounds) == false)
- return false;
- continue;
- }
- if (renderer->hasOverflowClip() == false) {
- if (nodeIsAnchor && test->hasTagName(HTMLNames::divTag)) {
- IntRect bounds = renderer->absoluteBoundingBoxRect(); // x, y fixup done by AddPartRect
- int left = bounds.x() + renderer->paddingLeft()
- + renderer->borderLeft();
- int top = bounds.y() + renderer->paddingTop()
- + renderer->borderTop();
- int right = bounds.right() - renderer->paddingRight()
- - renderer->borderRight();
- int bottom = bounds.bottom() - renderer->paddingBottom()
- - renderer->borderBottom();
- if (left >= right || top >= bottom)
- continue;
- bounds = IntRect(left, top, right - left, bottom - top);
- if (AddPartRect(bounds, x, y, result, focusBounds) == false)
- return false;
- }
- continue;
- }
- Node* lastChild = test->lastChild();
- if (lastChild == NULL)
- continue;
- clipTracker.grow(clipTracker.size() + 1);
- ClipColumnTracker& clip = clipTracker.last();
- clip.mBounds = renderer->absoluteBoundingBoxRect(); // x, y fixup done by ConstructTextRect
- clip.mLastChild = OneAfter(lastChild);
- clip.mNode = test;
- } while (test != last && (test = test->traverseNextNode()) != NULL);
- }
- if (result->size() == 0 || focusBounds->width() < MINIMUM_FOCUSABLE_WIDTH
- || focusBounds->height() < MINIMUM_FOCUSABLE_HEIGHT) {
- if (bounds.width() < MINIMUM_FOCUSABLE_WIDTH)
- return false;
- if (bounds.height() < MINIMUM_FOCUSABLE_HEIGHT)
- return false;
- result->append(bounds);
- *focusBounds = bounds;
- }
- return true;
-}
-
-static inline bool isNotSpace(UChar c)
-{
- return c <= 0xA0 ? isUnicodeSpace(c) == false :
- WTF::Unicode::direction(c) != WTF::Unicode::WhiteSpaceNeutral;
-}
-
-bool CacheBuilder::ConstructTextRect(Text* textNode,
- InlineTextBox* textBox, int start, int relEnd, int x, int y,
- IntRect* focusBounds, const IntRect& clipBounds, WTF::Vector<IntRect>* result)
-{
- RenderText* renderText = (RenderText*) textNode->renderer();
- EVisibility vis = renderText->style()->visibility();
- StringImpl* string = textNode->string();
- const UChar* chars = string->characters();
- int renderX, renderY;
- renderText->absolutePosition(renderX, renderY);
- do {
- int textBoxStart = textBox->start();
- int textBoxEnd = textBoxStart + textBox->len();
- if (textBoxEnd <= start)
- continue;
- if (textBoxEnd > relEnd)
- textBoxEnd = relEnd;
- IntRect bounds = textBox->selectionRect(renderX, renderY,
- start, textBoxEnd);
- bounds.intersect(clipBounds);
- if (bounds.isEmpty())
- continue;
- bool drawable = false;
- for (int index = start; index < textBoxEnd; index++)
- if ((drawable |= isNotSpace(chars[index])) != false)
- break;
- if (drawable && vis != HIDDEN) {
- if (AddPartRect(bounds, x, y, result, focusBounds) == false)
- return false;
- }
- if (textBoxEnd == relEnd)
- break;
- } while ((textBox = textBox->nextTextBox()) != NULL);
- return true;
-}
-
-bool CacheBuilder::ConstructTextRects(Text* node, int start,
- Text* last, int end, int x, int y, IntRect* focusBounds,
- const IntRect& clipBounds, WTF::Vector<IntRect>* result)
-{
- result->clear();
- *focusBounds = IntRect(0, 0, 0, 0);
- do {
- RenderText* renderText = (RenderText*) node->renderer();
- int relEnd = node == last ? end : renderText->textLength();
- InlineTextBox *textBox = renderText->firstTextBox();
- if (textBox != NULL) {
- do {
- if ((int) textBox->end() >= start)
- break;
- } while ((textBox = textBox->nextTextBox()) != NULL);
- if (ConstructTextRect(node, textBox, start, relEnd,
- x, y, focusBounds, clipBounds, result) == false)
- return false;
- }
- start = 0;
- do {
- if (node == last)
- return true;
- node = (Text*) node->traverseNextNode();
- ASSERT(node != NULL);
- } while (node->isTextNode() == false || node->renderer() == NULL);
- } while (true);
-}
-
-}
diff --git a/WebKit/android/nav/CacheBuilder.h b/WebKit/android/nav/CacheBuilder.h
deleted file mode 100644
index 07040e2..0000000
--- a/WebKit/android/nav/CacheBuilder.h
+++ /dev/null
@@ -1,272 +0,0 @@
-/*
- * Copyright 2006, 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 APPLE COMPUTER, INC. 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 CacheBuilder_H
-#define CacheBuilder_H
-
-#include "CachedDebug.h"
-#include "CachedNodeType.h"
-#include "IntRect.h"
-#include "PlatformString.h"
-#include "TextDirection.h"
-#include "wtf/HashMap.h"
-#include "wtf/Vector.h"
-
-#define NAVIGATION_MAX_PHONE_LENGTH 14
-
-using namespace WebCore;
-
-namespace WebCore {
-
-class Document;
-class Frame;
-class HTMLAreaElement;
-class InlineTextBox;
-class Node;
-class PlatformGraphicsContext;
-class RenderFlow;
-class RenderImage;
-class RenderObject;
-class RenderLayer;
-class Text;
-
-}
-
-namespace android {
-
-class CachedFrame;
-class CachedNode;
-class CachedRoot;
-
-class CacheBuilder {
-public:
- enum Direction {
- UNINITIALIZED = -1,
- LEFT,
- RIGHT,
- UP,
- DOWN,
- DIRECTION_COUNT,
- UP_DOWN = UP & DOWN, // mask and result
- RIGHT_DOWN = RIGHT & DOWN, // mask and result
- };
- enum FoundState {
- FOUND_NONE,
- FOUND_PARTIAL,
- FOUND_COMPLETE
- };
- CacheBuilder();
- void allowAllTextDetection() { mAllowableTypes = ALL_CACHEDNODETYPES; }
- void buildCache(CachedRoot* root);
- static bool ConstructPartRects(Node* node, const IntRect& bounds,
- IntRect* focusBounds, int x, int y, WTF::Vector<IntRect>* result);
- Node* currentFocus() const;
- void disallowAddressDetection() { mAllowableTypes = (CachedNodeType) (
- mAllowableTypes & ~ADDRESS_CACHEDNODETYPE); }
- void disallowEmailDetection() { mAllowableTypes = (CachedNodeType) (
- mAllowableTypes & ~EMAIL_CACHEDNODETYPE); }
- void disallowPhoneDetection() { mAllowableTypes = (CachedNodeType) (
- mAllowableTypes & ~PHONE_CACHEDNODETYPE); }
- static FoundState FindAddress(const UChar* , unsigned length, int* start, int* end);
- Node* findByCenter(int x, int y) const;
- static void GetGlobalOffset(Frame* , int* x, int * y);
- static void GetGlobalOffset(Node* , int* x, int * y);
- bool outOfDate();
- void setLastFocus(Node* );
- bool validNode(void* framePtr, void* nodePtr) const;
-private:
- enum AddressProgress {
- NO_ADDRESS,
- SKIP_TO_SPACE,
- HOUSE_NUMBER,
- NUMBER_TRAILING_SPACE,
- ADDRESS_LINE,
- STATE_NAME,
- SECOND_HALF,
- ZIP_CODE,
- PLUS_4,
- FIND_STREET
- };
- struct NodeWalk {
- NodeWalk() { reset(); }
- int mStart;
- int mEnd;
- Node* mFinalNode;
- InlineTextBox* mLastInline;
- bool mMore;
- void reset() { mMore = false; }
- };
- struct BoundsPart {
- IntRect mRect;
- int mStart;
- int mEnd;
- };
- struct Bounds {
- typedef bool (*FindText)(BoundsPart* result, InlineTextBox* , const String& match);
- IntRect mNodeBounds;
- BoundsPart mPart;
- WTF::Vector<BoundsPart> mParts;
- char mStore[NAVIGATION_MAX_PHONE_LENGTH + 1];
- CachedNodeType mStoreType;
- int mPartIndex;
- Node* mNode;
- Node* mFinalNode;
- void reset() { mNode = NULL; }
- };
- struct FindState {
- int mStartResult;
- int mEndResult;
- const UChar* mCurrentStart;
- const UChar* mEnd;
- AddressProgress mProgress;
- int mNumberCount;
- int mLetterCount;
- unsigned mWordCount;
- int mLineCount;
- const UChar* mFirstLower;
- const UChar* mZipStart;
- const UChar* mBases[16]; // FIXME: random guess, maybe too small, maybe too big
- const UChar* mWords[16];
- const UChar* mStarts[16]; // text is not necessarily contiguous
- const char* mStates;
- int mEndWord;
- int mStateWord;
- int mZipHint;
- int mSectionLength;
- unsigned mNumberWords; // must contain as many bits as mWords contains elements
- char* mPattern;
- UChar mStore[NAVIGATION_MAX_PHONE_LENGTH + 1];
- UChar* mStorePtr;
- UChar mBackOne;
- UChar mBackTwo;
- UChar mCurrent;
- bool mUnparsed;
- bool mZipDelimiter;
- bool mOpenParen;
- bool mInitialized;
- bool mContinuationNode;
- };
- struct ClipColumnTracker {
- IntRect mBounds;
- Node* mLastChild;
- Node* mNode;
- WTF::Vector<IntRect>* mColumns;
- int mColumnGap;
- TextDirection mDirection;
- bool mHasClip;
- };
- struct TabIndexTracker {
- int mTabIndex;
- Node* mLastChild;
- };
- struct Tracker {
- int mCachedNodeIndex;
- int mTabIndex;
- Node* mLastChild;
- Node* mParentLastChild;
- bool mSomeParentTakesFocus;
- };
- void adjustForColumns(const ClipColumnTracker& track,
- CachedNode* node, IntRect* bounds);
- static bool AddPartRect(IntRect& bounds, int x, int y,
- WTF::Vector<IntRect>* result, IntRect* focusBounds);
- static bool AnyIsClick(Node* node);
- static bool AnyChildIsClick(Node* node);
- void BuildFrame(Frame* root, Frame* frame,
- CachedRoot* cachedRoot, CachedFrame* cachedFrame);
- bool CleanUpContainedNodes(CachedFrame* cachedFrame,
- const Tracker* 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);
- static bool ConstructTextRects(Text* node, int start,
- Text* last, int end, int x, int y, IntRect* focusBounds,
- const IntRect& clip, WTF::Vector<IntRect>* result);
- static FoundState FindPartialAddress(const UChar* , const UChar* , unsigned length, FindState* );
- static FoundState FindPartialEMail(const UChar* , unsigned length, FindState* );
- static FoundState FindPartialNumber(const UChar* , unsigned length, FindState* );
- static FoundState FindPhoneNumber(const UChar* chars, unsigned length, int* start, int* end);
- static void FindReset(FindState* );
- static void FindResetNumber(FindState* );
- static Frame* FrameAnd(CacheBuilder* focusNav);
- static Frame* FrameAnd(const CacheBuilder* focusNav);
- static CacheBuilder* Builder(Frame* );
- IntRect getAreaRect(const HTMLAreaElement* area) const;
- static Frame* HasFrame(Node* );
- static bool HasOverOrOut(Node* );
- static bool HasTriggerEvent(Node* );
- static bool IsDomainChar(UChar ch);
- bool isFocusableText(NodeWalk* , bool oldMore, Node* , CachedNodeType* type,
- String* exported) const; //returns true if it is focusable
- static bool IsMailboxChar(UChar ch);
- static bool IsRealNode(Frame* , Node* );
- int overlap(int left, int right); // returns distance scale factor as 16.16 scalar
- bool setData(CachedFrame* );
- Node* tryFocus(Direction direction);
- Node* trySegment(Direction direction, int mainStart, int mainEnd);
- Node* mLastKnownFocus;
- IntRect mLastKnownFocusBounds;
- CachedNodeType mAllowableTypes;
- WTF::HashMap<const HTMLAreaElement* , RenderImage* > m_areaBoundsMap;
-#if DUMP_NAV_CACHE
-public:
- class Debug {
-public:
- void frameName(char*& namePtr, const char* max) const;
- void init(char* buffer, size_t size);
- static int ParentIndex(Node* node, int count, Node* parent);
- void print() { frames(); }
- void print(const char* name);
- void wideString(const String& str);
-private:
- void attr(const AtomicString& name, const AtomicString& value);
- void comma(const char* str);
- int flowBoxes(RenderFlow* flow, int ifIndex, int indent);
- void flush();
- Frame* frameAnd() const;
- void frames();
- void groups();
- bool isFocusable(Node* node);
- void localName(Node* node);
- void newLine(int indent = 0);
- void print(const char* name, unsigned len);
- void renderTree(RenderObject* , int indent, Node* , int count);
- void setIndent(int );
- void uChar(const UChar* name, unsigned len, bool hex);
- void validateFrame();
- void validateStringData();
- void wideString(const UChar* chars, int length, bool hex);
- char* mBuffer;
- size_t mBufferSize;
- int mIndex;
- const char* mPrefix;
- int mMinPrefix;
- } mDebug;
-#endif
-};
-
-}
-
-#endif
diff --git a/WebKit/android/nav/CachedDebug.h b/WebKit/android/nav/CachedDebug.h
deleted file mode 100644
index 3127112..0000000
--- a/WebKit/android/nav/CachedDebug.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright 2007, 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 APPLE COMPUTER, INC. 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 CachedDebug_H
-#define CachedDebug_H
-
-#ifndef DUMP_NAV_CACHE
-#ifdef NDEBUG
-#define DUMP_NAV_CACHE 0
-#else
-#define DUMP_NAV_CACHE 1
-#endif
-#endif
-
-#ifndef DEBUG_NAV_UI
-#ifdef NDEBUG
-#define DEBUG_NAV_UI 0
-#else
-#define DEBUG_NAV_UI 1
-#endif
-#endif
-
-#if DEBUG_NAV_UI
-#define DBG_NAV_LOG(message) LOGD("%s %s", __FUNCTION__, message)
-#define DBG_NAV_LOGD(format, ...) LOGD("%s " format, __FUNCTION__, __VA_ARGS__)
-#define DEBUG_NAV_UI_LOGD(...) LOGD(__VA_ARGS__)
-#else
-#define DBG_NAV_LOG(message) ((void)0)
-#define DBG_NAV_LOGD(format, ...) ((void)0)
-#define DBG_NAV_LOGD_THROTTLE(format, ...) ((void)0)
-#define DEBUG_NAV_UI_LOGD(...) ((void)0)
-#endif
-
-#if DUMP_NAV_CACHE != 0 && !defined DUMP_NAV_CACHE_USING_PRINTF && defined NDEBUG
-#define DUMP_NAV_CACHE_USING_PRINTF
-#endif
-
-#if DUMP_NAV_CACHE
-#ifdef DUMP_NAV_CACHE_USING_PRINTF
-#include <stdio.h>
-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)
-#else
-#define DUMP_NAV_LOGD(...) LOGD(__VA_ARGS__)
-#endif
-#else
-#define DUMP_NAV_LOGD(...) ((void)0)
-#endif
-
-#endif
diff --git a/WebKit/android/nav/CachedFrame.cpp b/WebKit/android/nav/CachedFrame.cpp
deleted file mode 100644
index 4db9e40..0000000
--- a/WebKit/android/nav/CachedFrame.cpp
+++ /dev/null
@@ -1,1318 +0,0 @@
-/*
- * Copyright 2007, 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 APPLE COMPUTER, INC. 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 "CachedHistory.h"
-#include "CachedNode.h"
-#include "CachedRoot.h"
-
-#include "CachedFrame.h"
-
-#define OFFSETOF(type, field) ((char*)&(((type*)1)->field) - (char*)1) // avoids gnu warning
-
-#define MIN_OVERLAP 3 // if rects overlap by 2 pixels or fewer, treat them as non-intersecting
-
-namespace android {
-
-bool CachedFrame::CheckBetween(Direction direction, const WebCore::IntRect& bestRect,
- const WebCore::IntRect& prior, WebCore::IntRect* result)
-{
- int left, top, width, height;
- if (direction & UP_DOWN) {
- top = direction == UP ? bestRect.bottom() : prior.bottom();
- int bottom = direction == UP ? prior.y() : bestRect.y();
- height = bottom - top;
- if (height < 0)
- return false;
- left = prior.x();
- int testLeft = bestRect.x();
- if (left > testLeft)
- left = testLeft;
- int right = prior.right();
- int testRight = bestRect.right();
- if (right < testRight)
- right = testRight;
- width = right - left;
- } else {
- left = direction == LEFT ? bestRect.right() : prior.right();
- int right = direction == LEFT ? prior.x() : bestRect.x();
- width = right - left;
- if (width < 0)
- return false;
- top = prior.y();
- int testTop = bestRect.y();
- if (top > testTop)
- top = testTop;
- int bottom = prior.bottom();
- int testBottom = bestRect.bottom();
- if (bottom < testBottom)
- bottom = testBottom;
- height = bottom - top;
- }
- *result = WebCore::IntRect(left, top, width, height);
- return true;
-}
-
-bool CachedFrame::checkBetween(BestData* best, Direction direction)
-{
- const WebCore::IntRect& bestRect = best->bounds();
- BestData test;
- test.mDistance = INT_MAX;
- test.mNode = NULL;
- int index = direction;
- int limit = index + DIRECTION_COUNT;
- do {
- WebCore::IntRect edges;
- Direction check = (Direction) (index & DIRECTION_MASK);
- if (CheckBetween(check, bestRect,
- history()->priorBounds(), &edges) == false)
- continue;
- WebCore::IntRect clip = mRoot->scrolledBounds();
- clip.intersect(edges);
- if (clip.isEmpty())
- continue;
- findClosest(&test, direction, check, &clip);
- if (test.mNode == NULL)
- continue;
- if (direction == check)
- break;
- } while (++index < limit);
- if (test.mNode == NULL)
- return false;
- *best = test;
- return true;
-}
-
-bool CachedFrame::checkVisited(const CachedNode* node, Direction direction) const
-{
- return history()->checkVisited(node, direction);
-}
-
-void CachedFrame::clearFocus()
-{
- if (mFocus < 0)
- return;
- CachedNode& focus = mCachedNodes[mFocus];
- focus.clearFocus(this);
- mFocus = -1;
-}
-
-// the thing that sucks is that when you're on a link, you want to navigate next door to a link just like this one, but can't make it
-// so with all my other sucky compares, maybe there needs to be one that prefers links that are aligned with the current focus...
-
-// 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* focus) const
-{
- if (testData.mNode->tabIndex() != bestData.mNode->tabIndex()) {
- if (testData.mNode->tabIndex() < bestData.mNode->tabIndex()
- || (focus && focus->tabIndex() < bestData.mNode->tabIndex())) {
- testData.mNode->setCondition(CachedNode::HIGHER_TAB_INDEX);
- return REJECT_TEST;
- }
- return TEST_IS_BEST;
- }
-// start here;
- // if the test minor axis line intersects the line segment between focus center and best center, choose it
- // give more weight to exact major axis alignment (rows, columns)
- if (testData.mInNav != bestData.mInNav) {
- if (bestData.mInNav) {
- testData.mNode->setCondition(CachedNode::IN_FOCUS);
- return REJECT_TEST;
- }
- return TEST_IS_BEST;
- }
- if (testData.mInNav) {
- if (bestData.mMajorDelta < testData.mMajorDelta) {
- testData.mNode->setCondition(CachedNode::CLOSER_IN_FOCUS);
- return REJECT_TEST;
- }
- if (testData.mMajorDelta < bestData.mMajorDelta)
- return TEST_IS_BEST;
- }
- if (testData.mMajorDelta < 0 && bestData.mMajorDelta >= 0) {
- testData.mNode->setCondition(CachedNode::FURTHER);
- return REJECT_TEST;
- }
- if ((testData.mMajorDelta ^ bestData.mMajorDelta) < 0) // one above, one below (or one left, one right)
- return TEST_IS_BEST;
-// SkFixed focusMultiplier = SK_Fixed1;
-// if (focus != NULL) {
-// if (testData.mMajorDelta < bestData.mMajorDelta) {
-// // use bestData.mMajorDelta,
-// } else if (bestData.mMajorDelta < testData.mMajorDelta) {
-//
-// }
- bool bestInWorking = bestData.inOrSubsumesWorking();
- bool testInWorking = testData.inOrSubsumesWorking();
- if (bestInWorking && testData.mWorkingOutside && testData.mNavOutside) {
- testData.mNode->setCondition(CachedNode::IN_WORKING);
- return REJECT_TEST;
- }
- if (testInWorking && bestData.mWorkingOutside && bestData.mNavOutside)
- return TEST_IS_BEST;
- bool bestInNav = directionChange() && bestData.inOrSubsumesNav();
- bool testInNav = directionChange() && testData.inOrSubsumesNav();
- if (bestInWorking == false && testInWorking == false) {
- if (bestInNav && testData.mNavOutside) {
- testData.mNode->setCondition(CachedNode::IN_UMBRA);
- return REJECT_TEST;
- }
- if (testInNav && bestData.mNavOutside)
- return TEST_IS_BEST;
- }
-#if 01 // hopefully butt test will remove need for this
- if (testData.mFocusChild != bestData.mFocusChild) {
- if (bestData.mFocusChild) {
- testData.mNode->setCondition(CachedNode::IN_FOCUS_CHILDREN);
- return REJECT_TEST;
- }
- return TEST_IS_BEST;
- }
-#endif
- bool bestTestIn = (bestInWorking || bestInNav) && (testInWorking || testInNav);
- bool testOverlap = bestTestIn || (testData.mWorkingOverlap != 0 && bestData.mWorkingOverlap == 0);
- bool bestOverlap = bestTestIn || (testData.mWorkingOverlap == 0 && bestData.mWorkingOverlap != 0);
-#if 01 // this isn't working?
- if (testOverlap == bestOverlap) {
- if (bestData.mMajorButt < 10 && testData.mMajorButt >= 40) {
- testData.mNode->setCondition(CachedNode::BUTTED_UP);
- return REJECT_TEST;
- }
- if (testData.mMajorButt < 10 && bestData.mMajorButt >= 40)
- return TEST_IS_BEST;
- }
-#endif
- if (bestOverlap && bestData.mMajorDelta < testData.mMajorDelta) { // choose closest major axis center
- testData.mNode->setCondition(CachedNode::CLOSER);
- return REJECT_TEST;
- }
- if (testOverlap && testData.mMajorDelta < bestData.mMajorDelta)
- return TEST_IS_BEST;
- if (bestOverlap && bestData.mMajorDelta2 < testData.mMajorDelta2) {
- testData.mNode->setCondition(CachedNode::CLOSER_TOP);
- return REJECT_TEST;
- }
- if (testOverlap && testData.mMajorDelta2 < bestData.mMajorDelta2)
- return TEST_IS_BEST;
-#if 01
- if (bestOverlap && ((bestData.mSideDistance <= 0 && testData.mSideDistance > 0) ||
- abs(bestData.mSideDistance) < abs(testData.mSideDistance))) {
- testData.mNode->setCondition(CachedNode::LEFTMOST);
- return REJECT_TEST;
- }
- if (testOverlap && ((testData.mSideDistance <= 0 && bestData.mSideDistance > 0) ||
- abs(testData.mSideDistance) < abs(bestData.mSideDistance)))
- return TEST_IS_BEST;
-// fix me : the following ASSERT fires -- not sure if this case should be handled or not
-// ASSERT(bestOverlap == false && testOverlap == false);
-#endif
- SkFixed testMultiplier = testData.mWorkingOverlap > testData.mNavOverlap ?
- testData.mWorkingOverlap : testData.mNavOverlap;
- SkFixed bestMultiplier = bestData.mWorkingOverlap > bestData.mNavOverlap ?
- bestData.mWorkingOverlap : bestData.mNavOverlap;
- int testDistance = testData.mDistance;
- int bestDistance = bestData.mDistance;
-// start here;
- // this fails if they're off by 1
- // try once again to implement sliding scale so that off by 1 is nearly like zero,
- // and off by a lot causes sideDistance to have little or no effect
- // try elliptical distance -- lengthen side contribution
- // these ASSERTs should not fire, but do fire on mail.google.com
- // can't debug yet, won't reproduce
- ASSERT(testDistance >= 0);
- ASSERT(bestDistance >= 0);
- testDistance += testDistance; // multiply by 2
- testDistance *= testDistance;
- bestDistance += bestDistance; // multiply by 2
- bestDistance *= bestDistance;
- int side = testData.mSideDistance;
- int negative = side < 0 && bestData.mSideDistance > 0;
- side *= side;
- if (negative)
- side = -side;
- testDistance += side;
- side = bestData.mSideDistance;
- negative = side < 0 && testData.mSideDistance > 0;
- side *= side;
- if (negative)
- side = -side;
- bestDistance += side;
- if (testMultiplier > (SK_Fixed1 >> 1) || bestMultiplier > (SK_Fixed1 >> 1)) { // considerable working overlap?
- testDistance = SkFixedMul(testDistance, bestMultiplier);
- bestDistance = SkFixedMul(bestDistance, testMultiplier);
- }
- if (bestDistance < testDistance) {
- testData.mNode->setCondition(CachedNode::CLOSER_OVERLAP);
- return REJECT_TEST;
- }
- if (testDistance < bestDistance)
- return TEST_IS_BEST;
-#if 0
- int distance = testData.mDistance + testData.mSideDistance;
- int best = bestData.mDistance + bestData.mSideDistance;
- if (distance > best) {
- testData.mNode->setCondition(CachedNode::CLOSER_RAW_DISTANCE);
- return REJECT_TEST;
- }
- else if (distance < best)
- return TEST_IS_BEST;
- best = bestData.mSideDistance;
- if (testData.mSideDistance > best) {
- testData.mNode->setCondition(CachedNode::SIDE_DISTANCE);
- return REJECT_TEST;
- }
- if (testData.mSideDistance < best)
- return TEST_IS_BEST;
-#endif
- if (testData.mPreferred < bestData.mPreferred) {
- testData.mNode->setCondition(CachedNode::PREFERRED);
- return REJECT_TEST;
- }
- if (testData.mPreferred > bestData.mPreferred)
- return TEST_IS_BEST;
- return UNDECIDED;
-}
-
-const CachedNode* CachedFrame::currentFocus(const CachedFrame** framePtr) const
-{
- if (framePtr)
- *framePtr = this;
- if (mFocus < 0)
- return NULL;
- const CachedNode* result = &mCachedNodes[mFocus];
- const CachedFrame* frame = hasFrame(result);
- if (frame != NULL)
- return frame->currentFocus(framePtr);
- (const_cast<CachedNode*>(result))->fixUpFocusRects();
- return result;
-}
-
-bool CachedFrame::directionChange() const
-{
- return history()->directionChange();
-}
-
-#ifdef BROWSER_DEBUG
-CachedNode* CachedFrame::find(WebCore::Node* node) // !!! probably debugging only
-{
- for (CachedNode* test = mCachedNodes.begin(); test != mCachedNodes.end(); test++)
- if (node == test->webCoreNode())
- return test;
- for (CachedFrame* frame = mCachedFrames.begin(); frame != mCachedFrames.end();
- frame++) {
- CachedNode* result = frame->find(node);
- if (result != NULL)
- return result;
- }
- return NULL;
-}
-#endif
-
-const CachedNode* CachedFrame::findBestAt(const WebCore::IntRect& rect,
- int* best, const CachedNode** directHit, const CachedFrame** framePtr, int* x, int* y) const
-{
- const CachedNode* result = NULL;
- int rectWidth = rect.width();
- WebCore::IntPoint center = WebCore::IntPoint(rect.x() + (rectWidth >> 1),
- rect.y() + (rect.height() >> 1));
- mRoot->setupScrolledBounds();
- for (const CachedNode* test = mCachedNodes.begin(); test != mCachedNodes.end(); test++) {
- if (test->disabled())
- continue;
- size_t parts = test->navableRects();
- BestData testData;
- testData.mNode = test;
- testData.mMouseBounds = testData.mNodeBounds = test->getBounds();
- bool checkForHidden = true;
- for (size_t part = 0; part < parts; part++) {
- if (test->focusRings().at(part).intersects(rect)) {
- if (checkForHidden && mRoot->maskIfHidden(&testData) == true)
- break;
- checkForHidden = false;
- WebCore::IntRect testRect = test->focusRings().at(part);
- testRect.intersect(testData.mMouseBounds);
- if (testRect.contains(center)) {
- // We have a direct hit.
- if (*directHit == NULL) {
- *directHit = test;
- *framePtr = this;
- *x = center.x();
- *y = center.y();
- } else {
- // We have hit another one before
- const CachedNode* d = *directHit;
- if (d->getBounds().contains(testRect)) {
- // This rectangle is inside the other one, so it is
- // the best one.
- *directHit = test;
- *framePtr = this;
- }
- }
- }
- if (NULL != *directHit) {
- // If we have a direct hit already, there is no need to
- // calculate the distances, or check the other focusring parts
- break;
- }
- WebCore::IntRect both = rect;
- int smaller = testRect.width() < testRect.height() ?
- testRect.width() : testRect.height();
- smaller -= rectWidth;
- int inset = smaller < rectWidth ? smaller : rectWidth;
- inset >>= 1; // inflate doubles the width decrease
- if (inset > 1)
- both.inflate(1 - inset);
- both.intersect(testRect);
- if (both.isEmpty())
- continue;
- WebCore::IntPoint testCenter = WebCore::IntPoint(testRect.x() +
- (testRect.width() >> 1), testRect.y() + (testRect.height() >> 1));
- int dx = testCenter.x() - center.x();
- int dy = testCenter.y() - center.y();
- int distance = dx * dx + dy * dy;
- if (*best > distance) {
- *best = distance;
- result = test;
- *framePtr = this;
- *x = both.x() + (both.width() >> 1);
- *y = both.y() + (both.height() >> 1);
- }
- }
- }
- }
- for (const CachedFrame* frame = mCachedFrames.begin();
- frame != mCachedFrames.end(); frame++) {
- const CachedNode* frameResult = frame->findBestAt(rect, best, directHit,
- framePtr, x, y);
- if (NULL != frameResult)
- result = frameResult;
- }
- if (NULL != *directHit) {
- result = *directHit;
- }
- return result;
-}
-
-const CachedFrame* CachedFrame::findBestFrameAt(int x, int y) const
-{
- if (mLocalViewBounds.contains(x, y) == false)
- return NULL;
- const CachedFrame* result = this;
- for (const CachedFrame* frame = mCachedFrames.begin();
- frame != mCachedFrames.end(); frame++) {
- const CachedFrame* frameResult = frame->findBestFrameAt(x, y);
- if (NULL != frameResult)
- result = frameResult;
- }
- return result;
-}
-
-const CachedNode* CachedFrame::findBestHitAt(const WebCore::IntRect& rect,
- int* best, const CachedFrame** framePtr, int* x, int* y) const
-{
- const CachedNode* result = NULL;
- int rectWidth = rect.width();
- WebCore::IntPoint center = WebCore::IntPoint(rect.x() + (rectWidth >> 1),
- rect.y() + (rect.height() >> 1));
- mRoot->setupScrolledBounds();
- for (const CachedNode* test = mCachedNodes.begin(); test != mCachedNodes.end(); test++) {
- if (test->disabled())
- continue;
- const WebCore::IntRect& testRect = test->hitBounds();
- if (testRect.intersects(rect) == false)
- continue;
- BestData testData;
- testData.mNode = test;
- testData.mMouseBounds = testData.mNodeBounds = testRect;
- if (mRoot->maskIfHidden(&testData) == true)
- continue;
- const WebCore::IntRect& bounds = testData.mMouseBounds;
- WebCore::IntPoint testCenter = WebCore::IntPoint(bounds.x() +
- (bounds.width() >> 1), bounds.y() + (bounds.height() >> 1));
- int dx = testCenter.x() - center.x();
- int dy = testCenter.y() - center.y();
- int distance = dx * dx + dy * dy;
- if (*best <= distance)
- continue;
- *best = distance;
- result = test;
- *framePtr = this;
- const WebCore::IntRect& focusRect = test->focusRings().at(0);
- *x = focusRect.x() + (focusRect.width() >> 1);
- *y = focusRect.y() + (focusRect.height() >> 1);
- }
- for (const CachedFrame* frame = mCachedFrames.begin();
- frame != mCachedFrames.end(); frame++) {
- const CachedNode* frameResult = frame->findBestHitAt(rect, best,
- framePtr, x, y);
- if (NULL != frameResult)
- result = frameResult;
- }
- return result;
-}
-
-void CachedFrame::findClosest(BestData* bestData, Direction originalDirection,
- Direction direction, WebCore::IntRect* clip) const
-{
- const CachedNode* test = mCachedNodes.begin();
- while ((test = test->traverseNextNode()) != NULL) {
- const CachedFrame* child = hasFrame(test);
- if (child != NULL) {
- const CachedNode* childDoc = child->validDocument();
- if (childDoc == NULL)
- continue;
- child->findClosest(bestData, originalDirection, direction, clip);
- }
- if (test->noSecondChance())
- continue;
- if (test->isFocusable(*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->focusRings().at(part);
- if (clip->intersects(testBounds) == false)
- continue;
- if (clip->contains(testBounds) == false) {
- if (direction & UP_DOWN) {
-// if (testBounds.x() > clip->x() || testBounds.right() < clip->right())
-// continue;
- testBounds.setX(clip->x());
- testBounds.setWidth(clip->width());
- } else {
-// if (testBounds.y() > clip->y() || testBounds.bottom() < clip->bottom())
-// continue;
- testBounds.setY(clip->y());
- testBounds.setHeight(clip->height());
- }
- if (clip->contains(testBounds) == false)
- continue;
- }
- int distance;
- // seems like distance for UP for instance needs to be 'test top closest to
- // clip bottom' -- keep the old code but try this instead
- switch (direction) {
-#if 0
- case LEFT: distance = testBounds.x() - clip->x(); break;
- case RIGHT: distance = clip->right() - testBounds.right(); break;
- case UP: distance = testBounds.y() - clip->y(); break;
- case DOWN: distance = clip->bottom() - testBounds.bottom(); break;
-#else
- case LEFT: distance = clip->right() - testBounds.x(); break;
- case RIGHT: distance = testBounds.right() - clip->x(); break;
- case UP: distance = clip->bottom() - testBounds.y(); break;
- case DOWN: distance = testBounds.bottom() - clip->y(); break;
-#endif
- default:
- distance = 0; ASSERT(0);
- }
- if (distance < bestData->mDistance) {
- bestData->mNode = test;
- bestData->mFrame = this;
- bestData->mDistance = distance;
- bestData->mMouseBounds = bestData->mNodeBounds =
- test->focusRings().at(part);
- CachedHistory* cachedHistory = history();
- switch (direction) {
- case LEFT:
- bestData->setLeftDirection(cachedHistory);
- break;
- case RIGHT:
- bestData->setRightDirection(cachedHistory);
- break;
- case UP:
- bestData->setUpDirection(cachedHistory);
- break;
- case DOWN:
- bestData->setDownDirection(cachedHistory);
- break;
- default:
- ASSERT(0);
- }
- }
- }
- }
-}
-
-bool CachedFrame::finishInit()
-{
- CachedNode* lastCached = lastNode();
- lastCached->setLast();
- CachedFrame* child = mCachedFrames.begin();
- while (child != mCachedFrames.end()) {
- child->mParent = this;
- if (child->finishInit())
- setFocusIndex(child->indexInParent());
- child++;
- }
- return focusIndex() > 0;
-}
-
-const CachedNode* CachedFrame::frameDown(const CachedNode* test, const CachedNode* limit, BestData* bestData,
- const CachedNode* focus) const
-{
- BestData originalData = *bestData;
- do {
- if (moveInFrame(&CachedFrame::frameDown, test, bestData, focus))
- continue;
- BestData testData;
- if (frameNodeCommon(testData, test, bestData, &originalData, focus) == 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->focusRings().at(part);
- if (testData.setDownDirection(history()))
- continue;
- int result = framePartCommon(testData, test, bestData, focus);
- 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, focus);
- if (checkVisited(innerData.mNode, DOWN)) {
- *bestData = innerData;
- continue;
- }
- }
- if (checkVisited(test, DOWN))
- *bestData = testData;
- }
- } while ((test = test->traverseNextNode()) != limit);
- ASSERT(focus == NULL || bestData->mNode != focus);
- // does the best contain something (or, is it contained by an area which is not the focus?)
- // 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
- //
- return bestData->mNode;
-}
-
-const CachedNode* CachedFrame::frameLeft(const CachedNode* test, const CachedNode* limit, BestData* bestData,
- const CachedNode* focus) const
-{
- BestData originalData = *bestData;
- do {
- if (moveInFrame(&CachedFrame::frameLeft, test, bestData, focus))
- continue;
- BestData testData;
- if (frameNodeCommon(testData, test, bestData, &originalData, focus) == 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->focusRings().at(part);
- if (testData.setLeftDirection(history()))
- continue;
- int result = framePartCommon(testData, test, bestData, focus);
- 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, focus);
- if (checkVisited(innerData.mNode, LEFT)) {
- *bestData = innerData;
- continue;
- }
- }
- if (checkVisited(test, LEFT))
- *bestData = testData;
- }
- } while ((test = test->traverseNextNode()) != limit); // FIXME ??? left and up should use traversePreviousNode to choose reverse document order
- ASSERT(focus == NULL || bestData->mNode != focus);
- return bestData->mNode;
-}
-
-int CachedFrame::frameNodeCommon(BestData& testData, const CachedNode* test, BestData* bestData, BestData* originalData,
- const CachedNode* focus) const
-{
- testData.mFrame = this;
- testData.mNode = test;
- test->clearCondition();
- if (test->disabled()) {
- testData.mNode->setCondition(CachedNode::DISABLED);
- return REJECT_TEST;
- }
- if (mRoot->scrolledBounds().intersects(test->bounds()) == false) {
- testData.mNode->setCondition(CachedNode::FOCUSABLE);
- return REJECT_TEST;
- }
-// if (isFocusable(test, &testData.mNodeBounds, walk) == false) {
-// testData.mNode->setCondition(CachedNode::FOCUSABLE);
-// return REJECT_TEST;
-// }
-//
- if (test == focus) {
- testData.mNode->setCondition(CachedNode::NOT_FOCUS_NODE);
- return REJECT_TEST;
- }
-// if (test->bounds().contains(mRoot->focusBounds())) {
-// testData.mNode->setCondition(CachedNode::NOT_ENCLOSING_FOCUS);
-// return REJECT_TEST;
-// }
- void* par = focus ? focus->parentGroup() : NULL;
- testData.mFocusChild = test->parentGroup() == par;
-#if 0 // not debugged
- if (focus && focus->hasMouseOver() && test->hasMouseOver() == false &&
- focus->bounds().contains(test->bounds()))
- return REJECT_TEST;
-#endif
- if (bestData->mNode == NULL)
- return TEST_IS_BEST;
-#if 0 // not debugged
- if (focus && focus->hasMouseOver() && test->hasMouseOver() == false &&
- focus->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 (focus && testData.mNode->parentIndex() != bestData->mNode->parentIndex()) {
- int focusParentIndex = focus->parentIndex();
- if (focusParentIndex >= 0) {
- if (bestData->mNode->parentIndex() == focusParentIndex)
- return REJECT_TEST;
- if (testData.mNode->parentIndex() == focusParentIndex)
- return TEST_IS_BEST;
- }
- }
- if (testData.mNode->parent() == bestData->mNode) {
- testData.mNode->setCondition(CachedNode::CHILD);
- return REJECT_TEST;
- }
- if (testData.mNode == bestData->mNode->parent())
- return TEST_IS_BEST;
- int testInBest = testData.isContainer(bestData); /* -1 pick best over test, 0 no containership, 1 pick test over best */
- if (testInBest == 1) {
- if (test->isArea() || bestData->mNode->isArea())
- return UNDECIDED;
- bestData->mNode = NULL; // force part tests to be ignored, yet still set up remaining test data for later comparisons
- return TEST_IS_BEST;
- }
- if (testInBest == -1) {
- testData.mNode->setCondition(CachedNode::OUTSIDE_OF_BEST);
- return REJECT_TEST;
- }
- if (originalData->mNode != NULL) { // test is best case
- testInBest = testData.isContainer(originalData);
- if (testInBest == -1) { /* test is inside best */
- testData.mNode->setCondition(CachedNode::OUTSIDE_OF_ORIGINAL);
- return REJECT_TEST;
- }
- }
- return UNDECIDED;
-}
-
-int CachedFrame::framePartCommon(BestData& testData,
- const CachedNode* test, BestData* bestData, const CachedNode* focus) const
-{
- if (testData.mNodeBounds.contains(mRoot->focusBounds())) {
- testData.mNode->setCondition(CachedNode::NOT_ENCLOSING_FOCUS);
- return REJECT_TEST;
- }
- testData.setDistances();
- if (bestData->mNode != NULL) {
- int compared = compare(testData, *bestData, focus);
- if (compared == 0 && test->isArea() == false && bestData->mNode->isArea() == false)
- goto pickTest;
- if (compared >= 0)
- return compared;
- }
-pickTest:
- return -1; // pick test
-}
-
-const CachedNode* CachedFrame::frameRight(const CachedNode* test, const CachedNode* limit, BestData* bestData,
- const CachedNode* focus) const
-{
- BestData originalData = *bestData;
- do {
- if (moveInFrame(&CachedFrame::frameRight, test, bestData, focus))
- continue;
- BestData testData;
- if (frameNodeCommon(testData, test, bestData, &originalData, focus) == 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->focusRings().at(part);
- if (testData.setRightDirection(history()))
- continue;
- int result = framePartCommon(testData, test, bestData, focus);
- 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, focus);
- if (checkVisited(innerData.mNode, RIGHT)) {
- *bestData = innerData;
- continue;
- }
- }
- if (checkVisited(test, RIGHT))
- *bestData = testData;
- }
- } while ((test = test->traverseNextNode()) != limit);
- ASSERT(focus == NULL || bestData->mNode != focus);
- return bestData->mNode;
-}
-
-const CachedNode* CachedFrame::frameUp(const CachedNode* test, const CachedNode* limit, BestData* bestData,
- const CachedNode* focus) const
-{
- BestData originalData = *bestData;
- do {
- if (moveInFrame(&CachedFrame::frameUp, test, bestData, focus))
- continue;
- BestData testData;
- if (frameNodeCommon(testData, test, bestData, &originalData, focus) == 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->focusRings().at(part);
- if (testData.setUpDirection(history()))
- continue;
- int result = framePartCommon(testData, test, bestData, focus);
- 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, focus);
- if (checkVisited(innerData.mNode, UP)) {
- *bestData = innerData;
- continue;
- }
- }
- if (checkVisited(test, UP))
- *bestData = testData;
- }
- } while ((test = test->traverseNextNode()) != limit); // FIXME ??? left and up should use traversePreviousNode to choose reverse document order
- ASSERT(focus == NULL || bestData->mNode != focus);
- return bestData->mNode;
-}
-
-const CachedFrame* CachedFrame::hasFrame(const CachedNode* node) const
-{
- return node->isFrame() ? &mCachedFrames[node->childFrameIndex()] : NULL;
-}
-
-CachedHistory* CachedFrame::history() const
-{
- return mRoot->rootHistory();
-}
-
-void CachedFrame::init(const CachedRoot* root, int childFrameIndex,
- WebCore::Frame* frame)
-{
- mContents = WebCore::IntRect(0, 0, 0, 0); // fixed up for real in setData()
- mLocalViewBounds = WebCore::IntRect(0, 0, 0, 0);
- mViewBounds = WebCore::IntRect(0, 0, 0, 0);
- mRoot = root;
- mFocus = -1;
- mFrame = frame;
- mParent = NULL; // set up parents after stretchy arrays are set up
- mIndex = childFrameIndex;
-}
-
-int CachedFrame::minWorkingHorizontal() const
-{
- return history()->minWorkingHorizontal();
-}
-
-int CachedFrame::minWorkingVertical() const
-{
- return history()->minWorkingVertical();
-}
-
-int CachedFrame::maxWorkingHorizontal() const
-{
- return history()->maxWorkingHorizontal();
-}
-
-int CachedFrame::maxWorkingVertical() const
-{
- return history()->maxWorkingVertical();
-}
-
-bool CachedFrame::moveInFrame(MoveInDirection moveInDirection,
- const CachedNode* test, BestData* bestData,
- const CachedNode* focus) const
-{
- const CachedFrame* frame = hasFrame(test);
- if (frame == NULL)
- return false; // if it's not a frame, let the caller have another swing at it
- const CachedNode* childDoc = frame->validDocument();
- if (childDoc == NULL)
- return true;
- (frame->*moveInDirection)(childDoc, NULL, bestData, focus);
- return true;
-}
-
-const WebCore::IntRect& CachedFrame::_navBounds() const
-{
- return history()->navBounds();
-}
-
-void CachedFrame::resetClippedOut()
-{
- for (CachedNode* test = mCachedNodes.begin(); test != mCachedNodes.end(); test++)
- {
- if (test->clippedOut()) {
- test->setDisabled(false);
- test->setClippedOut(false);
- }
- }
- for (CachedFrame* frame = mCachedFrames.begin(); frame != mCachedFrames.end();
- frame++) {
- frame->resetClippedOut();
- }
-}
-
-bool CachedFrame::sameFrame(const CachedFrame* test) const
-{
- ASSERT(test);
- if (mIndex != test->mIndex)
- return false;
- if (mIndex == -1) // index within parent's array of children, or -1 if root
- return true;
- return mParent->sameFrame(test->mParent);
-}
-
-void CachedFrame::setData()
-{
- if (this != mRoot) {
- mViewBounds = mLocalViewBounds;
- mViewBounds.intersect(mRoot->mViewBounds);
- }
- int x, y;
- if (parent() == NULL)
- x = y = 0;
- else {
- x = mLocalViewBounds.x();
- y = mLocalViewBounds.y();
- }
- mContents.setX(x);
- mContents.setY(y);
- CachedFrame* child = mCachedFrames.begin();
- while (child != mCachedFrames.end()) {
- child->setData();
- child++;
- }
-}
-
-bool CachedFrame::setFocus(WebCore::Frame* frame, WebCore::Node* node,
- int x, int y)
-{
- if (NULL == node) {
- const_cast<CachedRoot*>(mRoot)->setCachedFocus(NULL, NULL);
- return true;
- }
- if (mFrame != frame) {
- for (CachedFrame* testF = mCachedFrames.begin(); testF != mCachedFrames.end();
- testF++) {
- if (testF->setFocus(frame, node, x, y))
- return true;
- }
- DBG_NAV_LOGD("no frame frame=%p node=%p", frame, node);
- return false;
- }
- bool first = true;
- CachedNode const * const end = mCachedNodes.end();
- do {
- for (CachedNode* test = mCachedNodes.begin(); test != end; test++) {
- if (test->nodePointer() != node && first)
- continue;
- size_t partMax = test->navableRects();
- WTF::Vector<WebCore::IntRect>& focusRings = test->focusRings();
- for (size_t part = 0; part < partMax; part++) {
- const WebCore::IntRect& testBounds = focusRings.at(part);
- if (testBounds.contains(x, y) == false)
- continue;
- if (test->isFocus()) {
- DBG_NAV_LOGD("already set? test=%d frame=%p node=%p x=%d y=%d",
- test->index(), frame, node, x, y);
- return true;
- }
- const_cast<CachedRoot*>(mRoot)->setCachedFocus(this, test);
- return true;
- }
- }
- DBG_NAV_LOGD("moved? frame=%p node=%p x=%d y=%d", frame, node, x, y);
- } while ((first ^= true) == false);
-failed:
- DBG_NAV_LOGD("no match frame=%p node=%p", frame, node);
- return false;
-}
-
-const CachedNode* CachedFrame::validDocument() const
-{
- const CachedNode* doc = document();
- return doc != NULL && mViewBounds.isEmpty() == false ? doc : NULL;
-}
-
-bool CachedFrame::BestData::canBeReachedByAnotherDirection()
-{
- if (mMajorButt > -MIN_OVERLAP)
- return false;
- mMajorButt = -mMajorButt;
- return mNavOutside;
-}
-
-int CachedFrame::BestData::isContainer(CachedFrame::BestData* other)
-{
- int _x = x();
- int otherRight = other->right();
- if (_x >= otherRight)
- return 0; // does not intersect
- int _y = y();
- int otherBottom = other->bottom();
- if (_y >= otherBottom)
- return 0; // does not intersect
- int _right = right();
- int otherX = other->x();
- if (otherX >= _right)
- return 0; // does not intersect
- int _bottom = bottom();
- int otherY = other->y();
- if (otherY >= _bottom)
- return 0; // does not intersect
- int intoX = otherX - _x;
- int intoY = otherY - _y;
- int intoRight = otherRight - _right;
- int intoBottom = otherBottom - _bottom;
- bool contains = intoX >= 0 && intoY >= 0 && intoRight <= 0 && intoBottom <= 0;
- if (contains && mNode->partRectsContains(other->mNode)) {
-// if (mIsArea == false && hasMouseOver())
-// other->mMouseOver = mNode;
- return mNode->isArea() ? 1 : -1;
- }
- bool containedBy = intoX <= 0 && intoY <= 0 && intoRight >= 0 && intoBottom >= 0;
- if (containedBy && other->mNode->partRectsContains(mNode)) {
-// if (other->mIsArea == false && other->hasMouseOver())
-// mMouseOver = other->mNode;
- return other->mNode->isArea() ? -1 : 1;
- }
- return 0;
-}
-
-// distance scale factor factor as a 16.16 scalar
-SkFixed CachedFrame::BestData::Overlap(int span, int left, int right)
-{
- unsigned result;
- if (left > 0 && left < span && right > span)
- result = (unsigned) left;
- else if (right > 0 && right < span && left > span)
- result = (unsigned) right;
- else if (left > 0 && right > 0)
- return SK_Fixed1;
- else
- return 0;
- result = (result << 16) / (unsigned) span; // linear proportion, always less than fixed 1
- return (SkFixed) result;
-// !!! experiment with weight -- enable if overlaps are preferred too much
-// or reverse weighting if overlaps are preferred to little
-// return (SkFixed) (result * result >> 16); // but fall off with square
-}
-
-void CachedFrame::BestData::setDistances()
-{
- mDistance = abs(mMajorDelta);
- int sideDistance = mWorkingDelta;
- if (mWorkingOverlap < SK_Fixed1) {
- if (mPreferred > 0)
- sideDistance = mWorkingDelta2;
- } else if (sideDistance >= 0 && mWorkingDelta2 >=- 0)
- sideDistance = 0;
- else {
- ASSERT(sideDistance <= 0 && mWorkingDelta2 <= 0);
- if (sideDistance < mWorkingDelta2)
- sideDistance = mWorkingDelta2;
- }
- // if overlap, smaller abs mWorkingDelta is better, smaller abs majorDelta is better
- // if not overlap, positive mWorkingDelta is better
- mSideDistance = sideDistance;
-}
-
-bool CachedFrame::BestData::setDownDirection(const CachedHistory* history)
-{
- const WebCore::IntRect& navBounds = history->navBounds();
- mMajorButt = mNodeBounds.y() - navBounds.bottom();
- int testX = mNodeBounds.x();
- int testRight = mNodeBounds.right();
- setNavOverlap(navBounds.width(), navBounds.right() - testX,
- testRight - navBounds.x());
- if (canBeReachedByAnotherDirection()) {
- mNode->setCondition(CachedNode::BEST_DIRECTION);
- return REJECT_TEST;
- }
- int inNavTop = mNodeBounds.y() - navBounds.y();
- mMajorDelta2 = inNavTop;
- mMajorDelta = mMajorDelta2 + ((mNodeBounds.height() -
- navBounds.height()) >> 1);
- if (mMajorDelta2 <= 1 && mMajorDelta <= 1) {
- mNode->setCondition(CachedNode::CENTER_FURTHER); // never move up or sideways
- return REJECT_TEST;
- }
- int inNavBottom = navBounds.bottom() - mNodeBounds.bottom();
- setNavInclusion(testRight - navBounds.right(), navBounds.x() - testX);
- bool subsumes = navBounds.height() > 0 && inOrSubsumesNav();
- if (inNavTop <= 0 && inNavBottom <= 0 && subsumes) {
- mNode->setCondition(CachedNode::NOT_ENCLOSING_FOCUS);
- return REJECT_TEST;
- }
- int maxV = history->maxWorkingVertical();
- int minV = history->minWorkingVertical();
- setWorkingOverlap(testRight - testX, maxV - testX, testRight - minV);
- setWorkingInclusion(testRight - maxV, minV - testX);
- if (mWorkingOverlap == 0 && mNavOverlap == 0 && inNavBottom >= 0) {
- mNode->setCondition(CachedNode::OVERLAP_OR_EDGE_FURTHER);
- return REJECT_TEST;
- }
- mInNav = history->directionChange() && inNavTop >= 0 &&
- inNavBottom > 0 && subsumes;
- return false;
-}
-
-bool CachedFrame::BestData::setLeftDirection(const CachedHistory* history)
-{
- const WebCore::IntRect& navBounds = history->navBounds();
- mMajorButt = navBounds.x() - mNodeBounds.right();
- int testY = mNodeBounds.y();
- int testBottom = mNodeBounds.bottom();
- setNavOverlap(navBounds.height(), navBounds.bottom() - testY,
- testBottom - navBounds.y());
- if (canBeReachedByAnotherDirection()) {
- mNode->setCondition(CachedNode::BEST_DIRECTION);
- return REJECT_TEST;
- }
- int inNavRight = navBounds.right() - mNodeBounds.right();
- mMajorDelta2 = inNavRight;
- mMajorDelta = mMajorDelta2 - ((navBounds.width() -
- mNodeBounds.width()) >> 1);
- if (mMajorDelta2 <= 1 && mMajorDelta <= 1) {
- mNode->setCondition(CachedNode::CENTER_FURTHER); // never move right or sideways
- return REJECT_TEST;
- }
- int inNavLeft = mNodeBounds.x() - navBounds.x();
- setNavInclusion(navBounds.y() - testY, testBottom - navBounds.bottom());
- bool subsumes = navBounds.width() > 0 && inOrSubsumesNav();
- if (inNavLeft <= 0 && inNavRight <= 0 && subsumes) {
- mNode->setCondition(CachedNode::NOT_ENCLOSING_FOCUS);
- return REJECT_TEST;
- }
- int maxH = history->maxWorkingHorizontal();
- int minH = history->minWorkingHorizontal();
- setWorkingOverlap(testBottom - testY, maxH - testY, testBottom - minH);
- setWorkingInclusion(minH - testY, testBottom - maxH);
- if (mWorkingOverlap == 0 && mNavOverlap == 0 && inNavLeft >= 0) {
- mNode->setCondition(CachedNode::OVERLAP_OR_EDGE_FURTHER);
- return REJECT_TEST;
- }
- mInNav = history->directionChange() && inNavLeft >= 0 &&
- inNavRight > 0 && subsumes; /* both L/R in or out */
- return false;
-}
-
-bool CachedFrame::BestData::setRightDirection(const CachedHistory* history)
-{
- const WebCore::IntRect& navBounds = history->navBounds();
- mMajorButt = mNodeBounds.x() - navBounds.right();
- int testY = mNodeBounds.y();
- int testBottom = mNodeBounds.bottom();
- setNavOverlap(navBounds.height(), navBounds.bottom() - testY,
- testBottom - navBounds.y());
- if (canBeReachedByAnotherDirection()) {
- mNode->setCondition(CachedNode::BEST_DIRECTION);
- return REJECT_TEST;
- }
- int inNavLeft = mNodeBounds.x() - navBounds.x();
- mMajorDelta2 = inNavLeft;
- mMajorDelta = mMajorDelta2 + ((mNodeBounds.width() -
- navBounds.width()) >> 1);
- if (mMajorDelta2 <= 1 && mMajorDelta <= 1) {
- mNode->setCondition(CachedNode::CENTER_FURTHER); // never move left or sideways
- return REJECT_TEST;
- }
- int inNavRight = navBounds.right() - mNodeBounds.right();
- setNavInclusion(testBottom - navBounds.bottom(), navBounds.y() - testY);
- bool subsumes = navBounds.width() > 0 && inOrSubsumesNav();
- if (inNavLeft <= 0 && inNavRight <= 0 && subsumes) {
- mNode->setCondition(CachedNode::NOT_ENCLOSING_FOCUS);
- return REJECT_TEST;
- }
- int maxH = history->maxWorkingHorizontal();
- int minH = history->minWorkingHorizontal();
- setWorkingOverlap(testBottom - testY, testBottom - minH, maxH - testY);
- setWorkingInclusion(testBottom - maxH, minH - testY);
- if (mWorkingOverlap == 0 && mNavOverlap == 0 && inNavRight >= 0) {
- mNode->setCondition(CachedNode::OVERLAP_OR_EDGE_FURTHER);
- return REJECT_TEST;
- }
- mInNav = history->directionChange() && inNavLeft >= 0 &&
- inNavRight > 0 && subsumes; /* both L/R in or out */
- return false;
-}
-
-bool CachedFrame::BestData::setUpDirection(const CachedHistory* history)
-{
- const WebCore::IntRect& navBounds = history->navBounds();
- mMajorButt = navBounds.y() - mNodeBounds.bottom();
- int testX = mNodeBounds.x();
- int testRight = mNodeBounds.right();
- setNavOverlap(navBounds.width(), navBounds.right() - testX,
- testRight - navBounds.x());
- if (canBeReachedByAnotherDirection()) {
- mNode->setCondition(CachedNode::BEST_DIRECTION);
- return REJECT_TEST;
- }
- int inNavBottom = navBounds.bottom() - mNodeBounds.bottom();
- mMajorDelta2 = inNavBottom;
- mMajorDelta = mMajorDelta2 - ((navBounds.height() -
- mNodeBounds.height()) >> 1);
- if (mMajorDelta2 <= 1 && mMajorDelta <= 1) {
- mNode->setCondition(CachedNode::CENTER_FURTHER); // never move down or sideways
- return REJECT_TEST;
- }
- int inNavTop = mNodeBounds.y() - navBounds.y();
- setNavInclusion(navBounds.x() - testX, testRight - navBounds.right());
- bool subsumes = navBounds.height() > 0 && inOrSubsumesNav();
- if (inNavTop <= 0 && inNavBottom <= 0 && subsumes) {
- mNode->setCondition(CachedNode::NOT_ENCLOSING_FOCUS);
- return REJECT_TEST;
- }
- int maxV = history->maxWorkingVertical();
- int minV = history->minWorkingVertical();
- setWorkingOverlap(testRight - testX, testRight - minV, maxV - testX);
- setWorkingInclusion(minV - testX, testRight - maxV);
- if (mWorkingOverlap == 0 && mNavOverlap == 0 && inNavTop >= 0) {
- mNode->setCondition(CachedNode::OVERLAP_OR_EDGE_FURTHER);
- return REJECT_TEST;
- }
- mInNav = history->directionChange() && inNavTop >= 0 &&
- inNavBottom > 0 && subsumes; /* both L/R in or out */
- return false;
-}
-
-void CachedFrame::BestData::setNavInclusion(int left, int right)
-{
- // if left and right <= 0, test node is completely in umbra of focus
- // prefer leftmost center
- // if left and right > 0, test node subsumes focus
- mNavDelta = left;
- mNavDelta2 = right;
-}
-
-void CachedFrame::BestData::setNavOverlap(int span, int left, int right)
-{
- mNavOutside = left < MIN_OVERLAP || right < MIN_OVERLAP; // if left or right < 0, test node is not in umbra of focus
- mNavOverlap = Overlap(span, left, right); // prefer smallest negative left
-}
-
-void CachedFrame::BestData::setWorkingInclusion(int left, int right)
-{
- mWorkingDelta = left;
- mWorkingDelta2 = right;
-}
-
-// distance scale factor factor as a 16.16 scalar
-void CachedFrame::BestData::setWorkingOverlap(int span, int left, int right)
-{
- mWorkingOutside = left < MIN_OVERLAP || right < MIN_OVERLAP; // if left or right < 0, test node is not in umbra of focus
- mWorkingOverlap = Overlap(span, left, right);
- mPreferred = left <= 0 ? 0 : left;
-}
-
-#if DUMP_NAV_CACHE
-
-#define DEBUG_PRINT_RECT(prefix, debugName, field) \
- { const WebCore::IntRect& r = b->field; \
- DUMP_NAV_LOGD("%s DebugTestRect TEST%s_" #debugName "={%d, %d, %d, %d}; //" #field "\n", \
- prefix, mFrameName, r.x(), r.y(), r.width(), r.height()); }
-
-CachedFrame* CachedFrame::Debug::base() const {
- CachedFrame* nav = (CachedFrame*) ((char*) this - OFFSETOF(CachedFrame, mDebug));
- return nav;
-}
-
-void CachedFrame::Debug::print() const
-{
- CachedFrame* b = base();
- 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++)
- node->mDebug.print();
- DUMP_NAV_LOGD("// }; // end of nodes\n");
- DUMP_NAV_LOGD("// CachedFrame mCachedFrames={ // count=%d\n", b->mCachedFrames.size());
- for (CachedFrame* child = b->mCachedFrames.begin();
- child != b->mCachedFrames.end(); child++)
- {
- child->mDebug.print();
- }
- DUMP_NAV_LOGD("// }; // end of child frames\n");
- DUMP_NAV_LOGD("// void* mFrame=(void*) %p;\n", b->mFrame);
- DUMP_NAV_LOGD("// CachedFrame* mParent=%p;\n", b->mParent);
- DUMP_NAV_LOGD("// int mIndex=%d;\n", b->mIndex);
- DUMP_NAV_LOGD("// const CachedRoot* mRoot=%p;\n", b->mRoot);
- DUMP_NAV_LOGD("// int mFocus=%d;\n", b->mFocus);
-}
-
-bool CachedFrame::Debug::validate(const CachedNode* node) const
-{
- const CachedFrame* b = base();
- if (b->mCachedNodes.size() == 0)
- return false;
- if (node >= b->mCachedNodes.begin() && node < b->mCachedNodes.end())
- return true;
- for (const CachedFrame* child = b->mCachedFrames.begin();
- child != b->mCachedFrames.end(); child++)
- if (child->mDebug.validate(node))
- return true;
- return false;
-}
-
-#undef DEBUG_PRINT_RECT
-
-#endif
-
-}
diff --git a/WebKit/android/nav/CachedFrame.h b/WebKit/android/nav/CachedFrame.h
deleted file mode 100644
index 8e77470..0000000
--- a/WebKit/android/nav/CachedFrame.h
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- * Copyright 2007, 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 APPLE COMPUTER, INC. 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 CachedFrame_H
-#define CachedFrame_H
-
-#include "CachedNode.h"
-#include "IntRect.h"
-#include "SkFixed.h"
-#include "wtf/Vector.h"
-
-namespace WebCore {
- class Frame;
- class Node;
-}
-
-namespace android {
-
-class CachedHistory;
-class CachedRoot;
-
- // first node referenced by cache is always document
-class CachedFrame {
-public:
- enum Direction {
- UNINITIALIZED = -1,
- LEFT,
- RIGHT,
- UP,
- DOWN,
- DIRECTION_COUNT,
- DIRECTION_MASK = DIRECTION_COUNT - 1,
- UP_DOWN = UP & DOWN, // mask and result
- RIGHT_DOWN = RIGHT & DOWN, // mask and result
- };
- enum Compare {
- UNDECIDED = -1,
- TEST_IS_BEST,
- REJECT_TEST
- };
- CachedFrame() {}
- void add(CachedNode& node) { mCachedNodes.append(node); }
- void addFrame(CachedFrame& child) { mCachedFrames.append(child); }
- bool checkVisited(const CachedNode* , CachedFrame::Direction ) const;
- size_t childCount() { return mCachedFrames.size(); }
- void clearFocus();
- const CachedNode* currentFocus() const { return currentFocus(NULL); }
- const CachedNode* currentFocus(const CachedFrame** ) const;
- bool directionChange() const;
- const CachedNode* document() const { return mCachedNodes.begin(); }
- bool empty() const { return mCachedNodes.size() < 2; } // must have 1 past doc
- const CachedNode* findBestAt(const WebCore::IntRect& , int* best,
- const CachedNode** , const CachedFrame** , int* x, int* y) const;
- const CachedFrame* findBestFrameAt(int x, int y) const;
- const CachedNode* findBestHitAt(const WebCore::IntRect& ,
- int* best, const CachedFrame** , int* x, int* y) const;
- bool finishInit();
- CachedFrame* firstChild() { return mCachedFrames.begin(); }
- const CachedFrame* firstChild() const { return mCachedFrames.begin(); }
- int focusIndex() const { return mFocus; }
- void* framePointer() const { return mFrame; }
- CachedNode* getIndex(int index) { return index >= 0 ?
- &mCachedNodes[index] : NULL; }
- const CachedFrame* hasFrame(const CachedNode* node) const;
- int indexInParent() const { return mIndex; }
- void init(const CachedRoot* root, int index, WebCore::Frame* frame);
- const CachedFrame* lastChild() const { return &mCachedFrames.last(); }
- CachedNode* lastNode() { return &mCachedNodes.last(); }
- CachedFrame* lastChild() { return &mCachedFrames.last(); }
- const CachedFrame* parent() const { return mParent; }
- CachedFrame* parent() { return mParent; }
- bool sameFrame(const CachedFrame* ) const;
- void removeLast() { mCachedNodes.removeLast(); }
- void resetClippedOut();
- void setContentsSize(int width, int height) { mContents.setWidth(width);
- mContents.setHeight(height); }
- void setData();
- bool setFocus(WebCore::Frame* , WebCore::Node* , int x, int y);
- void setFocusIndex(int focusIndex) const { mFocus = focusIndex; }
- void setLocalViewBounds(const WebCore::IntRect& bounds) { mLocalViewBounds = bounds; }
- int size() { return mCachedNodes.size(); }
- const CachedNode* validDocument() const;
-protected:
- struct BestData {
- WebCore::IntRect mNodeBounds;
- WebCore::IntRect mMouseBounds;
- int mDistance;
- int mSideDistance;
- int mMajorDelta; // difference of center of object
- // used only when leading and trailing edges contain another set of edges
- int mMajorDelta2; // difference of leading edge (only used when center is same)
- int mMajorButt; // checks for next cell butting up against or close to previous one
- int mWorkingDelta;
- int mWorkingDelta2;
- int mNavDelta;
- int mNavDelta2;
- const CachedFrame* mFrame;
- const CachedNode* mNode;
- SkFixed mWorkingOverlap; // this and below are fuzzy answers instead of bools
- SkFixed mNavOverlap;
- SkFixed mPreferred;
- bool mFocusChild;
- bool mInNav;
- bool mNavOutside;
- bool mWorkingOutside;
- int bottom() const { return bounds().bottom(); }
- const WebCore::IntRect& bounds() const { return mNodeBounds; }
- bool canBeReachedByAnotherDirection();
- int height() const { return bounds().height(); }
- bool inOrSubsumesNav() const { return (mNavDelta ^ mNavDelta2) >= 0; }
- bool inOrSubsumesWorking() const { return (mWorkingDelta ^ mWorkingDelta2) >= 0; }
- int isContainer(BestData* );
- static SkFixed Overlap(int span, int left, int right);
- void reset() { mNode = NULL; }
- int right() const { return bounds().right(); }
- void setDistances();
- bool setDownDirection(const CachedHistory* );
- bool setLeftDirection(const CachedHistory* );
- bool setRightDirection(const CachedHistory* );
- bool setUpDirection(const CachedHistory* );
- void setNavInclusion(int left, int right);
- void setNavOverlap(int span, int left, int right);
- void setWorkingInclusion(int left, int right);
- void setWorkingOverlap(int span, int left, int right);
- int width() const { return bounds().width(); }
- int x() const { return bounds().x(); }
- int y() const { return bounds().y(); }
- };
- typedef const CachedNode* (CachedFrame::*MoveInDirection)(
- const CachedNode* test, const CachedNode* limit, BestData* bestData,
- const CachedNode* focus) 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;
- 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;
- int framePartCommon(BestData& testData, const CachedNode* test,
- BestData* bestData, const CachedNode* focus) const;
- const CachedNode* frameDown(const CachedNode* test, const CachedNode* limit,
- BestData* , const CachedNode* focus) const;
- const CachedNode* frameLeft(const CachedNode* test, const CachedNode* limit,
- BestData* , const CachedNode* focus) const;
- const CachedNode* frameRight(const CachedNode* test, const CachedNode* limit,
- BestData* , const CachedNode* focus) const;
- const CachedNode* frameUp(const CachedNode* test, const CachedNode* limit,
- BestData* , const CachedNode* focus) 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;
- const WebCore::IntRect& _navBounds() const;
- WebCore::IntRect mContents;
- WebCore::IntRect mLocalViewBounds;
- WebCore::IntRect mViewBounds;
- WTF::Vector<CachedNode> mCachedNodes;
- WTF::Vector<CachedFrame> mCachedFrames;
- void* mFrame; // WebCore::Frame*, used only to compare pointers
- CachedFrame* mParent;
- int mIndex; // index within parent's array of children, or -1 if root
- const CachedRoot* mRoot;
- mutable int mFocus;
-private:
- CachedHistory* history() const;
-#ifdef BROWSER_DEBUG
-public:
- CachedNode* find(WebCore::Node* ); // !!! probably debugging only
- int mDebugIndex;
- int mDebugLoopbackOffset;
-#endif
-#if !defined NDEBUG || DUMP_NAV_CACHE
-public:
- class Debug {
-public:
- Debug() {
-#if DUMP_NAV_CACHE
- mFrameName[0] = '\0';
-#endif
-#if !defined NDEBUG
- mInUse = true;
-#endif
- }
-#if !defined NDEBUG
- ~Debug() { mInUse = false; }
- bool mInUse;
-#endif
-#if DUMP_NAV_CACHE
- CachedFrame* base() const;
- void print() const;
- bool validate(const CachedNode* ) const;
- char mFrameName[256];
-#endif
- } mDebug;
-#endif
-};
-
-}
-
-#endif
diff --git a/WebKit/android/nav/CachedHistory.cpp b/WebKit/android/nav/CachedHistory.cpp
deleted file mode 100644
index f75f237..0000000
--- a/WebKit/android/nav/CachedHistory.cpp
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * Copyright 2007, 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 APPLE COMPUTER, INC. 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 "CachedFrame.h"
-#include "CachedNode.h"
-#if DUMP_NAV_CACHE
-#include "CachedRoot.h"
-#endif
-
-#include "CachedHistory.h"
-
-namespace android {
-
-CachedHistory::CachedHistory() {
- memset(this, 0, sizeof(CachedHistory)); // this assume the class has no virtuals
- mLastMove = CachedFrame::UNINITIALIZED;
- mPriorMove = CachedFrame::UNINITIALIZED;
-}
-
-
-void CachedHistory::addToVisited(const CachedNode* node, CachedFrame::Direction direction)
-{
- memmove(&mVisited[1], &mVisited[0], sizeof(mVisited) - sizeof(mVisited[0]));
- mVisited[0].mNode = node;
- mVisited[0].mDirection = direction;
-}
-
-bool CachedHistory::checkVisited(const CachedNode* node, CachedFrame::Direction direction) const
-{
- // if the direction is unchanged and we've already visited this node, don't visit it again
- int index = 0;
- while (index < NAVIGATION_VISIT_DEPTH - 1) {
- if (direction != mVisited[index].mDirection)
- break;
- index++; // compare with last direction, previous to last node (where the arrow took us from)
- if (node == mVisited[index].mNode)
- return false;
- }
- return true;
-}
-
-void CachedHistory::pinMaxMin(const WebCore::IntRect& viewBounds)
-{
- if (mMinWorkingHorizontal < viewBounds.y() ||
- mMinWorkingHorizontal >= viewBounds.bottom())
- mMinWorkingHorizontal = viewBounds.y();
- if (mMaxWorkingHorizontal > viewBounds.bottom() ||
- mMaxWorkingHorizontal <= viewBounds.y())
- mMaxWorkingHorizontal = viewBounds.bottom();
- if (mMinWorkingVertical < viewBounds.x() ||
- mMinWorkingVertical >= viewBounds.right())
- mMinWorkingVertical = viewBounds.x();
- if (mMaxWorkingVertical > viewBounds.right() ||
- mMaxWorkingVertical <= viewBounds.x())
- mMaxWorkingVertical = viewBounds.right();
-}
-
-void CachedHistory::reset()
-{
- memset(mVisited, 0, sizeof(mVisited));
-// mLastScroll = 0;
- mPriorBounds = WebCore::IntRect(0, 0, 0, 0);
- mDirectionChange = false;
- mFocusIsInput = false;
- mPriorIsInput = false;
- mDidFirstLayout = false;
- mPriorMove = mLastMove = CachedFrame::UNINITIALIZED;
- mMinWorkingHorizontal = mMinWorkingVertical = INT_MIN;
- mMaxWorkingHorizontal = mMaxWorkingVertical = INT_MAX;
-}
-
-void CachedHistory::setWorking(CachedFrame::Direction newMove,
- const CachedNode* focus, 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);
- bool change = newAxis != lastAxis;
- mDirectionChange = change && mLastMove != CachedFrame::UNINITIALIZED;
- if (focus != NULL || mLastMove != CachedFrame::UNINITIALIZED) {
- mPriorMove = mLastMove;
- mLastMove = newMove;
- }
- const WebCore::IntRect* navBounds = &mNavBounds;
- if (focus != NULL) {
- WebCore::IntRect focusBounds;
- focus->getBounds(&focusBounds);
- if (focusBounds.isEmpty() == false)
- mNavBounds = focusBounds;
- mPriorIsInput = mFocusIsInput;
- mFocusIsInput = focus->isInput(); // focus->localName() == "input";
- }
- if (change) { // uninitialized or change in direction
- if (lastAxis != CachedFrame::LEFT && navBounds->height() > 0) {
- mMinWorkingHorizontal = navBounds->y();
- mMaxWorkingHorizontal = navBounds->bottom();
- }
- if (lastAxis != CachedFrame::UP && navBounds->width() > 0) {
- mMinWorkingVertical = navBounds->x();
- mMaxWorkingVertical = navBounds->right();
- }
- } else if (mPriorIsInput) {
- if (newAxis == CachedFrame::UP_DOWN) {
- if (mPriorBounds.x() == mMinWorkingVertical && mPriorBounds.right() == mMaxWorkingVertical) {
- mMinWorkingVertical = navBounds->x();
- mMaxWorkingVertical = navBounds->right();
- }
- } else {
- if (mPriorBounds.y() == mMinWorkingHorizontal && mPriorBounds.bottom() == mMaxWorkingHorizontal) {
- mMinWorkingHorizontal = navBounds->y();
- mMaxWorkingHorizontal = navBounds->bottom();
- }
- }
- }
- pinMaxMin(viewBounds);
-}
-
-#if DUMP_NAV_CACHE
-
-#define DEBUG_PRINT_BOOL(field) \
- DUMP_NAV_LOGD("// bool " #field "=%s;\n", b->field ? "true" : "false")
-
-#define DEBUG_PRINT_RECT(field) \
- { const WebCore::IntRect& r = b->field; \
- DUMP_NAV_LOGD("// IntRect " #field "={%d, %d, %d, %d};\n", \
- r.x(), r.y(), r.width(), r.height()); }
-
-CachedHistory* CachedHistory::Debug::base() const {
- CachedHistory* nav = (CachedHistory*) ((char*) this - OFFSETOF(CachedHistory, mDebug));
- return nav;
-}
-
-const char* CachedHistory::Debug::direction(CachedFrame::Direction d) const
-{
- switch (d) {
- case CachedFrame::LEFT: return "LEFT"; break;
- case CachedFrame::RIGHT: return "RIGHT"; break;
- case CachedFrame::UP: return "UP"; break;
- case CachedFrame::DOWN: return "DOWN"; break;
- default: return "UNINITIALIZED";
- }
-}
-
-void CachedHistory::Debug::print(CachedRoot* root) const
-{
- CachedHistory* b = base();
- DUMP_NAV_LOGD("// Visited mVisited[]={\n");
- for (size_t i = 0; i < NAVIGATION_VISIT_DEPTH; i++) {
- const Visited& visit = b->mVisited[i];
- const CachedNode* node = visit.mNode;
- int index = root != NULL && root->CachedFrame::mDebug.validate(node) ?
- node->index() : -1;
- DUMP_NAV_LOGD(" // { 0x%p (%d), %s },\n", node, index, direction(visit.mDirection));
- }
- DUMP_NAV_LOGD("// };\n");
-// DUMP_NAV_LOGD("// int mLastScroll=%d;\n", b->mLastScroll);
- DEBUG_PRINT_RECT(mNavBounds);
- DEBUG_PRINT_RECT(mPriorBounds);
- DEBUG_PRINT_BOOL(mDirectionChange);
- DEBUG_PRINT_BOOL(mFocusIsInput);
- DEBUG_PRINT_BOOL(mPriorIsInput);
- DUMP_NAV_LOGD("// CachedFrame::Direction mLastMove=%s, mPriorMove=%s;\n",
- direction(b->mLastMove), direction(b->mPriorMove));
- int max = b->mMaxWorkingHorizontal;
- DUMP_NAV_LOGD("static int TEST_MAX_H = %d;\n", max);
- int min = b->mMinWorkingHorizontal;
- if (min == INT_MIN)
- min++;
- DUMP_NAV_LOGD("static int TEST_MIN_H = %d;\n", min);
- max = b->mMaxWorkingVertical;
- DUMP_NAV_LOGD("static int TEST_MAX_V = %d;\n", max);
- min = b->mMinWorkingVertical;
- if (min == INT_MIN)
- min++;
- DUMP_NAV_LOGD("static int TEST_MIN_V = %d;\n", min);
- DUMP_NAV_LOGD("\n");
-}
-
-#endif
-
-}
diff --git a/WebKit/android/nav/CachedHistory.h b/WebKit/android/nav/CachedHistory.h
deleted file mode 100644
index e48d44b..0000000
--- a/WebKit/android/nav/CachedHistory.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright 2007, 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 APPLE COMPUTER, INC. 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 CachedHistory_H
-#define CachedHistory_H
-
-#include "CachedFrame.h"
-
-#define NAVIGATION_VISIT_DEPTH 8 // the number of nodes last visited -- used to detect ping-ponging (number should be tuned)
-
-namespace android {
-
-class CachedRoot;
-
-// CachedHistory is maintained even if DOM is rebuilt by running script.
-// It uses blind pointers for comparison in the previously visited nodes.
-class CachedHistory {
-public:
- CachedHistory();
- void addToVisited(const CachedNode* , CachedFrame::Direction );
- bool checkVisited(const CachedNode* , CachedFrame::Direction ) const;
- bool didFirstLayout() const { return mDidFirstLayout; }
- bool directionChange() const { return mDirectionChange; }
- int minWorkingHorizontal() const { return mMinWorkingHorizontal; }
- int minWorkingVertical() const { return mMinWorkingVertical; }
- int maxWorkingHorizontal() const { return mMaxWorkingHorizontal; }
- int maxWorkingVertical() const { return mMaxWorkingVertical; }
- const WebCore::IntRect& navBounds() const { return mNavBounds; }
- const WebCore::IntRect& priorBounds() const { return mPriorBounds; }
- void setDidFirstLayout(bool did) { mDidFirstLayout = did; }
- void setNavBounds(const WebCore::IntRect& loc) { mNavBounds = loc; }
- void setWorking(CachedFrame::Direction , const CachedNode* focus,
- const WebCore::IntRect& viewBounds);
- void reset();
-private:
- void pinMaxMin(const WebCore::IntRect& viewBounds);
- struct Visited {
- const CachedNode* mNode;
- CachedFrame::Direction mDirection;
- } mVisited[NAVIGATION_VISIT_DEPTH];
- WebCore::IntRect mMouseBounds; // constricted bounds, if focus ring is partially visible
- WebCore::IntRect mNavBounds; // focus ring bounds plus optional keystroke movement
- WebCore::IntRect mPriorBounds; // prior chosen focus ring (for reversing narrowing)
- bool mDirectionChange;
- bool mFocusIsInput; // defer max/min to non-focus node if focus is too broad
- bool mPriorIsInput; // defer max/min to non-focus node if focus is too broad
- bool mDidFirstLayout; // set true when page is newly laid out
- CachedFrame::Direction mLastMove;
- CachedFrame::Direction mPriorMove;
- int mMinWorkingHorizontal;
- int mMaxWorkingHorizontal;
- int mMinWorkingVertical;
- int mMaxWorkingVertical;
- friend class CachedRoot;
-#if DUMP_NAV_CACHE
-public:
- class Debug {
-public:
- CachedHistory* base() const;
- const char* direction(CachedFrame::Direction d) const;
- void print(CachedRoot* ) const;
- } mDebug;
-#endif
-};
-
-}
-
-#endif
diff --git a/WebKit/android/nav/CachedNode.cpp b/WebKit/android/nav/CachedNode.cpp
deleted file mode 100644
index b786677..0000000
--- a/WebKit/android/nav/CachedNode.cpp
+++ /dev/null
@@ -1,346 +0,0 @@
-/*
- * Copyright 2007, 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 APPLE COMPUTER, INC. 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 "CachedFrame.h"
-#include "CachedHistory.h"
-#include "Node.h"
-#include "PlatformString.h"
-
-#include "android_graphics.h"
-#include "CachedNode.h"
-
-namespace android {
-
-void CachedNode::clearFocus(CachedFrame* parent)
-{
- if (isFrame()) {
- CachedFrame* child = const_cast<CachedFrame*>(parent->hasFrame(this));
- child->clearFocus();
- }
- mIsFocus = false;
-}
-
-bool CachedNode::Clip(const WebCore::IntRect& outer, WebCore::IntRect* inner,
- WTF::Vector<WebCore::IntRect>* rings)
-{
- if (outer.contains(*inner))
- return true;
-// DBG_NAV_LOGD("outer:{%d,%d,%d,%d} does not contain inner:{%d,%d,%d,%d}",
-// outer.x(), outer.y(), outer.width(), outer.height(),
-// inner->x(), inner->y(), inner->width(), inner->height());
- bool intersects = outer.intersects(*inner);
- size_t size = intersects ? rings->size() : 0;
- *inner = WebCore::IntRect(0, 0, 0, 0);
- if (intersects) {
- WebCore::IntRect * const start = rings->begin();
- WebCore::IntRect* ring = start + size - 1;
- do {
- ring->intersect(outer);
- if (ring->isEmpty()) {
- if ((size_t) (ring - start) != --size)
- *ring = start[size];
- } else
- inner->unite(*ring);
- } while (ring-- != start);
- }
- rings->shrink(size);
-// DBG_NAV_LOGD("size:%d", size);
- return size != 0;
-}
-
-bool CachedNode::clip(const WebCore::IntRect& bounds)
-{
- return Clip(bounds, &mBounds, &mFocusRing);
-}
-
-#define OVERLAP 3
-
-void CachedNode::fixUpFocusRects()
-{
- if (mFixedUpFocusRects)
- return;
- mFixedUpFocusRects = true;
- if (mNavableRects <= 1)
- return;
-#if DEBUG_NAV_UI
- {
- WebCore::IntRect* boundsPtr = mFocusRing.begin() - 1;
- const WebCore::IntRect* const boundsEnd = mFocusRing.begin() + mFocusRing.size();
- while (++boundsPtr < boundsEnd)
- LOGD("%s %d:(%d, %d, %d, %d)\n", __FUNCTION__, boundsPtr - mFocusRing.begin(),
- boundsPtr->x(), boundsPtr->y(), boundsPtr->width(), boundsPtr->height());
- }
-#endif
- // q: need to know when rects are for drawing and hit-testing, but not mouse down calcs?
- bool again;
- do {
- again = false;
- size_t size = mFocusRing.size();
- WebCore::IntRect* unitBoundsPtr = mFocusRing.begin() - 1;
- const WebCore::IntRect* const unitBoundsEnd = mFocusRing.begin() + size;
- while (++unitBoundsPtr < unitBoundsEnd) {
- // any other unitBounds to the left or right of this one?
- int unitTop = unitBoundsPtr->y();
- int unitBottom = unitBoundsPtr->bottom();
- int unitLeft = unitBoundsPtr->x();
- int unitRight = unitBoundsPtr->right();
- WebCore::IntRect* testBoundsPtr = mFocusRing.begin() - 1;
- while (++testBoundsPtr < unitBoundsEnd) {
- if (unitBoundsPtr == testBoundsPtr)
- continue;
- int testTop = testBoundsPtr->y();
- int testBottom = testBoundsPtr->bottom();
- int testLeft = testBoundsPtr->x();
- int testRight = testBoundsPtr->right();
- int candidateTop = unitTop > testTop ? unitTop : testTop;
- int candidateBottom = unitBottom < testBottom ? unitBottom : testBottom;
- int candidateLeft = unitRight < testLeft ? unitRight : testRight;
- int candidateRight = unitRight > testLeft ? unitLeft : testLeft;
- bool leftRight = true;
- if (candidateTop + OVERLAP >= candidateBottom ||
- candidateLeft + OVERLAP >= candidateRight) {
- candidateTop = unitBottom < testTop ? unitBottom : testBottom;
- candidateBottom = unitBottom > testTop ? unitTop : testTop;
- candidateLeft = unitLeft > testLeft ? unitLeft : testLeft;
- candidateRight = unitRight < testRight ? unitRight : testRight;
- if (candidateTop + OVERLAP >= candidateBottom ||
- candidateLeft + OVERLAP >= candidateRight)
- continue;
- leftRight = false;
- }
- // construct candidate to add
- WebCore::IntRect candidate = WebCore::IntRect(candidateLeft, candidateTop,
- candidateRight - candidateLeft, candidateBottom - candidateTop);
- // does a different unit bounds intersect the candidate? if so, don't add
- WebCore::IntRect* checkBoundsPtr = mFocusRing.begin() - 1;
- while (++checkBoundsPtr < unitBoundsEnd) {
- if (checkBoundsPtr->intersects(candidate) == false)
- continue;
- if (leftRight) {
- if (candidateTop >= checkBoundsPtr->y() &&
- candidateBottom > checkBoundsPtr->bottom())
- candidateTop = checkBoundsPtr->bottom();
- else if (candidateTop < checkBoundsPtr->y() &&
- candidateBottom <= checkBoundsPtr->bottom())
- candidateBottom = checkBoundsPtr->y();
- else
- goto nextCheck;
- } else {
- if (candidateLeft >= checkBoundsPtr->x() &&
- candidateRight > checkBoundsPtr->right())
- candidateLeft = checkBoundsPtr->right();
- else if (candidateLeft < checkBoundsPtr->x() &&
- candidateRight <= checkBoundsPtr->right())
- candidateRight = checkBoundsPtr->x();
- else
- goto nextCheck;
- }
- }
- candidate = WebCore::IntRect(candidateLeft, candidateTop,
- candidateRight - candidateLeft, candidateBottom - candidateTop);
- ASSERT(candidate.isEmpty() == false);
-#if DEBUG_NAV_UI
- LOGD("%s %d:(%d, %d, %d, %d)\n", __FUNCTION__, mFocusRing.size(),
- candidate.x(), candidate.y(), candidate.width(), candidate.height());
-#endif
- mFocusRing.append(candidate);
- again = true;
- goto tryAgain;
- nextCheck:
- continue;
- }
- }
-tryAgain:
- ;
- } while (again);
-}
-
-
-void CachedNode::focusRingBounds(WebCore::IntRect* bounds) const
-{
- int partMax = mNavableRects;
- ASSERT(partMax > 0);
- *bounds = mFocusRing[0];
- for (int partIndex = 1; partIndex < partMax; partIndex++)
- bounds->unite(mFocusRing[partIndex]);
- bounds->inflate(FOCUS_RING_HIT_TEST_RADIUS);
-}
-
-void CachedNode::init(WebCore::Node* node)
-{
- bzero(this, sizeof(CachedNode));
- mExport = WebCore::String();
- mName = WebCore::String();
- mNode = node;
- mParentIndex = mChildFrameIndex = -1;
- mType = android::NORMAL_CACHEDNODETYPE;
-}
-
-void CachedNode::move(int x, int y)
-{
- mBounds.move(x, y);
- // mHitTestBounds will be moved by caller
- WebCore::IntRect* first = mFocusRing.begin();
- WebCore::IntRect* last = first + mFocusRing.size();
- --first;
- while (++first != last)
- first->move(x, y);
-}
-
-bool CachedNode::partRectsContains(const CachedNode* other) const
-{
- int outerIndex = 0;
- int outerMax = mNavableRects;
- int innerMax = other->mNavableRects;
- do {
- const WebCore::IntRect& outerBounds = mFocusRing[outerIndex];
- int innerIndex = 0;
- do {
- const WebCore::IntRect& innerBounds = other->mFocusRing[innerIndex];
- if (innerBounds.contains(outerBounds))
- return true;
- } while (++innerIndex < innerMax);
- } while (++outerIndex < outerMax);
- return false;
-}
-
-#if DUMP_NAV_CACHE
-
-#define DEBUG_PRINT_BOOL(field) \
- DUMP_NAV_LOGD("// bool " #field "=%s;\n", b->field ? "true" : "false")
-
-#define DEBUG_PRINT_RECT(field) \
- { const WebCore::IntRect& r = b->field; \
- DUMP_NAV_LOGD("// IntRect " #field "={%d, %d, %d, %d};\n", \
- r.x(), r.y(), r.width(), r.height()); }
-
-CachedNode* CachedNode::Debug::base() const {
- CachedNode* nav = (CachedNode*) ((char*) this - OFFSETOF(CachedNode, mDebug));
- return nav;
-}
-
-const char* CachedNode::Debug::condition(Condition t) const
-{
- switch (t) {
- case NOT_REJECTED: return "NOT_REJECTED"; break;
- case BUTTED_UP: return "BUTTED_UP"; break;
- case CENTER_FURTHER: return "CENTER_FURTHER"; break;
- case CLOSER: return "CLOSER"; break;
- case CLOSER_IN_FOCUS: return "CLOSER_IN_FOCUS"; break;
- case CLOSER_OVERLAP: return "CLOSER_OVERLAP"; break;
- case CLOSER_TOP: return "CLOSER_TOP"; break;
- case FOCUSABLE: return "FOCUSABLE"; break;
- case FURTHER: return "FURTHER"; break;
- case IN_UMBRA: return "IN_UMBRA"; break;
- case IN_WORKING: return "IN_WORKING"; break;
- case LEFTMOST: return "LEFTMOST"; break;
- case OVERLAP_OR_EDGE_FURTHER: return "OVERLAP_OR_EDGE_FURTHER"; break;
- case PREFERRED: return "PREFERRED"; break;
- case ANCHOR_IN_ANCHOR: return "ANCHOR_IN_ANCHOR"; break;
- case BEST_DIRECTION: return "BEST_DIRECTION"; break;
- case CHILD: return "CHILD"; break;
- case DISABLED: return "DISABLED"; break;
- case HIGHER_TAB_INDEX: return "HIGHER_TAB_INDEX"; break;
- case IN_FOCUS: return "IN_FOCUS"; break;
- case IN_FOCUS_CHILDREN: return "IN_FOCUS_CHILDREN"; break;
- case NOT_ENCLOSING_FOCUS: return "NOT_ENCLOSING_FOCUS"; break;
- // case NOT_FOCUS_CHILD: return "NOT_FOCUS_CHILD"; break;
- case NOT_FOCUS_NODE: return "NOT_FOCUS_NODE"; break;
- case OUTSIDE_OF_BEST: return "OUTSIDE_OF_BEST"; break;
- case OUTSIDE_OF_ORIGINAL: return "OUTSIDE_OF_ORIGINAL"; break;
- default: return "???";
- }
-}
-
-const char* CachedNode::Debug::type(android::CachedNodeType t) const
-{
- switch (t) {
- case NORMAL_CACHEDNODETYPE: return "NORMAL"; break;
- case ADDRESS_CACHEDNODETYPE: return "ADDRESS"; break;
- case EMAIL_CACHEDNODETYPE: return "EMAIL"; break;
- case PHONE_CACHEDNODETYPE: return "PHONE"; break;
- default: return "???";
- }
-}
-
-void CachedNode::Debug::print() const
-{
- CachedNode* b = base();
- char scratch[256];
- size_t index = snprintf(scratch, sizeof(scratch), "// char* mExport=\"");
- const UChar* ch = b->mExport.characters();
- while (ch && *ch && index < sizeof(scratch))
- scratch[index++] = *ch++;
- DUMP_NAV_LOGD("%.*s\"\n", index, scratch);
- index = snprintf(scratch, sizeof(scratch), "// char* mName=\"");
- ch = b->mName.characters();
- while (ch && *ch && index < sizeof(scratch))
- scratch[index++] = *ch++;
- DUMP_NAV_LOGD("%.*s\"\n", index, scratch);
- DEBUG_PRINT_RECT(mBounds);
- DEBUG_PRINT_RECT(mHitBounds);
- const WTF::Vector<WebCore::IntRect>& rects = b->focusRings();
- size_t size = rects.size();
- DUMP_NAV_LOGD("// IntRect focusRings={ // 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);
- 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);
- DUMP_NAV_LOGD("// int mChildFrameIndex=%d;\n", b->mChildFrameIndex);
- DUMP_NAV_LOGD("// int mIndex=%d;\n", b->mIndex);
- DUMP_NAV_LOGD("// int mMaxLength=%d;\n", b->mMaxLength);
- DUMP_NAV_LOGD("// int mNavableRects=%d;\n", b->mNavableRects);
- DUMP_NAV_LOGD("// int mParentIndex=%d;\n", b->mParentIndex);
- DUMP_NAV_LOGD("// int mTextSize=%d;\n", b->mTextSize);
- DUMP_NAV_LOGD("// int mTabIndex=%d;\n", b->mTabIndex);
- DUMP_NAV_LOGD("// Condition mCondition=%s;\n", condition(b->mCondition));
- DUMP_NAV_LOGD("// Type mType=%s;\n", type(b->mType));
- DEBUG_PRINT_BOOL(mClippedOut);
- DEBUG_PRINT_BOOL(mDisabled);
- DEBUG_PRINT_BOOL(mFixedUpFocusRects);
- DEBUG_PRINT_BOOL(mHasFocusRing);
- DEBUG_PRINT_BOOL(mHasMouseOver);
- DEBUG_PRINT_BOOL(mIsAnchor);
- DEBUG_PRINT_BOOL(mIsArea);
- DEBUG_PRINT_BOOL(mIsFocus);
- DEBUG_PRINT_BOOL(mIsInput);
- DEBUG_PRINT_BOOL(mIsParentAnchor);
- DEBUG_PRINT_BOOL(mIsPassword);
- DEBUG_PRINT_BOOL(mIsRtlText);
- DEBUG_PRINT_BOOL(mIsTextArea);
- DEBUG_PRINT_BOOL(mIsTextField);
- DEBUG_PRINT_BOOL(mIsTransparent);
- DEBUG_PRINT_BOOL(mIsUnclipped);
- DEBUG_PRINT_BOOL(mLast);
- DEBUG_PRINT_BOOL(mWantsKeyEvents);
- DUMP_NAV_LOGD("\n");
-}
-
-#endif
-
-}
diff --git a/WebKit/android/nav/CachedNode.h b/WebKit/android/nav/CachedNode.h
deleted file mode 100644
index aa64982..0000000
--- a/WebKit/android/nav/CachedNode.h
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- * Copyright 2007, 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 APPLE COMPUTER, INC. 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 CachedNode_H
-#define CachedNode_H
-
-#include "AtomicString.h"
-#include "CachedDebug.h"
-#include "CachedNodeType.h"
-#include "IntRect.h"
-#include "PlatformString.h"
-#include "wtf/Vector.h"
-
-namespace WebCore {
- class Node;
-}
-
-namespace android {
-
-class CachedFrame;
-
-class CachedNode {
-public:
-// Nodes are rejected because either they are spacially not the best (first set)
-// or because they have the wrong DOM attribute (in focus, a focused child, etc)
-// findClosest() gives only spacially rejected nodes a second chance
- enum Condition { // if bigger than 32, increase bitfield size below
- // rejections that get a second chance
- NOT_REJECTED = 0,
- SECOND_CHANCE_START = NOT_REJECTED, // must be first in list
- BUTTED_UP,
- CENTER_FURTHER,
- CLOSER,
- CLOSER_IN_FOCUS,
- CLOSER_OVERLAP,
- CLOSER_TOP,
- FOCUSABLE,
- FURTHER,
- IN_UMBRA,
- IN_WORKING,
- LEFTMOST,
- OVERLAP_OR_EDGE_FURTHER,
- PREFERRED, // better overlap measure
- SECOND_CHANCE_END = PREFERRED, // must be last in list
- // rejections that don't get a second chance
- ANCHOR_IN_ANCHOR,
- BEST_DIRECTION, // can be reached by another direction
- CHILD,
- DISABLED,
- HIGHER_TAB_INDEX,
- IN_FOCUS,
- IN_FOCUS_CHILDREN,
- NOT_ENCLOSING_FOCUS,
- // NOT_FOCUS_CHILD,
- NOT_FOCUS_NODE,
- OUTSIDE_OF_BEST, // containership
- OUTSIDE_OF_ORIGINAL, // containership
- CONDITION_SIZE // FIXME: test that CONDITION_SIZE fits in mCondition
- };
- CachedNode() {
- // The node is initiaized to 0 in its array, so nothing to do in the
- // constructor
- }
-
- const WebCore::IntRect& bounds() const { return mBounds; }
- WebCore::IntRect* boundsPtr() { return &mBounds; }
- int childFrameIndex() const { return mChildFrameIndex; }
- void clearCondition() const { mCondition = NOT_REJECTED; }
- void clearFocus(CachedFrame* );
- static bool Clip(const WebCore::IntRect& outer, WebCore::IntRect* inner,
- WTF::Vector<WebCore::IntRect>* rings);
- bool clip(const WebCore::IntRect& );
- bool clippedOut() { return mClippedOut; }
- bool disabled() const { return mDisabled; }
- const CachedNode* document() const { return &this[-mIndex]; }
- void fixUpFocusRects();
- void focusRingBounds(WebCore::IntRect* ) const;
- WTF::Vector<WebCore::IntRect>& focusRings() { return mFocusRing; }
- const WTF::Vector<WebCore::IntRect>& focusRings() const { return mFocusRing; }
- const WebCore::IntRect& getBounds() const { return mBounds; }
- void getBounds(WebCore::IntRect* bounds) const { *bounds = mBounds; }
- const WebCore::String& getExport() const { return mExport; }
- bool hasFocusRing() const { return mHasFocusRing; }
- bool hasMouseOver() const { return mHasMouseOver; }
- const WebCore::IntRect& hitBounds() const { return mHitBounds; }
- int index() const { return mIndex; }
- void init(WebCore::Node* node);
- bool isAnchor() const { return mIsAnchor; }
- bool isArea() const { return mIsArea; }
- bool isFocus() const { return mIsFocus; }
- bool isFocusable(const WebCore::IntRect& clip) const {
- return clip.intersects(mBounds);
- }
- bool isFrame() const { return mChildFrameIndex >= 0 ; }
- bool isInput() const { return mIsInput; }
- bool isPassword() const { return mIsPassword; }
- bool isRtlText() const { return mIsRtlText; }
- bool isTextArea() const { return mIsTextArea; }
- bool isTextField() const { return mIsTextField; }
- bool isTransparent() const { return mIsTransparent; }
- bool isUnclipped() const { return mIsUnclipped; }
- bool isWantsKeyEvents() const { return mWantsKeyEvents; }
-
- int maxLength() const { return mMaxLength; };
- void move(int x, int y);
- const WebCore::String& name() const { return mName; }
- int navableRects() const { return mNavableRects; }
- void* nodePointer() const { return mNode; }
- bool noSecondChance() const { return mCondition > SECOND_CHANCE_END; }
- const CachedNode* parent() const { return document() + mParentIndex; }
- void* parentGroup() const { return mParentGroup; }
- int parentIndex() const { return mParentIndex; }
- bool partRectsContains(const CachedNode* other) const;
- void reset();
- void setBounds(const WebCore::IntRect& bounds) { mBounds = bounds; }
- void setChildFrameIndex(int index) { mChildFrameIndex = index; }
- void setClippedOut(bool clipped) { mClippedOut = clipped; }
- void setCondition(Condition condition) const { mCondition = condition; }
- void setDisabled(bool disabled) { mDisabled = disabled; }
- void setExport(const WebCore::String& exported) { mExport = exported; }
- void setHasFocusRing(bool hasFocusRing) { mHasFocusRing = hasFocusRing; }
- void setHasMouseOver(bool hasMouseOver) { mHasMouseOver = hasMouseOver; }
- void setHitBounds(const WebCore::IntRect& bounds) { mHitBounds = bounds; }
- void setIndex(int index) { mIndex = index; }
- void setIsAnchor(bool isAnchor) { mIsAnchor = isAnchor; }
- void setIsArea(bool isArea) { mIsArea = isArea; }
- void setIsFocus(bool isFocus) { mIsFocus = isFocus; }
- void setIsInput(bool isInput) { mIsInput = isInput; }
- void setIsParentAnchor(bool isAnchor) { mIsParentAnchor = isAnchor; }
- void setIsPassword(bool isPassword) { mIsPassword = isPassword; }
- void setIsRtlText(bool isRtlText) { mIsRtlText = isRtlText; }
- void setIsTextArea(bool isTextArea) { mIsTextArea = isTextArea; }
- void setIsTextField(bool isTextField) { mIsTextField = isTextField; }
- void setIsTransparent(bool isTransparent) { mIsTransparent = isTransparent; }
- void setIsUnclipped(bool unclipped) { mIsUnclipped = unclipped; }
- void setLast() { mLast = true; }
- void setMaxLength(int maxLength) { mMaxLength = maxLength; }
- void setName(const WebCore::String& name) { mName = name; }
- void setNavableRects() { mNavableRects = mFocusRing.size(); }
- void setParentGroup(void* group) { mParentGroup = group; }
- void setParentIndex(int parent) { mParentIndex = parent; }
- void setTabIndex(int index) { mTabIndex = index; }
- void setTextSize(int textSize) { mTextSize = textSize; }
- void setType(CachedNodeType type) { mType = type; }
- void setWantsKeyEvents(bool wantsKeys) { mWantsKeyEvents = wantsKeys; }
- int tabIndex() const { return mTabIndex; }
- const CachedNode* traverseNextNode() const { return mLast ? NULL : &this[1]; }
- int textSize() const { return mTextSize; }
- CachedNodeType type() const { return mType; }
-private:
- WebCore::String mExport;
- WebCore::String mName;
- WebCore::IntRect mBounds;
- WebCore::IntRect mHitBounds;
- WTF::Vector<WebCore::IntRect> mFocusRing;
- void* mNode; // WebCore::Node*, only used to match pointers
- void* mParentGroup; // WebCore::Node*, only used to match pointers
- int mChildFrameIndex; // set to -1 if node is not a frame
- int mIndex; // index of itself, to find first in array (document)
- int mMaxLength;
- int mNavableRects; // FIXME: could be bitfield once I limit max number of rects
- int mParentIndex;
- int mTextSize;
- int mTabIndex;
- mutable Condition mCondition : 5; // why the node was not chosen on the first pass
- CachedNodeType mType : 3;
- bool mClippedOut : 1;
- bool mDisabled : 1;
- bool mFixedUpFocusRects : 1;
- bool mHasFocusRing : 1;
- bool mHasMouseOver : 1;
- bool mIsAnchor : 1;
- bool mIsArea : 1;
- bool mIsFocus : 1;
- bool mIsInput : 1;
- bool mIsParentAnchor : 1;
- bool mIsPassword : 1;
- bool mIsRtlText : 1;
- bool mIsTextArea : 1;
- bool mIsTextField : 1;
- bool mIsTransparent : 1;
- bool mIsUnclipped : 1;
- bool mLast : 1; // true if this is the last node in a group
- bool mWantsKeyEvents : 1; // true for nodes like plugins
-#ifdef BROWSER_DEBUG
-public:
- WebCore::Node* webCoreNode() const { return (WebCore::Node*) mNode; }
- bool mDisplayMeasure;
- mutable bool mInCompare;
- // mutable int mCondition;
- int mSideDistance;
- int mSecondSide;
-#endif
-#if DEBUG_NAV_UI || DUMP_NAV_CACHE
-public:
- class Debug {
-public:
- CachedNode* base() const;
- const char* condition(Condition t) const;
- void print() const;
- const char* type(CachedNodeType t) const;
-#if DUMP_NAV_CACHE
- int mNodeIndex;
- int mParentGroupIndex;
-#endif
- } mDebug;
- friend class CachedNode::Debug;
-#endif
-};
-
-}
-
-#endif
diff --git a/WebKit/android/nav/CachedNodeType.h b/WebKit/android/nav/CachedNodeType.h
deleted file mode 100644
index 07346ac..0000000
--- a/WebKit/android/nav/CachedNodeType.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2007, 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 APPLE COMPUTER, INC. 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 CachedNodeType_H
-#define CachedNodeType_H
-
-namespace android {
-
-enum CachedNodeType {
- NORMAL_CACHEDNODETYPE = 0,
- ADDRESS_CACHEDNODETYPE = 1,
- EMAIL_CACHEDNODETYPE = 2,
- PHONE_CACHEDNODETYPE = 4,
- ALL_CACHEDNODETYPES = 7
-};
-
-}
-
-#endif
diff --git a/WebKit/android/nav/CachedPrefix.h b/WebKit/android/nav/CachedPrefix.h
deleted file mode 100644
index b466771..0000000
--- a/WebKit/android/nav/CachedPrefix.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright 2007, 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 APPLE COMPUTER, INC. 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 CachedPrefix_H
-#define CachedPrefix_H
-
-#ifndef LOG_TAG
-#define LOG_TAG "navcache"
-#endif
-
-#include "config.h"
-#include "CachedDebug.h"
-
-#ifndef _LIBS_CUTILS_LOG_H
- #ifdef LOG
- #undef LOG
- #endif
-
- #include <utils/Log.h>
-#endif
-
-#define OFFSETOF(type, field) ((char*)&(((type*)1)->field) - (char*)1) // avoids gnu warning
-
-#endif
diff --git a/WebKit/android/nav/CachedRoot.cpp b/WebKit/android/nav/CachedRoot.cpp
deleted file mode 100644
index 4a50c80..0000000
--- a/WebKit/android/nav/CachedRoot.cpp
+++ /dev/null
@@ -1,1087 +0,0 @@
-/*
- * Copyright 2007, 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 APPLE COMPUTER, INC. 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 "CachedHistory.h"
-#include "CachedNode.h"
-#include "SkBitmap.h"
-#include "SkBounder.h"
-#include "SkCanvas.h"
-#include "SkPixelRef.h"
-#include "SkRegion.h"
-
-#include "CachedRoot.h"
-
-#ifdef DUMP_NAV_CACHE_USING_PRINTF
- extern android::Mutex gWriteLogMutex;
-#endif
-
-namespace android {
-
-class CommonCheck : public SkBounder {
-public:
- enum Type {
- kNo_Type,
- kDrawBitmap_Type,
- kDrawGlyph_Type,
- kDrawPaint_Type,
- kDrawPath_Type,
- kDrawPicture_Type,
- kDrawPoints_Type,
- kDrawPosText_Type,
- kDrawPosTextH_Type,
- kDrawRect_Type,
- kDrawSprite_Type,
- kDrawText_Type,
- kDrawTextOnPath_Type
- };
-
- static bool isTextType(Type t) {
- return t == kDrawPosTextH_Type || t == kDrawText_Type;
- }
-
- CommonCheck() : mType(kNo_Type), mAllOpaque(true), mIsOpaque(true) {
- setEmpty();
- }
-
- bool doRect(Type type) {
- mType = type;
- return doIRect(mUnion);
- }
-
- bool joinGlyphs(const SkIRect& rect) {
- bool isGlyph = mType == kDrawGlyph_Type;
- if (isGlyph)
- mUnion.join(rect);
- return isGlyph;
- }
-
- void setAllOpaque(bool opaque) { mAllOpaque = opaque; }
- void setEmpty() { mUnion.setEmpty(); }
- void setIsOpaque(bool opaque) { mIsOpaque = opaque; }
- void setType(Type type) { mType = type; }
-
- Type mType;
- SkIRect mUnion;
- bool mAllOpaque;
- bool mIsOpaque;
-};
-
-#if DEBUG_NAV_UI && !defined BROWSER_DEBUG
- static const char* TypeNames[] = {
- "kNo_Type",
- "kDrawBitmap_Type",
- "kDrawGlyph_Type",
- "kDrawPaint_Type",
- "kDrawPath_Type",
- "kDrawPicture_Type",
- "kDrawPoints_Type",
- "kDrawPosText_Type",
- "kDrawPosTextH_Type",
- "kDrawRect_Type",
- "kDrawSprite_Type",
- "kDrawText_Type",
- "kDrawTextOnPath_Type"
- };
-#endif
-
-#define kMargin 16
-#define kSlop 2
-
-class BoundsCheck : public CommonCheck {
-public:
- BoundsCheck() {
- mAllDrawnIn.setEmpty();
- mLastAll.setEmpty();
- mLastOver.setEmpty();
- }
-
- static int Area(SkIRect test) {
- return test.width() * test.height();
- }
-
- void checkLast() {
- if (mAllDrawnIn.isEmpty())
- return;
- if (mLastAll.isEmpty() || Area(mLastAll) < Area(mAllDrawnIn)) {
- mLastAll = mAllDrawnIn;
- mDrawnOver.setEmpty();
- }
- mAllDrawnIn.setEmpty();
- }
-
- bool hidden() {
- return (mLastAll.isEmpty() && mLastOver.isEmpty()) ||
- mDrawnOver.contains(mBounds);
- }
-
- virtual bool onIRect(const SkIRect& rect) {
- if (joinGlyphs(rect))
- return false;
- bool interestingType = mType == kDrawBitmap_Type ||
- mType == kDrawRect_Type || isTextType(mType);
- if (SkIRect::Intersects(mBounds, rect) == false) {
-#if DEBUG_NAV_UI && !defined BROWSER_DEBUG
- LOGD("%s (no intersect) rect={%d,%d,%d,%d} mType=%s\n", __FUNCTION__,
- rect.fLeft, rect.fTop, rect.fRight, rect.fBottom,
- TypeNames[mType]);
-#endif
- if (interestingType)
- checkLast();
- return false;
- }
- if (interestingType == false)
- return false;
- if (mBoundsSlop.contains(rect) ||
- (mBounds.fLeft == rect.fLeft && mBounds.fRight == rect.fRight &&
- mBounds.fTop >= rect.fTop && mBounds.fBottom <= rect.fBottom) ||
- (mBounds.fTop == rect.fTop && mBounds.fBottom == rect.fBottom &&
- mBounds.fLeft >= rect.fLeft && mBounds.fRight <= rect.fRight)) {
- mDrawnOver.setEmpty();
- mAllDrawnIn.join(rect);
-#if DEBUG_NAV_UI && !defined BROWSER_DEBUG
- LOGD("%s (contains) rect={%d,%d,%d,%d}"
- " mAllDrawnIn={%d,%d,%d,%d} mType=%s\n", __FUNCTION__,
- rect.fLeft, rect.fTop, rect.fRight, rect.fBottom,
- mAllDrawnIn.fLeft, mAllDrawnIn.fTop, mAllDrawnIn.fRight, mAllDrawnIn.fBottom,
- TypeNames[mType]);
-#endif
- } else {
- checkLast();
- if (!isTextType(mType)) {
- if (
-#if 0
-// should the opaqueness of the bitmap disallow its ability to draw over?
-// not sure that this test is needed
- (mType != kDrawBitmap_Type ||
- (mIsOpaque && mAllOpaque)) &&
-#endif
- mLastAll.isEmpty() == false)
- mDrawnOver.op(rect, SkRegion::kUnion_Op);
- } else {
-// FIXME
-// sometimes the text is not drawn entirely inside the focus area, even though
-// it is the correct text. Until I figure out why, I allow text drawn at the
-// end that is not covered up by something else to represent the focusable link
-// example that triggers this that should be figured out:
-// http://cdn.labpixies.com/campaigns/blackjack/blackjack.html?lang=en&country=US&libs=assets/feature/core
-// ( http://tinyurl.com/ywsyzb )
- mLastOver = rect;
- }
-#if DEBUG_NAV_UI && !defined BROWSER_DEBUG
- const SkIRect& drawnOver = mDrawnOver.getBounds();
- LOGD("%s (overlaps) rect={%d,%d,%d,%d}"
- " mDrawnOver={%d,%d,%d,%d} mType=%s mIsOpaque=%s mAllOpaque=%s\n", __FUNCTION__,
- rect.fLeft, rect.fTop, rect.fRight, rect.fBottom,
- drawnOver.fLeft, drawnOver.fTop, drawnOver.fRight, drawnOver.fBottom,
- TypeNames[mType], mIsOpaque ? "true" : "false", mAllOpaque ? "true" : "false");
-#endif
- }
- return false;
- }
-
- SkIRect mBounds;
- SkIRect mBoundsSlop;
- SkRegion mDrawnOver;
- SkIRect mLastOver;
- SkIRect mAllDrawnIn;
- SkIRect mLastAll;
-};
-
-class BoundsCanvas : public SkCanvas {
-public:
-
- BoundsCanvas(CommonCheck* bounder) : mBounder(*bounder) {
- mTransparentLayer = 0;
- setBounder(bounder);
- }
-
- virtual ~BoundsCanvas() {
- setBounder(NULL);
- }
-
- virtual void drawPaint(const SkPaint& paint) {
- mBounder.setType(CommonCheck::kDrawPaint_Type);
- SkCanvas::drawPaint(paint);
- }
-
- virtual void drawPoints(PointMode mode, size_t count, const SkPoint pts[],
- const SkPaint& paint) {
- mBounder.setType(CommonCheck::kDrawPoints_Type);
- SkCanvas::drawPoints(mode, count, pts, paint);
- }
-
- virtual void drawRect(const SkRect& rect, const SkPaint& paint) {
- mBounder.setType(CommonCheck::kDrawRect_Type);
- SkCanvas::drawRect(rect, paint);
- }
-
- virtual void drawPath(const SkPath& path, const SkPaint& paint) {
- mBounder.setType(CommonCheck::kDrawPath_Type);
- SkCanvas::drawPath(path, paint);
- }
-
- virtual void commonDrawBitmap(const SkBitmap& bitmap,
- const SkMatrix& matrix, const SkPaint& paint) {
- mBounder.setType(CommonCheck::kDrawBitmap_Type);
- mBounder.setIsOpaque(bitmap.isOpaque());
- SkCanvas::commonDrawBitmap(bitmap, matrix, paint);
- }
-
- virtual void drawSprite(const SkBitmap& bitmap, int left, int top,
- const SkPaint* paint = NULL) {
- mBounder.setType(CommonCheck::kDrawSprite_Type);
- mBounder.setIsOpaque(bitmap.isOpaque());
- SkCanvas::drawSprite(bitmap, left, top, paint);
- }
-
- virtual void drawText(const void* text, size_t byteLength, SkScalar x,
- SkScalar y, const SkPaint& paint) {
- mBounder.setEmpty();
- mBounder.setType(CommonCheck::kDrawGlyph_Type);
- SkCanvas::drawText(text, byteLength, x, y, paint);
- mBounder.doRect(CommonCheck::kDrawText_Type);
- }
-
- virtual void drawPosText(const void* text, size_t byteLength,
- const SkPoint pos[], const SkPaint& paint) {
- mBounder.setEmpty();
- mBounder.setType(CommonCheck::kDrawGlyph_Type);
- SkCanvas::drawPosText(text, byteLength, pos, paint);
- mBounder.doRect(CommonCheck::kDrawPosText_Type);
- }
-
- virtual void drawPosTextH(const void* text, size_t byteLength,
- const SkScalar xpos[], SkScalar constY,
- const SkPaint& paint) {
- mBounder.setEmpty();
- mBounder.setType(CommonCheck::kDrawGlyph_Type);
- SkCanvas::drawPosTextH(text, byteLength, xpos, constY, paint);
- if (mBounder.mUnion.isEmpty())
- return;
- SkPaint::FontMetrics metrics;
- paint.getFontMetrics(&metrics);
- SkPoint upDown[2] = { {xpos[0], constY + metrics.fAscent},
- {xpos[0], constY + metrics.fDescent} };
- const SkMatrix& matrix = getTotalMatrix();
- matrix.mapPoints(upDown, 2);
- if (upDown[0].fX == upDown[1].fX) {
- mBounder.mUnion.fTop = SkScalarFloor(upDown[0].fY);
- mBounder.mUnion.fBottom = SkScalarFloor(upDown[1].fY);
- }
- mBounder.doRect(CommonCheck::kDrawPosTextH_Type);
- }
-
- virtual void drawTextOnPath(const void* text, size_t byteLength,
- const SkPath& path, const SkMatrix* matrix,
- const SkPaint& paint) {
- mBounder.setEmpty();
- mBounder.setType(CommonCheck::kDrawGlyph_Type);
- SkCanvas::drawTextOnPath(text, byteLength, path, matrix, paint);
- mBounder.doRect(CommonCheck::kDrawTextOnPath_Type);
- }
-
- virtual void drawPicture(SkPicture& picture) {
- mBounder.setType(CommonCheck::kDrawPicture_Type);
- SkCanvas::drawPicture(picture);
- }
-
- virtual int saveLayer(const SkRect* bounds, const SkPaint* paint,
- SaveFlags flags) {
- int depth = SkCanvas::saveLayer(bounds, paint, flags);
- if (mTransparentLayer == 0 && paint && paint->getAlpha() < 255) {
- mTransparentLayer = depth;
- mBounder.setAllOpaque(false);
- }
- return depth;
- }
-
- virtual void restore() {
- int depth = getSaveCount();
- if (depth == mTransparentLayer) {
- mTransparentLayer = 0;
- mBounder.setAllOpaque(true);
- }
- SkCanvas::restore();
- }
-
- int mTransparentLayer;
- CommonCheck& mBounder;
-};
-
-/*
-CenterCheck examines the text in a picture, within a viewable rectangle,
-and returns via center() the optimal amount to scroll in x to display the
-paragraph of text.
-
-The caller of CenterCheck has configured (but not allocated) a bitmap
-the height and three times the width of the view. The picture is drawn centered
-in the bitmap, so text that would be revealed, if the view was scrolled up to
-a view-width to the left or right, is considered.
-*/
-class CenterCheck : public CommonCheck {
-public:
- CenterCheck(int x, int y, int width) : mX(x), mY(y),
- mHitLeft(x), mHitRight(x), mMostLeft(INT_MAX), mMostRight(-INT_MAX),
- mViewLeft(width), mViewRight(width << 1) {
- mHit.set(x - CENTER_SLOP, y - CENTER_SLOP,
- x + CENTER_SLOP, y + CENTER_SLOP);
- mPartial.setEmpty();
- }
-
- int center() {
- doRect(); // process the final line of text
- /* If the touch coordinates aren't near any text, return 0 */
- if (mHitLeft == mHitRight) {
- DBG_NAV_LOGD("abort: mHitLeft=%d ==mHitRight", mHitLeft);
- return 0;
- }
- int leftOver = mHitLeft - mViewLeft;
- int rightOver = mHitRight - mViewRight;
- int center;
- /* If the touched text is too large to entirely fit on the screen,
- center it. */
- if (leftOver < 0 && rightOver > 0) {
- center = (leftOver + rightOver) >> 1;
- DBG_NAV_LOGD("overlap: leftOver=%d rightOver=%d center=%d",
- leftOver, rightOver, center);
- return center;
- }
- center = (mMostLeft + mMostRight) >> 1; // the paragraph center
- if (leftOver > 0 && rightOver >= 0) { // off to the right
- if (center > mMostLeft) // move to center loses left-most text?
- center = mMostLeft;
- } else if (rightOver < 0 && leftOver <= 0) { // off to the left
- if (center < mMostRight) // move to center loses right-most text?
- center = mMostRight;
- } else {
-#ifdef DONT_CENTER_IF_ALREADY_VISIBLE
- center = 0; // paragraph is already fully visible
-#endif
- }
- DBG_NAV_LOGD("scroll: leftOver=%d rightOver=%d center=%d",
- leftOver, rightOver, center);
- return center;
- }
-
-protected:
- virtual bool onIRect(const SkIRect& rect) {
- if (joinGlyphs(rect)) // assembles glyphs into a text string
- return false;
- if (!isTextType(mType))
- return false;
- /* Text on one line may be broken into several parts. Reassemble
- the text into a rectangle before considering it. */
- if (rect.fTop < mPartial.fBottom && rect.fBottom >
- mPartial.fTop && mPartial.fRight + CENTER_SLOP >= rect.fLeft) {
- DBG_NAV_LOGD("join mPartial=(%d, %d, %d, %d) rect=(%d, %d, %d, %d)",
- mPartial.fLeft, mPartial.fTop, mPartial.fRight, mPartial.fBottom,
- rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
- mPartial.join(rect);
- return false;
- }
- if (mPartial.isEmpty() == false)
- doRect(); // process the previous line of text
- mPartial = rect;
- return false;
- }
-
- void doRect()
- {
- /* Record the outer bounds of the lines of text that was 'hit' by the
- touch coordinates, given some slop */
- if (SkIRect::Intersects(mPartial, mHit)) {
- if (mHitLeft > mPartial.fLeft)
- mHitLeft = mPartial.fLeft;
- if (mHitRight < mPartial.fRight)
- mHitRight = mPartial.fRight;
- DBG_NAV_LOGD("mHitLeft=%d mHitRight=%d", mHitLeft, mHitRight);
- }
- /* If the considered text is completely to the left or right of the
- touch coordinates, skip it */
- if (mPartial.fLeft > mX || mPartial.fRight < mX)
- return;
- int leftOver = mPartial.fLeft - mViewLeft;
- int rightOver = mPartial.fRight - mViewRight;
- /* If leftOver <= 0, the text starts off the screen.
- If rightOver >= 0, the text ends off the screen.
- */
- if (leftOver <= 0 && rightOver >= 0) // discard wider than screen
- return;
-#ifdef DONT_CENTER_IF_ALREADY_VISIBLE
- if (leftOver > 0 && rightOver < 0) // discard already visible
- return;
-#endif
- /* record the smallest margins on the left and right */
- if (mMostLeft > leftOver)
- mMostLeft = leftOver;
- if (mMostRight < rightOver)
- mMostRight = rightOver;
- DBG_NAV_LOGD("leftOver=%d rightOver=%d mMostLeft=%d mMostRight=%d",
- leftOver, rightOver, mMostLeft, mMostRight);
- }
-
- static const int CENTER_SLOP = 10; // space between text parts and lines
- /* const */ SkIRect mHit; // sloppy hit rectangle
- SkIRect mPartial; // accumulated text bounds, per line
- const int mX; // touch location
- const int mY;
- int mHitLeft; // touched text extremes
- int mHitRight;
- int mMostLeft; // paragraph extremes
- int mMostRight;
- const int mViewLeft; // middle third of 3x-wide view
- const int mViewRight;
-};
-
-class ImageCanvas : public SkCanvas {
-public:
- ImageCanvas(SkBounder* bounder) : mURI(NULL) {
- setBounder(bounder);
- }
-
-// Currently webkit's bitmap draws always seem to be cull'd before this entry
-// point is called, so we assume that any bitmap that gets here is inside our
-// tiny clip (may not be true in the future)
- virtual void commonDrawBitmap(const SkBitmap& bitmap,
- const SkMatrix& , const SkPaint& ) {
- SkPixelRef* pixelRef = bitmap.pixelRef();
- if (pixelRef != NULL) {
- mURI = pixelRef->getURI();
- }
- }
-
- const char* mURI;
-};
-
-class ImageCheck : public SkBounder {
-public:
- virtual bool onIRect(const SkIRect& rect) {
- return false;
- }
-};
-
-class JiggleCheck : public CommonCheck {
-public:
- JiggleCheck(int delta, int width) : mDelta(delta), mMaxX(width) {
- mMaxJiggle = 0;
- mMinX = mMinJiggle = abs(delta);
- mMaxWidth = width + mMinX;
- }
-
- int jiggle() {
- if (mMinJiggle > mMaxJiggle)
- return mDelta;
- int avg = (mMinJiggle + mMaxJiggle + 1) >> 1;
- return mDelta < 0 ? -avg : avg;
- }
-
- virtual bool onIRect(const SkIRect& rect) {
- if (joinGlyphs(rect))
- return false;
- if (mType != kDrawBitmap_Type && !isTextType(mType))
- return false;
- int min, max;
- if (mDelta < 0) {
- min = mMinX - rect.fLeft;
- max = mMaxWidth - rect.fRight;
- } else {
- min = rect.fRight - mMaxX;
- max = rect.fLeft;
- }
- if (min <= 0)
- return false;
- if (max >= mMinX)
- return false;
- if (mMinJiggle > min)
- mMinJiggle = min;
- if (mMaxJiggle < max)
- mMaxJiggle = max;
- return false;
- }
-
- int mDelta;
- int mMaxJiggle;
- int mMaxX;
- int mMinJiggle;
- int mMinX;
- int mMaxWidth;
-};
-
-bool CachedRoot::adjustForScroll(BestData* best, CachedFrame::Direction direction,
- WebCore::IntPoint* scrollPtr, bool findClosest)
-{
- WebCore::IntRect newOutset;
- const CachedNode* newNode = best->mNode;
- // see if there's a middle node
- // if the middle node is in the visited list,
- // or if none was computed and the newNode is in the visited list,
- // treat result as NULL
- if (newNode != NULL && findClosest) {
- if (best->bounds().intersects(mHistory->mPriorBounds) == false &&
- checkBetween(best, direction))
- newNode = best->mNode;
- if (findClosest && maskIfHidden(best)) {
- innerMove(document(), best, direction, scrollPtr, false);
- return true;
- }
- newNode->focusRingBounds(&newOutset);
- }
- int delta;
- bool newNodeInView = scrollDelta(newOutset, direction, &delta);
- if (delta && scrollPtr && (newNode == NULL || newNodeInView == false ||
- (best->mNavOutside && best->mWorkingOutside)))
- *scrollPtr = WebCore::IntPoint(direction & UP_DOWN ? 0 : delta,
- direction & UP_DOWN ? delta : 0);
- return false;
-}
-
-
-int CachedRoot::checkForCenter(int x, int y) const
-{
- int width = mViewBounds.width();
- CenterCheck centerCheck(x + width - mViewBounds.x(), y - mViewBounds.y(),
- width);
- BoundsCanvas checker(&centerCheck);
- SkBitmap bitmap;
- bitmap.setConfig(SkBitmap::kARGB_8888_Config, width * 3,
- mViewBounds.height());
- checker.setBitmapDevice(bitmap);
- checker.translate(SkIntToScalar(width - mViewBounds.x()),
- SkIntToScalar(-mViewBounds.y()));
- checker.drawPicture(*mPicture);
- return centerCheck.center();
-}
-
-void CachedRoot::checkForJiggle(int* xDeltaPtr) const
-{
- int xDelta = *xDeltaPtr;
- JiggleCheck jiggleCheck(xDelta, mViewBounds.width());
- BoundsCanvas checker(&jiggleCheck);
- SkBitmap bitmap;
- int absDelta = abs(xDelta);
- 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);
- *xDeltaPtr = jiggleCheck.jiggle();
-}
-
-const CachedNode* CachedRoot::findAt(const WebCore::IntRect& rect,
- const CachedFrame** framePtr, int* x, int* y) const
-{
- int best = INT_MAX;
- (const_cast<CachedRoot*>(this))->resetClippedOut();
- const CachedNode* directHit = NULL;
- const CachedNode* node = findBestAt(rect, &best, &directHit, framePtr, x, y);
- DBG_NAV_LOGD("node=%d (%p)", node == NULL ? 0 : node->index(),
- node == NULL ? NULL : node->nodePointer());
- if (node == NULL) {
- node = findBestHitAt(rect, &best, framePtr, x, y);
- DBG_NAV_LOGD("node=%d (%p)", node == NULL ? 0 : node->index(),
- node == NULL ? NULL : node->nodePointer());
- }
- if (node == NULL) {
- *framePtr = findBestFrameAt(rect.x() + (rect.width() >> 1),
- rect.y() + (rect.height() >> 1));
- }
- return node;
-}
-
-WebCore::IntPoint CachedRoot::focusLocation() const
-{
- const WebCore::IntRect& bounds = mHistory->mNavBounds;
- return WebCore::IntPoint(bounds.x() + (bounds.width() >> 1),
- bounds.y() + (bounds.height() >> 1));
-}
-
-// These reset the values because we only want to get the selection the first time.
-// After that, the selection is no longer accurate.
-int CachedRoot::getAndResetSelectionEnd()
-{
- int end = mSelectionEnd;
- mSelectionEnd = -1;
- return end;
-}
-
-int CachedRoot::getAndResetSelectionStart()
-{
- int start = mSelectionStart;
- mSelectionStart = -1;
- return start;
-}
-
-void CachedRoot::getSimulatedMousePosition(WebCore::IntPoint* point)
-{
-#ifndef NDEBUG
- ASSERT(CachedFrame::mDebug.mInUse);
-#endif
- const WebCore::IntRect& mouseBounds = mHistory->mMouseBounds;
- point->setX(mouseBounds.x() + (mouseBounds.width() >> 1));
- point->setY(mouseBounds.y() + (mouseBounds.height() >> 1));
-#if DEBUG_NAV_UI && !defined BROWSER_DEBUG
- const WebCore::IntRect& navBounds = mHistory->mNavBounds;
- LOGD("%s mHistory->mNavBounds={%d,%d,%d,%d} "
- "mHistory->mMouseBounds={%d,%d,%d,%d} point={%d,%d}\n", __FUNCTION__,
- navBounds.x(), navBounds.y(), navBounds.width(), navBounds.height(),
- mouseBounds.x(), mouseBounds.y(), mouseBounds.width(), mouseBounds.height(),
- point->x(), point->y());
-#endif
-}
-
-void CachedRoot::init(WebCore::Frame* frame, CachedHistory* history)
-{
- CachedFrame::init(this, -1, frame);
- reset();
- mHistory = history;
- mPicture = NULL;
-}
-
-bool CachedRoot::innerDown(const CachedNode* test, BestData* bestData) const
-{
- ASSERT(minWorkingVertical() >= mViewBounds.x());
- ASSERT(maxWorkingVertical() <= mViewBounds.right());
- setupScrolledBounds();
- // (line up)
- mScrolledBounds.setHeight(mScrolledBounds.height() + mMaxYScroll);
- int testTop = mScrolledBounds.y();
- int viewBottom = mViewBounds.bottom();
- if (mFocusBounds.isEmpty() == false &&
- mFocusBounds.bottom() > viewBottom && viewBottom < mContents.height())
- return false;
- if (mHistory->mNavBounds.isEmpty() == false) {
- int navTop = mHistory->mNavBounds.y();
- int scrollBottom;
- if (testTop < navTop && navTop < (scrollBottom = mScrolledBounds.bottom())) {
- mScrolledBounds.setHeight(scrollBottom - navTop);
- mScrolledBounds.setY(navTop);
- }
- }
- frameDown(test, NULL, bestData, currentFocus());
- return true;
-}
-
-bool CachedRoot::innerLeft(const CachedNode* test, BestData* bestData) const
-{
- ASSERT(minWorkingHorizontal() >= mViewBounds.y());
- ASSERT(maxWorkingHorizontal() <= mViewBounds.bottom());
- setupScrolledBounds();
- mScrolledBounds.setX(mScrolledBounds.x() - mMaxXScroll);
- mScrolledBounds.setWidth(mScrolledBounds.width() + mMaxXScroll);
- int testRight = mScrolledBounds.right();
- int viewLeft = mViewBounds.x();
- if (mFocusBounds.isEmpty() == false &&
- mFocusBounds.x() < viewLeft && viewLeft > mContents.x())
- return false;
- if (mHistory->mNavBounds.isEmpty() == false) {
- int navRight = mHistory->mNavBounds.right();
- int scrollLeft;
- if (testRight > navRight && navRight > (scrollLeft = mScrolledBounds.x()))
- mScrolledBounds.setWidth(navRight - scrollLeft);
- }
- frameLeft(test, NULL, bestData, currentFocus());
- return true;
-}
-
-
-void CachedRoot::innerMove(const CachedNode* node, BestData* bestData,
- Direction direction, WebCore::IntPoint* scroll, bool firstCall)
-{
- bestData->reset();
- mFocusChild = false;
- bool outOfFocus = mFocus < 0;
- bool firstTime = mHistory->didFirstLayout() && outOfFocus;
-#if DEBUG_NAV_UI && !defined BROWSER_DEBUG
- LOGD("%s mHistory->didFirstLayout()=%s && mFocus=%d\n", __FUNCTION__,
- mHistory->didFirstLayout() ? "true" : "false", mFocus);
-#endif
- if (firstTime)
- mHistory->reset();
- const CachedNode* focus = currentFocus();
- mHistory->setWorking(direction, focus, mViewBounds);
- mFocusBounds = WebCore::IntRect(0, 0, 0, 0);
- if (focus != NULL)
- focus->getBounds(&mFocusBounds);
- bool findClosest = false;
- if (mScrollOnly == false) {
- switch (direction) {
- case LEFT:
- if (outOfFocus)
- mHistory->mNavBounds = WebCore::IntRect(mViewBounds.right(),
- mViewBounds.y(), 1, mViewBounds.height());
- findClosest = innerLeft(node, bestData);
- break;
- case RIGHT:
- if (outOfFocus)
- mHistory->mNavBounds = WebCore::IntRect(mViewBounds.x() - 1,
- mViewBounds.y(), 1, mViewBounds.height());
- findClosest = innerRight(node, bestData);
- break;
- case UP:
- if (outOfFocus)
- mHistory->mNavBounds = WebCore::IntRect(mViewBounds.x(),
- mViewBounds.bottom(), mViewBounds.width(), 1);
- findClosest = innerUp(node, bestData);
- break;
- case DOWN:
- if (outOfFocus)
- mHistory->mNavBounds = WebCore::IntRect(mViewBounds.x(),
- mViewBounds.y() - 1, mViewBounds.width(), 1);
- findClosest = innerDown(node, bestData);
- break;
- case UNINITIALIZED:
- default:
- ASSERT(0);
- }
- }
- if (firstCall)
- mHistory->mPriorBounds = mHistory->mNavBounds; // bounds always advances, even if new node is ultimately NULL
- bestData->mMouseBounds = bestData->mNodeBounds;
- if (adjustForScroll(bestData, direction, scroll, findClosest))
- return;
- if (bestData->mNode != NULL) {
- mHistory->addToVisited(bestData->mNode, direction);
- mHistory->mNavBounds = mFocusBounds = bestData->mNodeBounds;
- mHistory->mMouseBounds = bestData->mMouseBounds;
- } else if (scroll->x() != 0 || scroll->y() != 0) {
- WebCore::IntRect newBounds = mHistory->mNavBounds;
- int offsetX = scroll->x();
- int offsetY = scroll->y();
- newBounds.move(offsetX, offsetY);
- if (mViewBounds.x() > newBounds.x())
- offsetX = mViewBounds.x() - mHistory->mNavBounds.x();
- else if (mViewBounds.right() < newBounds.right())
- offsetX = mViewBounds.right() - mHistory->mNavBounds.right();
- if (mViewBounds.y() > newBounds.y())
- offsetY = mViewBounds.y() - mHistory->mNavBounds.y();
- else if (mViewBounds.bottom() < newBounds.bottom())
- offsetY = mViewBounds.bottom() - mHistory->mNavBounds.bottom();
- mHistory->mNavBounds.move(offsetX, offsetY);
- }
- mHistory->setDidFirstLayout(false);
-}
-
-bool CachedRoot::innerRight(const CachedNode* test, BestData* bestData) const
-{
- ASSERT(minWorkingHorizontal() >= mViewBounds.y());
- ASSERT(maxWorkingHorizontal() <= mViewBounds.bottom());
- setupScrolledBounds();
- // (align)
- mScrolledBounds.setWidth(mScrolledBounds.width() + mMaxXScroll);
- int testLeft = mScrolledBounds.x();
- int viewRight = mViewBounds.right();
- if (mFocusBounds.isEmpty() == false &&
- mFocusBounds.right() > viewRight && viewRight < mContents.width())
- return false;
- if (mHistory->mNavBounds.isEmpty() == false) {
- int navLeft = mHistory->mNavBounds.x();
- int scrollRight;
- if (testLeft < navLeft && navLeft < (scrollRight = mScrolledBounds.right())) {
- mScrolledBounds.setWidth(scrollRight - navLeft);
- mScrolledBounds.setX(navLeft);
- }
- }
- frameRight(test, NULL, bestData, currentFocus());
- return true;
-}
-
-bool CachedRoot::innerUp(const CachedNode* test, BestData* bestData) const
-{
- ASSERT(minWorkingVertical() >= mViewBounds.x());
- ASSERT(maxWorkingVertical() <= mViewBounds.right());
- setupScrolledBounds();
- mScrolledBounds.setY(mScrolledBounds.y() - mMaxYScroll);
- mScrolledBounds.setHeight(mScrolledBounds.height() + mMaxYScroll);
- int testBottom = mScrolledBounds.bottom();
- int viewTop = mViewBounds.y();
- if (mFocusBounds.isEmpty() == false &&
- mFocusBounds.y() < viewTop && viewTop > mContents.y())
- return false;
- if (mHistory->mNavBounds.isEmpty() == false) {
- int navBottom = mHistory->mNavBounds.bottom();
- int scrollTop;
- if (testBottom > navBottom && navBottom > (scrollTop = mScrolledBounds.y()))
- mScrolledBounds.setHeight(navBottom - scrollTop);
- }
- frameUp(test, NULL, bestData, currentFocus());
- return true;
-}
-
-WebCore::String CachedRoot::imageURI(int x, int y) const
-{
- ImageCheck imageCheck;
- ImageCanvas checker(&imageCheck);
- SkBitmap bitmap;
- bitmap.setConfig(SkBitmap::kARGB_8888_Config, 1, 1);
- checker.setBitmapDevice(bitmap);
- checker.translate(SkIntToScalar(-x), SkIntToScalar(-y));
- checker.drawPicture(*mPicture);
- return WebCore::String(checker.mURI);
-}
-
-bool CachedRoot::maskIfHidden(BestData* best) const
-{
- if (mPicture == NULL) {
-#if DEBUG_NAV_UI && !defined BROWSER_DEBUG
- LOGD("%s missing picture\n", __FUNCTION__);
-#endif
- return false;
- }
- const CachedNode* bestNode = best->mNode;
- if (bestNode->isUnclipped())
- return false;
- // given the picture matching this nav cache
- // create an SkBitmap with dimensions of the focus intersected w/ extended view
- const WebCore::IntRect& nodeBounds = bestNode->getBounds();
- WebCore::IntRect bounds = nodeBounds;
- bounds.intersect(mScrolledBounds);
- int leftMargin = bounds.x() == nodeBounds.x() ? kMargin : 0;
- int topMargin = bounds.y() == nodeBounds.y() ? kMargin : 0;
- int rightMargin = bounds.right() == nodeBounds.right() ? kMargin : 0;
- int bottomMargin = bounds.bottom() == nodeBounds.bottom() ? kMargin : 0;
- bool unclipped = (leftMargin & topMargin & rightMargin & bottomMargin) != 0;
- WebCore::IntRect marginBounds = nodeBounds;
- marginBounds.inflate(kMargin);
- marginBounds.intersect(mScrolledBounds);
- BoundsCheck boundsCheck;
- BoundsCanvas checker(&boundsCheck);
- boundsCheck.mBounds.set(leftMargin, topMargin,
- leftMargin + bounds.width(), topMargin + bounds.height());
- boundsCheck.mBoundsSlop = boundsCheck.mBounds;
- boundsCheck.mBoundsSlop.inset(-kSlop, -kSlop);
- SkBitmap bitmap;
- bitmap.setConfig(SkBitmap::kARGB_8888_Config, marginBounds.width(),
- marginBounds.height());
- checker.setBitmapDevice(bitmap);
- // insert probes to be called when the data corresponding to this focus ring is drawn
- // need to know if focus ring was generated by text, image, or parent (like div)
- // ? need to know (like imdb menu bar) to give up sometimes (when?)
- checker.translate(SkIntToScalar(leftMargin - bounds.x()),
- SkIntToScalar(topMargin - bounds.y()));
- checker.drawPicture(*mPicture);
- boundsCheck.checkLast();
- // was it not drawn or clipped out?
- if (boundsCheck.hidden()) { // if hidden, return false so that nav can try again
- CachedNode* node = const_cast<CachedNode*>(best->mNode);
-#if DEBUG_NAV_UI && !defined BROWSER_DEBUG
- const SkIRect& m = boundsCheck.mBounds;
- const SkIRect& s = boundsCheck.mBoundsSlop;
- LOGD("%s hidden node:%p (%d) mBounds={%d,%d,%d,%d} mBoundsSlop="
- "{%d,%d,%d,%d}\n", __FUNCTION__, node, node->index(),
- m.fLeft, m.fTop, m.fRight, m.fBottom,
- s.fLeft, s.fTop, s.fRight, s.fBottom);
- const SkIRect& o = boundsCheck.mDrawnOver.getBounds();
- const SkIRect& l = boundsCheck.mLastAll;
- const SkIRect& u = boundsCheck.mUnion;
- LOGD("%s hidden mDrawnOver={%d,%d,%d,%d} mLastAll={%d,%d,%d,%d}"
- " mUnion={%d,%d,%d,%d}\n", __FUNCTION__,
- o.fLeft, o.fTop, o.fRight, o.fBottom,
- l.fLeft, l.fTop, l.fRight, l.fBottom,
- u.fLeft, u.fTop, u.fRight, u.fBottom);
- const SkIRect& a = boundsCheck.mAllDrawnIn;
- const WebCore::IntRect& c = mScrolledBounds;
- const WebCore::IntRect& b = nodeBounds;
- LOGD("%s hidden mAllDrawnIn={%d,%d,%d,%d} mScrolledBounds={%d,%d,%d,%d}"
- " nodeBounds={%d,%d,%d,%d}\n", __FUNCTION__,
- a.fLeft, a.fTop, a.fRight, a.fBottom,
- c.x(), c.y(), c.right(), c.bottom(),
- b.x(), b.y(), b.right(), b.bottom());
- LOGD("%s bits.mWidth=%d bits.mHeight=%d transX=%d transY=%d\n", __FUNCTION__,
- marginBounds.width(),marginBounds.height(),
- kMargin - bounds.x(), kMargin - bounds.y());
-#endif
- node->setDisabled(true);
- node->setClippedOut(unclipped == false);
- return true;
- }
- // was it partially occluded by later drawing?
- // if partially occluded, modify the bounds so that the mouse click has a better x,y
- const SkIRect& over = boundsCheck.mDrawnOver.getBounds();
- if (over.isEmpty() == false) {
-#if DEBUG_NAV_UI && !defined BROWSER_DEBUG
- SkIRect orig = boundsCheck.mBounds;
-#endif
- SkIRect& base = boundsCheck.mBounds;
- if (base.fLeft < over.fRight && base.fRight > over.fRight)
- base.fLeft = over.fRight;
- else if (base.fRight > over.fLeft && base.fLeft < over.fLeft)
- base.fRight = over.fLeft;
- if (base.fTop < over.fBottom && base.fBottom > over.fBottom)
- base.fTop = over.fBottom;
- else if (base.fBottom > over.fTop && base.fTop < over.fTop)
- base.fBottom = over.fTop;
-#if DEBUG_NAV_UI && !defined BROWSER_DEBUG
- const SkIRect& modded = boundsCheck.mBounds;
- LOGD("%s partially occluded node:%p (%d) old:{%d,%d,%d,%d} new:{%d,%d,%d,%d}\n",
- __FUNCTION__, best->mNode, best->mNode->index(),
- 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());
- }
- return false;
-}
-
-const CachedNode* CachedRoot::moveFocus(Direction direction, const CachedFrame** framePtr,
- WebCore::IntPoint* scroll)
-{
-#ifndef NDEBUG
- ASSERT(CachedFrame::mDebug.mInUse);
-#endif
- CachedRoot* frame = this;
- const CachedNode* node = frame->document();
- if (node == NULL)
- return NULL;
- if (mViewBounds.isEmpty())
- return NULL;
- resetClippedOut();
- setData();
- BestData bestData;
- innerMove(node, &bestData, direction, scroll, true);
- *framePtr = bestData.mFrame;
- return const_cast<CachedNode*>(bestData.mNode);
-}
-
-void CachedRoot::reset()
-{
-#ifndef NDEBUG
- ASSERT(CachedFrame::mDebug.mInUse);
-#endif
- mContents = mViewBounds = WebCore::IntRect(0, 0, 0, 0);
- mMaxXScroll = mMaxYScroll = 0;
- mSelectionStart = mSelectionEnd = -1;
- mScrollOnly = false;
- mFocusBounds = WebCore::IntRect(0, 0, 0, 0);
-}
-
-bool CachedRoot::scrollDelta(WebCore::IntRect& newOutset, Direction direction, int* delta)
-{
- switch (direction) {
- case LEFT:
- *delta = -mMaxXScroll;
- return newOutset.x() >= mViewBounds.x();
- case RIGHT:
- *delta = mMaxXScroll;
- return newOutset.right() <= mViewBounds.right();
- case UP:
- *delta = -mMaxYScroll;
- return newOutset.y() >= mViewBounds.y();
- case DOWN:
- *delta = mMaxYScroll;
- return newOutset.bottom() <= mViewBounds.bottom();
- default:
- *delta = 0;
- ASSERT(0);
- }
- return false;
-}
-
-void CachedRoot::setCachedFocus(CachedFrame* frame, CachedNode* node)
-{
-#if !defined NDEBUG
- ASSERT(CachedFrame::mDebug.mInUse);
-#endif
-#if DEBUG_NAV_UI && !defined BROWSER_DEBUG
- const CachedNode* focus = currentFocus();
- WebCore::IntRect bounds;
- if (focus)
- bounds = focus->bounds();
- LOGD("%s old focus %d (nodePointer=%p) bounds={%d,%d,%d,%d}\n", __FUNCTION__,
- focus ? focus->index() : 0,
- focus ? focus->nodePointer() : NULL, bounds.x(), bounds.y(),
- bounds.width(), bounds.height());
-#endif
- clearFocus();
- if (node == NULL)
- return;
- node->setIsFocus(true);
- ASSERT(node->isFrame() == false);
- frame->setFocusIndex(node - frame->document());
- ASSERT(frame->focusIndex() > 0 && frame->focusIndex() < (int) frame->size());
- CachedFrame* parent;
- while ((parent = frame->parent()) != NULL) {
- parent->setFocusIndex(frame->indexInParent());
- frame = parent;
- }
-#if DEBUG_NAV_UI && !defined BROWSER_DEBUG
- focus = currentFocus();
- bounds = WebCore::IntRect(0, 0, 0, 0);
- if (focus)
- bounds = focus->bounds();
- LOGD("%s new focus %d (nodePointer=%p) bounds={%d,%d,%d,%d}\n", __FUNCTION__,
- focus ? focus->index() : 0,
- focus ? focus->nodePointer() : NULL, bounds.x(), bounds.y(),
- bounds.width(), bounds.height());
-#endif
-}
-
-void CachedRoot::setupScrolledBounds() const
-{
- mScrolledBounds = mViewBounds;
-}
-
-#if DUMP_NAV_CACHE
-
-#define DEBUG_PRINT_BOOL(field) \
- DUMP_NAV_LOGD("// bool " #field "=%s;\n", b->field ? "true" : "false")
-
-#define DEBUG_PRINT_RECT(field) \
- { const WebCore::IntRect& r = b->field; \
- DUMP_NAV_LOGD("// IntRect " #field "={%d, %d, %d, %d};\n", \
- r.x(), r.y(), r.width(), r.height()); }
-
-CachedRoot* CachedRoot::Debug::base() const {
- CachedRoot* nav = (CachedRoot*) ((char*) this - OFFSETOF(CachedRoot, mDebug));
- return nav;
-}
-
-void CachedRoot::Debug::print() const
-{
-#ifdef DUMP_NAV_CACHE_USING_PRINTF
- gWriteLogMutex.lock();
- ASSERT(gNavCacheLogFile == NULL);
- gNavCacheLogFile = fopen(NAV_CACHE_LOG_FILE, "a");
-#endif
- CachedRoot* b = base();
- b->CachedFrame::mDebug.print();
- b->mHistory->mDebug.print(b);
- DEBUG_PRINT_RECT(mFocusBounds);
- DUMP_NAV_LOGD("// int mMaxXScroll=%d, mMaxYScroll=%d;\n",
- b->mMaxXScroll, b->mMaxYScroll);
- DEBUG_PRINT_BOOL(mFocusChild);
-#ifdef DUMP_NAV_CACHE_USING_PRINTF
- if (gNavCacheLogFile)
- fclose(gNavCacheLogFile);
- gNavCacheLogFile = NULL;
- gWriteLogMutex.unlock();
-#endif
-}
-
-#endif
-
-}
diff --git a/WebKit/android/nav/CachedRoot.h b/WebKit/android/nav/CachedRoot.h
deleted file mode 100644
index ab1b823..0000000
--- a/WebKit/android/nav/CachedRoot.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright 2007, 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 APPLE COMPUTER, INC. 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 CachedRoot_H
-#define CachedRoot_H
-
-#include "CachedFrame.h"
-#include "IntPoint.h"
-#include "SkPicture.h"
-
-class SkRect;
-
-namespace android {
-
-class CachedHistory;
-class CachedNode;
-
-class CachedRoot : public CachedFrame {
-public:
- bool adjustForScroll(BestData* , Direction , WebCore::IntPoint* scrollPtr,
- bool findClosest);
- int checkForCenter(int x, int y) const;
- void checkForJiggle(int* ) const;
- int documentHeight() { return mContents.height(); }
- int documentWidth() { return mContents.width(); }
- const CachedNode* findAt(const WebCore::IntRect& , const CachedFrame** ,
- int* x, int* y) const;
- const WebCore::IntRect& focusBounds() const { return mFocusBounds; }
- bool focusChild() const { return mFocusChild; }
- WebCore::IntPoint focusLocation() const;
- int generation() const { return mGeneration; }
- SkPicture* getPicture() { return mPicture; }
- int getAndResetSelectionEnd();
- int getAndResetSelectionStart();
-// const WebCore::IntRect& navClipBounds() const { return mClippedBounds; }
- void getSimulatedMousePosition(WebCore::IntPoint* );
-// bool hasNavClipBounds() { return mClippedBounds.isEmpty() == false; }
- void init(WebCore::Frame* , CachedHistory* );
- bool innerDown(const CachedNode* , BestData* ) const;
- bool innerLeft(const CachedNode* , BestData* ) const;
- void innerMove(const CachedNode* ,BestData* bestData, Direction ,
- WebCore::IntPoint* scroll, bool firstCall);
- bool innerRight(const CachedNode* , BestData* ) const;
- bool innerUp(const CachedNode* , BestData* ) const;
- WebCore::String imageURI(int x, int y) const;
- bool maskIfHidden(BestData* ) const;
- const CachedNode* moveFocus(Direction , const CachedFrame** , WebCore::IntPoint* scroll);
- void reset();
-// void resetNavClipBounds() { mClippedBounds = WebCore::IntRect(-1, -1, 0, 0); }
- CachedHistory* rootHistory() const { return mHistory; }
- bool scrollDelta(WebCore::IntRect& focusRingBounds, Direction , int* delta);
- const WebCore::IntRect& scrolledBounds() const { return mScrolledBounds; }
- void setCachedFocus(CachedFrame* , CachedNode* );
- void setFocusBounds(const WebCore::IntRect& r) { mFocusBounds = r; }
- void setGeneration(int generation) { mGeneration = generation; }
- void setTextGeneration(int textGeneration) { mTextGeneration = textGeneration; }
- void setFocusChild(bool state) const { mFocusChild = state; }
- void setMaxScroll(int x, int y) { mMaxXScroll = x; mMaxYScroll = y; }
-// void setNavClipBounds(const WebCore::IntRect& r) { mClippedBounds = r; }
- void setPicture(SkPicture* picture) { mPicture = picture; }
- void setScrollOnly(bool state) { mScrollOnly = state; }
- void setSelection(int start, int end) { mSelectionStart = start; mSelectionEnd = end; }
- void setupScrolledBounds() const;
- void setVisibleRect(const WebCore::IntRect& r) { mViewBounds = r; }
- int textGeneration() const { return mTextGeneration; }
- int width() const { return mPicture ? mPicture->width() : 0; }
-private:
- CachedHistory* mHistory;
- SkPicture* mPicture;
- WebCore::IntRect mFocusBounds; // chosen focus ring
- mutable WebCore::IntRect mScrolledBounds; // view bounds + amount visible as result of scroll
- int mGeneration;
- int mTextGeneration;
- int mMaxXScroll;
- int mMaxYScroll;
- // These two are ONLY used when the tree is rebuilt and the focus is a textfield/area
- int mSelectionStart;
- int mSelectionEnd;
- mutable bool mFocusChild; // temporary state set if walked nodes are children of focus
- bool mScrollOnly;
-#if DUMP_NAV_CACHE
-public:
- class Debug {
-public:
- CachedRoot* base() const;
- void print() const;
- } mDebug;
-#endif
-};
-
-}
-
-#endif
diff --git a/WebKit/android/nav/FindCanvas.cpp b/WebKit/android/nav/FindCanvas.cpp
deleted file mode 100644
index 61bb07e..0000000
--- a/WebKit/android/nav/FindCanvas.cpp
+++ /dev/null
@@ -1,458 +0,0 @@
-/*
- * Copyright 2008, 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 APPLE COMPUTER, INC. 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 "config.h"
-#include "FindCanvas.h"
-
-#include "SkRect.h"
-
-// MatchInfo methods
-////////////////////////////////////////////////////////////////////////////////
-
-MatchInfo::MatchInfo() {
- m_picture = 0;
-}
-
-MatchInfo::~MatchInfo() {
- m_picture->safeUnref();
-}
-
-MatchInfo::MatchInfo(const MatchInfo& src) {
- m_location = src.m_location;
- m_picture = src.m_picture;
- m_picture->safeRef();
-}
-
-void MatchInfo::set(const SkRegion& region, SkPicture* pic) {
- m_picture->safeUnref();
- m_location = region;
- m_picture = pic;
- SkASSERT(pic);
- pic->ref();
-}
-
-// GlyphSet methods
-////////////////////////////////////////////////////////////////////////////////
-
-GlyphSet::GlyphSet(const SkPaint& paint, const UChar* lower, const UChar* upper,
- size_t byteLength) {
- SkPaint clonePaint(paint);
- clonePaint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
- mTypeface = paint.getTypeface();
- mCount = clonePaint.textToGlyphs(lower, byteLength, NULL);
- if (mCount > MAX_STORAGE_COUNT) {
- mLowerGlyphs = new uint16_t[2*mCount];
- } else {
- mLowerGlyphs = &mStorage[0];
- }
- // Use one array, and have mUpperGlyphs point to a portion of it,
- // so that we can reduce the number of new/deletes
- mUpperGlyphs = mLowerGlyphs + mCount;
- int count2 = clonePaint.textToGlyphs(lower, byteLength, mLowerGlyphs);
- SkASSERT(mCount == count2);
- count2 = clonePaint.textToGlyphs(upper, byteLength, mUpperGlyphs);
- SkASSERT(mCount == count2);
-}
-
-GlyphSet::~GlyphSet() {
- // Do not need to delete mTypeface, which is not owned by us.
- if (mCount > MAX_STORAGE_COUNT) {
- delete[] mLowerGlyphs;
- } // Otherwise, we just used local storage space, so no need to delete
- // Also do not need to delete mUpperGlyphs, which simply points to a
- // part of mLowerGlyphs
-}
-
-GlyphSet::GlyphSet& GlyphSet::operator=(GlyphSet& src) {
- mTypeface = src.mTypeface;
- mCount = src.mCount;
- if (mCount > MAX_STORAGE_COUNT) {
- mLowerGlyphs = new uint16_t[2*mCount];
- } else {
- mLowerGlyphs = &mStorage[0];
- }
- memcpy(mLowerGlyphs, src.mLowerGlyphs, 2*mCount*sizeof(uint16_t));
- mUpperGlyphs = mLowerGlyphs + mCount;
- return *this;
-}
-
-bool GlyphSet::characterMatches(uint16_t c, int index) {
- SkASSERT(index < mCount && index >= 0);
- return c == mLowerGlyphs[index] || c == mUpperGlyphs[index];
-}
-
-// FindCanvas methods
-////////////////////////////////////////////////////////////////////////////////
-
-FindCanvas::FindCanvas(int width, int height, const UChar* lower,
- const UChar* upper, size_t byteLength)
- : mLowerText(lower)
- , mUpperText(upper)
- , mLength(byteLength)
- , mNumFound(0) {
-
- setBounder(&mBounder);
- mOutset = -SkIntToScalar(2);
- mMatches = new WTF::Vector<MatchInfo>();
- mWorkingIndex = 0;
- mWorkingCanvas = 0;
- mWorkingPicture = 0;
-}
-
-FindCanvas::~FindCanvas() {
- setBounder(NULL);
- /* Just in case getAndClear was not called. */
- delete mMatches;
- mWorkingPicture->safeUnref();
-}
-
-// Each version of addMatch returns a rectangle for a match.
-// Not all of the parameters are used by each version.
-SkRect FindCanvas::addMatchNormal(int index,
- const SkPaint& paint, int count, const uint16_t* glyphs,
- const SkScalar pos[], SkScalar y) {
- const uint16_t* lineStart = glyphs - index;
- /* Use the original paint, since "text" is in glyphs */
- SkScalar before = paint.measureText(lineStart, index * sizeof(uint16_t), 0);
- SkRect rect;
- rect.fLeft = pos[0] + before;
- int countInBytes = count * sizeof(uint16_t);
- rect.fRight = paint.measureText(glyphs, countInBytes, 0) + rect.fLeft;
- SkPaint::FontMetrics fontMetrics;
- paint.getFontMetrics(&fontMetrics);
- SkScalar baseline = y;
- rect.fTop = baseline + fontMetrics.fAscent;
- rect.fBottom = baseline + fontMetrics.fDescent;
- const SkMatrix& matrix = getTotalMatrix();
- matrix.mapRect(&rect);
- // Add the text to our picture.
- SkCanvas* canvas = getWorkingCanvas();
- int saveCount = canvas->save();
- canvas->concat(matrix);
- canvas->drawText(glyphs, countInBytes, pos[0] + before, y, paint);
- canvas->restoreToCount(saveCount);
- return rect;
-}
-
-SkRect FindCanvas::addMatchPos(int index,
- const SkPaint& paint, int count, const uint16_t* glyphs,
- const SkScalar xPos[], SkScalar /* y */) {
- SkRect r;
- r.setEmpty();
- const SkPoint* temp = reinterpret_cast<const SkPoint*> (xPos);
- const SkPoint* points = &temp[index];
- int countInBytes = count * sizeof(uint16_t);
- SkPaint::FontMetrics fontMetrics;
- paint.getFontMetrics(&fontMetrics);
- // Need to check each character individually, since the heights may be
- // different.
- for (int j = 0; j < count; j++) {
- SkRect bounds;
- bounds.fLeft = points[j].fX;
- bounds.fRight = bounds.fLeft +
- paint.measureText(&glyphs[j], sizeof(uint16_t), 0);
- SkScalar baseline = points[j].fY;
- bounds.fTop = baseline + fontMetrics.fAscent;
- bounds.fBottom = baseline + fontMetrics.fDescent;
- /* Accumulate and then add the resulting rect to mMatches */
- r.join(bounds);
- }
- SkMatrix matrix = getTotalMatrix();
- matrix.mapRect(&r);
- SkCanvas* canvas = getWorkingCanvas();
- int saveCount = canvas->save();
- canvas->concat(matrix);
- canvas->drawPosText(glyphs, countInBytes, points, paint);
- canvas->restoreToCount(saveCount);
- return r;
-}
-
-SkRect FindCanvas::addMatchPosH(int index,
- const SkPaint& paint, int count, const uint16_t* glyphs,
- const SkScalar position[], SkScalar constY) {
- SkRect r;
- // We only care about the positions starting at the index of our match
- const SkScalar* xPos = &position[index];
- // This assumes that the position array is monotonic increasing
- // The left bounds will be the position of the left most character
- r.fLeft = xPos[0];
- // The right bounds will be the position of the last character plus its
- // width
- int lastIndex = count - 1;
- r.fRight = paint.measureText(&glyphs[lastIndex], sizeof(uint16_t), 0)
- + xPos[lastIndex];
- // Grab font metrics to determine the top and bottom of the bounds
- SkPaint::FontMetrics fontMetrics;
- paint.getFontMetrics(&fontMetrics);
- r.fTop = constY + fontMetrics.fAscent;
- r.fBottom = constY + fontMetrics.fDescent;
- const SkMatrix& matrix = getTotalMatrix();
- matrix.mapRect(&r);
- SkCanvas* canvas = getWorkingCanvas();
- int saveCount = canvas->save();
- canvas->concat(matrix);
- canvas->drawPosTextH(glyphs, count * sizeof(uint16_t), xPos, constY, paint);
- canvas->restoreToCount(saveCount);
- return r;
-}
-
-void FindCanvas::drawText(const void* text, size_t byteLength, SkScalar x,
- SkScalar y, const SkPaint& paint) {
- findHelper(text, byteLength, paint, &x, y, &FindCanvas::addMatchNormal);
-}
-
-void FindCanvas::drawPosText(const void* text, size_t byteLength,
- const SkPoint pos[], const SkPaint& paint) {
- // Pass in the first y coordinate for y so that we can check to see whether
- // it is lower than the last draw call (to check if we are continuing to
- // another line).
- findHelper(text, byteLength, paint, (const SkScalar*) pos, pos[0].fY,
- &FindCanvas::addMatchPos);
-}
-
-void FindCanvas::drawPosTextH(const void* text, size_t byteLength,
- const SkScalar xpos[], SkScalar constY,
- const SkPaint& paint) {
- findHelper(text, byteLength, paint, xpos, constY,
- &FindCanvas::addMatchPosH);
-}
-
-/* The current behavior is to skip substring matches. This means that in the
- * string
- * batbatbat
- * a search for
- * batbat
- * will return 1 match. If the desired behavior is to return 2 matches, define
- * INCLUDE_SUBSTRING_MATCHES to be 1.
- */
-#define INCLUDE_SUBSTRING_MATCHES 0
-
-// Need a quick way to know a maximum distance between drawText calls to know if
-// they are part of the same logical phrase when searching. By crude
-// inspection, half the point size seems a good guess at the width of a space
-// character.
-static inline SkScalar approximateSpaceWidth(const SkPaint& paint) {
- return SkScalarHalf(paint.getTextSize());
-}
-
-void FindCanvas::findHelper(const void* text, size_t byteLength,
- const SkPaint& paint, const SkScalar positions[],
- SkScalar y,
- SkRect (FindCanvas::*addMatch)(int index,
- const SkPaint& paint, int count,
- const uint16_t* glyphs,
- const SkScalar positions[], SkScalar y)) {
- SkASSERT(paint.getTextEncoding() == SkPaint::kGlyphID_TextEncoding);
- SkASSERT(mMatches);
- GlyphSet* glyphSet = getGlyphs(paint);
- const int count = glyphSet->getCount();
- int numCharacters = byteLength >> 1;
- const uint16_t* chars = (const uint16_t*) text;
- // This block will check to see if we are continuing from another line. If
- // so, the user needs to have added a space, which we do not draw.
- if (mWorkingIndex) {
- SkPoint newY;
- getTotalMatrix().mapXY(0, y, &newY);
- SkIRect bounds = mWorkingRegion.getBounds();
- if (bounds.fBottom < SkScalarRound(newY.fY)) {
- // Now we know that this line is lower than our partial match.
- SkPaint clonePaint(paint);
- clonePaint.setTextEncoding(SkPaint::kUTF8_TextEncoding);
- uint16_t space;
- clonePaint.textToGlyphs(" ", 1, &space);
- if (glyphSet->characterMatches(space, mWorkingIndex)) {
- mWorkingIndex++;
- if (mWorkingIndex == count) {
- // We already know that it is not clipped out because we
- // checked for that before saving the working region.
- insertMatchInfo(mWorkingRegion);
-
- resetWorkingCanvas();
- mWorkingIndex = 0;
- mWorkingRegion.setEmpty();
- // We have found a match, so continue on this line from
- // scratch.
- }
- } else {
- resetWorkingCanvas();
- mWorkingIndex = 0;
- mWorkingRegion.setEmpty();
- }
- }
- }
- // j is the position in the search text
- // Start off with mWorkingIndex in case we are continuing from a prior call
- int j = mWorkingIndex;
- // index is the position in the drawn text
- int index = 0;
- for ( ; index != numCharacters; index++) {
- if (glyphSet->characterMatches(chars[index], j)) {
- // The jth character in the search text matches the indexth position
- // in the drawn text, so increase j.
- j++;
- if (j != count) {
- continue;
- }
- // The last count characters match, so we found the entire
- // search string.
- int remaining = count - mWorkingIndex;
- int matchIndex = index - remaining + 1;
- // Set up a pointer to the matching text in 'chars'.
- const uint16_t* glyphs = chars + matchIndex;
- SkRect rect = (this->*addMatch)(matchIndex, paint,
- remaining, glyphs, positions, y);
- rect.inset(mOutset, mOutset);
- // We need an SkIRect for SkRegion operations.
- SkIRect iRect;
- rect.roundOut(&iRect);
- // If the rectangle is partially clipped, assume that the text is
- // not visible, so skip this match.
- if (getTotalClip().contains(iRect)) {
- SkRegion regionToAdd(iRect);
- if (!mWorkingRegion.isEmpty()) {
- // If this is on the same line as our working region, make
- // sure that they are close enough together that they are
- // supposed to be part of the same text string.
- // The width of two spaces has arbitrarily been chosen.
- const SkIRect& workingBounds = mWorkingRegion.getBounds();
- if (workingBounds.fTop <= iRect.fBottom &&
- workingBounds.fBottom >= iRect.fTop &&
- SkIntToScalar(iRect.fLeft - workingBounds.fRight) >
- approximateSpaceWidth(paint)) {
- index = -1; // Will increase to 0 on next run
- // In this case, we need to start from the beginning of
- // the text being searched and our search term.
- j = 0;
- mWorkingIndex = 0;
- mWorkingRegion.setEmpty();
- continue;
- }
- // Add the mWorkingRegion, which contains rectangles from
- // the previous line(s).
- regionToAdd.op(mWorkingRegion, SkRegion::kUnion_Op);
- }
- insertMatchInfo(regionToAdd);
-#if INCLUDE_SUBSTRING_MATCHES
- // Reset index to the location of the match and reset j to the
- // beginning, so that on the next iteration of the loop, index
- // will advance by 1 and we will compare the next character in
- // chars to the first character in the GlyphSet.
- index = matchIndex;
-#endif
- } else {
- // This match was clipped out, so begin looking at the next
- // character from our hidden match
- index = matchIndex;
- }
- // Whether the clip contained it or not, we need to start over
- // with our recording canvas
- resetWorkingCanvas();
- } else {
- // Index needs to be set to index - j + 1.
- // This is a ridiculous case, but imagine the situation where the
- // user is looking for the string "jjog" in the drawText call for
- // "jjjog". The first two letters match. However, when the index
- // is 2, and we discover that 'o' and 'j' do not match, we should go
- // back to 1, where we do, in fact, have a match
- // FIXME: This does not work if (as in our example) "jj" is in one
- // draw call and "jog" is in the next. Doing so would require a
- // stack, keeping track of multiple possible working indeces and
- // regions. This is likely an uncommon case.
- index = index - j; // index will be increased by one on the next
- // iteration
- }
- // We reach here in one of two cases:
- // 1) We just completed a match, so any working rectangle/index is no
- // longer needed, and we will start over from the beginning
- // 2) The glyphs do not match, so we start over at the beginning of
- // the search string.
- j = 0;
- mWorkingIndex = 0;
- mWorkingRegion.setEmpty();
- }
- // At this point, we have searched all of the text in the current drawText
- // call.
- // Keep track of a partial match that may start on this line.
- if (j > 0) { // if j is greater than 0, we have a partial match
- int partialIndex = index - j + mWorkingIndex;
- const uint16_t* partialGlyphs = chars + partialIndex;
- SkRect partial = (this->*addMatch)(partialIndex, paint, j,
- partialGlyphs, positions, y);
- partial.inset(mOutset, mOutset);
- getTotalMatrix().mapRect(&partial);
- SkIRect dest;
- partial.roundOut(&dest);
- // Only save a partial if it is in the current clip.
- if (getTotalClip().contains(dest)) {
- mWorkingRegion.op(dest, SkRegion::kUnion_Op);
- mWorkingIndex = j;
- // From one perspective, it seems like we would want to draw here,
- // since we have all the information (paint, matrix, etc)
- // However, we only want to draw if we find the rest
- return;
- }
- }
- // This string doesn't go into the next drawText, so reset our working
- // variables
- mWorkingRegion.setEmpty();
- mWorkingIndex = 0;
-}
-
-SkCanvas* FindCanvas::getWorkingCanvas() {
- if (!mWorkingPicture) {
- mWorkingPicture = new SkPicture;
- mWorkingCanvas = mWorkingPicture->beginRecording(0,0);
- }
- return mWorkingCanvas;
-}
-
-GlyphSet* FindCanvas::getGlyphs(const SkPaint& paint) {
- SkTypeface* typeface = paint.getTypeface();
- GlyphSet* end = mGlyphSets.end();
- for (GlyphSet* ptr = mGlyphSets.begin();ptr != end; ptr++) {
- if (ptr->getTypeface() == typeface) {
- return ptr;
- }
- }
-
- GlyphSet set(paint, mLowerText, mUpperText, mLength);
- *mGlyphSets.append() = set;
- return &(mGlyphSets.top());
-}
-
-void FindCanvas::insertMatchInfo(const SkRegion& region) {
- mNumFound++;
- mWorkingPicture->endRecording();
- MatchInfo matchInfo;
- mMatches->append(matchInfo);
- mMatches->last().set(region, mWorkingPicture);
-}
-
-void FindCanvas::resetWorkingCanvas() {
- mWorkingPicture->unref();
- mWorkingPicture = 0;
- // Do not need to reset mWorkingCanvas itself because we only access it via
- // getWorkingCanvas.
-}
diff --git a/WebKit/android/nav/FindCanvas.h b/WebKit/android/nav/FindCanvas.h
deleted file mode 100644
index 5d79b4c..0000000
--- a/WebKit/android/nav/FindCanvas.h
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * Copyright 2008, 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 APPLE COMPUTER, INC. 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 Find_Canvas_h
-#define Find_Canvas_h
-
-#include "SkBounder.h"
-#include "SkCanvas.h"
-#include "SkPicture.h"
-#include "SkRegion.h"
-#include "SkTDArray.h"
-#include "icu/unicode/umachine.h"
-#include "wtf/Vector.h"
-
-class SkRect;
-class SkTypeface;
-
-// 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.
-// This class owns its SkPicture
-class MatchInfo {
-public:
- MatchInfo();
- ~MatchInfo();
- MatchInfo(const MatchInfo& src);
- const SkRegion& getLocation() const { return m_location; }
- // Return a pointer to our picture, representing the matching text. Does
- // not transfer ownership of the picture.
- 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);
-private:
- MatchInfo& operator=(MatchInfo& src);
- SkRegion m_location;
- SkPicture* m_picture;
-};
-
-// A class containing a typeface for reference, the length in glyphs, and
-// the upper and lower case representations of the search string.
-class GlyphSet {
-public:
- GlyphSet(const SkPaint& paint, const UChar* lower, const UChar* upper,
- size_t byteLength);
- ~GlyphSet();
- GlyphSet& operator=(GlyphSet& src);
-
- // Return true iff c matches one of our glyph arrays at index
- bool characterMatches(uint16_t c, int index);
-
- int getCount() const { return mCount; }
-
- const SkTypeface* getTypeface() const { return mTypeface; }
-
-private:
- // Disallow copy constructor
- GlyphSet(GlyphSet& src) { }
-
- // mTypeface is used for comparison only
- const SkTypeface* mTypeface;
- // mLowerGlyphs points to all of our storage space: the lower set followed
- // by the upper set. mUpperGlyphs is purely a convenience pointer to the
- // start of the upper case glyphs.
- uint16_t* mLowerGlyphs;
- uint16_t* mUpperGlyphs;
- // mCount is the number of glyphs of the search string. Must be the same
- // for both the lower case set and the upper case set.
- int mCount;
-
- // Arbitrarily chose the maximum storage to use in the GlyphSet. This is
- // based on the length of the word being searched. If users are always
- // searching for 3 letter words (for example), an ideal number would be 3.
- // Each time the user searches for a word longer than (in this case, 3) that
- // will result in calling new/delete.
- enum Storage {
- MAX_STORAGE_COUNT = 16
- };
- // In order to eliminate new/deletes, create storage that will be enough
- // most of the time
- uint16_t mStorage[2*MAX_STORAGE_COUNT];
-};
-
-class FindBounder : public SkBounder {
-public:
- FindBounder() {}
- ~FindBounder() {}
-protected:
- virtual bool onIRect(const SkIRect&) { return false; }
-};
-
-class FindCanvas : public SkCanvas {
-public:
- FindCanvas(int width, int height, const UChar* , const UChar*,
- size_t byteLength);
-
- virtual ~FindCanvas();
-
- virtual void drawText(const void* text, size_t byteLength, SkScalar x,
- SkScalar y, const SkPaint& paint);
-
- /* FIXME: This path has not been tested. */
- virtual void drawPosText(const void* text, size_t byteLength,
- const SkPoint pos[], const SkPaint& paint);
-
- /* Also untested */
- virtual void drawPosTextH(const void* text, size_t byteLength,
- const SkScalar xpos[], SkScalar constY,
- const SkPaint& paint);
-
- /* Not sure what to do here or for drawTextOnPathHV */
- virtual void drawTextOnPath(const void* text, size_t byteLength,
- const SkPath& path, const SkMatrix* matrix,
- const SkPaint& paint) {
- }
-
- int found() const { return mNumFound; }
-
- // This method detaches our array of matches and passes ownership to
- // the caller, who is then responsible for deleting them.
- WTF::Vector<MatchInfo>* detachMatches() {
- WTF::Vector<MatchInfo>* array = mMatches;
- mMatches = NULL;
- return array;
- }
-
-private:
- // These calls are made by findHelper to store information about each match
- // that is found. They return a rectangle which is used to highlight the
- // match. They also add to our SkPicture (which can be accessed with
- // getDrawnMatches) a draw of each match. This way it can be drawn after
- // the rectangle. The rect that is returned is in device coordinates.
- SkRect addMatchNormal(int index,
- const SkPaint& paint, int count, const uint16_t* glyphs,
- const SkScalar pos[], SkScalar y);
-
- SkRect addMatchPos(int index,
- const SkPaint& paint, int count, const uint16_t* glyphs,
- const SkScalar xPos[], SkScalar /* y */);
-
- SkRect addMatchPosH(int index,
- const SkPaint& paint, int count, const uint16_t* glyphs,
- const SkScalar position[], SkScalar constY);
-
- // Helper for each of our draw calls
- void findHelper(const void* text, size_t byteLength, const SkPaint& paint,
- const SkScalar xPos[], SkScalar y,
- SkRect (FindCanvas::*addMatch)(int index,
- const SkPaint& paint, int count, const uint16_t* glyphs,
- const SkScalar pos[], SkScalar y));
-
- // If we already have a working canvas, grab it. Otherwise, create a new
- // one.
- SkCanvas* getWorkingCanvas();
-
- // Return the set of glyphs and its count for the text being searched for
- // and the parameter paint. If one has already been created and cached
- // for this paint, use it. If not, create a new one and cache it.
- GlyphSet* getGlyphs(const SkPaint& paint);
-
- // Store all the accumulated info about a match in our vector.
- void insertMatchInfo(const SkRegion& region);
-
- // Throw away our cumulative information about our working SkCanvas. After
- // this call, next call to getWorkingCanvas will create a new one.
- void resetWorkingCanvas();
-
- // Since we may transfer ownership of this array (see detachRects()), we
- // hold a pointer to the array instead of just the array itself.
- WTF::Vector<MatchInfo>* mMatches;
- const UChar* mLowerText;
- const UChar* mUpperText;
- size_t mLength;
- FindBounder mBounder;
- int mNumFound;
- SkScalar mOutset;
- SkTDArray<GlyphSet> mGlyphSets;
-
- SkPicture* mWorkingPicture;
- SkCanvas* mWorkingCanvas;
- SkRegion mWorkingRegion;
- int mWorkingIndex;
-};
-
-#endif // Find_Canvas_h
-
diff --git a/WebKit/android/nav/SelectText.cpp b/WebKit/android/nav/SelectText.cpp
deleted file mode 100644
index 7bdbf14..0000000
--- a/WebKit/android/nav/SelectText.cpp
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * Copyright 2008, 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 APPLE COMPUTER, INC. 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.
- */
-#define LOG_TAG "webcoreglue"
-
-#include "CachedPrefix.h"
-#include "SelectText.h"
-#include "SkBitmap.h"
-#include "SkBounder.h"
-#include "SkCanvas.h"
-#include "SkMatrix.h"
-#include "SkPicture.h"
-#include "SkPoint.h"
-#include "SkRect.h"
-#include "SkRegion.h"
-
-class CommonCheck : public SkBounder {
-public:
- CommonCheck() : mMatrix(NULL), mPaint(NULL) {}
-
- virtual void setUp(const SkPaint& paint, const SkMatrix& matrix, SkScalar y) {
- mMatrix = &matrix;
- mPaint = &paint;
- mY = y;
- mBase = mBottom = mTop = INT_MAX;
- }
-
- int base() {
- if (mBase == INT_MAX) {
- SkPoint result;
- mMatrix->mapXY(0, mY, &result);
- mBase = SkScalarFloor(result.fY);
- }
- return mBase;
- }
-
- int bottom() {
- if (mBottom == INT_MAX) {
- SkPoint result;
- SkPaint::FontMetrics metrics;
- mPaint->getFontMetrics(&metrics);
- mMatrix->mapXY(0, metrics.fDescent + mY, &result);
- mBottom = SkScalarCeil(result.fY);
- }
- return mBottom;
- }
-
- int top() {
- if (mTop == INT_MAX) {
- SkPoint result;
- SkPaint::FontMetrics metrics;
- mPaint->getFontMetrics(&metrics);
- mMatrix->mapXY(0, metrics.fAscent + mY, &result);
- mTop = SkScalarFloor(result.fY);
- }
- return mTop;
- }
-
-protected:
- const SkMatrix* mMatrix;
- const SkPaint* mPaint;
- int mBase;
- int mBottom;
- int mTop;
- SkScalar mY;
-};
-
-class FirstCheck : public CommonCheck {
-public:
- FirstCheck(int x, int y)
- : mDistance(INT_MAX), mFocusX(x), mFocusY(y) {
- mBestBounds.setEmpty();
- }
-
- const SkIRect& bestBounds() {
- DBG_NAV_LOGD("mBestBounds:(%d, %d, %d, %d) mTop=%d mBottom=%d",
- mBestBounds.fLeft, mBestBounds.fTop, mBestBounds.fRight,
- mBestBounds.fBottom, mTop, mBottom);
- return mBestBounds;
- }
-
- void offsetBounds(int dx, int dy) {
- mBestBounds.offset(dx, dy);
- }
-
- virtual bool onIRect(const SkIRect& rect) {
- int dx = ((rect.fLeft + rect.fRight) >> 1) - mFocusX;
- int dy = ((top() + bottom()) >> 1) - mFocusY;
- int distance = dx * dx + dy * dy;
-#ifdef EXTRA_NOISY_LOGGING
- if (distance < 500 || abs(distance - mDistance) < 500)
- DBG_NAV_LOGD("distance=%d mDistance=%d", distance, mDistance);
-#endif
- if (mDistance > distance) {
- mDistance = distance;
- mBestBounds.set(rect.fLeft, top(), rect.fRight, bottom());
-#ifdef EXTRA_NOISY_LOGGING
- DBG_NAV_LOGD("mBestBounds={%d,%d,r=%d,b=%d}",
- mBestBounds.fLeft, mBestBounds.fTop,
- mBestBounds.fRight, mBestBounds.fBottom);
-#endif
- }
- return false;
- }
-protected:
- SkIRect mBestBounds;
- int mDistance;
- int mFocusX;
- int mFocusY;
-};
-
-class MultilineBuilder : public CommonCheck {
-public:
- MultilineBuilder(const SkIRect& start, const SkIRect& end, int dx, int dy,
- SkRegion* region)
- : mStart(start), mEnd(end), mSelectRegion(region), mCapture(false) {
- mLast.setEmpty();
- mLastBase = INT_MAX;
- mStart.offset(-dx, -dy);
- mEnd.offset(-dx, -dy);
- }
-
- virtual bool onIRect(const SkIRect& rect) {
- bool captureLast = false;
- if ((rect.fLeft == mStart.fLeft && rect.fRight == mStart.fRight &&
- top() == mStart.fTop && bottom() == mStart.fBottom) ||
- (rect.fLeft == mEnd.fLeft && rect.fRight == mEnd.fRight &&
- top() == mEnd.fTop && bottom() == mEnd.fBottom)) {
- captureLast = mCapture;
- mCapture ^= true;
- }
- if (mCapture || captureLast) {
- SkIRect full;
- full.set(rect.fLeft, top(), rect.fRight, bottom());
- if ((mLast.fTop < base() && mLast.fBottom >= base())
- || (mLastBase <= full.fBottom && mLastBase > full.fTop)) {
- if (full.fLeft > mLast.fRight)
- full.fLeft = mLast.fRight;
- else if (full.fRight < mLast.fLeft)
- full.fRight = mLast.fLeft;
- }
- mSelectRegion->op(full, SkRegion::kUnion_Op);
- mLast = full;
- mLastBase = base();
- if (mStart == mEnd)
- mCapture = false;
- }
- return false;
- }
-protected:
- SkIRect mStart;
- SkIRect mEnd;
- SkIRect mLast;
- int mLastBase;
- SkRegion* mSelectRegion;
- bool mCapture;
-};
-
-class TextCanvas : public SkCanvas {
-public:
-
- TextCanvas(CommonCheck* bounder, const SkPicture& picture, const SkIRect& area)
- : mBounder(*bounder) {
- setBounder(bounder);
- SkBitmap bitmap;
- bitmap.setConfig(SkBitmap::kARGB_8888_Config, area.width(),
- area.height());
- setBitmapDevice(bitmap);
- translate(SkIntToScalar(-area.fLeft), SkIntToScalar(-area.fTop));
- }
-
- virtual ~TextCanvas() {
- setBounder(NULL);
- }
-
- virtual void drawPaint(const SkPaint& paint) {
- }
-
- virtual void drawPoints(PointMode mode, size_t count, const SkPoint pts[],
- const SkPaint& paint) {
- }
-
- virtual void drawRect(const SkRect& rect, const SkPaint& paint) {
- }
-
- virtual void drawPath(const SkPath& path, const SkPaint& paint) {
- }
-
- virtual void commonDrawBitmap(const SkBitmap& bitmap,
- const SkMatrix& matrix, const SkPaint& paint) {
- }
-
- virtual void drawSprite(const SkBitmap& bitmap, int left, int top,
- const SkPaint* paint = NULL) {
- }
-
- virtual void drawText(const void* text, size_t byteLength, SkScalar x,
- SkScalar y, const SkPaint& paint) {
- mBounder.setUp(paint, getTotalMatrix(), y);
- SkCanvas::drawText(text, byteLength, x, y, paint);
- }
-
- virtual void drawPosTextH(const void* text, size_t byteLength,
- const SkScalar xpos[], SkScalar constY,
- const SkPaint& paint) {
- mBounder.setUp(paint, getTotalMatrix(), constY);
- SkCanvas::drawPosTextH(text, byteLength, xpos, constY, paint);
- }
-
- virtual void drawVertices(VertexMode vmode, int vertexCount,
- const SkPoint vertices[], const SkPoint texs[],
- const SkColor colors[], SkXfermode* xmode,
- const uint16_t indices[], int indexCount,
- const SkPaint& paint) {
- }
-
- CommonCheck& mBounder;
-};
-
-void CopyPaste::buildSelection(const SkPicture& picture, const SkIRect& area,
- const SkIRect& selStart, const SkIRect& selEnd, SkRegion* region) {
- DBG_NAV_LOGD("area=(%d, %d, %d, %d) selStart=(%d, %d, %d, %d)"
- " selEnd=(%d, %d, %d, %d)",
- area.fLeft, area.fTop, area.fRight, area.fBottom,
- selStart.fLeft, selStart.fTop, selStart.fRight, selStart.fBottom,
- selEnd.fLeft, selEnd.fTop, selEnd.fRight, selEnd.fBottom);
- MultilineBuilder builder(selStart, selEnd, area.fLeft, area.fTop, region);
- TextCanvas checker(&builder, picture, area);
- checker.drawPicture(const_cast<SkPicture&>(picture));
- region->translate(area.fLeft, area.fTop);
-}
-
-SkIRect CopyPaste::findClosest(const SkPicture& picture, const SkIRect& area,
- int x, int y) {
- FirstCheck _check(x - area.fLeft, y - area.fTop);
- DBG_NAV_LOGD("area=(%d, %d, %d, %d) x=%d y=%d", area.fLeft, area.fTop,
- area.fRight, area.fBottom, x, y);
- TextCanvas checker(&_check, picture, area);
- checker.drawPicture(const_cast<SkPicture&>(picture));
- _check.offsetBounds(area.fLeft, area.fTop);
- return _check.bestBounds();
-}
diff --git a/WebKit/android/nav/SelectText.h b/WebKit/android/nav/SelectText.h
deleted file mode 100644
index b991198..0000000
--- a/WebKit/android/nav/SelectText.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2008, 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 APPLE COMPUTER, INC. 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 SELECT_TEXT_H
-#define SELECT_TEXT_H
-
-class SkPicture;
-struct SkIRect;
-struct SkIPoint;
-class SkRegion;
-
-class CopyPaste {
-public:
- static void buildSelection(const SkPicture& , const SkIRect& area,
- const SkIRect& selStart, const SkIRect& selEnd, SkRegion* region);
- static SkIRect findClosest(const SkPicture& , const SkIRect& area,
- int x, int y);
-};
-
-#endif
diff --git a/WebKit/android/nav/WebView.cpp b/WebKit/android/nav/WebView.cpp
deleted file mode 100644
index 52bb6a5..0000000
--- a/WebKit/android/nav/WebView.cpp
+++ /dev/null
@@ -1,2322 +0,0 @@
-/*
- * Copyright 2007, 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 APPLE COMPUTER, INC. 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.
- */
-
-#define LOG_TAG "webviewglue"
-
-#include <config.h>
-
-#include "android_graphics.h"
-#include "AndroidLog.h"
-#include "AtomicString.h"
-#include "CachedFrame.h"
-#include "CachedNode.h"
-#include "CachedRoot.h"
-#include "FindCanvas.h"
-#include "Frame.h"
-#include "GraphicsJNI.h"
-#include "IntPoint.h"
-#include "IntRect.h"
-#include "Node.h"
-#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"
-#include "SkPixelXorXfermode.h"
-#include "SkRect.h"
-#include "SkTime.h"
-#include "WebCoreJni.h"
-#include "WebViewCore.h"
-#include "jni_utility.h"
-
-#ifdef ANDROID_INSTRUMENT
-#include "TimeCounter.h"
-#endif
-
-#ifdef GET_NATIVE_VIEW
-#undef GET_NATIVE_VIEW
-#endif
-
-#define GET_NATIVE_VIEW(env, obj) ((WebView*)env->GetIntField(obj, gWebViewField))
-
-#include <ui/KeycodeLabels.h>
-#include <JNIHelp.h>
-#include <jni.h>
-
-#define REPLAY_BUFFER_SIZE 4096
-
-namespace android {
-
-struct CommonParams {
- enum Trigger {
- NoData,
- ClearFocusParams,
- FirstMoveFocusParams,
- MoveFocusParams,
- MotionUpParams
- } m_trigger;
- int m_generation;
-};
-
-struct CacheParams {
- void setFocus(const CachedNode* node,
- const CachedFrame* frame, const CachedRoot* root,
- const WebCore::IntPoint& focusLocation)
- {
- m_node = (WebCore::Node*) (node ? node->nodePointer() : 0);
- m_frame = (WebCore::Frame*) (node ? frame->framePointer() : 0);
- m_x = focusLocation.x();
- m_y = focusLocation.y();
- }
-
- WebCore::Node* m_node;
- WebCore::Frame* m_frame;
- int m_x;
- int m_y;
-};
-
-struct ClearFocusParams {
- CommonParams d;
- CacheParams c;
- int m_x;
- int m_y;
-};
-
-struct MotionUpParams {
- CommonParams d;
- int m_x;
- int m_y;
- int m_slop;
- bool m_isClick;
-};
-
-struct FirstMoveFocusParams {
- CommonParams d;
- int m_keyCode;
- int m_count;
- bool m_ignoreScroll;
-};
-
-struct MoveFocusParams {
- FirstMoveFocusParams d;
- CacheParams c;
- void* m_sentFocus;
- WebCore::IntRect m_sentBounds;
- WebCore::IntRect m_visibleRect;
- CachedHistory m_history; // FIXME: make this a subset
- int m_xMax;
- int m_yMax;
-};
-
-typedef MoveFocusParams LargestParams;
-
-#if DEBUG_NAV_UI
-static const char* TriggerNames[] = {
- "*** no data ! ***",
- "clearFocus",
- "firstMoveFocus",
- "moveFocus",
- "motionUp"
-};
-#endif
-
-class FocusReplay {
-public:
-FocusReplay() : m_start(m_buffer), m_end(m_buffer), m_lastGeneration(0)
-{
-}
-
-// find the most recent common data
-void add(const CommonParams& data, size_t len)
-{
- DBG_NAV_LOGD("m_start=%d m_end=%d trigger=%s moveGeneration=%d", m_start - m_buffer,
- m_end - m_buffer, TriggerNames[data.m_trigger], data.m_generation);
- m_lastGeneration = data.m_generation;
- char* limit = m_buffer + sizeof(m_buffer);
- int used = m_end - m_start;
- if (used < 0)
- used += sizeof(m_buffer);
- int needed = (int) len - ((int) sizeof(m_buffer) - used);
- if (needed >= 0)
- reclaim(++needed);
- if (m_end + len <= limit) {
- memcpy(m_end, (void*) &data, len);
- m_end += len;
- DBG_NAV_LOGD("m_start=%d m_end=%d", m_start - m_buffer, m_end - m_buffer);
- return;
- }
- size_t partial = limit - m_end;
- memcpy(m_end, (void*) &data, partial);
- const void* remainder = (const void*) ((const char*) &data + partial);
- partial = len - partial;
- memcpy(m_buffer, remainder, partial);
- m_end = m_buffer + partial;
- DBG_NAV_LOGD("wrap m_start=%d m_end=%d",
- m_start - m_buffer, m_end - m_buffer);
-}
-
-int count()
-{
- DBG_NAV_LOGD("m_start=%d m_end=%d",
- m_start - m_buffer, m_end - m_buffer);
- if (m_start == m_end)
- return 0;
- char* limit = m_buffer + sizeof(m_buffer);
- char* saveStart = m_start;
- int result = 0;
- while (true) {
- ++result;
- m_start += triggerSize();
- if (m_start == m_end)
- break;
- if (m_start < limit)
- continue;
- m_start -= sizeof(m_buffer);
- if (m_start == m_end)
- break;
- }
- m_start = saveStart;
- DBG_NAV_LOGD("count=%d", result);
- return result;
-}
-
-void discard(int generation)
-{
- DBG_NAV_LOGD("generation=%d", generation);
- LargestParams storage;
- const CommonParams& params = storage.d.d;
- char* pos = position();
- retrieve(&storage.d.d);
- if (params.m_generation > generation) {
- DBG_NAV_LOGD("params.m_generation=%d > generation=%d",
- params.m_generation, generation);
- rewind(pos);
- DBG_NAV_LOGD("m_start=%d m_end=%d", m_start - m_buffer, m_end - m_buffer);
- return;
- }
- LOG_ASSERT(params.m_generation == generation, "params.m_generation != generation");
- DBG_NAV_LOGD("m_start=%d m_end=%d", m_start - m_buffer, m_end - m_buffer);
-}
-
-int lastAdd()
-{
- return m_lastGeneration;
-}
-
-char* position()
-{
- return m_start;
-}
-
-int retrieve(CommonParams* data)
-{
- if (m_end == m_start) {
- // changed from LOGD to LOGV, as it always fires when I click to center
- // text (mrr)
- LOGV("%s *** no data to retrieve (error condition) ***", __FUNCTION__);
- data->m_trigger = CommonParams::NoData;
- return data->m_generation = INT_MAX;
- }
- DBG_NAV_LOGD("m_start=%d m_end=%d",
- m_start - m_buffer, m_end - m_buffer);
- char* limit = m_buffer + sizeof(m_buffer);
- size_t size = triggerSize();
- if (m_start < m_end) {
- LOG_ASSERT((size_t) (m_end - m_start) >= size, "m_end - m_start < size");
- memcpy(data, m_start, size);
- m_start += size;
- } else {
- int partial = limit - m_start;
- if (partial > (int) size)
- partial = size;
- memcpy(data, m_start, partial);
- m_start += partial;
- void* remainder = (void*) ((char*) data + partial);
- partial = size - partial;
- if (partial > 0) {
- memcpy(remainder, m_buffer, partial);
- m_start = m_buffer + partial;
- LOG_ASSERT(m_start <= m_end, "m_start > m_end");
- }
- }
- if (m_start == limit) {
- m_start = m_buffer;
- if (m_end == limit)
- m_end = m_buffer;
- }
- DBG_NAV_LOGD("m_start=%d m_end=%d trigger=%s moveGeneration=%d",
- m_start - m_buffer, m_end - m_buffer, TriggerNames[data->m_trigger],
- data->m_generation);
- return data->m_generation;
-}
-
-void rewind(char* pos)
-{
- m_start = pos;
-}
-
-private:
-void reclaim(int needed)
-{
- DBG_NAV_LOGD("needed=%d", needed);
- char* limit = m_buffer + sizeof(m_buffer);
- do {
- size_t size = triggerSize();
- m_start += size;
- needed -= size;
- if (m_start >= limit) {
- m_start = m_buffer + (m_start - limit);
- if (m_end == limit)
- m_end = m_buffer;
- }
- } while (needed > 0 && m_start != m_end);
- DBG_NAV_LOGD("m_start=%d m_end=%d",
- m_start - m_buffer, m_end - m_buffer);
-}
-
-size_t triggerSize()
-{
- LOG_ASSERT(m_start != m_end, "m_start == m_end");
- char* limit = m_buffer + sizeof(m_buffer);
- LOG_ASSERT(m_start + sizeof(CommonParams::Trigger) <= limit, "trigger not in limit");
- CommonParams::Trigger trigger;
- memcpy(&trigger, m_start, sizeof(trigger));
- switch (trigger) {
- case CommonParams::ClearFocusParams:
- return sizeof(ClearFocusParams);
- case CommonParams::FirstMoveFocusParams:
- return sizeof(FirstMoveFocusParams);
- case CommonParams::MoveFocusParams:
- return sizeof(MoveFocusParams);
- case CommonParams::MotionUpParams:
- return sizeof(MotionUpParams);
- default:
- LOG_ASSERT(0, "trigger undefined");
- }
- return 0;
-}
-
-char m_buffer[REPLAY_BUFFER_SIZE];
-char* m_start;
-char* m_end;
-int m_lastGeneration;
-}; // end of helper class ReplayFocus
-
-static jfieldID gWebViewField;
-
-//-------------------------------------
-
-static jmethodID GetJMethod(JNIEnv* env, jclass clazz, const char name[], const char signature[])
-{
- jmethodID m = env->GetMethodID(clazz, name, signature);
- LOG_ASSERT(m, "Could not find method %s", name);
- return m;
-}
-
-//-------------------------------------
-// This class provides JNI for making calls into native code from the UI side
-// of the multi-threaded WebView.
-class WebView
-{
-public:
-enum FrameCachePermission {
- DontAllowNewer,
- AllowNewer,
- AllowNewest
-};
-
-enum OutOfFocusFix {
- DoNothing,
- ClearTextEntry,
- UpdateTextEntry
-};
-
-struct JavaGlue {
- jobject m_obj;
- jmethodID m_clearTextEntry;
- jmethodID m_overrideLoading;
- jmethodID m_scrollBy;
- jmethodID m_sendFinalFocus;
- jmethodID m_sendKitFocus;
- jmethodID m_sendMotionUp;
- jmethodID m_setFocusData;
- jmethodID m_getScaledMaxXScroll;
- jmethodID m_getScaledMaxYScroll;
- jmethodID m_getVisibleRect;
- jmethodID m_updateTextEntry;
- jmethodID m_displaySoftKeyboard;
- jmethodID m_viewInvalidate;
- jmethodID m_viewInvalidateRect;
- jmethodID m_postInvalidateDelayed;
- jfieldID m_rectLeft;
- jfieldID m_rectTop;
- jmethodID m_rectWidth;
- jmethodID m_rectHeight;
- jfieldID m_focusNode;
- jmethodID m_setAll;
- AutoJObject object(JNIEnv* env) {
- return getRealObject(env, m_obj);
- }
-} m_javaGlue;
-
-WebView(JNIEnv* env, jobject javaWebView, int viewImpl)
-{
- jclass clazz = env->FindClass("android/webkit/WebView");
- // m_javaGlue = new JavaGlue;
- m_javaGlue.m_obj = adoptGlobalRef(env, javaWebView);
- m_javaGlue.m_scrollBy = GetJMethod(env, clazz, "setContentScrollBy", "(IIZ)V");
- m_javaGlue.m_clearTextEntry = GetJMethod(env, clazz, "clearTextEntry", "()V");
- m_javaGlue.m_overrideLoading = GetJMethod(env, clazz, "overrideLoading", "(Ljava/lang/String;)V");
- m_javaGlue.m_sendFinalFocus = GetJMethod(env, clazz, "sendFinalFocus", "(IIII)V");
- m_javaGlue.m_sendKitFocus = GetJMethod(env, clazz, "sendKitFocus", "()V");
- m_javaGlue.m_sendMotionUp = GetJMethod(env, clazz, "sendMotionUp", "(IIIIIIIZZ)V");
- m_javaGlue.m_setFocusData = GetJMethod(env, clazz, "setFocusData", "(IIIIIIZ)V");
- 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_updateTextEntry = GetJMethod(env, clazz, "updateTextEntry", "()V");
- m_javaGlue.m_displaySoftKeyboard = GetJMethod(env, clazz, "displaySoftKeyboard", "()V");
- m_javaGlue.m_viewInvalidate = GetJMethod(env, clazz, "viewInvalidate", "()V");
- m_javaGlue.m_viewInvalidateRect = GetJMethod(env, clazz, "viewInvalidate", "(IIII)V");
- m_javaGlue.m_postInvalidateDelayed = GetJMethod(env, clazz,
- "viewInvalidateDelayed", "(JIIII)V");
- jclass rectClass = env->FindClass("android/graphics/Rect");
- LOG_ASSERT(rectClass, "Could not find Rect class");
- m_javaGlue.m_rectLeft = env->GetFieldID(rectClass, "left", "I");
- 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");
-
- // Set up class for updateFocusNode
- jclass focusnodeClass = env->FindClass("android/webkit/WebView$FocusNode");
- LOG_ASSERT(focusnodeClass, "Could not find FocusNode class!");
- m_javaGlue.m_focusNode = env->GetFieldID(clazz, "mFocusNode", "Landroid/webkit/WebView$FocusNode;");
- m_javaGlue.m_setAll = GetJMethod(env, focusnodeClass, "setAll", "(ZZZZZIIIIIIIILjava/lang/String;Ljava/lang/String;I)V");
- env->DeleteLocalRef(focusnodeClass);
-
- env->SetIntField(javaWebView, gWebViewField, (jint)this);
- m_viewImpl = (WebViewCore*) viewImpl;
- m_frameCacheUI = 0;
- m_navPictureUI = 0;
- m_invalidNode = 0;
- m_generation = 0;
- m_heightCanMeasure = false;
- m_followedLink = false;
- m_lastDx = 0;
- m_lastDxTime = 0;
- m_ringAnimationEnd = 0;
- m_selStart.setEmpty();
- m_selEnd.setEmpty();
- m_matches = 0;
- m_hasCurrentLocation = false;
- m_isFindPaintSetUp = false;
-}
-
-~WebView()
-{
- if (m_javaGlue.m_obj)
- {
- JNIEnv* env = JSC::Bindings::getJNIEnv();
- env->DeleteGlobalRef(m_javaGlue.m_obj);
- m_javaGlue.m_obj = 0;
- }
- delete m_frameCacheUI;
- delete m_navPictureUI;
- if (m_matches)
- delete m_matches;
-}
-
-void clearFocus(int x, int y, bool inval)
-{
- DBG_NAV_LOGD("x=%d y=%d inval=%s", x, y,
- inval ? "true" : "false");
- clearTextEntry();
- CachedRoot* root = getFrameCache(AllowNewer);
- if (!root)
- return;
- const CachedFrame* oldFrame = 0;
- const CachedNode* oldFocusNode = root->currentFocus(&oldFrame);
- WebCore::IntPoint focusLocation = WebCore::IntPoint(0, 0);
- setFocusData(root->generation(), 0, 0, x, y, !oldFocusNode);
- sendKitFocus();
- if (oldFocusNode) {
- DBG_NAV_LOG("oldFocusNode");
- focusLocation = root->focusLocation();
- root->setCachedFocus(0, 0);
- if (inval)
- viewInvalidate();
- }
- ClearFocusParams params;
- params.d.m_trigger = CommonParams::ClearFocusParams;
- params.d.m_generation = m_generation;
- params.c.setFocus(oldFocusNode, oldFrame, root, focusLocation);
- params.m_x = x;
- params.m_y = y;
- m_replay.add(params.d, sizeof(params));
-}
-
-void clearTextEntry()
-{
- DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
- JNIEnv* env = JSC::Bindings::getJNIEnv();
- env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_clearTextEntry);
- checkException(env);
-}
-
-#if DUMP_NAV_CACHE
-void debugDump()
-{
- CachedRoot* root = getFrameCache(DontAllowNewer);
- if (root)
- root->mDebug.print();
-}
-#endif
-
-// Traverse our stored array of buttons that are in our picture, and update
-// their subpictures according to their current focus state.
-// Called from the UI thread. This is the one place in the UI thread where we
-// access the buttons stored in the WebCore thread.
-// hasFocus keeps track of whether the WebView has focus && windowFocus.
-// If not, we do not want to draw the button in a focused or pressed state
-void nativeRecordButtons(bool hasFocus, bool pressed, bool invalidate)
-{
- bool focusIsButton = false;
- const CachedNode* cachedFocus = 0;
- // Lock the mutex, since we now share with the WebCore thread.
- m_viewImpl->gButtonMutex.lock();
- if (m_viewImpl->m_buttons.size()) {
- // Find the focused node so we can determine which node has focus, and
- // therefore which state to paint them in.
- // FIXME: In a future change, we should keep track of whether the focus
- // has changed to short circuit (note that we would still need to update
- // if we received new buttons from the WebCore thread).
- WebCore::Node* focus = 0;
- CachedRoot* root = getFrameCache(DontAllowNewer);
- if (root) {
- cachedFocus = root->currentFocus();
- if (cachedFocus)
- focus = (WebCore::Node*) cachedFocus->nodePointer();
- }
-
- // Traverse the array, and update each button, depending on whether it
- // is focused.
- Container* end = m_viewImpl->m_buttons.end();
- for (Container* ptr = m_viewImpl->m_buttons.begin(); ptr != end; ptr++) {
- WebCore::RenderSkinAndroid::State state;
- if (ptr->matches(focus)) {
- focusIsButton = true;
- // If the WebView is out of focus/window focus, set the state to
- // normal, but still keep track of the fact that the focus is a
- // button
- if (!hasFocus) {
- state = WebCore::RenderSkinAndroid::kNormal;
- } else if (m_followedLink || pressed) {
- state = WebCore::RenderSkinAndroid::kPressed;
- } else {
- state = WebCore::RenderSkinAndroid::kFocused;
- }
- } else {
- state = WebCore::RenderSkinAndroid::kNormal;
- }
- ptr->updateFocusState(state);
- }
- }
- m_viewImpl->gButtonMutex.unlock();
- if (invalidate && cachedFocus && focusIsButton) {
- const WebCore::IntRect& b = cachedFocus->getBounds();
- 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);
-}
-
-// 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 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();
- int left = currentMatchBounds.fLeft;
- int top = currentMatchBounds.fTop;
- int right = currentMatchBounds.fRight;
- int bottom = currentMatchBounds.fBottom;
- WebCore::IntRect visible;
- getVisibleRect(&visible);
- // Check to make sure that the highlighted match is on screen. If not,
- // scroll it onscreen and return.
- int dx = 0;
- if (left < visible.x()) {
- dx = left - visible.x();
- // Only scroll right if the entire width can fit on screen.
- } else if (right > visible.right() && right - left < visible.width()) {
- dx = right - visible.right();
- }
- int dy = 0;
- if (top < visible.y()) {
- dy = top - visible.y();
- // Only scroll down if the entire height can fit on screen
- } else if (bottom > visible.bottom() && bottom - top < visible.height()) {
- dy = bottom - visible.bottom();
- }
- if ((dx|dy)) {
- scrollBy(dx, dy);
- viewInvalidate();
- return;
- }
- // 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) {
- SkIRect visibleIRect;
- android_setrect(&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);
- }
- }
-}
-
-void drawFocusRing(SkCanvas* canvas)
-{
- const CachedRoot* root = getFrameCache(AllowNewer);
- if (!root) {
- DBG_NAV_LOG("!root");
- m_followedLink = false;
- return;
- }
- const CachedNode* node = root->currentFocus();
- if (!node) {
- DBG_NAV_LOG("!node");
- m_followedLink = false;
- return;
- }
- if (!node->hasFocusRing()) {
- DBG_NAV_LOG("!node->hasFocusRing()");
- return;
- }
- const WTF::Vector<WebCore::IntRect>& rings = node->focusRings();
- if (!rings.size()) {
- DBG_NAV_LOG("!rings.size()");
- return;
- }
-
- bool isButton = false;
- m_viewImpl->gButtonMutex.lock();
- // If this is a button drawn by us (rather than webkit) do not draw the
- // focus ring, since its focus will be shown by a change in what we draw.
- // Should be in sync with recordButtons, since that will be called
- // before this.
- if (m_viewImpl->m_buttons.size() > 0) {
- WebCore::Node* focusPointer = (WebCore::Node*) node->nodePointer();
- Container* end = m_viewImpl->m_buttons.end();
- for (Container* ptr = m_viewImpl->m_buttons.begin(); ptr != end; ptr++) {
- if (ptr->matches(focusPointer)) {
- isButton = true;
- break;
- }
- }
- }
- m_viewImpl->gButtonMutex.unlock();
- WebCore::IntRect bounds = node->bounds();
- bounds.inflate(SkScalarCeil(FOCUS_RING_OUTER_DIAMETER));
- SkRect sbounds;
- android_setrect(&sbounds, bounds);
- if (canvas->quickReject(sbounds, SkCanvas::kAA_EdgeType)) {
- DBG_NAV_LOG("canvas->quickReject");
- m_followedLink = false;
- return;
- }
- FocusRing::Flavor flavor = FocusRing::NORMAL_FLAVOR;
- if (!isButton) {
- flavor = node->type() != NORMAL_CACHEDNODETYPE ?
- FocusRing::FAKE_FLAVOR : node->nodePointer() == m_invalidNode ?
- FocusRing::INVALID_FLAVOR : FocusRing::NORMAL_FLAVOR;
- if (flavor != FocusRing::INVALID_FLAVOR && m_followedLink) {
- flavor = (FocusRing::Flavor) (flavor + FocusRing::NORMAL_ANIMATING);
- }
-#if DEBUG_NAV_UI
- const WebCore::IntRect& ring = rings[0];
- DBG_NAV_LOGD("cachedFocusNode=%d (nodePointer=%p) flavor=%s rings=%d"
- " (%d, %d, %d, %d)", node->index(), node->nodePointer(),
- flavor == FocusRing::FAKE_FLAVOR ? "FAKE_FLAVOR" :
- flavor == FocusRing::INVALID_FLAVOR ? "INVALID_FLAVOR" :
- flavor == FocusRing::NORMAL_ANIMATING ? "NORMAL_ANIMATING" :
- flavor == FocusRing::FAKE_ANIMATING ? "FAKE_ANIMATING" : "NORMAL_FLAVOR",
- rings.size(), ring.x(), ring.y(), ring.width(), ring.height());
-#endif
- }
- if (isButton || flavor >= FocusRing::NORMAL_ANIMATING) {
- SkMSec time = SkTime::GetMSecs();
- if (time < m_ringAnimationEnd) {
- // views assume that inval bounds coordinates are non-negative
- bounds.intersect(WebCore::IntRect(0, 0, INT_MAX, INT_MAX));
- postInvalidateDelayed(m_ringAnimationEnd - time, bounds);
- } else {
- m_followedLink = false;
- flavor = (FocusRing::Flavor) (flavor - FocusRing::NORMAL_ANIMATING);
- }
- }
- if (!isButton)
- FocusRing::DrawRing(canvas, rings, flavor);
-}
-
-OutOfFocusFix fixOutOfDateFocus(bool useReplay)
-{
- if (!m_frameCacheUI) {
- DBG_NAV_LOG("!m_frameCacheUI");
- return DoNothing;
- }
- const CachedFrame* cachedFrame = 0;
- const CachedNode* cachedFocusNode = m_frameCacheUI->currentFocus(&cachedFrame);
- if (!cachedFocusNode) {
- DBG_NAV_LOG("!cachedFocusNode");
- return DoNothing;
- }
- CachedRoot* webRoot = m_viewImpl->m_frameCacheKit;
- if (!webRoot) {
- DBG_NAV_LOG("!webRoot");
- return DoNothing;
- }
- int uiWidth = m_frameCacheUI->width();
- int webWidth = webRoot->width();
- if (uiWidth != webWidth) {
- DBG_NAV_LOGD("uiWidth=%d webWidth=%d", uiWidth, webWidth);
- return DoNothing; // allow text inputs to preserve their state
- } else {
- const WebCore::IntRect& cachedBounds = m_frameCacheUI->focusBounds();
- const CachedFrame* webFrame = 0;
- const CachedNode* webFocusNode = webRoot->currentFocus(&webFrame);
- DBG_NAV_LOGD("cachedBounds=(%d,%d,w=%d,h=%d) cachedFrame=%p (%d)"
- " webFocusNode=%p (%d) webFrame=%p (%d)",
- cachedBounds.x(), cachedBounds.y(),
- cachedBounds.width(), cachedBounds.height(),
- cachedFrame, cachedFrame ? cachedFrame->indexInParent() : -1,
- webFocusNode, webFocusNode ? webFocusNode->index() : -1,
- webFrame, webFrame ? webFrame->indexInParent() : -1);
- if (webFocusNode && webFrame && webFrame->sameFrame(cachedFrame)) {
- if (useReplay && !m_replay.count()) {
- DBG_NAV_LOG("!m_replay.count()");
- return DoNothing;
- }
- if (webFocusNode->index() == cachedFocusNode->index()) {
- DBG_NAV_LOG("index ==");
- return DoNothing;
- }
- const WebCore::IntRect& webBounds = webRoot->focusBounds();
- DBG_NAV_LOGD("webBounds=(%d,%d,w=%d,h=%d)",
- webBounds.x(), webBounds.y(),
- webBounds.width(), webBounds.height());
- if (cachedBounds.contains(webBounds)) {
- DBG_NAV_LOG("contains");
- return DoNothing;
- }
- if (webBounds.contains(cachedBounds)) {
- DBG_NAV_LOG("webBounds contains");
- return DoNothing;
- }
- }
- const CachedFrame* foundFrame = 0;
- int x, y;
- const CachedNode* found = findAt(webRoot, cachedBounds, &foundFrame, &x, &y);
-#if DEBUG_NAV_UI
- DBG_NAV_LOGD("found=%p (%d) frame=%p (%d)",
- found, found ? found->index() : -1,
- foundFrame, foundFrame ? foundFrame->indexInParent() : -1);
- if (found) {
- WebCore::IntRect newBounds = found->bounds();
- DBG_NAV_LOGD("found=(%d,%d,w=%d,h=%d) x=%d y=%d",
- newBounds.x(), newBounds.y(), newBounds.width(),
- newBounds.height(), x, y);
- }
-#endif
- webRoot->setCachedFocus(const_cast<CachedFrame*>(foundFrame),
- const_cast<CachedNode*>(found));
- if (found)
- webRoot->rootHistory()->setNavBounds(found->bounds());
- WebCore::Frame* framePointer = foundFrame ? (WebCore::Frame*) foundFrame->framePointer() : 0;
- WebCore::Node* nodePointer = found ? (WebCore::Node*) found->nodePointer() : 0;
- setFocusData(webRoot->generation(), framePointer, nodePointer, x, y, !found);
- sendFinalFocus(framePointer, nodePointer, x, y);
- if (found && (found->isTextArea() || found->isTextField()))
- return UpdateTextEntry;
- }
-checkOldFocus:
- return cachedFocusNode->isTextArea() || cachedFocusNode->isTextField() ? ClearTextEntry : DoNothing;
-}
-
-bool focusIsTextArea(FrameCachePermission allowNewer)
-{
- CachedRoot* root = getFrameCache(allowNewer);
- if (!root) {
- DBG_NAV_LOG("!root");
- return false;
- }
- const CachedNode* focus = root->currentFocus();
- if (!focus)
- return false;
- return focus->isTextArea() || focus->isTextField();
-}
-
-void focusRingBounds(WebCore::IntRect* bounds)
-{
- DBG_NAV_LOGD("%s", "");
- CachedRoot* root = getFrameCache(DontAllowNewer);
- if (root) {
- const CachedNode* cachedNode = root->currentFocus();
- if (cachedNode) {
- cachedNode->focusRingBounds(bounds);
- DBG_NAV_LOGD("bounds={%d,%d,%d,%d}", bounds->x(), bounds->y(),
- bounds->width(), bounds->height());
- return;
- }
- }
- *bounds = WebCore::IntRect(0, 0, 0, 0);
-}
-
-CachedRoot* getFrameCache(FrameCachePermission allowNewer)
-{
- if (!m_viewImpl->m_updatedFrameCache)
- return m_frameCacheUI;
- m_viewImpl->gRecomputeFocusMutex.lock();
- bool recomputeInProgress = m_viewImpl->m_recomputeEvents.size() > 0;
- m_viewImpl->gRecomputeFocusMutex.unlock();
- if (allowNewer != AllowNewest && recomputeInProgress)
- return m_frameCacheUI;
- if (allowNewer == DontAllowNewer && m_viewImpl->m_lastGeneration < m_generation)
- return m_frameCacheUI;
- DBG_NAV_LOGD("%s", "m_viewImpl->m_updatedFrameCache == true");
- m_viewImpl->gFrameCacheMutex.lock();
- OutOfFocusFix fix = DoNothing;
- if (allowNewer != DontAllowNewer)
- fix = fixOutOfDateFocus(m_viewImpl->m_useReplay);
- delete m_frameCacheUI;
- delete m_navPictureUI;
- m_viewImpl->m_updatedFrameCache = false;
- m_frameCacheUI = m_viewImpl->m_frameCacheKit;
- m_navPictureUI = m_viewImpl->m_navPictureKit;
- m_viewImpl->m_frameCacheKit = 0;
- m_viewImpl->m_navPictureKit = 0;
- m_viewImpl->gFrameCacheMutex.unlock();
- if (fix == UpdateTextEntry)
- updateTextEntry();
- else if (fix == ClearTextEntry)
- clearTextEntry();
- return m_frameCacheUI;
-}
-
-int getScaledMaxXScroll()
-{
- LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
- JNIEnv* env = JSC::Bindings::getJNIEnv();
- int result = env->CallIntMethod(m_javaGlue.object(env).get(), m_javaGlue.m_getScaledMaxXScroll);
- checkException(env);
- return result;
-}
-
-int getScaledMaxYScroll()
-{
- LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
- JNIEnv* env = JSC::Bindings::getJNIEnv();
- int result = env->CallIntMethod(m_javaGlue.object(env).get(), m_javaGlue.m_getScaledMaxYScroll);
- checkException(env);
- return result;
-}
-
-void getVisibleRect(WebCore::IntRect* rect)
-{
- LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
- JNIEnv* env = JSC::Bindings::getJNIEnv();
- jobject jRect = env->CallObjectMethod(m_javaGlue.object(env).get(), m_javaGlue.m_getVisibleRect);
- checkException(env);
- int left = (int) env->GetIntField(jRect, m_javaGlue.m_rectLeft);
- checkException(env);
- rect->setX(left);
- int top = (int) env->GetIntField(jRect, m_javaGlue.m_rectTop);
- checkException(env);
- rect->setY(top);
- int width = (int) env->CallIntMethod(jRect, m_javaGlue.m_rectWidth);
- checkException(env);
- rect->setWidth(width);
- int height = (int) env->CallIntMethod(jRect, m_javaGlue.m_rectHeight);
- checkException(env);
- rect->setHeight(height);
- env->DeleteLocalRef(jRect);
- checkException(env);
-}
-
-static CachedFrame::Direction KeyToDirection(KeyCode keyCode)
-{
- switch (keyCode) {
- case kKeyCodeDpadRight:
- DBG_NAV_LOGD("keyCode=%s", "right");
- return CachedFrame::RIGHT;
- case kKeyCodeDpadLeft:
- DBG_NAV_LOGD("keyCode=%s", "left");
- return CachedFrame::LEFT;
- case kKeyCodeDpadDown:
- DBG_NAV_LOGD("keyCode=%s", "down");
- return CachedFrame::DOWN;
- case kKeyCodeDpadUp:
- DBG_NAV_LOGD("keyCode=%s", "up");
- return CachedFrame::UP;
- default:
- LOGD("------- bad key sent to WebView::moveFocus");
- return CachedFrame::UNINITIALIZED;
- }
-}
-
-bool invalidFrame(WebCore::Frame* frame, const CachedRoot* root)
-{
- if (!frame)
- return false;
- int frameBuild = m_viewImpl->retrieveFrameGeneration(frame);
- int rootBuild = root->generation();
- return frameBuild > rootBuild;
-}
-
-WebCore::String imageURI(int x, int y)
-{
- const CachedRoot* root = getFrameCache(DontAllowNewer);
- return root ? root->imageURI(x, y) : WebCore::String();
-}
-
-bool focusNodeWantsKeyEvents()
-{
- const CachedRoot* root = getFrameCache(DontAllowNewer);
- if (root) {
- const CachedNode* focus = root->currentFocus();
- if (focus) {
- return focus->isWantsKeyEvents();
- }
- }
- return false;
-}
-
-/* returns true if the key had no effect (neither scrolled nor changed focus) */
-bool moveFocus(int keyCode, int count, bool ignoreScroll, bool inval,
- void* lastSentFocus, const WebCore::IntRect* lastSentBounds)
-{
- CachedRoot* root = getFrameCache(AllowNewer);
- if (!root) {
- DBG_NAV_LOG("!root");
- setFocusData(0, 0, 0, 0, 0, true);
- sendKitFocus(); // will build cache and retry
- FirstMoveFocusParams params;
- params.d.m_trigger = CommonParams::FirstMoveFocusParams;
- params.d.m_generation = m_generation;
- params.m_keyCode = keyCode;
- params.m_count = count;
- params.m_ignoreScroll = ignoreScroll;
- m_replay.add(params.d, sizeof(params));
- return true;
- }
-
- CachedFrame::Direction direction = KeyToDirection((KeyCode) keyCode);
- const CachedFrame* cachedFrame, * oldFrame = 0;
- const CachedNode* focus = root->currentFocus(&oldFrame);
- WebCore::IntPoint focusLocation = root->focusLocation();
- DBG_NAV_LOGD("old focus %d (nativeNode=%p) focusLocation={%d, %d}",
- focus ? focus->index() : 0,
- focus ? focus->nodePointer() : 0, focusLocation.x(), focusLocation.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);
- int xMax = getScaledMaxXScroll();
- int yMax = getScaledMaxYScroll();
- root->setMaxScroll(xMax, yMax);
- CachedHistory savedHistory = *root->rootHistory();
- bool oldNodeIsTextArea = focusIsTextArea(DontAllowNewer);
- const CachedNode* cachedNode = 0;
- int dx = 0;
- int dy = 0;
- int counter = count;
- if (!focus || !focus->isInput() || !m_followedLink)
- root->setScrollOnly(m_followedLink);
- while (--counter >= 0) {
- WebCore::IntPoint scroll = WebCore::IntPoint(0, 0);
- cachedNode = root->moveFocus(direction, &cachedFrame, &scroll);
- dx += scroll.x();
- dy += scroll.y();
- }
- DBG_NAV_LOGD("new focus %d (nativeNode=%p) focusLocation={%d, %d}",
- cachedNode ? cachedNode->index() : 0,
- cachedNode ? cachedNode->nodePointer() : 0, root->focusLocation().x(),
- root->focusLocation().y());
- // If !m_heightCanMeasure (such as in the browser), we want to scroll no
- // matter what
- if (!ignoreScroll && (!m_heightCanMeasure ||
- !cachedNode ||
- (focus && focus->nodePointer() == cachedNode->nodePointer())))
- {
- if (count == 1 && dx != 0 && dy == 0 && -m_lastDx == dx &&
- SkTime::GetMSecs() - m_lastDxTime < 1000)
- root->checkForJiggle(&dx);
- DBG_NAV_LOGD("scrollBy %d,%d", dx, dy);
- if ((dx | dy))
- this->scrollBy(dx, dy);
- m_lastDx = dx;
- m_lastDxTime = SkTime::GetMSecs();
- ignoreScroll = true; // if move re-executes, don't scroll the second time
- }
- bool result = false;
- if (cachedNode) {
- WebCore::IntPoint pos;
- root->setCachedFocus((CachedFrame*) cachedFrame, (CachedNode*) cachedNode);
- root->getSimulatedMousePosition(&pos);
- if (lastSentFocus == cachedNode->nodePointer() && lastSentBounds &&
- *lastSentBounds == cachedNode->bounds())
- {
- sendFinalFocus((WebCore::Frame*) cachedFrame->framePointer(),
- (WebCore::Node*) cachedNode->nodePointer(), pos.x(), pos.y());
- } else {
- setFocusData(root->generation(),
- (WebCore::Frame*) cachedFrame->framePointer(),
- (WebCore::Node*) cachedNode->nodePointer(), pos.x(), pos.y(),
- true);
- sendKitFocus();
- if (inval)
- viewInvalidate();
- MoveFocusParams params;
- params.d.d.m_trigger = CommonParams::MoveFocusParams;
- params.d.d.m_generation = m_generation;
- params.c.setFocus(focus, oldFrame, root, focusLocation);
- params.m_sentFocus = cachedNode->nodePointer();
- params.m_sentBounds = cachedNode->bounds();
- params.m_visibleRect = visibleRect;
- params.m_history = savedHistory;
- DBG_NAV_LOGD("history.mDidFirstLayout=%s",
- params.m_history.didFirstLayout() ? "true" : "false");
- params.m_xMax = xMax;
- params.m_yMax = yMax;
- params.d.m_keyCode = keyCode;
- params.d.m_count = count;
- params.d.m_ignoreScroll = ignoreScroll;
- m_replay.add(params.d.d, sizeof(params));
- }
- } else {
- if (visibleRect.intersects(root->focusBounds()) == false) {
- setFocusData(root->generation(), 0, 0, 0, 0, true);
- sendKitFocus(); // will build cache and retry
- }
- FirstMoveFocusParams params;
- params.d.m_trigger = CommonParams::FirstMoveFocusParams;
- params.d.m_generation = m_generation;
- params.m_keyCode = keyCode;
- params.m_count = count;
- params.m_ignoreScroll = ignoreScroll;
- m_replay.add(params.d, sizeof(params));
- int docHeight = root->documentHeight();
- int docWidth = root->documentWidth();
- if (visibleRect.bottom() + dy > docHeight)
- dy = docHeight - visibleRect.bottom();
- else if (visibleRect.y() + dy < 0)
- dy = -visibleRect.y();
- if (visibleRect.right() + dx > docWidth)
- dx = docWidth - visibleRect.right();
- else if (visibleRect.x() < 0)
- dx = -visibleRect.x();
- result = direction == CachedFrame::LEFT ? dx >= 0 :
- direction == CachedFrame::RIGHT ? dx <= 0 :
- direction == CachedFrame::UP ? dy >= 0 : dy <= 0;
- }
- if (focusIsTextArea(DontAllowNewer))
- updateTextEntry();
- else if (oldNodeIsTextArea)
- clearTextEntry();
- return result;
-}
-
-void notifyFocusSet(FrameCachePermission inEditingMode)
-{
- CachedRoot* root = getFrameCache(DontAllowNewer);
- if (root) {
- // make sure the mFocusData in WebView.java is in sync with WebView.cpp
- const CachedFrame* frame = 0;
- const CachedNode* node = root->currentFocus(&frame);
- const WebCore::IntPoint& focusLocation = root->focusLocation();
- setFocusData(root->generation(),
- frame ? (WebCore::Frame*) frame->framePointer() : 0,
- node ? (WebCore::Node*) node->nodePointer() : 0,
- focusLocation.x(), focusLocation.y(), false);
- }
-
- if (focusIsTextArea(inEditingMode))
- updateTextEntry();
- else if (inEditingMode)
- clearTextEntry();
-#if DEBUG_NAV_UI
- if (m_frameCacheUI) {
- const CachedNode* focus = m_frameCacheUI->currentFocus();
- DBG_NAV_LOGD("focus %d (nativeNode=%p)",
- focus ? focus->index() : 0,
- focus ? focus->nodePointer() : 0);
- }
-#endif
-}
-
-void notifyProgressFinished()
-{
- DBG_NAV_LOGD("focusIsTextArea=%d", focusIsTextArea(DontAllowNewer));
- updateTextEntry();
-#if DEBUG_NAV_UI
- if (m_frameCacheUI) {
- const CachedNode* focus = m_frameCacheUI->currentFocus();
- DBG_NAV_LOGD("focus %d (nativeNode=%p)",
- focus ? focus->index() : 0,
- focus ? focus->nodePointer() : 0);
- }
-#endif
-}
-
-void recomputeFocus()
-{
- int generation;
- do {
- m_viewImpl->gRecomputeFocusMutex.lock();
- if (!m_viewImpl->m_recomputeEvents.size()) {
- m_viewImpl->gRecomputeFocusMutex.unlock();
- return;
- }
- generation = m_viewImpl->m_recomputeEvents.first();
- m_viewImpl->m_recomputeEvents.remove(0);
- m_viewImpl->gRecomputeFocusMutex.unlock();
- DBG_NAV_LOGD("generation=%d", generation);
- CachedRoot* root = getFrameCache(AllowNewest);
- if (!root) {
- DBG_NAV_LOG("!root");
- return;
- }
- LargestParams storage;
- const CommonParams& params = storage.d.d;
- char* pos = m_replay.position();
- while (m_replay.retrieve(&storage.d.d) < generation)
- DBG_NAV_LOGD("dropped ", params.m_generation);
- if (params.m_generation > generation) {
- DBG_NAV_LOGD("params.m_generation=%d > generation=%d",
- params.m_generation, generation);
- m_replay.rewind(pos);
- return;
- }
- int lastAdd = m_replay.lastAdd();
- do {
- LOG_ASSERT(params.m_trigger != CommonParams::NoData, "expected data");
- bool inval = generation == m_generation;
- switch (params.m_trigger) {
- case CommonParams::ClearFocusParams: {
- const ClearFocusParams& sParams = *(ClearFocusParams*) &storage;
- const CacheParams& cParams = sParams.c;
- if (invalidFrame(cParams.m_frame, root)) {
- DBG_NAV_LOGD("dropped %s generation=%d",
- TriggerNames[params.m_trigger], generation);
- return;
- }
- root->setFocus(cParams.m_frame, cParams.m_node, cParams.m_x, cParams.m_y);
- clearFocus(sParams.m_x, sParams.m_y, inval);
- DBG_NAV_LOGD("clearFocus(x,y)={%d,%d}", sParams.m_x, sParams.m_y);
- } break;
- case CommonParams::MotionUpParams: {
- const MotionUpParams& mParams = *(MotionUpParams*) &storage;
- // const CacheParams& cParams = mParams.c;
- // if (invalidFrame(cParams.m_frame, root) == false)
- // root->setFocus(cParams.m_frame, cParams.m_node,
- // cParams.m_x, cParams.m_y);
- motionUp(mParams.m_x, mParams.m_y, mParams.m_slop, mParams.m_isClick, inval, true);
- DBG_NAV_LOGD("motionUp m_x=%d m_y=%d", mParams.m_x, mParams.m_y);
- } break;
- case CommonParams::FirstMoveFocusParams: {
- if (invalidFrame((WebCore::Frame*) root->framePointer(), root)) {
- DBG_NAV_LOGD("dropped %s generation=%d",
- TriggerNames[params.m_trigger], generation);
- return;
- }
- const FirstMoveFocusParams& fParams = *(FirstMoveFocusParams*) &storage;
- DBG_NAV_LOGD("first moveFocus keyCode=%d count=%d"
- " ignoreScroll=%s", fParams.m_keyCode, fParams.m_count,
- fParams.m_ignoreScroll ? "true" : "false");
- moveFocus(fParams.m_keyCode, fParams.m_count,
- fParams.m_ignoreScroll, inval, 0, 0);
- } break;
- case CommonParams::MoveFocusParams: {
- const MoveFocusParams& mParams = *(MoveFocusParams*) &storage;
- const CacheParams& cParams = mParams.c;
- if (invalidFrame(cParams.m_frame, root)) {
- DBG_NAV_LOGD("dropped %s generation=%d",
- TriggerNames[params.m_trigger], generation);
- return;
- }
- DBG_NAV_LOGD("moveFocus keyCode=%d count=%d ignoreScroll=%s "
- "history.mDidFirstLayout=%s", mParams.d.m_keyCode,
- mParams.d.m_count, mParams.d.m_ignoreScroll ? "true" : "false",
- mParams.m_history.didFirstLayout() ? "true" : "false");
- if (!root->setFocus(cParams.m_frame, cParams.m_node,
- cParams.m_x, cParams.m_y)) {
- DBG_NAV_LOGD("can't restore focus frame=%p node=%p",
- "x=%d y=%d %s", cParams.m_frame, cParams.m_node,
- cParams.m_x, cParams.m_y, TriggerNames[params.m_trigger]);
- return;
- }
- root->setVisibleRect(mParams.m_visibleRect);
- root->setMaxScroll(mParams.m_xMax, mParams.m_yMax);
- *root->rootHistory() = mParams.m_history;
- moveFocus(mParams.d.m_keyCode, mParams.d.m_count,
- mParams.d.m_ignoreScroll, inval,
- mParams.m_sentFocus, &mParams.m_sentBounds);
- } break;
- default:
- LOG_ASSERT(0, "unknown trigger");
- }
- if (params.m_generation >= lastAdd)
- break;
- root = getFrameCache(DontAllowNewer); // re-execution may have retrieved newer cache
- m_replay.retrieve(&storage.d.d);
- DBG_NAV_LOGD("continuation m_generation %d", params.m_generation);
- } while (true);
- } while (true);
-}
-
-void resetFocus()
-{
- DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
- CachedRoot* root = getFrameCache(AllowNewer);
- if (!root)
- return;
- root->setCachedFocus(0, 0);
-}
-
-const CachedNode* findAt(CachedRoot* root, const WebCore::IntRect& rect,
- const CachedFrame** framePtr, int* rxPtr, int* ryPtr)
-{
- *rxPtr = 0;
- *ryPtr = 0;
- *framePtr = 0;
- if (!root)
- return 0;
- WebCore::IntRect visibleRect;
- getVisibleRect(&visibleRect);
- root->setVisibleRect(visibleRect);
- return root->findAt(rect, framePtr, rxPtr, ryPtr);
-}
-
-void selectBestAt(const WebCore::IntRect& rect)
-{
- const CachedFrame* frame;
- int rx, ry;
- CachedRoot* root = getFrameCache(DontAllowNewer);
- const CachedNode* node = findAt(root, rect, &frame, &rx, &ry);
- int rootGeneration = root ? root->generation() : 0;
- setFocusData(rootGeneration,
- frame ? (WebCore::Frame*) frame->framePointer() : 0,
- node ? (WebCore::Node*) node->nodePointer() : 0, rx, ry, false);
- if (!node) {
- DBG_NAV_LOGD("no nodes found root=%p", root);
- if (root) {
- root->clearFocus();
- root->setCachedFocus(0, 0);
- }
- sendKitFocus();
- viewInvalidate();
- clearTextEntry();
- return;
- }
- DBG_NAV_LOGD("CachedNode:%p (%d)", node, node->index());
- const CachedFrame* oldFrame = 0;
- const CachedNode* oldFocusNode = root->currentFocus(&oldFrame);
- bool oldNodeIsTextArea = focusIsTextArea(DontAllowNewer);
- root->setCachedFocus(const_cast<CachedFrame*>(frame),
- const_cast<CachedNode*>(node));
- viewInvalidate();
- if (focusIsTextArea(DontAllowNewer))
- updateTextEntry();
- else if (oldNodeIsTextArea)
- clearTextEntry();
-}
-
-WebCore::IntRect getNavBounds()
-{
- CachedRoot* root = getFrameCache(DontAllowNewer);
- if (!root)
- return WebCore::IntRect(0, 0, 0, 0);
- return root->rootHistory()->navBounds();
-}
-
-void setNavBounds(const WebCore::IntRect& rect)
-{
- CachedRoot* root = getFrameCache(DontAllowNewer);
- if (!root)
- return;
- root->rootHistory()->setNavBounds(rect);
-}
-
-void markNodeInvalid(WebCore::Node* node)
-{
- DBG_NAV_LOGD("node=%p", node);
- m_invalidNode = node;
- viewInvalidate();
-}
-
-bool motionUp(int x, int y, int slop, bool isClick, bool inval, bool retry)
-{
- bool pageScrolled = false;
- m_followedLink = false;
- const CachedFrame* frame;
- WebCore::IntRect rect = WebCore::IntRect(x - slop, y - slop, slop * 2, slop * 2);
- int rx, ry;
- CachedRoot* root = getFrameCache(AllowNewer);
- const CachedNode* result = findAt(root, rect, &frame, &rx, &ry);
- if (!result) {
- DBG_NAV_LOGD("no nodes found root=%p", root);
- int rootGeneration = 0;
- if (root) {
- root->clearFocus();
- rootGeneration = root->generation();
- if (!retry) { // scroll first time only
- int dx = root->checkForCenter(x, y);
- if (dx) {
- scrollBy(dx, 0);
- retry = true; // don't recompute later since we scrolled
- pageScrolled = true;
- }
- }
- }
- sendMotionUp(rootGeneration, frame ?
- (WebCore::Frame*) frame->framePointer() : 0,
- 0, x, y, slop, isClick, retry);
- if (inval)
- viewInvalidate();
- if (!retry) {
- MotionUpParams params;
- params.d.m_trigger = CommonParams::MotionUpParams;
- params.d.m_generation = m_generation;
- params.m_x = x;
- params.m_y = y;
- params.m_slop = slop;
- params.m_isClick = isClick;
- m_replay.add(params.d, sizeof(params));
- }
- clearTextEntry();
- return pageScrolled;
- }
- DBG_NAV_LOGD("CachedNode:%p (%d) x=%d y=%d rx=%d ry=%d", result,
- result->index(), x, y, rx, ry);
- // const CachedFrame* oldFrame = 0;
- // const CachedNode* oldFocusNode = root->currentFocus(&oldFrame);
- // WebCore::IntPoint focusLocation = root->focusLocation();
- bool oldNodeIsTextArea = !retry && focusIsTextArea(DontAllowNewer);
- root->setCachedFocus(const_cast<CachedFrame*>(frame),
- const_cast<CachedNode*>(result));
- bool newNodeIsTextArea = focusIsTextArea(DontAllowNewer);
- CachedNodeType type = result->type();
- if (type == NORMAL_CACHEDNODETYPE || newNodeIsTextArea) {
- sendMotionUp(root->generation(),
- frame ? (WebCore::Frame*) frame->framePointer() : 0,
- result ? (WebCore::Node*) result->nodePointer() : 0, rx, ry,
- slop, isClick, retry);
- if (inval)
- viewInvalidate();
- if (!retry) {
- MotionUpParams params;
- params.d.m_trigger = CommonParams::MotionUpParams;
- params.d.m_generation = m_generation;
- params.m_x = x;
- params.m_y = y;
- params.m_slop = slop;
- params.m_isClick = isClick;
- // params.c.setFocus(oldFocusNode, oldFrame, root, focusLocation);
- m_replay.add(params.d, sizeof(params));
- }
- } else if (inval)
- viewInvalidate();
- if (newNodeIsTextArea) {
- updateTextEntry();
- displaySoftKeyboard();
- } else {
- if (isClick) {
- setFollowedLink(true);
- if (type != NORMAL_CACHEDNODETYPE) {
- overrideUrlLoading(result->getExport());
- }
- }
- if (oldNodeIsTextArea)
- clearTextEntry();
- }
- return pageScrolled;
-}
-
-void overrideUrlLoading(const WebCore::String& url)
-{
- JNIEnv* env = JSC::Bindings::getJNIEnv();
- jstring jName = env->NewString((jchar*) url.characters(), url.length());
- env->CallVoidMethod(m_javaGlue.object(env).get(),
- m_javaGlue.m_overrideLoading, jName);
- env->DeleteLocalRef(jName);
-}
-
-void setFindIsUp(bool up)
-{
- m_viewImpl->m_findIsUp = up;
- if (!up)
- m_hasCurrentLocation = false;
-}
-
-void setFollowedLink(bool followed)
-{
- if ((m_followedLink = followed) != false) {
- m_ringAnimationEnd = SkTime::GetMSecs() + 500;
- viewInvalidate();
- }
-}
-
-void setHeightCanMeasure(bool measure)
-{
- m_heightCanMeasure = measure;
-}
-
-SkIRect m_selStart, m_selEnd;
-SkRegion m_selRegion;
-#define MIN_ARROW_DISTANCE (20 * 20)
-
-void moveSelection(int x, int y, bool extendSelection)
-{
- CachedRoot* root = getFrameCache(DontAllowNewer);
- if (!root)
- return;
- const SkPicture& picture = *m_navPictureUI;
- WebCore::IntRect r;
- getVisibleRect(&r);
- SkIRect area;
- area.set(r.x(), r.y(), r.right(), r.bottom());
- if (!extendSelection)
- m_selStart = m_selEnd = CopyPaste::findClosest(picture, area, x, y);
- else
- m_selEnd = CopyPaste::findClosest(picture, area, x, y);
- DBG_NAV_LOGD("x=%d y=%d extendSelection=%s m_selStart=(%d, %d, %d, %d)"
- " m_selEnd=(%d, %d, %d, %d)", x, y, extendSelection ? "true" : "false",
- m_selStart.fLeft, m_selStart.fTop, m_selStart.fRight, m_selStart.fBottom,
- m_selEnd.fLeft, m_selEnd.fTop, m_selEnd.fRight, m_selEnd.fBottom);
-}
-
-const SkRegion& getSelection()
-{
- return m_selRegion;
-}
-
-void drawSelection(SkCanvas* canvas, int x, int y, bool extendSelection)
-{
- if (!extendSelection) {
- int dx = x - m_selStart.fLeft;
- dx *= dx;
- int otherX = x - m_selStart.fRight;
- if (dx > (otherX *= otherX))
- dx = otherX;
- int dy = y - m_selStart.fTop;
- int dist = dx * dx + dy * dy;
- if (dist > MIN_ARROW_DISTANCE)
- drawSelectionArrow(canvas, x, y);
- else
- drawSelectionPointer(canvas, x, y, true);
- } else {
- drawSelectionRegion(canvas);
- drawSelectionPointer(canvas, x, y, false);
- }
-}
-
-void drawSelectionRegion(SkCanvas* canvas)
-{
- CachedRoot* root = getFrameCache(DontAllowNewer);
- if (!root)
- return;
- WebCore::IntRect r;
- getVisibleRect(&r);
- SkIRect area;
- area.set(r.x(), r.y(), r.right(), r.bottom());
- m_selRegion.setEmpty();
- CopyPaste::buildSelection(*m_navPictureUI, area, m_selStart, m_selEnd, &m_selRegion);
- SkPath path;
- m_selRegion.getBoundaryPath(&path);
- SkPaint paint;
- paint.setAntiAlias(true);
- paint.setColor(SkColorSetARGB(0x40, 255, 51, 204));
- canvas->drawPath(path, paint);
-}
-
-void drawSelectionPointer(SkCanvas* canvas, int x, int y, bool gridded)
-{
- SkPath path;
- getSelectionCaret(&path);
- SkPaint paint;
- paint.setAntiAlias(true);
- paint.setStyle(SkPaint::kStroke_Style);
- paint.setColor(SK_ColorBLACK);
- SkPixelXorXfermode xorMode(SK_ColorWHITE);
- paint.setXfermode(&xorMode);
- int sc = canvas->save();
- if (gridded) {
- bool useLeft = x <= (m_selStart.fLeft + m_selStart.fRight) >> 1;
- canvas->translate(SkIntToScalar(useLeft ? m_selStart.fLeft :
- m_selStart.fRight), SkIntToScalar(m_selStart.fTop));
- } else
- canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
- canvas->drawPath(path, paint);
- canvas->restoreToCount(sc);
-}
-
-void drawSelectionArrow(SkCanvas* canvas, int x, int y)
-{
- SkPath path;
- getSelectionArrow(&path);
- SkPaint paint;
- paint.setAntiAlias(true);
- paint.setStyle(SkPaint::kStroke_Style);
- paint.setColor(SK_ColorBLACK);
- paint.setStrokeWidth(SK_Scalar1 * 2);
- int sc = canvas->save();
- canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
- canvas->drawPath(path, paint);
- paint.setStyle(SkPaint::kFill_Style);
- paint.setColor(SK_ColorWHITE);
- canvas->drawPath(path, paint);
- canvas->restoreToCount(sc);
-}
-
-void getSelectionArrow(SkPath* path)
-{
- const int arrow[] = {
- 0, 14, 3, 11, 5, 15, 9, 15, 7, 11, 11, 11
- };
- for (unsigned index = 0; index < sizeof(arrow)/sizeof(arrow[0]); index += 2)
- path->lineTo(SkIntToScalar(arrow[index]), SkIntToScalar(arrow[index + 1]));
- path->close();
-}
-
-void getSelectionCaret(SkPath* path)
-{
- SkScalar height = SkIntToScalar(m_selStart.fBottom - m_selStart.fTop);
- SkScalar dist = height / 4;
- path->lineTo(0, height);
- SkScalar bottom = height + dist;
- path->lineTo(-dist, bottom);
- SkScalar edge = bottom - SK_Scalar1/2;
- path->moveTo(-dist, edge);
- path->lineTo(dist, edge);
- path->moveTo(dist, bottom);
- path->lineTo(0, height);
-}
-
-void sendFinalFocus(WebCore::Frame* framePtr, WebCore::Node* nodePtr, int x, int y)
-{
- DBG_NAV_LOGD("framePtr=%p nodePtr=%p x=%d y=%d", framePtr, nodePtr, x, y);
- LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
- JNIEnv* env = JSC::Bindings::getJNIEnv();
- env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_sendFinalFocus,
- (jint) framePtr, (jint) nodePtr, x, y);
- checkException(env);
-}
-
-void sendKitFocus()
-{
- LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
- JNIEnv* env = JSC::Bindings::getJNIEnv();
- env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_sendKitFocus);
- checkException(env);
-}
-
-void sendMotionUp(int buildGeneration,
- WebCore::Frame* framePtr, WebCore::Node* nodePtr, int x, int y, int slop,
- bool isClick, bool retry)
-{
- m_viewImpl->m_touchGeneration = m_viewImpl->m_generation = ++m_generation;
- DBG_NAV_LOGD("buildGeneration=%d m_generation=%d framePtr=%p nodePtr=%p"
- " x=%d y=%d slop=%d", buildGeneration,
- m_generation, framePtr, nodePtr, x, y, slop);
- LOG_ASSERT(m_javaGlue.m_obj, "A WebView was not associated with this WebViewNative!");
- JNIEnv* env = JSC::Bindings::getJNIEnv();
- env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_sendMotionUp, m_generation,
- buildGeneration, (jint) framePtr, (jint) nodePtr, x, y, slop, isClick, retry);
- checkException(env);
-}
-
-void setFocusData(int buildGeneration, WebCore::Frame* framePtr,
- WebCore::Node* nodePtr, int x, int y, bool ignoreNullFocus)
-{
- m_viewImpl->m_moveGeneration = m_viewImpl->m_generation = ++m_generation;
- DBG_NAV_LOGD("moveGeneration=%d buildGeneration=%d framePtr=%p nodePtr=%p"
- " x=%d y=%d", m_generation, buildGeneration, framePtr, nodePtr, x, y);
- LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
- JNIEnv* env = JSC::Bindings::getJNIEnv();
- env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_setFocusData, m_generation,
- buildGeneration, (jint) framePtr, (jint) nodePtr, x, y, ignoreNullFocus);
- 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();
- viewInvalidate();
-}
-
-// With this call, WebView takes ownership of matches, and is responsible for
-// 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;
- }
- viewInvalidate();
-}
-
-void scrollBy(int dx, int dy)
-{
- LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
-
- JNIEnv* env = JSC::Bindings::getJNIEnv();
- env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_scrollBy,
- dx, dy, true);
- checkException(env);
-}
-
-bool updateFocusNode(JNIEnv* env)
-{
- CachedRoot* root = getFrameCache(DontAllowNewer);
- if (!root) {
- DBG_NAV_LOG("!root");
- return false;
- }
- const CachedFrame* cachedFrame = 0;
- const CachedNode* cachedFocusNode = root->currentFocus(&cachedFrame);
- if (!cachedFocusNode) {
- DBG_NAV_LOG("!cachedFocusNode");
- return false;
- }
- DBG_NAV_LOGD("cachedFocusNode=%d (nodePointer=%p)",
- cachedFocusNode->index(),
- cachedFocusNode->nodePointer());
- jobject focusnode = env->GetObjectField(m_javaGlue.object(env).get(), m_javaGlue.m_focusNode);
- LOG_ASSERT(focusnode, "Could not find WebView's FocusNode");
-
- bool isTextArea = cachedFocusNode->isTextArea();
- bool isTextField = cachedFocusNode->isTextField();
- int maxLength;
- jstring jName;
- if (isTextField) {
- maxLength = cachedFocusNode->maxLength();
- const WebCore::String& name = cachedFocusNode->name();
- jName = env->NewString((jchar*)name.characters(), name.length());
- } else {
- maxLength = -1;
- jName = 0;
- }
- WebCore::IntRect bounds = cachedFocusNode->bounds();
- WebCore::String value = cachedFocusNode->getExport();
- jstring val = !value.isEmpty() ? env->NewString((jchar *)value.characters(), value.length()) : 0;
- env->CallVoidMethod(focusnode, m_javaGlue.m_setAll, isTextField, isTextArea, cachedFocusNode->isPassword(),
- cachedFocusNode->isAnchor(), cachedFocusNode->isRtlText(), maxLength, cachedFocusNode->textSize(),
- bounds.x(), bounds.y(), bounds.right(), bounds.bottom(), (int)(cachedFocusNode->nodePointer()),
- (int)(cachedFrame->framePointer()), val, jName, root->textGeneration());
- env->DeleteLocalRef(val);
- env->DeleteLocalRef(focusnode);
- if (isTextField)
- env->DeleteLocalRef(jName);
- return true;
-}
-
-void updateTextEntry()
-{
- JNIEnv* env = JSC::Bindings::getJNIEnv();
- env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_updateTextEntry);
- checkException(env);
-}
-
-void displaySoftKeyboard()
-{
- JNIEnv* env = JSC::Bindings::getJNIEnv();
- env->CallVoidMethod(m_javaGlue.object(env).get(),
- m_javaGlue.m_displaySoftKeyboard);
- checkException(env);
-}
-
-void viewInvalidate()
-{
- JNIEnv* env = JSC::Bindings::getJNIEnv();
- env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_viewInvalidate);
- checkException(env);
-}
-
-void viewInvalidateRect(int l, int t, int r, int b)
-{
- JNIEnv* env = JSC::Bindings::getJNIEnv();
- env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_viewInvalidateRect, l, r, t, b);
- checkException(env);
-}
-
-void postInvalidateDelayed(int64_t delay, const WebCore::IntRect& bounds)
-{
- JNIEnv* env = JSC::Bindings::getJNIEnv();
- env->CallVoidMethod(m_javaGlue.object(env).get(), m_javaGlue.m_postInvalidateDelayed,
- delay, bounds.x(), bounds.y(), bounds.right(), bounds.bottom());
- checkException(env);
-}
-
-private: // local state for WebView
- // private to getFrameCache(); other functions operate in a different thread
- CachedRoot* m_frameCacheUI; // navigation data ready for use
- FocusReplay m_replay;
- WebViewCore* m_viewImpl;
- WebCore::Node* m_invalidNode;
- int m_generation; // associate unique ID with sent kit focus to match with ui
- SkPicture* m_navPictureUI;
- bool m_followedLink;
- SkMSec m_ringAnimationEnd;
- // Corresponds to the same-named boolean on the java side.
- 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;
-}; // end of WebView class
-
-/*
- * Native JNI methods
- */
-static jstring WebCoreStringToJString(JNIEnv *env, WebCore::String string)
-{
- int length = string.length();
- if (!length)
- return 0;
- jstring ret = env->NewString((jchar *)string.characters(), length);
- env->DeleteLocalRef(ret);
- return ret;
-}
-
-static void nativeClearFocus(JNIEnv *env, jobject obj, int x, int y)
-{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
- view->clearFocus(x, y, true);
-}
-
-static void nativeCreate(JNIEnv *env, jobject obj, int viewImpl)
-{
- WebView* webview = new WebView(env, obj, viewImpl);
- // NEED THIS OR SOMETHING LIKE IT!
- //Release(obj);
-}
-
-static void nativeDebugDump(JNIEnv *env, jobject obj)
-{
-#if DUMP_NAV_CACHE
- WebView* view = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
- view->debugDump();
-#endif
-}
-
-static void nativeDrawMatches(JNIEnv *env, jobject obj, jobject canv)
-{
- SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv);
- if (!canv) {
- DBG_NAV_LOG("!canv");
- return;
- }
- WebView* view = GET_NATIVE_VIEW(env, obj);
- if (!view) {
- DBG_NAV_LOG("!view");
- return;
- }
- view->drawMatches(canvas);
-}
-
-static void nativeDrawFocusRing(JNIEnv *env, jobject obj,
- jobject canv)
-{
- SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv);
- if (!canv) {
- DBG_NAV_LOG("!canv");
- return;
- }
- WebView* view = GET_NATIVE_VIEW(env, obj);
- if (!view) {
- DBG_NAV_LOG("!view");
- return;
- }
- view->drawFocusRing(canvas);
-}
-
-static void nativeDrawSelection(JNIEnv *env, jobject obj,
- jobject canv, jint x, jint y, bool ex)
-{
- SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv);
- if (!canv) {
- DBG_NAV_LOG("!canv");
- return;
- }
- WebView* view = GET_NATIVE_VIEW(env, obj);
- if (!view) {
- DBG_NAV_LOG("!view");
- return;
- }
- view->drawSelection(canvas, x, y, ex);
-}
-
-static void nativeDrawSelectionRegion(JNIEnv *env, jobject obj, jobject canv)
-{
- SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv);
- if (!canv) {
- DBG_NAV_LOG("!canv");
- return;
- }
- WebView* view = GET_NATIVE_VIEW(env, obj);
- if (!view) {
- DBG_NAV_LOG("!view");
- return;
- }
- view->drawSelectionRegion(canvas);
-}
-
-static jobject nativeImageURI(JNIEnv *env, jobject obj, jint x, jint y)
-{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
- WebCore::String uri = view->imageURI(x, y);
- jstring ret = 0;
- unsigned len = uri.length();
- if (len) {
- ret = env->NewString((jchar*) uri.characters(), len);
- env->DeleteLocalRef(ret);
- }
- return ret;
-}
-
-static bool nativeFocusNodeWantsKeyEvents(JNIEnv* env, jobject jwebview) {
- WebView* view = GET_NATIVE_VIEW(env, jwebview);
- LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
- return view->focusNodeWantsKeyEvents();
-}
-
-static void nativeInstrumentReport(JNIEnv *env, jobject obj)
-{
-#ifdef ANDROID_INSTRUMENT
- TimeCounter::reportNow();
-#endif
-}
-
-static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj)
-{
- int L, T, R, B;
- GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B);
- return WebCore::IntRect(L, T, R - L, B - T);
-}
-
-static void nativeSelectBestAt(JNIEnv *env, jobject obj, jobject jrect)
-{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
- WebCore::IntRect rect = jrect_to_webrect(env, jrect);
- view->selectBestAt(rect);
-}
-
-static void nativeMarkNodeInvalid(JNIEnv *env, jobject obj, int node)
-{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
- view->markNodeInvalid((WebCore::Node*) node);
-}
-
-static bool nativeMotionUp(JNIEnv *env, jobject obj,
- int x, int y, int slop, bool isClick)
-{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
- return view->motionUp(x, y, slop, isClick, true, false);
-}
-
-static bool nativeUpdateFocusNode(JNIEnv *env, jobject obj)
-{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
- return view->updateFocusNode(env);
-}
-
-static bool nativeMoveFocus(JNIEnv *env, jobject obj,
- int key, int count, bool ignoreScroll)
-{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- DBG_NAV_LOGD("env=%p obj=%p view=%p", env, obj, view);
- LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
- return view->moveFocus(key, count, ignoreScroll, true, 0, 0);
-}
-
-static void nativeNotifyFocusSet(JNIEnv *env, jobject obj, bool inEditingMode)
-{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
- view->notifyFocusSet((WebView::FrameCachePermission) inEditingMode);
-}
-
-static void nativeRecomputeFocus(JNIEnv *env, jobject obj)
-{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
- view->recomputeFocus();
-}
-
-static void nativeRecordButtons(JNIEnv* env, jobject obj, bool hasFocus,
- bool pressed, bool invalidate)
-{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
- view->nativeRecordButtons(hasFocus, pressed, invalidate);
-}
-
-static void nativeResetFocus(JNIEnv *env, jobject obj)
-{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
- view->resetFocus();
-}
-
-static void nativeSetFindIsDown(JNIEnv *env, jobject obj)
-{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
- view->setFindIsUp(false);
-}
-
-static void nativeSetFollowedLink(JNIEnv *env, jobject obj, bool followed)
-{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
- view->setFollowedLink(followed);
-}
-
-static void nativeSetHeightCanMeasure(JNIEnv *env, jobject obj, bool measure)
-{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(view, "view not set in nativeSetHeightCanMeasure");
- view->setHeightCanMeasure(measure);
-}
-
-static jobject nativeGetFocusRingBounds(JNIEnv *env, jobject obj)
-{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
- jclass rectClass = env->FindClass("android/graphics/Rect");
- LOG_ASSERT(rectClass, "Could not find Rect class!");
- jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
- LOG_ASSERT(init, "Could not find constructor for Rect");
- WebCore::IntRect webRect;
- view->focusRingBounds(&webRect);
- jobject rect = env->NewObject(rectClass, init, webRect.x(),
- webRect.y(), webRect.right(), webRect.bottom());
- return rect;
-}
-
-static jobject nativeGetNavBounds(JNIEnv *env, jobject obj)
-{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
- jclass rectClass = env->FindClass("android/graphics/Rect");
- LOG_ASSERT(rectClass, "Could not find Rect class!");
- jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
- LOG_ASSERT(init, "Could not find constructor for Rect");
- WebCore::IntRect webRect = view->getNavBounds();
- jobject rect = env->NewObject(rectClass, init, webRect.x(),
- webRect.y(), webRect.right(), webRect.bottom());
- return rect;
-}
-
-static void nativeSetNavBounds(JNIEnv *env, jobject obj, jobject jrect)
-{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
- WebCore::IntRect rect = jrect_to_webrect(env, jrect);
- view->setNavBounds(rect);
-}
-
-static int nativeFindAll(JNIEnv *env, jobject obj, jstring findLower,
- jstring findUpper)
-{
- // If one or the other is null, do not search.
- if (!(findLower && findUpper))
- return 0;
- // Obtain the characters for both the lower case string and the upper case
- // string representing the same word.
- const jchar* findLowerChars = env->GetStringChars(findLower, 0);
- const jchar* findUpperChars = env->GetStringChars(findUpper, 0);
- // If one or the other is null, do not search.
- if (!(findLowerChars && findUpperChars)) {
- if (findLowerChars)
- env->ReleaseStringChars(findLower, findLowerChars);
- if (findUpperChars)
- env->ReleaseStringChars(findUpper, findUpperChars);
- checkException(env);
- return 0;
- }
- WebView* view = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(view, "view not set in nativeFindAll");
- view->setFindIsUp(true);
- CachedRoot* root = view->getFrameCache(WebView::AllowNewer);
- if (!root) {
- env->ReleaseStringChars(findLower, findLowerChars);
- env->ReleaseStringChars(findUpper, findUpperChars);
- checkException(env);
- return 0;
- }
- int length = env->GetStringLength(findLower);
- // If the lengths of the strings do not match, then they are not the same
- // word, so do not search.
- if (!length || env->GetStringLength(findUpper) != length) {
- env->ReleaseStringChars(findLower, findLowerChars);
- env->ReleaseStringChars(findUpper, findUpperChars);
- checkException(env);
- return 0;
- }
-
- int width = root->documentWidth();
- int height = root->documentHeight();
- // Create a FindCanvas, which allows us to fake draw into it so we can
- // figure out where our search string is rendered (and how many times).
- FindCanvas canvas(width, height, (const UChar*) findLowerChars,
- (const UChar*) findUpperChars, length << 1);
- SkBitmap bitmap;
- bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
- canvas.setBitmapDevice(bitmap);
- canvas.drawPicture(*(root->getPicture()));
- WTF::Vector<MatchInfo>* matches = canvas.detachMatches();
- // With setMatches, the WebView takes ownership of matches
- view->setMatches(matches);
-
- env->ReleaseStringChars(findLower, findLowerChars);
- env->ReleaseStringChars(findUpper, findUpperChars);
- checkException(env);
- return canvas.found();
-}
-
-static void nativeFindNext(JNIEnv *env, jobject obj, bool forward)
-{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(view, "view not set in nativeFindNext");
- view->findNext(forward);
-}
-
-static void nativeUpdateCachedTextfield(JNIEnv *env, jobject obj, jstring updatedText, jint generation)
-{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(view, "view not set in nativeUpdateCachedTextfield");
- CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
- if (!root)
- return;
- const CachedNode* cachedFocusNode = root->currentFocus();
- if (!cachedFocusNode || (!cachedFocusNode->isTextField() && !cachedFocusNode->isTextArea()))
- return;
- WebCore::String webcoreString = to_string(env, updatedText);
- (const_cast<CachedNode*>(cachedFocusNode))->setExport(webcoreString);
- root->setTextGeneration(generation);
- checkException(env);
-}
-
-static void nativeDestroy(JNIEnv *env, jobject obj)
-{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- LOGD("nativeDestroy view: %p", view);
- LOG_ASSERT(view, "view not set in nativeDestroy");
- delete view;
-}
-
-static void nativeMoveSelection(JNIEnv *env, jobject obj, int x, int y, bool ex)
-{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
- view->moveSelection(x, y, ex);
-}
-
-static jobject nativeGetSelection(JNIEnv *env, jobject obj)
-{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
- return GraphicsJNI::createRegion(env, new SkRegion(view->getSelection()));
-}
-
-#ifdef ANDROID_DUMP_DISPLAY_TREE
-static void dumpToFile(const char text[], void* file) {
- fwrite(text, 1, strlen(text), reinterpret_cast<FILE*>(file));
- fwrite("\n", 1, 1, reinterpret_cast<FILE*>(file));
-}
-#endif
-
-static void nativeDumpDisplayTree(JNIEnv* env, jobject jwebview, jstring jurl)
-{
-#ifdef ANDROID_DUMP_DISPLAY_TREE
- WebView* view = GET_NATIVE_VIEW(env, jwebview);
- LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
-
- CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
- if (root) {
- SkPicture* picture = root->getPicture();
- if (picture) {
- FILE* file = fopen(DISPLAY_TREE_LOG_FILE, "w");
- if (file) {
- SkFormatDumper dumper(dumpToFile, file);
- // dump the URL
- if (jurl) {
- const char* str = env->GetStringUTFChars(jurl, 0);
- SkDebugf("Dumping %s to %s\n", str, DISPLAY_TREE_LOG_FILE);
- dumpToFile(str, file);
- env->ReleaseStringUTFChars(jurl, str);
- }
- // now dump the display tree
- SkDumpCanvas canvas(&dumper);
- // this will playback the picture into the canvas, which will
- // spew its contents to the dumper
- picture->draw(&canvas);
- // we're done with the file now
- fwrite("\n", 1, 1, file);
- fclose(file);
- }
- }
- }
-#endif
-}
-
-/*
- * JNI registration
- */
-static JNINativeMethod gJavaWebViewMethods[] = {
- { "nativeFindAll", "(Ljava/lang/String;Ljava/lang/String;)I",
- (void*) nativeFindAll },
- { "nativeFindNext", "(Z)V",
- (void*) nativeFindNext },
- { "nativeClearFocus", "(II)V",
- (void*) nativeClearFocus },
- { "nativeCreate", "(I)V",
- (void*) nativeCreate },
- { "nativeDebugDump", "()V",
- (void*) nativeDebugDump },
- { "nativeDestroy", "()V",
- (void*) nativeDestroy },
- { "nativeDrawMatches", "(Landroid/graphics/Canvas;)V",
- (void*) nativeDrawMatches },
- { "nativeDrawFocusRing", "(Landroid/graphics/Canvas;)V",
- (void*) nativeDrawFocusRing },
- { "nativeDrawSelection", "(Landroid/graphics/Canvas;IIZ)V",
- (void*) nativeDrawSelection },
- { "nativeDrawSelectionRegion", "(Landroid/graphics/Canvas;)V",
- (void*) nativeDrawSelectionRegion },
- { "nativeUpdateFocusNode", "()Z",
- (void*) nativeUpdateFocusNode },
- { "nativeGetFocusRingBounds", "()Landroid/graphics/Rect;",
- (void*) nativeGetFocusRingBounds },
- { "nativeGetNavBounds", "()Landroid/graphics/Rect;",
- (void*) nativeGetNavBounds },
- { "nativeInstrumentReport", "()V",
- (void*) nativeInstrumentReport },
- { "nativeMarkNodeInvalid", "(I)V",
- (void*) nativeMarkNodeInvalid },
- { "nativeMotionUp", "(IIIZ)Z",
- (void*) nativeMotionUp },
- { "nativeMoveFocus", "(IIZ)Z",
- (void*) nativeMoveFocus },
- { "nativeNotifyFocusSet", "(Z)V",
- (void*) nativeNotifyFocusSet },
- { "nativeRecomputeFocus", "()V",
- (void*) nativeRecomputeFocus },
- { "nativeRecordButtons", "(ZZZ)V",
- (void*) nativeRecordButtons },
- { "nativeResetFocus", "()V",
- (void*) nativeResetFocus },
- { "nativeSelectBestAt", "(Landroid/graphics/Rect;)V",
- (void*) nativeSelectBestAt },
- { "nativeSetFindIsDown", "()V",
- (void*) nativeSetFindIsDown },
- { "nativeSetFollowedLink", "(Z)V",
- (void*) nativeSetFollowedLink },
- { "nativeSetHeightCanMeasure", "(Z)V",
- (void*) nativeSetHeightCanMeasure },
- { "nativeSetNavBounds", "(Landroid/graphics/Rect;)V",
- (void*) nativeSetNavBounds },
- { "nativeImageURI", "(II)Ljava/lang/String;",
- (void*) nativeImageURI },
- { "nativeFocusNodeWantsKeyEvents", "()Z",
- (void*)nativeFocusNodeWantsKeyEvents },
- { "nativeUpdateCachedTextfield", "(Ljava/lang/String;I)V",
- (void*) nativeUpdateCachedTextfield },
- { "nativeMoveSelection", "(IIZ)V",
- (void*) nativeMoveSelection },
- { "nativeGetSelection", "()Landroid/graphics/Region;",
- (void*) nativeGetSelection },
- { "nativeDumpDisplayTree", "(Ljava/lang/String;)V",
- (void*) nativeDumpDisplayTree }
-};
-
-int register_webview(JNIEnv* env)
-{
- jclass clazz = env->FindClass("android/webkit/WebView");
- LOG_ASSERT(clazz, "Unable to find class android/webkit/WebView");
- gWebViewField = env->GetFieldID(clazz, "mNativeClass", "I");
- LOG_ASSERT(gWebViewField, "Unable to find android/webkit/WebView.mNativeClass");
-
- return jniRegisterNativeMethods(env, "android/webkit/WebView", gJavaWebViewMethods, NELEM(gJavaWebViewMethods));
-}
-
-} // namespace android