Home | History | Annotate | Download | only in nav
      1 /*
      2  * Copyright 2006, The Android Open Source Project
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  *  * Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  *  * Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include "CachedPrefix.h"
     27 #include "CachedNode.h"
     28 #include "CachedRoot.h"
     29 #include "ColumnInfo.h"
     30 #include "Document.h"
     31 #include "EventListener.h"
     32 #include "EventNames.h"
     33 #include "Frame.h"
     34 #include "FrameLoader.h"
     35 #include "FrameLoaderClientAndroid.h"
     36 #include "FrameTree.h"
     37 #include "FrameView.h"
     38 //#include "GraphicsContext.h"
     39 #include "HTMLAreaElement.h"
     40 #include "HTMLImageElement.h"
     41 #include "HTMLInputElement.h"
     42 #include "HTMLMapElement.h"
     43 #include "HTMLNames.h"
     44 #include "HTMLOptionElement.h"
     45 #include "HTMLSelectElement.h"
     46 #include "HTMLTextAreaElement.h"
     47 #include "InlineTextBox.h"
     48 #include "KURL.h"
     49 #include "LayerAndroid.h"
     50 #include "PluginView.h"
     51 #include "RegisteredEventListener.h"
     52 #include "RenderImage.h"
     53 #include "RenderInline.h"
     54 #include "RenderLayerBacking.h"
     55 #include "RenderListBox.h"
     56 #include "RenderSkinCombo.h"
     57 #include "RenderTextControl.h"
     58 #include "RenderView.h"
     59 #include "RenderWidget.h"
     60 #include "SkCanvas.h"
     61 #include "SkPoint.h"
     62 #include "Text.h"
     63 #include "WebCoreFrameBridge.h"
     64 #include "WebCoreViewBridge.h"
     65 #include "Widget.h"
     66 #include <wtf/unicode/Unicode.h>
     67 
     68 #ifdef DUMP_NAV_CACHE_USING_PRINTF
     69     FILE* gNavCacheLogFile = NULL;
     70     android::Mutex gWriteLogMutex;
     71 #endif
     72 
     73 #include "CacheBuilder.h"
     74 
     75 #define MINIMUM_FOCUSABLE_WIDTH 3
     76 #define MINIMUM_FOCUSABLE_HEIGHT 3
     77 #define MAXIMUM_FOCUS_RING_COUNT 32
     78 
     79 namespace android {
     80 
     81 CacheBuilder* CacheBuilder::Builder(Frame* frame) {
     82     return &((FrameLoaderClientAndroid*) frame->loader()->client())->getCacheBuilder();
     83 }
     84 
     85 Frame* CacheBuilder::FrameAnd(CacheBuilder* cacheBuilder) {
     86     FrameLoaderClientAndroid* loader = (FrameLoaderClientAndroid*)
     87         ((char*) cacheBuilder - OFFSETOF(FrameLoaderClientAndroid, m_cacheBuilder));
     88     return loader->getFrame();
     89 }
     90 
     91 Frame* CacheBuilder::FrameAnd(const CacheBuilder* cacheBuilder) {
     92     FrameLoaderClientAndroid* loader = (FrameLoaderClientAndroid*)
     93         ((char*) cacheBuilder - OFFSETOF(FrameLoaderClientAndroid, m_cacheBuilder));
     94     return loader->getFrame();
     95 }
     96 
     97 CacheBuilder::LayerTracker::~LayerTracker() {
     98     // Check for a stacking context to prevent a crash in layers without a
     99     // parent.
    100     if (mRenderLayer && mRenderLayer->stackingContext())
    101         // Restore the scroll position of the layer.  Does not affect layers
    102         // without overflow scroll as the layer will not be scrolled.
    103         mRenderLayer->scrollToOffset(mScroll.x(), mScroll.y());
    104 }
    105 
    106 #if DUMP_NAV_CACHE
    107 
    108 static bool hasEventListener(Node* node, const AtomicString& eventType) {
    109     if (!node->isElementNode())
    110         return false;
    111     Element* element = static_cast<Element*>(node);
    112     EventListener* listener = element->getAttributeEventListener(eventType);
    113     return 0 != listener;
    114 }
    115 
    116 #define DEBUG_BUFFER_SIZE 256
    117 #define DEBUG_WRAP_SIZE 150
    118 #define DEBUG_WRAP_MAX 170
    119 
    120 Frame* CacheBuilder::Debug::frameAnd() const {
    121     CacheBuilder* nav = (CacheBuilder*) ((char*) this - OFFSETOF(CacheBuilder, mDebug));
    122     return CacheBuilder::FrameAnd(nav);
    123 }
    124 
    125 void CacheBuilder::Debug::attr(const AtomicString& name, const AtomicString& value) {
    126     if (name.isNull() || name.isEmpty() || value.isNull() || value.isEmpty())
    127         return;
    128     uChar(name.characters(), name.length(), false);
    129     print("=");
    130     wideString(value.characters(), value.length(), false);
    131     print(" ");
    132 }
    133 
    134 void CacheBuilder::Debug::comma(const char* str) {
    135     print(str);
    136     print(", ");
    137 }
    138 
    139 void CacheBuilder::Debug::flush() {
    140     int len;
    141     do {
    142         int limit = mIndex;
    143         if (limit < DEBUG_WRAP_SIZE)
    144             return;
    145         if (limit < DEBUG_WRAP_MAX)
    146             len = limit;
    147         else {
    148             limit = DEBUG_WRAP_MAX;
    149             len = DEBUG_WRAP_SIZE;
    150             while (len < limit) {
    151                 char test = mBuffer[len];
    152                 if (test < '/' || (test > '9' && test < 'A') || (test > 'Z' && test  < 'a') || test > 'z')
    153                     break;
    154                 len++;
    155             }
    156             while (len > 0 && mBuffer[len - 1] == '\\')
    157                 len--;
    158             while (mBuffer[len] == '"')
    159                 len++;
    160         }
    161         const char* prefix = mPrefix;
    162         if (prefix[0] == '\"') {
    163             // see if we're inside a quote
    164             int quoteCount = 0;
    165             for (int index = 0; index < len; index++) {
    166                 if (mBuffer[index] == '\\') {
    167                     index++;
    168                     continue;
    169                 }
    170                 if (mBuffer[index] == '\n') {
    171                     quoteCount = 0;
    172                     continue;
    173                 }
    174                 if (mBuffer[index] == '"')
    175                     quoteCount++;
    176             }
    177             if ((quoteCount & 1) == 0)
    178                 prefix = "\n";
    179         }
    180         DUMP_NAV_LOGD("%.*s", len, mBuffer);
    181         int copy = mIndex - len;
    182         strcpy(mBuffer, prefix);
    183         memcpy(&mBuffer[strlen(prefix)], &mBuffer[len], copy);
    184         mIndex = strlen(prefix) + copy;
    185     } while (true);
    186 }
    187 
    188 void CacheBuilder::Debug::frameName(char*& namePtr, const char* max) const {
    189    if (namePtr >= max)
    190         return;
    191    Frame* frame = frameAnd();
    192    Frame* parent = frame->tree()->parent();
    193    if (parent)
    194         Builder(parent)->mDebug.frameName(namePtr, max);
    195     const AtomicString& name = frame->tree()->name();
    196     if (name.length() == 0)
    197         return;
    198     unsigned index = 0;
    199     if (name.startsWith(AtomicString("opener")))
    200         index = 6;
    201     for (; index < name.length(); index++) {
    202         char ch = name[index];
    203         if (ch <= ' ')
    204             ch = '_';
    205         if (WTF::isASCIIAlphanumeric(ch) || ch == '_')
    206             *namePtr++  = ch;
    207     }
    208 }
    209 
    210 void CacheBuilder::Debug::frames() {
    211     Frame* frame = frameAnd();
    212     Document* doc = frame->document();
    213     if (doc == NULL)
    214         return;
    215     bool top = frame->tree()->parent() == NULL;
    216     if (top) {
    217 #ifdef DUMP_NAV_CACHE_USING_PRINTF
    218         gWriteLogMutex.lock();
    219         ASSERT(gNavCacheLogFile == NULL);
    220         gNavCacheLogFile = fopen(NAV_CACHE_LOG_FILE, "a");
    221 #endif
    222         groups();
    223     }
    224     Frame* child = frame->tree()->firstChild();
    225     bool hasChild = child != NULL;
    226     if (top && hasChild)
    227         DUMP_NAV_LOGD("\nnamespace TEST_SPACE {\n\n");
    228     while (child) {
    229         Builder(child)->mDebug.frames();
    230         child = child->tree()->nextSibling();
    231     }
    232     if (hasChild) {
    233         child = frame->tree()->firstChild();
    234         while (child) {
    235             char childName[256];
    236             char* childNamePtr = childName;
    237             Builder(child)->mDebug.frameName(childNamePtr, childNamePtr + sizeof(childName) - 1);
    238             *childNamePtr = '\0';
    239             if (child == frame->tree()->firstChild())
    240                 DUMP_NAV_LOGD("DebugTestFrameGroup TEST%s_GROUP[] = {\n", childName);
    241             Frame* next = child->tree()->nextSibling();
    242             Document* doc = child->document();
    243             if (doc != NULL) {
    244                 RenderObject* renderer = doc->renderer();
    245                 if (renderer != NULL) {
    246                     RenderLayer* layer = renderer->enclosingLayer();
    247                     if (layer != NULL) {
    248                         DUMP_NAV_LOGD("{ ");
    249                         DUMP_NAV_LOGD("TEST%s_RECTS, ", childName);
    250                         DUMP_NAV_LOGD("TEST%s_RECT_COUNT, ", childName);
    251                         DUMP_NAV_LOGD("TEST%s_RECTPARTS, ", childName);
    252                         DUMP_NAV_LOGD("TEST%s_BOUNDS,\n", childName);
    253                         DUMP_NAV_LOGD("TEST%s_WIDTH, ", childName);
    254                         DUMP_NAV_LOGD("TEST%s_HEIGHT,\n", childName);
    255                         DUMP_NAV_LOGD("0, 0, 0, 0,\n");
    256                         DUMP_NAV_LOGD("TEST%s_FOCUS, ", childName);
    257                         Frame* grandChild = child->tree()->firstChild();
    258                          if (grandChild) {
    259                             char grandChildName[256];
    260                             char* grandChildNamePtr = grandChildName;
    261                             Builder(grandChild)->mDebug.frameName(grandChildNamePtr,
    262                                 grandChildNamePtr + sizeof(grandChildName) - 1);
    263                             *grandChildNamePtr = '\0';
    264                             DUMP_NAV_LOGD("TEST%s_GROUP, ", grandChildName);
    265                             DUMP_NAV_LOGD("sizeof(TEST%s_GROUP) / sizeof(DebugTestFrameGroup), ", grandChildName);
    266                         } else
    267                             DUMP_NAV_LOGD("NULL, 0, ");
    268                         DUMP_NAV_LOGD("\"%s\"\n", childName);
    269                         DUMP_NAV_LOGD("}%c\n", next ? ',' : ' ');
    270                     }
    271                 }
    272             }
    273             child = next;
    274         }
    275         DUMP_NAV_LOGD("};\n");
    276     }
    277     if (top) {
    278         if (hasChild)
    279             DUMP_NAV_LOGD("\n}  // end of namespace\n\n");
    280         char name[256];
    281         char* frameNamePtr = name;
    282         frameName(frameNamePtr, frameNamePtr + sizeof(name) - 1);
    283         *frameNamePtr = '\0';
    284         DUMP_NAV_LOGD("DebugTestFrameGroup TEST%s_GROUP = {\n", name);
    285         DUMP_NAV_LOGD("TEST%s_RECTS, ", name);
    286         DUMP_NAV_LOGD("TEST%s_RECT_COUNT, ", name);
    287         DUMP_NAV_LOGD("TEST%s_RECTPARTS, ", name);
    288         DUMP_NAV_LOGD("TEST%s_BOUNDS,\n", name);
    289         DUMP_NAV_LOGD("TEST%s_WIDTH, ", name);
    290         DUMP_NAV_LOGD("TEST%s_HEIGHT,\n", name);
    291         DUMP_NAV_LOGD("TEST%s_MAX_H, ", name);
    292         DUMP_NAV_LOGD("TEST%s_MIN_H, ", name);
    293         DUMP_NAV_LOGD("TEST%s_MAX_V, ", name);
    294         DUMP_NAV_LOGD("TEST%s_MIN_V,\n", name);
    295         DUMP_NAV_LOGD("TEST%s_FOCUS, ", name);
    296         if (hasChild) {
    297             child = frame->tree()->firstChild();
    298             char childName[256];
    299             char* childNamePtr = childName;
    300             Builder(child)->mDebug.frameName(childNamePtr, childNamePtr + sizeof(childName) - 1);
    301             *childNamePtr = '\0';
    302             DUMP_NAV_LOGD("TEST_SPACE::TEST%s_GROUP, ", childName);
    303             DUMP_NAV_LOGD("sizeof(TEST_SPACE::TEST%s_GROUP) / sizeof(DebugTestFrameGroup), \n" ,childName);
    304         } else
    305             DUMP_NAV_LOGD("NULL, 0, ");
    306         DUMP_NAV_LOGD("\"%s\"\n", name);
    307         DUMP_NAV_LOGD("};\n");
    308 #ifdef DUMP_NAV_CACHE_USING_PRINTF
    309         if (gNavCacheLogFile)
    310             fclose(gNavCacheLogFile);
    311         gNavCacheLogFile = NULL;
    312         gWriteLogMutex.unlock();
    313 #endif
    314     }
    315 }
    316 
    317 void CacheBuilder::Debug::init(char* buffer, size_t size) {
    318     mBuffer = buffer;
    319     mBufferSize = size;
    320     mIndex = 0;
    321     mPrefix = "";
    322 }
    323 
    324 void CacheBuilder::Debug::groups() {
    325     Frame* frame = frameAnd();
    326     Frame* child = frame->tree()->firstChild();
    327     bool hasChild = child != NULL;
    328     if (frame->tree()->parent() == NULL && hasChild)
    329         DUMP_NAV_LOGD("namespace TEST_SPACE {\n\n");
    330     while (child) {
    331         Builder(child)->mDebug.groups();
    332         child = child->tree()->nextSibling();
    333     }
    334     if (frame->tree()->parent() == NULL && hasChild)
    335         DUMP_NAV_LOGD("\n} // end of namespace\n\n");
    336     Document* doc = frame->document();
    337     char name[256];
    338     char* frameNamePtr = name;
    339     frameName(frameNamePtr, frameNamePtr + sizeof(name) - 1);
    340     *frameNamePtr = '\0';
    341     if (doc == NULL) {
    342         DUMP_NAV_LOGD("// %s has no document\n", name);
    343         return;
    344     }
    345     RenderObject* renderer = doc->renderer();
    346     if (renderer == NULL) {
    347         DUMP_NAV_LOGD("// %s has no renderer\n", name);
    348         return;
    349     }
    350     RenderLayer* layer = renderer->enclosingLayer();
    351     if (layer == NULL) {
    352         DUMP_NAV_LOGD("// %s has no enclosingLayer\n", name);
    353         return;
    354     }
    355     Node* node = doc;
    356     Node* focus = doc->focusedNode();
    357     bool atLeastOne = false;
    358     do {
    359         if ((atLeastOne |= isFocusable(node)) != false)
    360             break;
    361     } while ((node = node->traverseNextNode()) != NULL);
    362     int focusIndex = -1;
    363     if (atLeastOne == false) {
    364         DUMP_NAV_LOGD("static DebugTestNode TEST%s_RECTS[] = {\n"
    365             "{{0, 0, 0, 0}, \"\", 0, -1, \"\", {0, 0, 0, 0}, false, 0}\n"
    366             "};\n\n", name);
    367         DUMP_NAV_LOGD("static int TEST%s_RECT_COUNT = 1;"
    368             " // no focusable nodes\n", name);
    369         DUMP_NAV_LOGD("#define TEST%s_RECTPARTS NULL\n", name);
    370     } else {
    371         node = doc;
    372         int count = 1;
    373         DUMP_NAV_LOGD("static DebugTestNode TEST%s_RECTS[] = {\n", name);
    374         do {
    375             String properties;
    376             if (hasEventListener(node, eventNames().clickEvent))
    377                 properties.append("ONCLICK | ");
    378             if (hasEventListener(node, eventNames().mousedownEvent))
    379                 properties.append("MOUSEDOWN | ");
    380             if (hasEventListener(node, eventNames().mouseupEvent))
    381                 properties.append("MOUSEUP | ");
    382             if (hasEventListener(node, eventNames().mouseoverEvent))
    383                 properties.append("MOUSEOVER | ");
    384             if (hasEventListener(node, eventNames().mouseoutEvent))
    385                 properties.append("MOUSEOUT | ");
    386             if (hasEventListener(node, eventNames().keydownEvent))
    387                 properties.append("KEYDOWN | ");
    388             if (hasEventListener(node, eventNames().keyupEvent))
    389                 properties.append("KEYUP | ");
    390             if (CacheBuilder::HasFrame(node))
    391                 properties.append("FRAME | ");
    392             if (focus == node) {
    393                 properties.append("FOCUS | ");
    394                 focusIndex = count;
    395             }
    396             if (node->isKeyboardFocusable(NULL))
    397                 properties.append("KEYBOARD_FOCUSABLE | ");
    398             if (node->isMouseFocusable())
    399                 properties.append("MOUSE_FOCUSABLE | ");
    400             if (node->isFocusable())
    401                 properties.append("SIMPLE_FOCUSABLE | ");
    402             if (properties.isEmpty())
    403                 properties.append("0");
    404             else
    405                 properties.truncate(properties.length() - 3);
    406             IntRect rect = node->getRect();
    407             if (node->hasTagName(HTMLNames::areaTag))
    408                 rect = getAreaRect(static_cast<HTMLAreaElement*>(node));
    409             char buffer[DEBUG_BUFFER_SIZE];
    410             memset(buffer, 0, sizeof(buffer));
    411             mBuffer = buffer;
    412             mBufferSize = sizeof(buffer);
    413             mPrefix = "\"\n\"";
    414             mIndex = snprintf(buffer, sizeof(buffer), "{{%d, %d, %d, %d}, ", rect.x(), rect.y(),
    415                 rect.width(), rect.height());
    416             localName(node);
    417             uChar(properties.characters(), properties.length(), false);
    418             print(", ");
    419             int parentIndex = ParentIndex(node, count, node->parentNode());
    420             char scratch[256];
    421             snprintf(scratch, sizeof(scratch), "%d", parentIndex);
    422             comma(scratch);
    423             Element* element = static_cast<Element*>(node);
    424             if (node->isElementNode() && element->hasID())
    425                 wideString(element->getIdAttribute());
    426             else if (node->isTextNode()) {
    427  #if 01 // set to one to abbreviate text that can be omitted from the address detection code
    428                if (rect.isEmpty() && node->textContent().length() > 100) {
    429                     wideString(node->textContent().characters(), 100, false);
    430                     snprintf(scratch, sizeof(scratch), "/* + %d bytes */",
    431                         node->textContent().length() - 100);
    432                     print(scratch);
    433                 } else
    434  #endif
    435                    wideString(node->textContent().characters(), node->textContent().length(), true);
    436             } else if (node->hasTagName(HTMLNames::aTag) ||
    437                 node->hasTagName(HTMLNames::areaTag))
    438             {
    439                 HTMLAnchorElement* anchor = static_cast<HTMLAnchorElement*>(node);
    440                 wideString(anchor->href());
    441             } else if (node->hasTagName(HTMLNames::imgTag)) {
    442                 HTMLImageElement* image = static_cast<HTMLImageElement*>(node);
    443                 wideString(image->src());
    444             } else
    445                 print("\"\"");
    446             RenderObject* renderer = node->renderer();
    447             int tabindex = node->isElementNode() ? node->tabIndex() : 0;
    448             RenderLayer* layer = 0;
    449             if (renderer) {
    450                 const IntRect& absB = renderer->absoluteBoundingBoxRect();
    451                 bool hasLayer = renderer->hasLayer();
    452                 layer = hasLayer ? toRenderBoxModelObject(renderer)->layer() : 0;
    453                 snprintf(scratch, sizeof(scratch), ", {%d, %d, %d, %d}, %s"
    454                     ", %d, %s, %s},",
    455                     absB.x(), absB.y(), absB.width(), absB.height(),
    456                     renderer->hasOverflowClip() ? "true" : "false", tabindex,
    457                     hasLayer ? "true" : "false",
    458                     hasLayer && layer->isComposited() ? "true" : "false");
    459                 // TODO: add renderer->style()->visibility()
    460                 print(scratch);
    461             } else
    462                 print(", {0, 0, 0, 0}, false, 0},");
    463 
    464             flush();
    465             snprintf(scratch, sizeof(scratch), "// %d: ", count);
    466             mPrefix = "\n// ";
    467             print(scratch);
    468             //print(renderer ? renderer->information().ascii() : "NO_RENDER_INFO");
    469             if (node->isElementNode()) {
    470                 Element* element = static_cast<Element*>(node);
    471                 NamedNodeMap* attrs = element->attributes();
    472                 unsigned length = attrs->length();
    473                 if (length > 0) {
    474                     newLine();
    475                     print("// attr: ");
    476                     for (unsigned i = 0; i < length; i++) {
    477                         Attribute* a = attrs->attributeItem(i);
    478                         attr(a->localName(), a->value());
    479                     }
    480                 }
    481             }
    482             if (renderer) {
    483                 RenderStyle* style = renderer->style();
    484                 snprintf(scratch, sizeof(scratch), "// renderStyle:"
    485                     " visibility=%s hasBackGround=%d"
    486                     " tapHighlightColor().alpha()=0x%02x"
    487                     " isTransparent()=%s",
    488                     style->visibility() == HIDDEN ? "HIDDEN" : "VISIBLE",
    489                     renderer->hasBackground(), style->tapHighlightColor().alpha(),
    490                     renderer->isTransparent() ? "true" : "false");
    491                 newLine();
    492                 print(scratch);
    493                 RenderBlock* renderBlock = static_cast<RenderBlock*>(renderer);
    494                 if (renderer->isRenderBlock() && renderBlock->hasColumns()) {
    495                     const RenderBox* box = static_cast<RenderBox*>(renderer);
    496                     const IntRect& oRect = box->visibleOverflowRect();
    497                     snprintf(scratch, sizeof(scratch), "// renderBlock:"
    498                         " columnCount=%d columnGap=%d direction=%d"
    499                         " hasOverflowClip=%d overflow=(%d,%d,w=%d,h=%d)",
    500                         renderBlock->columnInfo()->columnCount(), renderBlock->columnGap(),
    501                         renderBlock->style()->direction(), renderer->hasOverflowClip(),
    502                         oRect.x(), oRect.y(), oRect.width(), oRect.height());
    503                     newLine();
    504                     print(scratch);
    505                 }
    506             }
    507  #if USE(ACCELERATED_COMPOSITING)
    508             if (renderer && renderer->hasLayer()) {
    509                 RenderLayer* layer = toRenderBoxModelObject(renderer)->layer();
    510                 RenderLayerBacking* back = layer->backing();
    511                 GraphicsLayer* grLayer = back ? back->graphicsLayer() : 0;
    512                 LayerAndroid* aLayer = grLayer ? grLayer->platformLayer() : 0;
    513                 const SkPicture* pict = aLayer ? aLayer->picture() : 0;
    514                 const IntRect& r = renderer->absoluteBoundingBoxRect();
    515                 snprintf(scratch, sizeof(scratch), "// layer:%p back:%p"
    516                     " gLayer:%p aLayer:%p pict:%p r:(%d,%d,w=%d,h=%d)",
    517                     layer, back, grLayer, aLayer, pict, r.x(), r.y(),
    518                     r.width(), r.height());
    519                 newLine();
    520                 print(scratch);
    521             }
    522  #endif
    523             count++;
    524             newLine();
    525         } while ((node = node->traverseNextNode()) != NULL);
    526         DUMP_NAV_LOGD("}; // focusables = %d\n", count - 1);
    527         DUMP_NAV_LOGD("\n");
    528         DUMP_NAV_LOGD("static int TEST%s_RECT_COUNT = %d;\n\n", name, count - 1);
    529         // look for rects with multiple parts
    530         node = doc;
    531         count = 1;
    532         bool hasRectParts = false;
    533         int globalOffsetX, globalOffsetY;
    534         GetGlobalOffset(frame, &globalOffsetX, &globalOffsetY);
    535         do {
    536             IntRect rect;
    537             bool _isFocusable = isFocusable(node) || (node->isTextNode()
    538               && node->getRect().isEmpty() == false
    539                 );
    540             int nodeIndex = count++;
    541             if (_isFocusable == false)
    542                 continue;
    543             RenderObject* renderer = node->renderer();
    544             if (renderer == NULL)
    545                 continue;
    546             WTF::Vector<IntRect> rects;
    547             IntRect clipBounds = IntRect(0, 0, INT_MAX, INT_MAX);
    548             IntRect focusBounds = IntRect(0, 0, INT_MAX, INT_MAX);
    549             IntRect* rectPtr = &focusBounds;
    550             int imageCount = 0;
    551             if (node->isTextNode()) {
    552                 Text* textNode = (Text*) node;
    553                 if (CacheBuilder::ConstructTextRects(textNode, 0, textNode,
    554                         INT_MAX, globalOffsetX, globalOffsetY, rectPtr,
    555                         clipBounds, &rects) == false)
    556                     continue;
    557             } else {
    558                 IntRect nodeBounds = node->getRect();
    559                 if (CacheBuilder::ConstructPartRects(node, nodeBounds, rectPtr,
    560                         globalOffsetX, globalOffsetY, &rects, &imageCount) == false)
    561                     continue;
    562             }
    563             unsigned arraySize = rects.size();
    564             if (arraySize > 1 || (arraySize == 1 && (rectPtr->width() != rect.width())) ||
    565                     rectPtr->height() != rect.height()) {
    566                 if (hasRectParts == false) {
    567                     DUMP_NAV_LOGD("static DebugTestRectPart TEST%s_RECTPARTS[] = {\n", name);
    568                     hasRectParts = true;
    569                 }
    570                 if (node->isTextNode() == false) {
    571                     unsigned rectIndex = 0;
    572                     for (; rectIndex < arraySize; rectIndex++) {
    573                         rectPtr = &rects.at(rectIndex);
    574                         DUMP_NAV_LOGD("{ %d, %d, %d, %d, %d }, // %d\n", nodeIndex,
    575                             rectPtr->x(), rectPtr->y(), rectPtr->width(),
    576                             rectPtr->height(), rectIndex + 1);
    577                     }
    578                 } else {
    579                     RenderText* renderText = (RenderText*) node->renderer();
    580                     InlineTextBox* textBox = renderText->firstTextBox();
    581                     unsigned rectIndex = 0;
    582                     while (textBox) {
    583                         FloatPoint pt = renderText->localToAbsolute();
    584                         IntRect rect = textBox->selectionRect((int) pt.x(), (int) pt.y(), 0, INT_MAX);
    585                         mIndex = 0;
    586                         mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex, "{ %d, %d, %d, %d, %d",
    587                             nodeIndex, rect.x(), rect.y(), rect.width(), rect.height());
    588                         mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex, ", %d, %d, %d",
    589                             textBox->len(), 0 /*textBox->selectionHeight()*/,
    590                             0 /*textBox->selectionTop()*/);
    591                         mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex, ", %d, %d, %d",
    592                             0 /*textBox->spaceAdd()*/, textBox->start(), 0 /*textBox->textPos()*/);
    593                         mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex, ", %d, %d, %d, %d",
    594                             textBox->x(), textBox->y(), textBox->logicalWidth(), textBox->logicalHeight());
    595                         int baseline = textBox->renderer()->style(textBox->isFirstLineStyle())->font().ascent();
    596                         mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex, ", %d, %d }, // %d ",
    597                             baseline, imageCount, ++rectIndex);
    598                         wideString(node->textContent().characters() + textBox->start(), textBox->len(), true);
    599                         DUMP_NAV_LOGD("%.*s\n", mIndex, mBuffer);
    600                         textBox = textBox->nextTextBox();
    601                     }
    602                 }
    603             }
    604         } while ((node = node->traverseNextNode()) != NULL);
    605         if (hasRectParts)
    606             DUMP_NAV_LOGD("{0}\n};\n\n");
    607         else
    608             DUMP_NAV_LOGD("static DebugTestRectPart* TEST%s_RECTPARTS = NULL;\n", name);
    609     }
    610     int contentsWidth = layer->width();
    611     int contentsHeight = layer->height();
    612     DUMP_NAV_LOGD("static int TEST%s_FOCUS = %d;\n", name, focusIndex);
    613     DUMP_NAV_LOGD("static int TEST%s_WIDTH = %d;\n", name, contentsWidth);
    614     DUMP_NAV_LOGD("static int TEST%s_HEIGHT = %d;\n\n", name, contentsHeight);
    615 }
    616 
    617 bool CacheBuilder::Debug::isFocusable(Node* node) {
    618     if (node->hasTagName(HTMLNames::areaTag))
    619         return true;
    620     if (node->renderer() == false)
    621         return false;
    622     if (node->isKeyboardFocusable(NULL))
    623         return true;
    624     if (node->isMouseFocusable())
    625         return true;
    626     if (node->isFocusable())
    627         return true;
    628     if (CacheBuilder::AnyIsClick(node))
    629         return false;
    630     if (CacheBuilder::HasTriggerEvent(node))
    631         return true;
    632     return false;
    633 }
    634 
    635 void CacheBuilder::Debug::localName(Node* node) {
    636     const AtomicString& local = node->localName();
    637     if (node->isTextNode())
    638         print("\"#text\"");
    639     else
    640         wideString(local.characters(), local.length(), false);
    641     print(", ");
    642 }
    643 
    644 void CacheBuilder::Debug::newLine(int indent) {
    645     if (mPrefix[0] != '\n')
    646         print(&mPrefix[0], 1);
    647     flush();
    648     int lastnewline = mIndex - 1;
    649     while (lastnewline >= 0 && mBuffer[lastnewline] != '\n')
    650         lastnewline--;
    651     lastnewline++;
    652     char* buffer = mBuffer;
    653     if (lastnewline > 0) {
    654         DUMP_NAV_LOGD("%.*s", lastnewline, buffer);
    655         mIndex -= lastnewline;
    656         buffer += lastnewline;
    657     }
    658     size_t prefixLen = strlen(mPrefix);
    659     int minPrefix = prefixLen - 1;
    660     while (minPrefix >= 0 && mPrefix[minPrefix] != '\n')
    661         minPrefix--;
    662     minPrefix = prefixLen - minPrefix - 1;
    663     if (mIndex > minPrefix)
    664         DUMP_NAV_LOGD("%.*s\n", mIndex, buffer);
    665     mIndex = 0;
    666     setIndent(indent);
    667 }
    668 
    669 int CacheBuilder::Debug::ParentIndex(Node* node, int count, Node* parent)
    670 {
    671     if (parent == NULL)
    672         return -1;
    673     ASSERT(node != parent);
    674     int result = count;
    675     Node* previous = node;
    676     do {
    677         result--;
    678         previous = previous->traversePreviousNode();
    679     } while (previous && previous != parent);
    680     if (previous != NULL)
    681         return result;
    682     result = count;
    683     do {
    684         result++;
    685     } while ((node = node->traverseNextNode()) != NULL && node != parent);
    686     if (node != NULL)
    687         return result;
    688     ASSERT(0);
    689     return -1;
    690 }
    691 
    692 void CacheBuilder::Debug::print(const char* name) {
    693     print(name, strlen(name));
    694 }
    695 
    696 void CacheBuilder::Debug::print(const char* name, unsigned len) {
    697     do {
    698         if (mIndex + len >= DEBUG_BUFFER_SIZE)
    699             flush();
    700         int copyLen = mIndex + len < DEBUG_BUFFER_SIZE ?
    701              len : DEBUG_BUFFER_SIZE - mIndex;
    702         memcpy(&mBuffer[mIndex], name, copyLen);
    703         mIndex += copyLen;
    704         name += copyLen;
    705         len -= copyLen;
    706     } while (len > 0);
    707     mBuffer[mIndex] = '\0';
    708 }
    709 
    710 void CacheBuilder::Debug::setIndent(int indent)
    711 {
    712     char scratch[64];
    713     snprintf(scratch, sizeof(scratch), "%.*s", indent,
    714         "                                                                    ");
    715     print(scratch);
    716 }
    717 
    718 void CacheBuilder::Debug::uChar(const UChar* name, unsigned len, bool hex) {
    719     const UChar* end = name + len;
    720     bool wroteHex = false;
    721     while (name < end) {
    722         unsigned ch = *name++;
    723         if (ch == '\t' || ch == '\n' || ch == '\r' || ch == 0xa0)
    724             ch = ' ';
    725         if (ch < ' ' || ch == 0x7f) {
    726             if (hex) {
    727                 mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex, "\\x%02x", ch);
    728                 wroteHex = true;
    729             } else
    730                 mBuffer[mIndex++] = '?';
    731         } else if (ch >= 0x80) {
    732             if (hex) {
    733                 if (ch < 0x800)
    734                     mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex,
    735                         "\\x%02x\\x%02x", ch >> 6 | 0xc0, (ch & 0x3f) | 0x80);
    736                 else
    737                     mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex,
    738                         "\\x%02x\\x%02x\\x%02x", ch >> 12 | 0xe0,
    739                         (ch >> 6 & 0x3f) | 0x80, (ch & 0x3f) | 0x80);
    740                 wroteHex = true;
    741             } else
    742                 mBuffer[mIndex++] = '?';
    743         } else {
    744             if (wroteHex && WTF::isASCIIHexDigit((UChar) ch))
    745                 mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex,
    746                     "\" \"");
    747             else if (ch == '"' || ch == '\\')
    748                 mBuffer[mIndex++] = '\\';
    749             mBuffer[mIndex++] = ch;
    750             wroteHex = false;
    751         }
    752         if (mIndex + 1 >= DEBUG_BUFFER_SIZE)
    753             flush();
    754     }
    755     flush();
    756 }
    757 
    758 void CacheBuilder::Debug::validateFrame() {
    759     Frame* frame = frameAnd();
    760     Page* page = frame->page();
    761     ASSERT(page);
    762     ASSERT((int) page > 0x10000);
    763     Frame* child = frame->tree()->firstChild();
    764     while (child) {
    765         Builder(child)->mDebug.validateFrame();
    766         child = child->tree()->nextSibling();
    767     }
    768 }
    769 
    770 void CacheBuilder::Debug::wideString(const UChar* chars, int length, bool hex) {
    771     if (length == 0)
    772         print("\"\"");
    773     else {
    774         print("\"");
    775         uChar(chars, length, hex);
    776         print("\"");
    777     }
    778 }
    779 
    780 void CacheBuilder::Debug::wideString(const String& str) {
    781     wideString(str.characters(), str.length(), false);
    782 }
    783 
    784 #endif // DUMP_NAV_CACHE
    785 
    786 CacheBuilder::CacheBuilder()
    787 {
    788     mAllowableTypes = ALL_CACHEDNODE_BITS;
    789 #ifdef DUMP_NAV_CACHE_USING_PRINTF
    790     gNavCacheLogFile = NULL;
    791 #endif
    792 }
    793 
    794 void CacheBuilder::adjustForColumns(const ClipColumnTracker& track,
    795     CachedNode* node, IntRect* bounds, RenderBlock* renderer)
    796 {
    797     if (!renderer->hasColumns())
    798         return;
    799     int x = 0;
    800     int y = 0;
    801     int tx = track.mBounds.x();
    802     int ty = track.mBounds.y();
    803     int columnGap = track.mColumnGap;
    804     size_t limit = track.mColumnInfo->columnCount();
    805     for (size_t index = 0; index < limit; index++) {
    806         IntRect column = renderer->columnRectAt(track.mColumnInfo, index);
    807         column.move(tx, ty);
    808         IntRect test = *bounds;
    809         test.move(x, y);
    810         if (column.contains(test)) {
    811             if ((x | y) == 0)
    812                 return;
    813             *bounds = test;
    814             node->move(x, y);
    815             return;
    816         }
    817         int xOffset = column.width() + columnGap;
    818         x += track.mDirection == LTR ? xOffset : -xOffset;
    819         y -= column.height();
    820     }
    821 }
    822 
    823 // Checks if a node has one of event listener types.
    824 bool CacheBuilder::NodeHasEventListeners(Node* node, AtomicString* eventTypes, int length) {
    825     for (int i = 0; i < length; ++i) {
    826         if (!node->getEventListeners(eventTypes[i]).isEmpty())
    827             return true;
    828     }
    829     return false;
    830 }
    831 
    832 bool CacheBuilder::AnyChildIsClick(Node* node)
    833 {
    834     AtomicString eventTypes[5] = {
    835         eventNames().clickEvent,
    836         eventNames().mousedownEvent,
    837         eventNames().mouseupEvent,
    838         eventNames().keydownEvent,
    839         eventNames().keyupEvent
    840     };
    841 
    842     Node* child = node->firstChild();
    843     while (child != NULL) {
    844         if (child->isFocusable() ||
    845             NodeHasEventListeners(child, eventTypes, 5))
    846                 return true;
    847         if (AnyChildIsClick(child))
    848             return true;
    849         child = child->nextSibling();
    850     }
    851     return false;
    852 }
    853 
    854 bool CacheBuilder::AnyIsClick(Node* node)
    855 {
    856     if (node->hasTagName(HTMLNames::bodyTag))
    857         return AnyChildIsClick(node);
    858 
    859     AtomicString eventTypeSetOne[4] = {
    860         eventNames().mouseoverEvent,
    861         eventNames().mouseoutEvent,
    862         eventNames().keydownEvent,
    863         eventNames().keyupEvent
    864     };
    865 
    866     if (!NodeHasEventListeners(node, eventTypeSetOne, 4))
    867         return false;
    868 
    869     AtomicString eventTypeSetTwo[3] = {
    870         eventNames().clickEvent,
    871         eventNames().mousedownEvent,
    872         eventNames().mouseupEvent
    873     };
    874 
    875     if (NodeHasEventListeners(node, eventTypeSetTwo, 3))
    876         return false;
    877 
    878     return AnyChildIsClick(node);
    879 }
    880 
    881 void CacheBuilder::buildCache(CachedRoot* root)
    882 {
    883     Frame* frame = FrameAnd(this);
    884     mPictureSetDisabled = false;
    885     BuildFrame(frame, frame, root, (CachedFrame*) root);
    886     root->finishInit(); // set up frame parent pointers, child pointers
    887     setData((CachedFrame*) root);
    888 }
    889 
    890 static Node* ParentWithChildren(Node* node)
    891 {
    892     Node* parent = node;
    893     while ((parent = parent->parentNode())) {
    894         if (parent->childNodeCount() > 1)
    895             return parent;
    896     }
    897     return 0;
    898 }
    899 
    900 // FIXME
    901 // Probably this should check for null instead of the caller. If the
    902 // Tracker object is the last thing in the dom, checking for null in the
    903 // caller in some cases fails to set up Tracker state which may be useful
    904 // to the nodes parsed immediately after the tracked noe.
    905 static Node* OneAfter(Node* node)
    906 {
    907     Node* parent = node;
    908     Node* sibling = NULL;
    909     while ((parent = parent->parentNode()) != NULL) {
    910         sibling = parent->nextSibling();
    911         if (sibling != NULL)
    912             break;
    913     }
    914     return sibling;
    915 }
    916 
    917 // return true if this renderer is really a pluinview, and it wants
    918 // key-events (i.e. focus)
    919 static bool checkForPluginViewThatWantsFocus(RenderObject* renderer) {
    920     if (renderer->isWidget()) {
    921         Widget* widget = static_cast<RenderWidget*>(renderer)->widget();
    922         if (widget && (widget->isPluginView() || widget->isPluginViewBase())) {
    923             // check if this plugin really wants key events (TODO)
    924             return true;
    925         }
    926     }
    927     return false;
    928 }
    929 
    930 #if USE(ACCELERATED_COMPOSITING)
    931 static void AddLayer(CachedFrame* frame, size_t index, const IntPoint& location, int id)
    932 {
    933     DBG_NAV_LOGD("frame=%p index=%d loc=(%d,%d) id=%d", frame, index,
    934         location.x(), location.y(), id);
    935     CachedLayer cachedLayer;
    936     cachedLayer.setCachedNodeIndex(index);
    937     cachedLayer.setOffset(location);
    938     cachedLayer.setUniqueId(id);
    939     frame->add(cachedLayer);
    940 }
    941 #endif
    942 
    943 static int FindColorIndex(WTF::Vector<CachedColor>& colorTracker,
    944     const CachedColor& cachedColor)
    945 {
    946     CachedColor* work = colorTracker.begin() - 1;
    947     CachedColor* end = colorTracker.end();
    948     while (++work < end) {
    949         if (*work == cachedColor)
    950             return work - colorTracker.begin();
    951     }
    952     int result = colorTracker.size();
    953     colorTracker.grow(result + 1);
    954     CachedColor& newColor = colorTracker.last();
    955     newColor = cachedColor;
    956     return result;
    957 }
    958 
    959 static void InitColor(CachedColor* color)
    960 {
    961     color->setFillColor(RenderStyle::initialRingFillColor());
    962     color->setInnerWidth(RenderStyle::initialRingInnerWidth());
    963     color->setOuterWidth(RenderStyle::initialRingOuterWidth());
    964     color->setOutset(RenderStyle::initialRingOutset());
    965     color->setPressedInnerColor(RenderStyle::initialRingPressedInnerColor());
    966     color->setPressedOuterColor(RenderStyle::initialRingPressedOuterColor());
    967     color->setRadius(RenderStyle::initialRingRadius());
    968     color->setSelectedInnerColor(RenderStyle::initialRingSelectedInnerColor());
    969     color->setSelectedOuterColor(RenderStyle::initialRingSelectedOuterColor());
    970 }
    971 
    972 // when new focus is found, push it's parent on a stack
    973     // as long as more focii are found with the same (grand) parent, note it
    974     // (which only requires retrieving the last parent on the stack)
    975 // when the parent's last child is found, pop the stack
    976 // different from Tracker in that Tracker only pushes focii with children
    977 
    978 // making this work with focus - child focus - grandchild focus is tricky
    979 // if I keep the generation number, I may be able to more quickly determine that
    980 // a node is a grandchild of the focus's parent
    981 // this additionally requires being able to find the grandchild's parent
    982 
    983 // keep nodes that are focusable
    984 void CacheBuilder::BuildFrame(Frame* root, Frame* frame,
    985     CachedRoot* cachedRoot, CachedFrame* cachedFrame)
    986 {
    987     WTF::Vector<FocusTracker> tracker(1); // sentinel
    988     {
    989         FocusTracker* baseTracker = tracker.data();
    990         bzero(baseTracker, sizeof(FocusTracker));
    991         baseTracker->mCachedNodeIndex = -1;
    992     }
    993     WTF::Vector<LayerTracker> layerTracker(1); // sentinel
    994     bzero(layerTracker.data(), sizeof(LayerTracker));
    995     WTF::Vector<ClipColumnTracker> clipTracker(1); // sentinel
    996     bzero(clipTracker.data(), sizeof(ClipColumnTracker));
    997     WTF::Vector<TabIndexTracker> tabIndexTracker(1); // sentinel
    998     bzero(tabIndexTracker.data(), sizeof(TabIndexTracker));
    999     WTF::Vector<CachedColor> colorTracker(1);
   1000     InitColor(colorTracker.data());
   1001 #if DUMP_NAV_CACHE
   1002     char* frameNamePtr = cachedFrame->mDebug.mFrameName;
   1003     Builder(frame)->mDebug.frameName(frameNamePtr, frameNamePtr +
   1004         sizeof(cachedFrame->mDebug.mFrameName) - 1);
   1005     *frameNamePtr = '\0';
   1006     int nodeIndex = 1;
   1007 #endif
   1008     NodeWalk walk;
   1009     Document* doc = frame->document();
   1010     Node* parent = doc;
   1011     CachedNode cachedParentNode;
   1012     cachedParentNode.init(parent);
   1013 #if DUMP_NAV_CACHE
   1014     cachedParentNode.mDebug.mNodeIndex = nodeIndex;
   1015 #endif
   1016     cachedFrame->add(colorTracker[0]);
   1017     cachedFrame->add(cachedParentNode);
   1018     Node* node = parent;
   1019     int cacheIndex = 1;
   1020     int colorIndex = 0; // assume no special css ring colors
   1021     const void* lastStyleDataPtr = 0;
   1022     int textInputIndex = 0;
   1023     Node* focused = doc->focusedNode();
   1024     if (focused)
   1025         cachedRoot->setFocusBounds(focused->getRect());
   1026     int globalOffsetX, globalOffsetY;
   1027     GetGlobalOffset(frame, &globalOffsetX, &globalOffsetY);
   1028 #if USE(ACCELERATED_COMPOSITING)
   1029     // The frame itself might be composited so we need to track the layer.  Do
   1030     // not track the base frame's layer as the main content is draw as part of
   1031     // BaseLayerAndroid's picture.
   1032     if (frame != root && frame->contentRenderer()
   1033         && frame->contentRenderer()->usesCompositing() && node->lastChild())
   1034         TrackLayer(layerTracker, frame->contentRenderer(), node->lastChild(),
   1035             globalOffsetX, globalOffsetY);
   1036 #endif
   1037     while (walk.mMore || (node = node->traverseNextNode()) != NULL) {
   1038 #if DUMP_NAV_CACHE
   1039         nodeIndex++;
   1040 #endif
   1041         FocusTracker* last = &tracker.last();
   1042         int lastChildIndex = cachedFrame->size() - 1;
   1043         while (node == last->mLastChild) {
   1044             if (CleanUpContainedNodes(cachedRoot, cachedFrame, last, lastChildIndex))
   1045                 cacheIndex--;
   1046             tracker.removeLast();
   1047             lastChildIndex = last->mCachedNodeIndex;
   1048             last = &tracker.last();
   1049         }
   1050         do {
   1051             const ClipColumnTracker* lastClip = &clipTracker.last();
   1052             if (node != lastClip->mLastChild)
   1053                 break;
   1054             clipTracker.removeLast();
   1055         } while (true);
   1056         do {
   1057             const LayerTracker* lastLayer = &layerTracker.last();
   1058             if (node != lastLayer->mLastChild)
   1059                 break;
   1060             layerTracker.removeLast();
   1061         } while (true);
   1062         do {
   1063             const TabIndexTracker* lastTabIndex = &tabIndexTracker.last();
   1064             if (node != lastTabIndex->mLastChild)
   1065                 break;
   1066             tabIndexTracker.removeLast();
   1067         } while (true);
   1068         Frame* child = HasFrame(node);
   1069         CachedNode cachedNode;
   1070         if (child != NULL) {
   1071             if (child->document() == NULL)
   1072                 continue;
   1073             RenderObject* nodeRenderer = node->renderer();
   1074             if (nodeRenderer != NULL && nodeRenderer->style()->visibility() == HIDDEN)
   1075                 continue;
   1076             CachedFrame cachedChild;
   1077             cachedChild.init(cachedRoot, cacheIndex, child);
   1078             int childFrameIndex = cachedFrame->childCount();
   1079             cachedFrame->addFrame(cachedChild);
   1080             cachedNode.init(node);
   1081             cachedNode.setIndex(cacheIndex++);
   1082             cachedNode.setDataIndex(childFrameIndex);
   1083             cachedNode.setType(FRAME_CACHEDNODETYPE);
   1084 #if DUMP_NAV_CACHE
   1085             cachedNode.mDebug.mNodeIndex = nodeIndex;
   1086             cachedNode.mDebug.mParentGroupIndex = Debug::ParentIndex(
   1087                 node, nodeIndex, NULL);
   1088 #endif
   1089             cachedFrame->add(cachedNode);
   1090             CachedFrame* childPtr = cachedFrame->lastChild();
   1091             BuildFrame(root, child, cachedRoot, childPtr);
   1092             continue;
   1093         }
   1094         int tabIndex = node->tabIndex();
   1095         Node* lastChild = node->lastChild();
   1096         if (tabIndex <= 0)
   1097             tabIndex = tabIndexTracker.last().mTabIndex;
   1098         else if (tabIndex > 0 && lastChild) {
   1099             DBG_NAV_LOGD("tabIndex=%d node=%p", tabIndex, node);
   1100             tabIndexTracker.grow(tabIndexTracker.size() + 1);
   1101             TabIndexTracker& indexTracker = tabIndexTracker.last();
   1102             indexTracker.mTabIndex = tabIndex;
   1103             indexTracker.mLastChild = OneAfter(lastChild);
   1104         }
   1105         RenderObject* nodeRenderer = node->renderer();
   1106         bool isTransparent = false;
   1107         bool hasCursorRing = true;
   1108         if (nodeRenderer != NULL) {
   1109             RenderStyle* style = nodeRenderer->style();
   1110             if (style->visibility() == HIDDEN)
   1111                 continue;
   1112             isTransparent = nodeRenderer->hasBackground() == false;
   1113 #ifdef ANDROID_CSS_TAP_HIGHLIGHT_COLOR
   1114             hasCursorRing = style->tapHighlightColor().alpha() > 0;
   1115 #endif
   1116 #if USE(ACCELERATED_COMPOSITING)
   1117             // If this renderer has its own layer and the layer is composited,
   1118             // start tracking it.
   1119             if (lastChild && nodeRenderer->hasLayer() && toRenderBoxModelObject(nodeRenderer)->layer()->backing())
   1120                 TrackLayer(layerTracker, nodeRenderer, lastChild, globalOffsetX, globalOffsetY);
   1121 #endif
   1122         }
   1123         bool more = walk.mMore;
   1124         walk.reset();
   1125      //   GetGlobalBounds(node, &bounds, false);
   1126         bool computeCursorRings = false;
   1127         bool hasClip = false;
   1128         bool hasMouseOver = false;
   1129         bool isUnclipped = false;
   1130         bool isFocus = node == focused;
   1131         bool takesFocus = false;
   1132         int columnGap = 0;
   1133         int imageCount = 0;
   1134         TextDirection direction = LTR;
   1135         String exported;
   1136         CachedNodeType type = NORMAL_CACHEDNODETYPE;
   1137         CachedColor cachedColor;
   1138         CachedInput cachedInput;
   1139         IntRect bounds;
   1140         IntRect absBounds;
   1141         IntRect originalAbsBounds;
   1142         ColumnInfo* columnInfo = NULL;
   1143         if (node->hasTagName(HTMLNames::areaTag)) {
   1144             type = AREA_CACHEDNODETYPE;
   1145             HTMLAreaElement* area = static_cast<HTMLAreaElement*>(node);
   1146             bounds = getAreaRect(area);
   1147             originalAbsBounds = bounds;
   1148             bounds.move(globalOffsetX, globalOffsetY);
   1149             absBounds = bounds;
   1150             isUnclipped = true;  // FIXME: areamaps require more effort to detect
   1151              // assume areamaps are always visible for now
   1152             takesFocus = true;
   1153             goto keepNode;
   1154         }
   1155         if (nodeRenderer == NULL)
   1156             continue;
   1157 
   1158         // some common setup
   1159         absBounds = nodeRenderer->absoluteBoundingBoxRect();
   1160         originalAbsBounds = absBounds;
   1161         absBounds.move(globalOffsetX, globalOffsetY);
   1162         hasClip = nodeRenderer->hasOverflowClip();
   1163 
   1164         if (checkForPluginViewThatWantsFocus(nodeRenderer)) {
   1165             bounds = absBounds;
   1166             isUnclipped = true;
   1167             takesFocus = true;
   1168             type = PLUGIN_CACHEDNODETYPE;
   1169             goto keepNode;
   1170         }
   1171         // Only use the root contentEditable element
   1172         if (node->rendererIsEditable() && !node->parentOrHostNode()->rendererIsEditable()) {
   1173             bounds = absBounds;
   1174             takesFocus = true;
   1175             type = CONTENT_EDITABLE_CACHEDNODETYPE;
   1176             goto keepNode;
   1177         }
   1178         if (nodeRenderer->isRenderBlock()) {
   1179             RenderBlock* renderBlock = (RenderBlock*) nodeRenderer;
   1180             if (renderBlock->hasColumns()) {
   1181                 columnInfo = renderBlock->columnInfo();
   1182                 columnGap = renderBlock->columnGap();
   1183                 direction = renderBlock->style()->direction();
   1184             }
   1185         }
   1186         if ((hasClip != false || columnInfo != NULL) && lastChild) {
   1187             clipTracker.grow(clipTracker.size() + 1);
   1188             ClipColumnTracker& clip = clipTracker.last();
   1189             clip.mBounds = absBounds;
   1190             clip.mLastChild = OneAfter(lastChild);
   1191             clip.mNode = node;
   1192             clip.mColumnInfo = columnInfo;
   1193             clip.mColumnGap = columnGap;
   1194             clip.mHasClip = hasClip;
   1195             clip.mDirection = direction;
   1196             if (columnInfo != NULL) {
   1197                 const IntRect& oRect = ((RenderBox*)nodeRenderer)->visualOverflowRect();
   1198                 clip.mBounds.move(oRect.x(), oRect.y());
   1199             }
   1200         }
   1201         if (node->isTextNode() && mAllowableTypes != NORMAL_CACHEDNODE_BITS) {
   1202             if (last->mSomeParentTakesFocus) // don't look at text inside focusable node
   1203                 continue;
   1204             CachedNodeType checkType;
   1205             if (isFocusableText(&walk, more, node, &checkType,
   1206                     &exported) == false)
   1207                 continue;
   1208         #if DUMP_NAV_CACHE
   1209             {
   1210                 char buffer[DEBUG_BUFFER_SIZE];
   1211                 mDebug.init(buffer, sizeof(buffer));
   1212                 mDebug.print("text link found: ");
   1213                 mDebug.wideString(exported);
   1214                 DUMP_NAV_LOGD("%s\n", buffer);
   1215             }
   1216         #endif
   1217             type = checkType;
   1218             // !!! test ! is the following line correctly needed for frames to work?
   1219             cachedNode.init(node);
   1220             const ClipColumnTracker& clipTrack = clipTracker.last();
   1221             const IntRect& clip = clipTrack.mHasClip ? clipTrack.mBounds :
   1222                 IntRect(0, 0, INT_MAX, INT_MAX);
   1223             if (ConstructTextRects((WebCore::Text*) node, walk.mStart,
   1224                     (WebCore::Text*) walk.mFinalNode, walk.mEnd, globalOffsetX,
   1225                     globalOffsetY, &bounds, clip, &cachedNode.mCursorRing) == false)
   1226                 continue;
   1227             absBounds = bounds;
   1228             cachedNode.setBounds(bounds);
   1229             if (bounds.width() < MINIMUM_FOCUSABLE_WIDTH)
   1230                 continue;
   1231             if (bounds.height() < MINIMUM_FOCUSABLE_HEIGHT)
   1232                 continue;
   1233             computeCursorRings = true;
   1234             isUnclipped = true;  // FIXME: to hide or partially occlude synthesized links, each
   1235                                  // focus ring will also need the offset and length of characters
   1236                                  // used to produce it
   1237             goto keepTextNode;
   1238         }
   1239         if (node->hasTagName(WebCore::HTMLNames::inputTag)) {
   1240             HTMLInputElement* input = static_cast<HTMLInputElement*>(node);
   1241             if (input->isTextField()) {
   1242                 if (input->readOnly())
   1243                     continue;
   1244                 type = TEXT_INPUT_CACHEDNODETYPE;
   1245                 cachedInput.init();
   1246                 cachedInput.setAutoComplete(input->autoComplete());
   1247                 cachedInput.setSpellcheck(input->spellcheck());
   1248                 cachedInput.setFormPointer(input->form());
   1249                 cachedInput.setIsTextField(true);
   1250                 exported = input->value().threadsafeCopy();
   1251                 cachedInput.setMaxLength(input->maxLength());
   1252                 cachedInput.setTypeFromElement(input);
   1253     // If this does not need to be threadsafe, we can use crossThreadString().
   1254     // See http://trac.webkit.org/changeset/49160.
   1255                 cachedInput.setName(input->name().string().threadsafeCopy());
   1256     // can't detect if this is drawn on top (example: deviant.com login parts)
   1257                 isUnclipped = isTransparent;
   1258             } else if (input->isInputTypeHidden())
   1259                 continue;
   1260             else if (input->isRadioButton() || input->isCheckbox())
   1261                 isTransparent = false;
   1262         } else if (node->hasTagName(HTMLNames::textareaTag)) {
   1263             HTMLTextAreaElement* area = static_cast<HTMLTextAreaElement*>(node);
   1264             if (area->readOnly())
   1265                 continue;
   1266             cachedInput.init();
   1267             type = TEXT_INPUT_CACHEDNODETYPE;
   1268             cachedInput.setFormPointer(area->form());
   1269             cachedInput.setIsTextArea(true);
   1270             cachedInput.setSpellcheck(area->spellcheck());
   1271             exported = area->value().threadsafeCopy();
   1272         } else if (node->hasTagName(HTMLNames::aTag)) {
   1273             const HTMLAnchorElement* anchorNode =
   1274                 (const HTMLAnchorElement*) node;
   1275             if (!anchorNode->isFocusable() && !HasTriggerEvent(node))
   1276                 continue;
   1277             if (node->disabled())
   1278                 continue;
   1279             hasMouseOver = NodeHasEventListeners(node, &eventNames().mouseoverEvent, 1);
   1280             type = ANCHOR_CACHEDNODETYPE;
   1281             KURL href = anchorNode->href();
   1282             if (!href.isEmpty() && !WebCore::protocolIsJavaScript(href.string()))
   1283                 // Set the exported string for all non-javascript anchors.
   1284                 exported = href.string().threadsafeCopy();
   1285         } else if (node->hasTagName(HTMLNames::selectTag)) {
   1286             type = SELECT_CACHEDNODETYPE;
   1287         }
   1288         if (type == TEXT_INPUT_CACHEDNODETYPE) {
   1289             RenderTextControl* renderText =
   1290                 static_cast<RenderTextControl*>(nodeRenderer);
   1291             if (isFocus)
   1292                 cachedRoot->setSelection(renderText->selectionStart(), renderText->selectionEnd());
   1293             // FIXME: Are we sure there will always be a style and font, and it's correct?
   1294             RenderStyle* style = nodeRenderer->style();
   1295             if (style) {
   1296                 isUnclipped |= !style->hasAppearance();
   1297                 int lineHeight = -1;
   1298                 Length lineHeightLength = style->lineHeight();
   1299                 // If the lineHeight is negative, WebTextView will calculate it
   1300                 // based on the text size, using the Paint.
   1301                 // See RenderStyle.computedLineHeight.
   1302                 if (lineHeightLength.isPositive())
   1303                     lineHeight = style->computedLineHeight();
   1304                 cachedInput.setLineHeight(lineHeight);
   1305                 cachedInput.setTextSize(style->font().size());
   1306                 cachedInput.setIsRtlText(style->direction() == RTL
   1307                         || style->textAlign() == WebCore::RIGHT
   1308                         || style->textAlign() == WebCore::WEBKIT_RIGHT);
   1309             }
   1310             cachedInput.setPaddingLeft(renderText->paddingLeft() + renderText->borderLeft());
   1311             cachedInput.setPaddingTop(renderText->paddingTop() + renderText->borderTop());
   1312             cachedInput.setPaddingRight(renderText->paddingRight() + renderText->borderRight());
   1313             cachedInput.setPaddingBottom(renderText->paddingBottom() + renderText->borderBottom());
   1314         }
   1315         takesFocus = true;
   1316         bounds = absBounds;
   1317         if (type != ANCHOR_CACHEDNODETYPE) {
   1318             bool isFocusable = node->isKeyboardFocusable(NULL) ||
   1319                 node->isMouseFocusable() || node->isFocusable();
   1320             if (isFocusable == false) {
   1321                 if (node->disabled())
   1322                     continue;
   1323                 bool overOrOut = HasOverOrOut(node);
   1324                 bool hasTrigger = HasTriggerEvent(node);
   1325                 if (overOrOut == false && hasTrigger == false)
   1326                     continue;
   1327                 takesFocus = hasTrigger;
   1328             }
   1329         }
   1330         computeCursorRings = true;
   1331     keepNode:
   1332         cachedNode.init(node);
   1333         if (computeCursorRings == false) {
   1334             cachedNode.setBounds(bounds);
   1335             cachedNode.mCursorRing.append(bounds);
   1336         } else if (ConstructPartRects(node, bounds, &cachedNode.mBounds,
   1337                 globalOffsetX, globalOffsetY, &cachedNode.mCursorRing,
   1338                 &imageCount) == false)
   1339             continue;
   1340     keepTextNode:
   1341         if (nodeRenderer) { // area tags' node->renderer() == 0
   1342             RenderStyle* style = nodeRenderer->style();
   1343             const void* styleDataPtr = style->ringData();
   1344             // to save time, see if we're pointing to the same style data as before
   1345             if (lastStyleDataPtr != styleDataPtr) {
   1346                 lastStyleDataPtr = styleDataPtr;
   1347                 cachedColor.setFillColor(style->ringFillColor());
   1348                 cachedColor.setInnerWidth(style->ringInnerWidth());
   1349                 cachedColor.setOuterWidth(style->ringOuterWidth());
   1350                 cachedColor.setOutset(style->ringOutset());
   1351                 cachedColor.setPressedInnerColor(style->ringPressedInnerColor());
   1352                 cachedColor.setPressedOuterColor(style->ringPressedOuterColor());
   1353                 cachedColor.setRadius(style->ringRadius());
   1354                 cachedColor.setSelectedInnerColor(style->ringSelectedInnerColor());
   1355                 cachedColor.setSelectedOuterColor(style->ringSelectedOuterColor());
   1356                 int oldSize = colorTracker.size();
   1357                 colorIndex = FindColorIndex(colorTracker, cachedColor);
   1358                 if (colorIndex == oldSize)
   1359                     cachedFrame->add(cachedColor);
   1360             }
   1361         } else
   1362             colorIndex = 0;
   1363         IntRect clip = hasClip ? bounds : absBounds;
   1364         size_t clipIndex = clipTracker.size();
   1365         if (clipTracker.last().mNode == node)
   1366             clipIndex -= 1;
   1367         while (--clipIndex > 0) {
   1368             const ClipColumnTracker& clipTrack = clipTracker.at(clipIndex);
   1369             if (clipTrack.mHasClip == false) {
   1370                 adjustForColumns(clipTrack, &cachedNode, &absBounds, static_cast<RenderBlock*>(nodeRenderer));
   1371                 continue;
   1372             }
   1373             const IntRect& parentClip = clipTrack.mBounds;
   1374             if (hasClip == false && type == ANCHOR_CACHEDNODETYPE)
   1375                 clip = parentClip;
   1376             else
   1377                 clip.intersect(parentClip);
   1378             hasClip = true;
   1379         }
   1380         bool isInLayer = false;
   1381 #if USE(ACCELERATED_COMPOSITING)
   1382         // If this renderer has a composited parent layer (including itself),
   1383         // add the node to the cached layer.
   1384         // FIXME: does not work for area rects
   1385         RenderLayer* enclosingLayer = nodeRenderer->enclosingLayer();
   1386         if (enclosingLayer && enclosingLayer->enclosingCompositingLayer()) {
   1387             LayerAndroid* layer = layerTracker.last().mLayer;
   1388             if (layer) {
   1389                 const IntRect& layerClip = layerTracker.last().mBounds;
   1390                 if (!layerClip.isEmpty() && !cachedNode.clip(layerClip)) {
   1391                     DBG_NAV_LOGD("skipped on layer clip %d", cacheIndex);
   1392                     continue; // skip this node if outside of the clip
   1393                 }
   1394                 isInLayer = true;
   1395                 isUnclipped = true; // assume that layers do not have occluded nodes
   1396                 hasClip = false;
   1397                 AddLayer(cachedFrame, cachedFrame->size(), layerClip.location(),
   1398                          layer->uniqueId());
   1399             }
   1400         }
   1401 #endif
   1402         if (hasClip) {
   1403             if (clip.isEmpty())
   1404                 continue; // skip this node if clip prevents all drawing
   1405             else if (cachedNode.clip(clip) == false)
   1406                 continue; // skip this node if outside of the clip
   1407         }
   1408         cachedNode.setColorIndex(colorIndex);
   1409         cachedNode.setExport(exported);
   1410         cachedNode.setHasCursorRing(hasCursorRing);
   1411         cachedNode.setHasMouseOver(hasMouseOver);
   1412         cachedNode.setHitBounds(absBounds);
   1413         cachedNode.setIndex(cacheIndex);
   1414         cachedNode.setIsFocus(isFocus);
   1415         cachedNode.setIsInLayer(isInLayer);
   1416         cachedNode.setIsTransparent(isTransparent);
   1417         cachedNode.setIsUnclipped(isUnclipped);
   1418         cachedNode.setOriginalAbsoluteBounds(originalAbsBounds);
   1419         cachedNode.setParentIndex(last->mCachedNodeIndex);
   1420         cachedNode.setParentGroup(ParentWithChildren(node));
   1421         cachedNode.setSingleImage(imageCount == 1);
   1422         cachedNode.setTabIndex(tabIndex);
   1423         cachedNode.setType(type);
   1424         if (type == TEXT_INPUT_CACHEDNODETYPE) {
   1425             cachedFrame->add(cachedInput);
   1426             cachedNode.setDataIndex(textInputIndex);
   1427             textInputIndex++;
   1428         } else
   1429             cachedNode.setDataIndex(-1);
   1430 #if DUMP_NAV_CACHE
   1431         cachedNode.mDebug.mNodeIndex = nodeIndex;
   1432         cachedNode.mDebug.mParentGroupIndex = Debug::ParentIndex(
   1433             node, nodeIndex, (Node*) cachedNode.parentGroup());
   1434 #endif
   1435         cachedFrame->add(cachedNode);
   1436         {
   1437             int lastIndex = cachedFrame->size() - 1;
   1438             if (node == focused) {
   1439                 CachedNode* cachedNodePtr = cachedFrame->getIndex(lastIndex);
   1440                 cachedRoot->setCachedFocus(cachedFrame, cachedNodePtr);
   1441             }
   1442             if (lastChild != NULL) {
   1443                 tracker.grow(tracker.size() + 1);
   1444                 FocusTracker& working = tracker.last();
   1445                 working.mCachedNodeIndex = lastIndex;
   1446                 working.mLastChild = OneAfter(lastChild);
   1447                 last = &tracker.at(tracker.size() - 2);
   1448                 working.mSomeParentTakesFocus = last->mSomeParentTakesFocus | takesFocus;
   1449             }
   1450         }
   1451         cacheIndex++;
   1452     }
   1453     while (tracker.size() > 1) {
   1454         FocusTracker* last = &tracker.last();
   1455         int lastChildIndex = cachedFrame->size() - 1;
   1456         if (CleanUpContainedNodes(cachedRoot, cachedFrame, last, lastChildIndex))
   1457             cacheIndex--;
   1458         tracker.removeLast();
   1459     }
   1460 }
   1461 
   1462 bool CacheBuilder::CleanUpContainedNodes(CachedRoot* cachedRoot,
   1463     CachedFrame* cachedFrame, const FocusTracker* last, int lastChildIndex)
   1464 {
   1465     // if outer is body, disable outer
   1466     // or if there's more than one inner, disable outer
   1467     // or if inner is keyboard focusable, disable outer
   1468     // else disable inner by removing it
   1469     int childCount = lastChildIndex - last->mCachedNodeIndex;
   1470     if (childCount == 0)
   1471         return false;
   1472     CachedNode* lastCached = cachedFrame->getIndex(last->mCachedNodeIndex);
   1473     Node* lastNode = (Node*) lastCached->nodePointer();
   1474     if ((childCount > 1 && lastNode->hasTagName(HTMLNames::selectTag) == false) ||
   1475             lastNode->hasTagName(HTMLNames::bodyTag) ||
   1476             lastNode->hasTagName(HTMLNames::formTag)) {
   1477         lastCached->setBounds(IntRect(0, 0, 0, 0));
   1478         lastCached->mCursorRing.clear();
   1479         return false;
   1480     }
   1481     CachedNode* onlyChildCached = cachedFrame->lastNode();
   1482     Node* onlyChild = (Node*) onlyChildCached->nodePointer();
   1483     bool outerIsMouseMoveOnly =
   1484         lastNode->isKeyboardFocusable(NULL) == false &&
   1485         lastNode->isMouseFocusable() == false &&
   1486         lastNode->isFocusable() == false &&
   1487         HasOverOrOut(lastNode) == true &&
   1488         HasTriggerEvent(lastNode) == false;
   1489     if (onlyChildCached->parent() == lastCached)
   1490         onlyChildCached->setParentIndex(lastCached->parentIndex());
   1491     bool hasFocus = lastCached->isFocus() || onlyChildCached->isFocus();
   1492     if (outerIsMouseMoveOnly || onlyChild->isKeyboardFocusable(NULL)
   1493             || onlyChildCached->isPlugin()) {
   1494         int index = lastCached->index();
   1495         *lastCached = *onlyChildCached;
   1496         lastCached->setIndex(index);
   1497         CachedFrame* frame = cachedFrame->hasFrame(lastCached);
   1498         if (frame)
   1499             frame->setIndexInParent(index);
   1500     }
   1501     cachedFrame->removeLast();
   1502     if (hasFocus)
   1503         cachedRoot->setCachedFocus(cachedFrame, cachedFrame->lastNode());
   1504     return true;
   1505 }
   1506 
   1507 Node* CacheBuilder::currentFocus() const
   1508 {
   1509     Frame* frame = FrameAnd(this);
   1510     Document* doc = frame->document();
   1511     if (doc != NULL) {
   1512         Node* focus = doc->focusedNode();
   1513         if (focus != NULL)
   1514             return focus;
   1515     }
   1516     Frame* child = frame->tree()->firstChild();
   1517     while (child) {
   1518         CacheBuilder* cacheBuilder = Builder(child);
   1519         Node* focus = cacheBuilder->currentFocus();
   1520         if (focus)
   1521             return focus;
   1522         child = child->tree()->nextSibling();
   1523     }
   1524     return NULL;
   1525 }
   1526 
   1527 static bool strCharCmp(const char* matches, const UChar* test, int wordLength,
   1528     int wordCount)
   1529 {
   1530     for (int index = 0; index < wordCount; index++) {
   1531         for (int inner = 0; inner < wordLength; inner++) {
   1532             if (matches[inner] != test[inner]) {
   1533                 matches += wordLength;
   1534                 goto next;
   1535             }
   1536         }
   1537         return true;
   1538 next:
   1539         ;
   1540     }
   1541     return false;
   1542 }
   1543 
   1544 static const int stateTwoLetter[] = {
   1545     0x02060c00,  // A followed by: [KLRSZ]
   1546     0x00000000,  // B
   1547     0x00084001,  // C followed by: [AOT]
   1548     0x00000014,  // D followed by: [CE]
   1549     0x00000000,  // E
   1550     0x00001800,  // F followed by: [LM]
   1551     0x00100001,  // G followed by: [AU]
   1552     0x00000100,  // H followed by: [I]
   1553     0x00002809,  // I followed by: [ADLN]
   1554     0x00000000,  // J
   1555     0x01040000,  // K followed by: [SY]
   1556     0x00000001,  // L followed by: [A]
   1557     0x000ce199,  // M followed by: [ADEHINOPST]
   1558     0x0120129c,  // N followed by: [CDEHJMVY]
   1559     0x00020480,  // O followed by: [HKR]
   1560     0x00420001,  // P followed by: [ARW]
   1561     0x00000000,  // Q
   1562     0x00000100,  // R followed by: [I]
   1563     0x0000000c,  // S followed by: [CD]
   1564     0x00802000,  // T followed by: [NX]
   1565     0x00080000,  // U followed by: [T]
   1566     0x00080101,  // V followed by: [AIT]
   1567     0x01200101   // W followed by: [AIVY]
   1568 };
   1569 
   1570 static const char firstIndex[] = {
   1571      0,  5,  5,  8, 10, 10, 12, 14,
   1572     15, 19, 19, 21, 22, 32, 40, 43,
   1573     46, 46, 47, 49, 51, 52, 55, 59
   1574 };
   1575 
   1576 // from http://infolab.stanford.edu/~manku/bitcount/bitcount.html
   1577 #define TWO(c)     (0x1u << (c))
   1578 #define MASK(c)    (((unsigned int)(-1)) / (TWO(TWO(c)) + 1u))
   1579 #define COUNT(x,c) ((x) & MASK(c)) + (((x) >> (TWO(c))) & MASK(c))
   1580 
   1581 int bitcount (unsigned int n)
   1582 {
   1583     n = COUNT(n, 0);
   1584     n = COUNT(n, 1);
   1585     n = COUNT(n, 2);
   1586     n = COUNT(n, 3);
   1587     return COUNT(n, 4);
   1588 }
   1589 
   1590 #undef TWO
   1591 #undef MASK
   1592 #undef COUNT
   1593 
   1594 static bool isUnicodeSpace(UChar ch)
   1595 {
   1596     return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' || ch == 0xa0;
   1597 }
   1598 
   1599 static bool validZip(int stateIndex, const UChar* zipPtr)
   1600 {
   1601     static const struct {
   1602         char mLow;
   1603         char mHigh;
   1604         char mException1;
   1605         char mException2;
   1606     } zipRange[] = {
   1607         { 99, 99, -1, -1 }, // AK Alaska
   1608         { 35, 36, -1, -1 }, // AL Alabama
   1609         { 71, 72, -1, -1 }, // AR Arkansas
   1610         { 96, 96, -1, -1 }, // AS American Samoa
   1611         { 85, 86, -1, -1 }, // AZ Arizona
   1612         { 90, 96, -1, -1 }, // CA California
   1613         { 80, 81, -1, -1 }, // CO Colorado
   1614         {  6,  6, -1, -1 }, // CT Connecticut
   1615         { 20, 20, -1, -1 }, // DC District of Columbia
   1616         { 19, 19, -1, -1 }, // DE Delaware
   1617         { 32, 34, -1, -1 }, // FL Florida
   1618         { 96, 96, -1, -1 }, // FM Federated States of Micronesia
   1619         { 30, 31, -1, -1 }, // GA Georgia
   1620         { 96, 96, -1, -1 }, // GU Guam
   1621         { 96, 96, -1, -1 }, // HI Hawaii
   1622         { 50, 52, -1, -1 }, // IA Iowa
   1623         { 83, 83, -1, -1 }, // ID Idaho
   1624         { 60, 62, -1, -1 }, // IL Illinois
   1625         { 46, 47, -1, -1 }, // IN Indiana
   1626         { 66, 67, 73, -1 }, // KS Kansas
   1627         { 40, 42, -1, -1 }, // KY Kentucky
   1628         { 70, 71, -1, -1 }, // LA Louisiana
   1629         {  1,  2, -1, -1 }, // MA Massachusetts
   1630         { 20, 21, -1, -1 }, // MD Maryland
   1631         {  3,  4, -1, -1 }, // ME Maine
   1632         { 96, 96, -1, -1 }, // MH Marshall Islands
   1633         { 48, 49, -1, -1 }, // MI Michigan
   1634         { 55, 56, -1, -1 }, // MN Minnesota
   1635         { 63, 65, -1, -1 }, // MO Missouri
   1636         { 96, 96, -1, -1 }, // MP Northern Mariana Islands
   1637         { 38, 39, -1, -1 }, // MS Mississippi
   1638         { 55, 56, -1, -1 }, // MT Montana
   1639         { 27, 28, -1, -1 }, // NC North Carolina
   1640         { 58, 58, -1, -1 }, // ND North Dakota
   1641         { 68, 69, -1, -1 }, // NE Nebraska
   1642         {  3,  4, -1, -1 }, // NH New Hampshire
   1643         {  7,  8, -1, -1 }, // NJ New Jersey
   1644         { 87, 88, 86, -1 }, // NM New Mexico
   1645         { 88, 89, 96, -1 }, // NV Nevada
   1646         { 10, 14,  0,  6 }, // NY New York
   1647         { 43, 45, -1, -1 }, // OH Ohio
   1648         { 73, 74, -1, -1 }, // OK Oklahoma
   1649         { 97, 97, -1, -1 }, // OR Oregon
   1650         { 15, 19, -1, -1 }, // PA Pennsylvania
   1651         {  6,  6,  0,  9 }, // PR Puerto Rico
   1652         { 96, 96, -1, -1 }, // PW Palau
   1653         {  2,  2, -1, -1 }, // RI Rhode Island
   1654         { 29, 29, -1, -1 }, // SC South Carolina
   1655         { 57, 57, -1, -1 }, // SD South Dakota
   1656         { 37, 38, -1, -1 }, // TN Tennessee
   1657         { 75, 79, 87, 88 }, // TX Texas
   1658         { 84, 84, -1, -1 }, // UT Utah
   1659         { 22, 24, 20, -1 }, // VA Virginia
   1660         {  6,  9, -1, -1 }, // VI Virgin Islands
   1661         {  5,  5, -1, -1 }, // VT Vermont
   1662         { 98, 99, -1, -1 }, // WA Washington
   1663         { 53, 54, -1, -1 }, // WI Wisconsin
   1664         { 24, 26, -1, -1 }, // WV West Virginia
   1665         { 82, 83, -1, -1 }  // WY Wyoming
   1666     };
   1667 
   1668     int zip = zipPtr[0] - '0';
   1669     zip *= 10;
   1670     zip += zipPtr[1] - '0';
   1671     int low = zipRange[stateIndex].mLow;
   1672     int high = zipRange[stateIndex].mHigh;
   1673     if (zip >= low && zip <= high)
   1674         return true;
   1675     if (zip == zipRange[stateIndex].mException1)
   1676         return true;
   1677     if (zip == zipRange[stateIndex].mException2)
   1678         return true;
   1679     return false;
   1680 }
   1681 
   1682 #define MAX_PLACE_NAME_LENGTH 25 // the longest allowable one word place name
   1683 
   1684 CacheBuilder::FoundState CacheBuilder::FindAddress(const UChar* chars,
   1685     unsigned length, int* start, int* end, bool caseInsensitive)
   1686 {
   1687     FindState addressState;
   1688     FindReset(&addressState);
   1689     addressState.mWords[0] = addressState.mStarts[0] = chars;
   1690     addressState.mCaseInsensitive = caseInsensitive;
   1691     FoundState state = FindPartialAddress(chars, chars, length, &addressState);
   1692     if (state == FOUND_PARTIAL && addressState.mProgress == ZIP_CODE &&
   1693             addressState.mNumberCount == 0) {
   1694         addressState.mProgress = FIND_STREET;
   1695         state = FindPartialAddress(NULL, NULL, 0, &addressState);
   1696     }
   1697     *start = addressState.mStartResult;
   1698     *end = addressState.mEndResult;
   1699     return state;
   1700 }
   1701 
   1702 CacheBuilder::FoundState CacheBuilder::FindPartialAddress(const UChar* baseChars,
   1703     const UChar* chars, unsigned length, FindState* s)
   1704 {
   1705     // lower case letters are optional; trailing asterisk is optional 's'
   1706     static char const* const longStreetNames[] = {
   1707         "\x04" "LleY" "\x04" "NneX" "\x05" "RCade" "\x05" "VEnue" "\x06" "LAMEDA", // A
   1708         "\x04" "aYoU" "\x04" "eaCH" "\x03" "eND" "\x05" "LuFf*" "\x05" "oTtoM"
   1709             "\x08" "ouLeVarD" "\x05" "Ranch" "\x05" "RidGe" "\x05" "RooK*"
   1710             "\x04" "urG*" "\x05" "YPass" "\x07" "roadWAY", // B
   1711         "\x05" "AMINO"
   1712         "\x03" "amP" "\x05" "anYoN" "\x03" "aPE" "\x07" "auSeWaY" "\x06" "enTeR*"
   1713             "\x06" "IRcle*" "\x05" "LiFf*" "\x03" "LuB" "\x05" "oMmoN" "\x06" "ORner*"
   1714             "\x05" "ouRSE" "\x05" "ourT*" "\x04" "oVe*" "\x04" "ReeK" "\x07" "REScent"
   1715             "\x04" "ReST" "\x07" "ROSSING" "\x08" "ROSSROAD" "\x04" "URVe"
   1716             "\x05" "AMINO" "\x06" "IRCULO" "\x07" "REScent", // C
   1717         "\x03" "aLe" "\x02" "aM" "\x05" "iVide" "\x05" "Rive*", // D
   1718         "\x06" "STate*" "\x09" "XPresswaY" "\x09" "XTension*", // E
   1719         "\x04" "ALL*" "\x04" "eRrY" "\x05" "ieLD*" "\x04" "LaT*" "\x04" "oRD*"
   1720             "\x05" "oReST" "\x05" "oRGe*" "\x04" "oRK*" "\x03" "orT" "\x06" "reeWaY", // F
   1721         "\x06" "arDeN*" "\x06" "aTeWaY" "\x04" "LeN*" "\x05" "ReeN*" "\x05" "RoVe*", // G
   1722         "\x06" "arBoR*" "\x04" "aVeN" "\x06" "eighTS" "\x06" "ighWaY" "\x04" "iLl*"
   1723             "\x05" "OLloW", // H
   1724         "\x04" "NLeT" "\x06" "Sland*" "\x03" "SLE", // I
   1725         "\x08" "unCTion*", // J
   1726         "\x03" "eY*" "\x05" "NoLl*", // K
   1727         "\x04" "aKe*" "\x03" "AND" "\x06" "aNDinG" "\x03" "aNe" "\x05" "iGhT*"
   1728             "\x03" "oaF" "\x04" "oCK*" "\x04" "oDGe" "\x03" "OOP", // L
   1729         "\x03" "ALL" "\x05" "aNoR*" "\x06" "eaDoW*" "\x03" "EWS" "\x04" "iLl*"
   1730             "\x06" "iSsioN" "\x07" "oTorWaY" "\x04" "ounT" "\x08" "ounTaiN*", // M
   1731         "\x03" "eCK", // N
   1732         "\x06" "RCHard" "\x03" "VAL" "\x07" "verPASs", // O
   1733         "\x04" "ARK*" "\x07" "arKWaY*" "\x03" "ASS" "\x06" "aSsaGE" "\x03" "ATH"
   1734             "\x03" "IKE" "\x04" "iNE*" "\x04" "Lace" "\x05" "LaiN*" "\x04" "LaZa"
   1735             "\x05" "oinT*" "\x04" "oRT*" "\x06" "Rairie" "\x06" "RIVADA", // P
   1736         NULL,
   1737         "\x05" "ADiaL" "\x03" "AMP" "\x04" "aNCH" "\x05" "aPiD*"
   1738             "\x03" "eST"
   1739             "\x05" "iDGe*" "\x04" "IVer" "\x04" "oaD*" "\x04" "ouTE" "\x02" "OW"
   1740             "\x02" "UE" "\x02" "UN", // R
   1741         "\x05" "HoaL*" "\x05" "HoRe*" "\x05" "KyWaY" "\x06" "PrinG*" "\x04" "PUR*"
   1742             "\x06" "Quare*" "\x06" "TAtion" "\x08" "TRAvenue" "\x05" "TReaM"
   1743             "\x06" "Treet*" "\x05" "uMmiT" "\x07" "PeeDWaY", // S
   1744         "\x06" "ERrace" "\x09" "hRoughWaY" "\x04" "RaCE" "\x04" "RAcK" "\x09" "RaFficwaY"
   1745             "\x04" "RaiL" "\x05" "UNneL" "\x07" "urnPiKE", // T
   1746         "\x08" "nderPASs" "\x05" "Nion*", // U
   1747         "\x06" "aLleY*" "\x06" "IAduct" "\x04" "ieW*" "\x07" "iLlaGe*" "\x04" "iLle"
   1748             "\x04" "ISta", // V
   1749         "\x04" "ALK*" "\x03" "ALL" "\x03" "AY*" "\x04" "eLl*", // W
   1750         "\x03" "ING" "\x02" "RD", // X
   1751     };
   1752 
   1753     static char const* const longStateNames[] = {
   1754         "\x8e" "la" "\x85" "bama" "\x02" "\x84" "ska" "\x01" "\x8f" "merican Samoa" "\x04"
   1755              "\x91" "r" "\x86" "izona" "\x05" "\x87" "kansas" "\x03",
   1756         NULL,
   1757         "\x8b" "alifornia" "\x06" "\x95" "o" "\x87" "lorado" "\x07" "\x8a" "nnecticut" "\x08",
   1758         "\x89" "elaware" "\x0a" "\x95" "istrict of Columbia" "\x09",
   1759         NULL,
   1760         "\x9f" "ederated States of Micronesia" "\x0c" "\x88" "lorida" "\x0b",
   1761         "\x85" "uam" "\x0e" "\x88" "eorgia" "\x0d",
   1762         "\x87" "awaii" "\x0f",
   1763         "\x86" "daho" "\x11" "\x89" "llinois" "\x12" "\x88" "ndiana" "\x13" "\x85"
   1764              "owa" "\x10",
   1765         NULL,
   1766         "\x87" "ansas" "\x14" "\x89" "entucky" "\x15",
   1767         "\x8a" "ouisiana" "\x16",
   1768         "\x86" "aine" "\x19" "\x99" "ar" "\x8e" "shall Islands" "\x1a" "\x86" "yland" "\x18"
   1769              "\x8e" "assachusetts" "\x17" "\x93" "i" "\x87" "chigan" "\x1b"
   1770              "\x88" "nnesota" "\x1c" "\x93" "iss" "\x88" "issippi" "\x1f" "\x85"
   1771              "ouri" "\x1d" "\x88" "ontana" "\x20",
   1772         "\x90" "e" "\x87" "braska" "\x23" "\x85" "vada" "\x27" "\xa5" "ew " "\x8a"
   1773              "Hampshire" "\x24" "\x87" "Jersey" "\x25" "\x87" "Mexico" "\x26"
   1774              "\x85" "York" "\x28" "\x98" "orth " "\x89" "Carolina" "\x21" "\x87"
   1775              "Dakota" "\x22" "\x99" "orthern Mariana Islands" "\x1e",
   1776         "\x85" "hio" "\x29" "\x89" "klahoma" "\x2a" "\x87" "regon" "\x2b",
   1777         "\x86" "alau" "\x2e" "\x8d" "ennsylvania" "\x2c" "\x8c" "uerto Rico" "\x2d",
   1778         NULL,
   1779         "\x8d" "hode Island" "\x2f",
   1780         "\x98" "outh " "\x89" "Carolina" "\x30" "\x87" "Dakota" "\x31",
   1781         "\x90" "e" "\x88" "nnessee" "\x32" "\x84" "xas" "\x33",
   1782         "\x85" "tah" "\x34",
   1783         "\x88" "ermont" "\x37" "\x94" "irgin" "\x89" " Islands" "\x36" "\x83" "ia" "\x35",
   1784         "\x8b" "ashington" "\x38" "\x8e" "est Virginia" "\x3a" "\x8a" "isconsin" "\x39"
   1785              "\x88" "yoming" "\x3b"
   1786     };
   1787 
   1788 #if 0 // DEBUG_NAV_UI
   1789     static char const* const progressNames[] = {
   1790         "NO_ADDRESS",
   1791         "SKIP_TO_SPACE",
   1792         "HOUSE_NUMBER",
   1793         "NUMBER_TRAILING_SPACE",
   1794         "ADDRESS_LINE",
   1795         "STATE_NAME",
   1796         "SECOND_HALF",
   1797         "ZIP_CODE",
   1798         "PLUS_4",
   1799         "FIND_STREET"
   1800     };
   1801 #endif
   1802     // strategy: US only support at first
   1803     // look for a 1 - 5 digit number for a street number (no support for 'One Microsoft Way')
   1804         // ignore if preceded by '#', Suite, Ste, Rm
   1805     // look for two or more words (up to 5? North Frank Lloyd Wright Blvd)
   1806             // note: "The Circle at North Hills St." has six words, and a lower 'at' -- allow at, by, of, in, the, and, ... ?
   1807         // if a word starts with a lowercase letter, no match
   1808         // allow: , . - # / (for 1/2) ' "
   1809         // don't look for street name type yet
   1810     // look for one or two delimiters to represent possible 2nd addr line and city name
   1811     // look for either full state name, or state two letters, and/or zip code (5 or 9 digits)
   1812     // now look for street suffix, either in full or abbreviated form, with optional 's' if there's an asterisk
   1813 
   1814     s->mCurrentStart = chars;
   1815     s->mEnd = chars + length;
   1816     int candIndex = 0;
   1817     bool retryState;
   1818     bool mustBeAllUpper = false;
   1819     bool secondHalf = false;
   1820     chars -= 1;
   1821     UChar ch = s->mCurrent;
   1822     while (++chars <= s->mEnd) {
   1823         UChar prior = ch;
   1824         ch = chars < s->mEnd ? *chars : ' ';
   1825         switch (s->mProgress) {
   1826             case NO_ADDRESS:
   1827                 if (WTF::isASCIIDigit(ch) == false) {
   1828                     if (ch != 'O') // letter 'O', not zero
   1829                         continue;
   1830                     if (s->mEnd - chars < 3)
   1831                         continue;
   1832                     prior = *++chars;
   1833                     ch = *++chars;
   1834                     if ((prior != 'n' || ch != 'e') && (prior != 'N' || ch != 'E'))
   1835                         continue;
   1836                     if (isUnicodeSpace(*++chars) == false)
   1837                         continue;
   1838                     s->mProgress = ADDRESS_LINE;
   1839                     s->mStartResult = chars - 3 - s->mCurrentStart;
   1840                     continue;
   1841                 }
   1842                 if (isUnicodeSpace(prior) == false) {
   1843                     s->mProgress = SKIP_TO_SPACE;
   1844                     continue;
   1845                 }
   1846                 s->mNumberCount = 1;
   1847                 s->mProgress = HOUSE_NUMBER;
   1848                 s->mStartResult = chars - s->mCurrentStart;
   1849                 continue;
   1850             case SKIP_TO_SPACE:
   1851                 if (isUnicodeSpace(ch) == false)
   1852                     continue;
   1853                 break;
   1854             case HOUSE_NUMBER:
   1855                 if (WTF::isASCIIDigit(ch)) {
   1856                     if (++s->mNumberCount >= 6)
   1857                         s->mProgress = SKIP_TO_SPACE;
   1858                     continue;
   1859                 }
   1860                 if (WTF::isASCIIUpper(ch)) { // allow one letter after house number, e.g. 12A SKOLFIELD PL, HARPSWELL, ME 04079
   1861                     if (WTF::isASCIIDigit(prior) == false)
   1862                         s->mProgress = SKIP_TO_SPACE;
   1863                     continue;
   1864                 }
   1865                 if (ch == '-') {
   1866                     if (s->mNumberCount > 0) { // permit 21-23 ELM ST
   1867                         ++s->mNumberCount;
   1868                         continue;
   1869                     }
   1870                 }
   1871                 s->mNumberCount = 0;
   1872                 s->mProgress = NUMBER_TRAILING_SPACE;
   1873             case NUMBER_TRAILING_SPACE:
   1874                 if (isUnicodeSpace(ch))
   1875                     continue;
   1876                 if (0 && WTF::isASCIIDigit(ch)) {
   1877                     s->mNumberCount = 1;
   1878                     s->mProgress = HOUSE_NUMBER;
   1879                     s->mStartResult = chars - s->mCurrentStart;
   1880                     continue;
   1881                 }
   1882                 if (WTF::isASCIIDigit(ch) == false && WTF::isASCIIUpper(ch) == false)
   1883                     break;
   1884                 s->mProgress = ADDRESS_LINE;
   1885             case ADDRESS_LINE:
   1886                 if (WTF::isASCIIAlpha(ch) || ch == '\'' || ch == '-' || ch == '&' || ch == '(' || ch == ')') {
   1887                     if (++s->mLetterCount > 1) {
   1888                         s->mNumberWords &= ~(1 << s->mWordCount);
   1889                         continue;
   1890                     }
   1891                     if (s->mNumberCount >= 5)
   1892                         break;
   1893 // FIXME: the test below was added to give up on a non-address, but it
   1894 // incorrectly discards addresses where the house number is in one node
   1895 // and the street name is in the next; I don't recall what the failing case
   1896 // is that suggested this fix.
   1897 //                    if (s->mWordCount == 0 && s->mContinuationNode)
   1898 //                        return FOUND_NONE;
   1899                     s->newWord(baseChars, chars);
   1900                     if (WTF::isASCIILower(ch) && s->mNumberCount == 0)
   1901                         s->mFirstLower = chars;
   1902                     s->mNumberCount = 0;
   1903                     if (WTF::isASCIILower(ch) || (WTF::isASCIIAlpha(ch) == false && ch != '-'))
   1904                         s->mNumberWords &= ~(1 << s->mWordCount);
   1905                     s->mUnparsed = true;
   1906                     continue;
   1907                 } else if (s->mLetterCount >= MAX_PLACE_NAME_LENGTH) {
   1908                     break;
   1909                 } else if (s->mFirstLower != NULL) {
   1910                     if (s->mCaseInsensitive)
   1911                         goto resetWord;
   1912                     size_t length = chars - s->mFirstLower;
   1913                     if (length > 3)
   1914                         break;
   1915                     if (length == 3 && strCharCmp("and" "the", s->mFirstLower, 3, 2) == false)
   1916                         break;
   1917                     if (length == 2 && strCharCmp("at" "by" "el" "in" "of", s->mFirstLower, 2, 5) == false)
   1918                         break;
   1919                     goto resetWord;
   1920                 }
   1921                 if (ch == ',' || ch == '*') { // delimits lines
   1922                     // asterisk as delimiter: http://www.sa.sc.edu/wellness/members.html
   1923                     if (++s->mLineCount > 5)
   1924                         break;
   1925                     goto lookForState;
   1926                 }
   1927                 if (isUnicodeSpace(ch) || prior == '-') {
   1928             lookForState:
   1929                     if (s->mUnparsed == false)
   1930                         continue;
   1931                     const UChar* candidate = s->mWords[s->mWordCount];
   1932                     UChar firstLetter = candidate[0];
   1933                     if (WTF::isASCIIUpper(firstLetter) == false && WTF::isASCIIDigit(firstLetter) == false)
   1934                         goto resetWord;
   1935                     s->mWordCount++;
   1936                     if ((s->mWordCount == 2 && s->mNumberWords == 3 && WTF::isASCIIDigit(s->mWords[1][1])) || // choose second of 8888 333 Main
   1937                         (s->mWordCount >= sizeof(s->mWords) / sizeof(s->mWords[0]) - 1)) { // subtract 1 since state names may have two parts
   1938                         // search for simple number already stored since first potential house # didn't pan out
   1939                         if (s->mNumberWords == 0)
   1940                             break;
   1941                         int shift = 0;
   1942                         while ((s->mNumberWords & (1 << shift)) == 0)
   1943                             shift++;
   1944                         s->mNumberWords >>= ++shift;
   1945                         if (s->mBases[0] != s->mBases[shift]) // if we're past the original node, bail
   1946                             break;
   1947                         s->shiftWords(shift);
   1948                         s->mStartResult = s->mWords[0] - s->mStarts[0];
   1949                         s->mWordCount -= shift;
   1950                         // FIXME: need to adjust lineCount to account for discarded delimiters
   1951                     }
   1952                     if (s->mWordCount < 4)
   1953                         goto resetWord;
   1954                     firstLetter -= 'A';
   1955                     if (firstLetter > 'W' - 'A')
   1956                         goto resetWord;
   1957                     UChar secondLetter = candidate[1];
   1958                     if (prior == '-')
   1959                         s->mLetterCount--; // trim trailing dashes, to accept CA-94043
   1960                     if (s->mLetterCount == 2) {
   1961                         secondLetter -= 'A';
   1962                         if (secondLetter > 'Z' - 'A')
   1963                             goto resetWord;
   1964                         if ((stateTwoLetter[firstLetter] & 1 << secondLetter) != 0) {
   1965                             // special case to ignore 'et al'
   1966                             if (strCharCmp("ET", s->mWords[s->mWordCount - 2], 2, 1) == false) {
   1967                                 s->mStateWord = s->mWordCount - 1;
   1968                                 s->mZipHint = firstIndex[firstLetter] +
   1969                                     bitcount(stateTwoLetter[firstLetter] & ((1 << secondLetter) - 1));
   1970                                 goto foundStateName;
   1971                             }
   1972                         }
   1973                         goto resetWord;
   1974                     }
   1975                     s->mStates = longStateNames[firstLetter];
   1976                     if (s->mStates == NULL)
   1977                         goto resetWord;
   1978                     mustBeAllUpper = false;
   1979                     s->mProgress = STATE_NAME;
   1980                     unsigned char section = s->mStates[0];
   1981                     ASSERT(section > 0x80);
   1982                     s->mSectionLength = section & 0x7f;
   1983                     candIndex = 1;
   1984                     secondHalf = false;
   1985                     s->mStateWord = s->mWordCount - 1;
   1986                     goto stateName;
   1987                 }
   1988                 if (WTF::isASCIIDigit(ch)) {
   1989                     if (s->mLetterCount == 0) {
   1990                         if (++s->mNumberCount > 1)
   1991                             continue;
   1992                         if (s->mWordCount == 0 && s->mContinuationNode)
   1993                             return FOUND_NONE;
   1994                         s->newWord(baseChars, chars);
   1995                         s->mNumberWords |= 1 << s->mWordCount;
   1996                         s->mUnparsed = true;
   1997                     }
   1998                     continue;
   1999                 }
   2000                 if (ch == '.') { // optionally can follow letters
   2001                     if (s->mLetterCount == 0)
   2002                         break;
   2003                     if (s->mNumberCount > 0)
   2004                         break;
   2005                     continue;
   2006                 }
   2007                 if (ch == '/') // between numbers (1/2) between words (12 Main / Ste 4d)
   2008                     goto resetWord;
   2009                 if (ch == '#') // can precede numbers, allow it to appear randomly
   2010                     goto resetWord;
   2011                 if (ch == '"') // sometimes parts of addresses are quoted (FIXME: cite an example here)
   2012                     continue;
   2013                 break;
   2014             case SECOND_HALF:
   2015                 if (WTF::isASCIIAlpha(ch)) {
   2016                     if (s->mLetterCount == 0) {
   2017                         s->newWord(baseChars, chars);
   2018                         s->mWordCount++;
   2019                     }
   2020                     s->mLetterCount++;
   2021                     continue;
   2022                 }
   2023                 if (WTF::isASCIIDigit(ch) == false) {
   2024                     if (s->mLetterCount > 0) {
   2025                         s->mProgress = STATE_NAME;
   2026                         candIndex = 0;
   2027                         secondHalf = true;
   2028                         goto stateName;
   2029                     }
   2030                     continue;
   2031                 }
   2032                 s->mProgress = ADDRESS_LINE;
   2033                 goto resetState;
   2034             case STATE_NAME:
   2035             stateName:
   2036                 // pick up length of first section
   2037                 do {
   2038                     int stateIndex = 1;
   2039                     int skip = 0;
   2040                     int prefix = 0;
   2041                     bool subStr = false;
   2042                     do {
   2043                         unsigned char match = s->mStates[stateIndex];
   2044                         if (match >= 0x80) {
   2045                             if (stateIndex == s->mSectionLength)
   2046                                 break;
   2047                             subStr = true;
   2048                   //          if (skip > 0)
   2049                   //              goto foundStateName;
   2050                             prefix = candIndex;
   2051                             skip = match & 0x7f;
   2052                             match = s->mStates[++stateIndex];
   2053                         }
   2054                         UChar candChar = s->mWords[s->mWordCount - 1][candIndex];
   2055                         if (mustBeAllUpper && WTF::isASCIILower(candChar))
   2056                             goto skipToNext;
   2057                         if (match != candChar) {
   2058                             if (match != WTF::toASCIILower(candChar)) {
   2059                        skipToNext:
   2060                                 if (subStr == false)
   2061                                     break;
   2062                                 if (stateIndex == s->mSectionLength) {
   2063                                     if (secondHalf) {
   2064                                         s->mProgress = ADDRESS_LINE;
   2065                                         goto resetState;
   2066                                     }
   2067                                     break;
   2068                                 }
   2069                                 stateIndex += skip;
   2070                                 skip = 0;
   2071                                 candIndex = prefix;
   2072                                 continue; // try next substring
   2073                             }
   2074                             mustBeAllUpper = true;
   2075                         }
   2076                         int nextindex = stateIndex + 1;
   2077                         if (++candIndex >= s->mLetterCount && s->mStates[nextindex] == ' ') {
   2078                             s->mProgress = SECOND_HALF;
   2079                             s->mStates += nextindex;
   2080                             s->mSectionLength -= nextindex;
   2081                             goto resetWord;
   2082                         }
   2083                         if (nextindex + 1 == s->mSectionLength || skip == 2) {
   2084                             s->mZipHint = s->mStates[nextindex] - 1;
   2085                             goto foundStateName;
   2086                         }
   2087                         stateIndex += 1;
   2088                         skip -= 1;
   2089                     } while (true);
   2090                     s->mStates += s->mSectionLength;
   2091                     ASSERT(s->mStates[0] == 0 || (unsigned) s->mStates[0] > 0x80);
   2092                     s->mSectionLength = s->mStates[0] & 0x7f;
   2093                     candIndex = 1;
   2094                     subStr = false;
   2095                 } while (s->mSectionLength != 0);
   2096                 s->mProgress = ADDRESS_LINE;
   2097                 goto resetState;
   2098             foundStateName:
   2099                 s->mEndResult = chars - s->mCurrentStart;
   2100                 s->mEndWord = s->mWordCount - 1;
   2101                 s->mProgress = ZIP_CODE;
   2102                 // a couple of delimiters is an indication that the state name is good
   2103                 // or, a non-space / non-alpha-digit is also good
   2104                 s->mZipDelimiter = s->mLineCount > 2
   2105                     || isUnicodeSpace(ch) == false
   2106                     || chars == s->mEnd;
   2107                 if (WTF::isASCIIDigit(ch))
   2108                     s->mZipStart = chars;
   2109                 goto resetState;
   2110             case ZIP_CODE:
   2111                 if (WTF::isASCIIDigit(ch)) {
   2112                     int count = ++s->mNumberCount;
   2113                     if (count == 1) {
   2114                         if (WTF::isASCIIDigit(prior))
   2115                             ++s->mNumberCount;
   2116                         else
   2117                             s->mZipStart = chars;
   2118                     }
   2119                     if (count <= 9)
   2120                         continue;
   2121                 } else if (isUnicodeSpace(ch)) {
   2122                     if (s->mNumberCount == 0) {
   2123                         s->mZipDelimiter = true; // two spaces delimit state name
   2124                         continue;
   2125                     }
   2126                 } else if (ch == '-') {
   2127                     if (s->mNumberCount == 5 && validZip(s->mZipHint, s->mZipStart)) {
   2128                         s->mNumberCount = 0;
   2129                         s->mProgress = PLUS_4;
   2130                         continue;
   2131                     }
   2132                     if (s->mNumberCount == 0)
   2133                         s->mZipDelimiter = true;
   2134                 } else if (WTF::isASCIIAlpha(ch) == false)
   2135                     s->mZipDelimiter = true;
   2136                 else {
   2137                     if (s->mLetterCount == 0) {
   2138                         s->newWord(baseChars, chars);
   2139                         s->mUnparsed = true;
   2140                     }
   2141                     ++s->mLetterCount;
   2142                 }
   2143                 if (s->mNumberCount == 5 || s->mNumberCount == 9) {
   2144                     if (validZip(s->mZipHint, s->mZipStart) == false)
   2145                         goto noZipMatch;
   2146                     s->mEndResult = chars - s->mCurrentStart;
   2147                     s->mEndWord = s->mWordCount - 1;
   2148                 } else if (s->mZipDelimiter == false) {
   2149             noZipMatch:
   2150                     --chars;
   2151                     s->mProgress = ADDRESS_LINE;
   2152                     continue;
   2153                 }
   2154                 s->mProgress = FIND_STREET;
   2155                 goto findStreet;
   2156             case PLUS_4:
   2157                 if (WTF::isASCIIDigit(ch)) {
   2158                     if (++s->mNumberCount <= 4)
   2159                         continue;
   2160                 }
   2161                 if (isUnicodeSpace(ch)) {
   2162                     if (s->mNumberCount == 0)
   2163                         continue;
   2164                 }
   2165                 if (s->mNumberCount == 4) {
   2166                     if (WTF::isASCIIAlpha(ch) == false) {
   2167                         s->mEndResult = chars - s->mCurrentStart;
   2168                         s->mEndWord = s->mWordCount - 1;
   2169                     }
   2170                 } else if (s->mNumberCount != 0)
   2171                     break;
   2172                 s->mProgress = FIND_STREET;
   2173             case FIND_STREET:
   2174             findStreet:
   2175                 retryState = false;
   2176                 for (int wordsIndex = s->mStateWord - 1; wordsIndex >= 0; --wordsIndex) {
   2177                     const UChar* test = s->mWords[wordsIndex];
   2178                     UChar letter = test[0];
   2179                     letter -= 'A';
   2180                     if (letter > 'X' - 'A')
   2181                         continue;
   2182                     const char* names = longStreetNames[letter];
   2183                     if (names == NULL)
   2184                         continue;
   2185                     int offset;
   2186                     while ((offset = *names++) != 0) {
   2187                         int testIndex = 1;
   2188                         bool abbr = false;
   2189                         for (int idx = 0; idx < offset; idx++) {
   2190                             char nameLetter = names[idx];
   2191                             char testUpper = WTF::toASCIIUpper(test[testIndex]);
   2192                             if (nameLetter == '*') {
   2193                                 if (testUpper == 'S')
   2194                                     testIndex++;
   2195                                 break;
   2196                             }
   2197                             bool fullOnly = WTF::isASCIILower(nameLetter);
   2198                             nameLetter = WTF::toASCIIUpper(nameLetter);
   2199                             if (testUpper == nameLetter) {
   2200                                 if (abbr && fullOnly)
   2201                                     goto nextTest;
   2202                                 testIndex++;
   2203                                 continue;
   2204                             }
   2205                             if (fullOnly == false)
   2206                                 goto nextTest;
   2207                             abbr = true;
   2208                         }
   2209                         letter = &test[testIndex] < s->mEnds[wordsIndex] ?
   2210                             test[testIndex] : ' ';
   2211                         if (WTF::isASCIIAlpha(letter) == false && WTF::isASCIIDigit(letter) == false) {
   2212                             if (s->mNumberWords != 0) {
   2213                                 int shift = 0;
   2214                                 int wordReduction = -1;
   2215                                 do {
   2216                                     while ((s->mNumberWords & (1 << shift)) == 0)
   2217                                         shift++;
   2218                                     if (shift > wordsIndex)
   2219                                         break;
   2220                                     wordReduction = shift;
   2221                                 } while (s->mNumberWords >> ++shift != 0);
   2222                                 if (wordReduction >= 0) {
   2223                                     if (s->mContinuationNode) {
   2224                                         if (retryState)
   2225                                             break;
   2226                                         return FOUND_NONE;
   2227                                     }
   2228                                     s->mStartResult = s->mWords[wordReduction] - s->mStarts[wordReduction];
   2229                                 }
   2230                             }
   2231                             if (wordsIndex != s->mStateWord - 1)
   2232                                 return FOUND_COMPLETE;
   2233                             retryState = true;
   2234                         }
   2235                     nextTest:
   2236                         names += offset;
   2237                     }
   2238                 }
   2239                 if (retryState) {
   2240                     s->mProgress = ADDRESS_LINE;
   2241                     s->mStates = NULL;
   2242                     continue;
   2243                 }
   2244                 if (s->mNumberWords != 0) {
   2245                     unsigned shift = 0;
   2246                     while ((s->mNumberWords & (1 << shift)) == 0)
   2247                         shift++;
   2248                     s->mNumberWords >>= ++shift;
   2249                     if (s->mBases[0] != s->mBases[shift])
   2250                         return FOUND_NONE;
   2251                     s->shiftWords(shift);
   2252                     s->mStartResult = s->mWords[0] - s->mStarts[0];
   2253                     s->mWordCount -= shift;
   2254                     s->mProgress = ADDRESS_LINE;
   2255                     --chars;
   2256                     continue;
   2257                 }
   2258                 break;
   2259         }
   2260         if (s->mContinuationNode)
   2261             return FOUND_NONE;
   2262         s->mProgress = NO_ADDRESS;
   2263         s->mWordCount = s->mLineCount = 0;
   2264         s->mNumberWords = 0;
   2265     resetState:
   2266         s->mStates = NULL;
   2267     resetWord:
   2268         s->mNumberCount = s->mLetterCount = 0;
   2269         s->mFirstLower = NULL;
   2270         s->mUnparsed = false;
   2271     }
   2272     s->mCurrent = ch;
   2273     return s->mProgress == NO_ADDRESS ? FOUND_NONE : FOUND_PARTIAL;
   2274 }
   2275 
   2276 // Recogize common email patterns only. Currently has lots of state, walks text forwards and backwards -- will be
   2277 // a real challenge to adapt to walk text across multiple nodes, I imagine
   2278 // FIXME: it's too hard for the caller to call these incrementally -- it's probably best for this to
   2279 // either walk the node tree directly or make a callout to get the next or previous node, if there is one
   2280 // walking directly will avoid adding logic in caller to track the multiple partial or full nodes that compose this
   2281 // text pattern.
   2282 CacheBuilder::FoundState CacheBuilder::FindPartialEMail(const UChar* chars, unsigned length,
   2283     FindState* s)
   2284 {
   2285     // the following tables were generated by tests/browser/focusNavigation/BrowserDebug.cpp
   2286     // hand-edit at your own risk
   2287     static const int domainTwoLetter[] = {
   2288         0x02df797c,  // a followed by: [cdefgilmnoqrstuwxz]
   2289         0x036e73fb,  // b followed by: [abdefghijmnorstvwyz]
   2290         0x03b67ded,  // c followed by: [acdfghiklmnorsuvxyz]
   2291         0x02005610,  // d followed by: [ejkmoz]
   2292         0x001e00d4,  // e followed by: [ceghrstu]
   2293         0x00025700,  // f followed by: [ijkmor]
   2294         0x015fb9fb,  // g followed by: [abdefghilmnpqrstuwy]
   2295         0x001a3400,  // h followed by: [kmnrtu]
   2296         0x000f7818,  // i followed by: [delmnoqrst]
   2297         0x0000d010,  // j followed by: [emop]
   2298         0x0342b1d0,  // k followed by: [eghimnprwyz]
   2299         0x013e0507,  // l followed by: [abcikrstuvy]
   2300         0x03fffccd,  // m followed by: [acdghklmnopqrstuvwxyz]
   2301         0x0212c975,  // n followed by: [acefgilopruz]
   2302         0x00001000,  // o followed by: [m]
   2303         0x014e3cf1,  // p followed by: [aefghklmnrstwy]
   2304         0x00000001,  // q followed by: [a]
   2305         0x00504010,  // r followed by: [eouw]
   2306         0x032a7fdf,  // s followed by: [abcdeghijklmnortvyz]
   2307         0x026afeec,  // t followed by: [cdfghjklmnoprtvwz]
   2308         0x03041441,  // u followed by: [agkmsyz]
   2309         0x00102155,  // v followed by: [aceginu]
   2310         0x00040020,  // w followed by: [fs]
   2311         0x00000000,  // x
   2312         0x00180010,  // y followed by: [etu]
   2313         0x00401001,  // z followed by: [amw]
   2314     };
   2315 
   2316     static char const* const longDomainNames[] = {
   2317         "\x03" "ero" "\x03" "rpa",  // aero, arpa
   2318         "\x02" "iz",  // biz
   2319         "\x02" "at" "\x02" "om" "\x03" "oop",  // cat, com, coop
   2320         NULL,  // d
   2321         "\x02" "du",  // edu
   2322         NULL,  // f
   2323         "\x02" "ov",  // gov
   2324         NULL,  // h
   2325         "\x03" "nfo" "\x02" "nt",  // info, int
   2326         "\x03" "obs",  // jobs
   2327         NULL,  // k
   2328         NULL,  // l
   2329         "\x02" "il" "\x03" "obi" "\x05" "useum",  // mil, mobi, museum
   2330         "\x03" "ame" "\x02" "et",  // name, net
   2331         "\x02" "rg",  // , org
   2332         "\x02" "ro",  // pro
   2333         NULL,  // q
   2334         NULL,  // r
   2335         NULL,  // s
   2336         "\x05" "ravel",  // travel
   2337         NULL,  // u
   2338         NULL,  // v
   2339         NULL,  // w
   2340         NULL,  // x
   2341         NULL,  // y
   2342         NULL,  // z
   2343     };
   2344 
   2345     const UChar* start = chars;
   2346     const UChar* end = chars + length;
   2347     while (chars < end) {
   2348         UChar ch = *chars++;
   2349         if (ch != '@')
   2350             continue;
   2351         const UChar* atLocation = chars - 1;
   2352         // search for domain
   2353         ch = *chars++ | 0x20; // convert uppercase to lower
   2354         if (ch < 'a' || ch > 'z')
   2355             continue;
   2356         while (chars < end) {
   2357             ch = *chars++;
   2358             if (IsDomainChar(ch) == false)
   2359                 goto nextAt;
   2360             if (ch != '.')
   2361                 continue;
   2362             UChar firstLetter = *chars++ | 0x20; // first letter of the domain
   2363             if (chars >= end)
   2364                 return FOUND_NONE; // only one letter; must be at least two
   2365             firstLetter -= 'a';
   2366             if (firstLetter > 'z' - 'a')
   2367                 continue; // non-letter followed '.'
   2368             int secondLetterMask = domainTwoLetter[firstLetter];
   2369             ch = *chars | 0x20; // second letter of the domain
   2370             ch -= 'a';
   2371             if (ch >= 'z' - 'a')
   2372                 continue;
   2373             bool secondMatch = (secondLetterMask & 1 << ch) != 0;
   2374             const char* wordMatch = longDomainNames[firstLetter];
   2375             int wordIndex = 0;
   2376             while (wordMatch != NULL) {
   2377                 int len = *wordMatch++;
   2378                 char match;
   2379                 do {
   2380                     match = wordMatch[wordIndex];
   2381                     if (match < 0x20)
   2382                         goto foundDomainStart;
   2383                     if (chars[wordIndex] != match)
   2384                         break;
   2385                     wordIndex++;
   2386                 } while (true);
   2387                 wordMatch += len;
   2388                 if (*wordMatch == '\0')
   2389                     break;
   2390                 wordIndex = 0;
   2391             }
   2392             if (secondMatch) {
   2393                 wordIndex = 1;
   2394         foundDomainStart:
   2395                 chars += wordIndex;
   2396                 if (chars < end) {
   2397                     ch = *chars;
   2398                     if (ch != '.') {
   2399                         if (IsDomainChar(ch))
   2400                             goto nextDot;
   2401                     } else if (chars + 1 < end && IsDomainChar(chars[1]))
   2402                         goto nextDot;
   2403                 }
   2404                 // found domain. Search backwards from '@' for beginning of email address
   2405                 s->mEndResult = chars - start;
   2406                 chars = atLocation;
   2407                 if (chars <= start)
   2408                     goto nextAt;
   2409                 ch = *--chars;
   2410                 if (ch == '.')
   2411                     goto nextAt; // mailbox can't end in period
   2412                 do {
   2413                     if (IsMailboxChar(ch) == false) {
   2414                         chars++;
   2415                         break;
   2416                     }
   2417                     if (chars == start)
   2418                         break;
   2419                     ch = *--chars;
   2420                 } while (true);
   2421                 UChar firstChar = *chars;
   2422                 if (firstChar == '.' || firstChar == '@') // mailbox can't start with period or be empty
   2423                     goto nextAt;
   2424                 s->mStartResult = chars - start;
   2425                 return FOUND_COMPLETE;
   2426             }
   2427     nextDot:
   2428             ;
   2429         }
   2430 nextAt:
   2431         chars = atLocation + 1;
   2432     }
   2433     return FOUND_NONE;
   2434 }
   2435 
   2436 #define PHONE_PATTERN "(200) /-.\\ 100 -. 0000" // poor man's regex: parens optional, any one of punct, digit smallest allowed
   2437 
   2438 CacheBuilder::FoundState CacheBuilder::FindPartialNumber(const UChar* chars, unsigned length,
   2439     FindState* s)
   2440 {
   2441     char* pattern = s->mPattern;
   2442     UChar* store = s->mStorePtr;
   2443     const UChar* start = chars;
   2444     const UChar* end = chars + length;
   2445     const UChar* lastDigit = NULL;
   2446     do {
   2447         bool initialized = s->mInitialized;
   2448         while (chars < end) {
   2449             if (initialized == false) {
   2450                 s->mBackTwo = s->mBackOne;
   2451                 s->mBackOne = s->mCurrent;
   2452             }
   2453             UChar ch = s->mCurrent = *chars;
   2454             do {
   2455                 char patternChar = *pattern;
   2456                 switch (patternChar) {
   2457                     case '2':
   2458                             if (initialized == false) {
   2459                                 s->mStartResult = chars - start;
   2460                                 initialized = true;
   2461                             }
   2462                     case '0':
   2463                     case '1':
   2464                         if (ch < patternChar || ch > '9')
   2465                             goto resetPattern;
   2466                         *store++ = ch;
   2467                         pattern++;
   2468                         lastDigit = chars;
   2469                         goto nextChar;
   2470                     case '\0':
   2471                         if (WTF::isASCIIDigit(ch) == false) {
   2472                             *store = '\0';
   2473                             goto checkMatch;
   2474                         }
   2475                         goto resetPattern;
   2476                     case ' ':
   2477                         if (ch == patternChar)
   2478                             goto nextChar;
   2479                         break;
   2480                     case '(':
   2481                         if (ch == patternChar) {
   2482                             s->mStartResult = chars - start;
   2483                             initialized = true;
   2484                             s->mOpenParen = true;
   2485                         }
   2486                         goto commonPunctuation;
   2487                     case ')':
   2488                         if ((ch == patternChar) ^ s->mOpenParen)
   2489                             goto resetPattern;
   2490                     default:
   2491                     commonPunctuation:
   2492                         if (ch == patternChar) {
   2493                             pattern++;
   2494                             goto nextChar;
   2495                         }
   2496                 }
   2497             } while (++pattern); // never false
   2498     nextChar:
   2499             chars++;
   2500         }
   2501         break;
   2502 resetPattern:
   2503         if (s->mContinuationNode)
   2504             return FOUND_NONE;
   2505         FindResetNumber(s);
   2506         pattern = s->mPattern;
   2507         store = s->mStorePtr;
   2508     } while (++chars < end);
   2509 checkMatch:
   2510     if (WTF::isASCIIDigit(s->mBackOne != '1' ? s->mBackOne : s->mBackTwo))
   2511         return FOUND_NONE;
   2512     *store = '\0';
   2513     s->mStorePtr = store;
   2514     s->mPattern = pattern;
   2515     s->mEndResult = lastDigit - start + 1;
   2516     char pState = pattern[0];
   2517     return pState == '\0' ? FOUND_COMPLETE : pState == '(' || (WTF::isASCIIDigit(pState) && WTF::isASCIIDigit(pattern[-1])) ?
   2518         FOUND_NONE : FOUND_PARTIAL;
   2519 }
   2520 
   2521 CacheBuilder::FoundState CacheBuilder::FindPhoneNumber(const UChar* chars, unsigned length,
   2522     int* start, int* end)
   2523 {
   2524     FindState state;
   2525     FindReset(&state);
   2526     FoundState result = FindPartialNumber(chars, length, &state);
   2527     *start = state.mStartResult;
   2528     *end = state.mEndResult;
   2529     return result;
   2530 }
   2531 
   2532 void CacheBuilder::FindReset(FindState* state)
   2533 {
   2534     memset(state, 0, sizeof(FindState));
   2535     state->mCurrent = ' ';
   2536     FindResetNumber(state);
   2537 }
   2538 
   2539 void CacheBuilder::FindResetNumber(FindState* state)
   2540 {
   2541     state->mOpenParen = false;
   2542     state->mPattern = (char*) PHONE_PATTERN;
   2543     state->mStorePtr = state->mStore;
   2544 }
   2545 
   2546 IntRect CacheBuilder::getAreaRect(const HTMLAreaElement* area)
   2547 {
   2548     Node* node = area->document();
   2549     while ((node = node->traverseNextNode()) != NULL) {
   2550         RenderObject* renderer = node->renderer();
   2551         if (renderer && renderer->isRenderImage()) {
   2552             RenderImage* image = static_cast<RenderImage*>(renderer);
   2553             HTMLMapElement* map = image->imageMap();
   2554             if (map) {
   2555                 Node* n;
   2556                 for (n = map->firstChild(); n;
   2557                         n = n->traverseNextNode(map)) {
   2558                     if (n == area) {
   2559                         if (area->isDefault())
   2560                             return image->absoluteBoundingBoxRect();
   2561                         return area->computeRect(image);
   2562                     }
   2563                 }
   2564             }
   2565         }
   2566     }
   2567     return IntRect();
   2568 }
   2569 
   2570 void CacheBuilder::GetGlobalOffset(Node* node, int* x, int * y)
   2571 {
   2572     GetGlobalOffset(node->document()->frame(), x, y);
   2573 }
   2574 
   2575 void CacheBuilder::GetGlobalOffset(Frame* frame, int* x, int* y)
   2576 {
   2577 //    TIMER_PROBE(__FUNCTION__);
   2578     ASSERT(x);
   2579     ASSERT(y);
   2580     *x = 0;
   2581     *y = 0;
   2582     if (!frame->view())
   2583         return;
   2584     Frame* parent;
   2585     while ((parent = frame->tree()->parent()) != NULL) {
   2586         const WebCore::IntRect& rect = frame->view()->platformWidget()->getBounds();
   2587         *x += rect.x();
   2588         *y += rect.y();
   2589         frame = parent;
   2590     }
   2591  //   TIMER_PROBE_END();
   2592 }
   2593 
   2594 Frame* CacheBuilder::HasFrame(Node* node)
   2595 {
   2596     RenderObject* renderer = node->renderer();
   2597     if (renderer == NULL)
   2598         return NULL;
   2599     if (renderer->isWidget() == false)
   2600         return NULL;
   2601     Widget* widget = static_cast<RenderWidget*>(renderer)->widget();
   2602     if (widget == NULL)
   2603         return NULL;
   2604     if (widget->isFrameView() == false)
   2605         return NULL;
   2606     return static_cast<FrameView*>(widget)->frame();
   2607 }
   2608 
   2609 bool CacheBuilder::HasOverOrOut(Node* node)
   2610 {
   2611     // eventNames are thread-local data, I avoid using 'static' variable here.
   2612     AtomicString eventTypes[2] = {
   2613         eventNames().mouseoverEvent,
   2614         eventNames().mouseoutEvent
   2615     };
   2616 
   2617     return NodeHasEventListeners(node, eventTypes, 2);
   2618 }
   2619 
   2620 bool CacheBuilder::HasTriggerEvent(Node* node)
   2621 {
   2622     AtomicString eventTypes[5] = {
   2623         eventNames().clickEvent,
   2624         eventNames().mousedownEvent,
   2625         eventNames().mouseupEvent,
   2626         eventNames().keydownEvent,
   2627         eventNames().keyupEvent
   2628     };
   2629 
   2630     return NodeHasEventListeners(node, eventTypes, 5);
   2631 }
   2632 
   2633 // #define EMAIL_PATTERN "x (at) y.d" // where 'x' is letters, numbers, and '-', '.', '_' ; 'y' is 'x' without the underscore, and 'd' is a valid domain
   2634 //  - 0x2D . 0x2E 0-9 0x30-39 A-Z 0x41-5A  _ 0x5F a-z 0x61-7A
   2635 
   2636 bool CacheBuilder::IsDomainChar(UChar ch)
   2637 {
   2638     static const unsigned body[] = {0x03ff6000, 0x07fffffe, 0x07fffffe}; // 0-9 . - A-Z a-z
   2639     ch -= 0x20;
   2640     if (ch > 'z' - 0x20)
   2641         return false;
   2642     return (body[ch >> 5] & 1 << (ch & 0x1f)) != 0;
   2643 }
   2644 
   2645 bool CacheBuilder::isFocusableText(NodeWalk* walk, bool more, Node* node,
   2646     CachedNodeType* type, String* exported) const
   2647 {
   2648     Text* textNode = static_cast<Text*>(node);
   2649     StringImpl* string = textNode->dataImpl();
   2650     const UChar* baseChars = string->characters();
   2651 //    const UChar* originalBase = baseChars;
   2652     int length = string->length();
   2653     int index = 0;
   2654     while (index < length && isUnicodeSpace(baseChars[index]))
   2655         index++;
   2656     if (index >= length)
   2657         return false;
   2658     if (more == false) {
   2659         walk->mStart = 0;
   2660         walk->mEnd = 0;
   2661         walk->mFinalNode = node;
   2662         walk->mLastInline = NULL;
   2663     }
   2664     // starting with this node, search forward for email, phone number, and address
   2665     // if any of the three is found, track it so that the remaining can be looked for later
   2666     FoundState state = FOUND_NONE;
   2667     RenderText* renderer = (RenderText*) node->renderer();
   2668     bool foundBetter = false;
   2669     InlineTextBox* baseInline = walk->mLastInline != NULL ? walk->mLastInline :
   2670         renderer->firstTextBox();
   2671     if (baseInline == NULL)
   2672         return false;
   2673     int start = walk->mEnd;
   2674     InlineTextBox* saveInline;
   2675     int baseStart, firstStart = start;
   2676     saveInline = baseInline;
   2677     baseStart = start;
   2678     for (CachedNodeType checkType = ADDRESS_CACHEDNODETYPE;
   2679         checkType <= PHONE_CACHEDNODETYPE;
   2680         checkType = static_cast<CachedNodeType>(checkType + 1))
   2681     {
   2682         if ((1 << (checkType - 1) & mAllowableTypes) == 0)
   2683             continue;
   2684         InlineTextBox* inlineTextBox = baseInline;
   2685         FindState findState;
   2686         FindReset(&findState);
   2687         start = baseStart;
   2688         if (checkType == ADDRESS_CACHEDNODETYPE) {
   2689             findState.mBases[0] = baseChars;
   2690             findState.mWords[0] = baseChars + start;
   2691             findState.mStarts[0] = baseChars + start;
   2692         }
   2693         Node* lastPartialNode = NULL;
   2694         int lastPartialEnd = -1;
   2695         bool lastPartialMore = false;
   2696         bool firstPartial = true;
   2697         InlineTextBox* lastPartialInline = NULL;
   2698         do {
   2699             do {
   2700                 const UChar* chars = baseChars + start;
   2701                 length = inlineTextBox == NULL ? 0 :
   2702                     inlineTextBox->end() - start + 1;
   2703                 bool wasInitialized = findState.mInitialized;
   2704                 switch (checkType) {
   2705                     case ADDRESS_CACHEDNODETYPE:
   2706                         state = FindPartialAddress(baseChars, chars, length, &findState);
   2707                     break;
   2708                     case EMAIL_CACHEDNODETYPE:
   2709                         state = FindPartialEMail(chars, length, &findState);
   2710                     break;
   2711                     case PHONE_CACHEDNODETYPE:
   2712                         state = FindPartialNumber(chars, length, &findState);
   2713                     break;
   2714                     default:
   2715                         ASSERT(0);
   2716                 }
   2717                 findState.mInitialized = state != FOUND_NONE;
   2718                 if (wasInitialized != findState.mInitialized)
   2719                     firstStart = start;
   2720                 if (state == FOUND_PARTIAL) {
   2721                     lastPartialNode = node;
   2722                     lastPartialEnd = findState.mEndResult + start;
   2723                     lastPartialMore = firstPartial &&
   2724                         lastPartialEnd < (int) string->length();
   2725                     firstPartial = false;
   2726                     lastPartialInline = inlineTextBox;
   2727                     findState.mContinuationNode = true;
   2728                 } else if (state == FOUND_COMPLETE) {
   2729                     if (foundBetter == false || walk->mStart > findState.mStartResult) {
   2730                         walk->mStart = findState.mStartResult + firstStart;
   2731                         if (findState.mEndResult > 0) {
   2732                             walk->mFinalNode = node;
   2733                             walk->mEnd = findState.mEndResult + start;
   2734                             walk->mMore = node == textNode &&
   2735                                 walk->mEnd < (int) string->length();
   2736                             walk->mLastInline = inlineTextBox;
   2737                         } else {
   2738                             walk->mFinalNode = lastPartialNode;
   2739                             walk->mEnd = lastPartialEnd;
   2740                             walk->mMore = lastPartialMore;
   2741                             walk->mLastInline = lastPartialInline;
   2742                         }
   2743                         *type = checkType;
   2744                         if (checkType == PHONE_CACHEDNODETYPE) {
   2745                             const UChar* store = findState.mStore;
   2746                             *exported = String(store);
   2747                         } else {
   2748                             Node* temp = textNode;
   2749                             length = 1;
   2750                             start = walk->mStart;
   2751                             exported->truncate(0);
   2752                             do {
   2753                                 Text* tempText = static_cast<Text*>(temp);
   2754                                 StringImpl* string = tempText->dataImpl();
   2755                                 int end = tempText == walk->mFinalNode ?
   2756                                     walk->mEnd : string->length();
   2757                                 exported->append(String(string->substring(
   2758                                     start, end - start)));
   2759                                 ASSERT(end > start);
   2760                                 length += end - start + 1;
   2761                                 if (temp == walk->mFinalNode)
   2762                                     break;
   2763                                 start = 0;
   2764                                 do {
   2765                                     temp = temp->traverseNextNode();
   2766                                     ASSERT(temp);
   2767                                 } while (temp->isTextNode() == false);
   2768                                 // add a space in between text nodes to avoid
   2769                                 // words collapsing together
   2770                                 exported->append(" ");
   2771                             } while (true);
   2772                         }
   2773                         foundBetter = true;
   2774                     }
   2775                     goto tryNextCheckType;
   2776                 } else if (findState.mContinuationNode)
   2777                     break;
   2778                 if (inlineTextBox == NULL)
   2779                     break;
   2780                 inlineTextBox = inlineTextBox->nextTextBox();
   2781                 if (inlineTextBox == NULL)
   2782                     break;
   2783                 start = inlineTextBox->start();
   2784                 if (state == FOUND_PARTIAL && node == textNode)
   2785                     findState.mContinuationNode = false;
   2786             } while (true);
   2787             if (state == FOUND_NONE)
   2788                 break;
   2789             // search for next text node, if any
   2790             Text* nextNode;
   2791             do {
   2792                 do {
   2793                     do {
   2794                         if (node)
   2795                             node = node->traverseNextNode();
   2796                         if (node == NULL || node->hasTagName(HTMLNames::aTag)
   2797                                 || node->hasTagName(HTMLNames::inputTag)
   2798                                 || node->hasTagName(HTMLNames::textareaTag)) {
   2799                             if (state == FOUND_PARTIAL &&
   2800                                     checkType == ADDRESS_CACHEDNODETYPE &&
   2801                                     findState.mProgress == ZIP_CODE &&
   2802                                     findState.mNumberCount == 0) {
   2803                                 baseChars = NULL;
   2804                                 inlineTextBox = NULL;
   2805                                 start = 0;
   2806                                 findState.mProgress = FIND_STREET;
   2807                                 goto finalNode;
   2808                             }
   2809                             goto tryNextCheckType;
   2810                         }
   2811                     } while (node->isTextNode() == false);
   2812                     nextNode = static_cast<Text*>(node);
   2813                     renderer = (RenderText*) nextNode->renderer();
   2814                 } while (renderer == NULL);
   2815                 baseInline = renderer->firstTextBox();
   2816             } while (baseInline == NULL);
   2817             string = nextNode->dataImpl();
   2818             baseChars = string->characters();
   2819             inlineTextBox = baseInline;
   2820             start = inlineTextBox->start();
   2821         finalNode:
   2822             findState.mEndResult = 0;
   2823         } while (true);
   2824 tryNextCheckType:
   2825         node = textNode;
   2826         baseInline = saveInline;
   2827         string = textNode->dataImpl();
   2828         baseChars = string->characters();
   2829     }
   2830     if (foundBetter) {
   2831         CachedNodeType temp = *type;
   2832         switch (temp) {
   2833             case ADDRESS_CACHEDNODETYPE: {
   2834                 static const char geoString[] = "geo:0,0?q=";
   2835                 exported->insert(String(geoString), 0);
   2836                 int index = sizeof(geoString) - 1;
   2837                 String escapedComma("%2C");
   2838                 while ((index = exported->find(',', index)) >= 0)
   2839                     exported->replace(index, 1, escapedComma);
   2840                 } break;
   2841             case EMAIL_CACHEDNODETYPE: {
   2842                 String encoded = WebCore::encodeWithURLEscapeSequences(*exported);
   2843                 exported->swap(encoded);
   2844                 exported->insert(WTF::String("mailto:"), 0);
   2845                 } break;
   2846             case PHONE_CACHEDNODETYPE:
   2847                 exported->insert(WTF::String("tel:"), 0);
   2848                 break;
   2849             default:
   2850                 break;
   2851         }
   2852         return true;
   2853     }
   2854 noTextMatch:
   2855     walk->reset();
   2856     return false;
   2857 }
   2858 
   2859 bool CacheBuilder::IsMailboxChar(UChar ch)
   2860 {
   2861     // According to http://en.wikipedia.org/wiki/Email_address
   2862     // ! # $ % & ' * + - . / 0-9 = ?
   2863     // A-Z ^ _
   2864     // ` a-z { | } ~
   2865     static const unsigned body[] = {0xa3ffecfa, 0xc7fffffe, 0x7fffffff};
   2866     ch -= 0x20;
   2867     if (ch > '~' - 0x20)
   2868         return false;
   2869     return (body[ch >> 5] & 1 << (ch & 0x1f)) != 0;
   2870 }
   2871 
   2872 bool CacheBuilder::setData(CachedFrame* cachedFrame)
   2873 {
   2874     Frame* frame = FrameAnd(this);
   2875     Document* doc = frame->document();
   2876     if (doc == NULL)
   2877         return false;
   2878     RenderObject* renderer = doc->renderer();
   2879     if (renderer == NULL)
   2880         return false;
   2881     RenderLayer* layer = renderer->enclosingLayer();
   2882     if (layer == NULL)
   2883         return false;
   2884     if (!frame->view())
   2885         return false;
   2886     int x, y;
   2887     GetGlobalOffset(frame, &x, &y);
   2888     WebCore::IntRect viewBounds = frame->view()->platformWidget()->getBounds();
   2889     if ((x | y) != 0)
   2890         viewBounds.setLocation(WebCore::IntPoint(x, y));
   2891     cachedFrame->setLocalViewBounds(viewBounds);
   2892     cachedFrame->setContentsSize(layer->scrollWidth(), layer->scrollHeight());
   2893     if (cachedFrame->childCount() == 0)
   2894         return true;
   2895     CachedFrame* lastCachedFrame = cachedFrame->lastChild();
   2896     cachedFrame = cachedFrame->firstChild();
   2897     do {
   2898         CacheBuilder* cacheBuilder = Builder((Frame* )cachedFrame->framePointer());
   2899         cacheBuilder->setData(cachedFrame);
   2900     } while (cachedFrame++ != lastCachedFrame);
   2901     return true;
   2902 }
   2903 
   2904 #if USE(ACCELERATED_COMPOSITING)
   2905 void CacheBuilder::TrackLayer(WTF::Vector<LayerTracker>& layerTracker,
   2906     RenderObject* nodeRenderer, Node* lastChild, int offsetX, int offsetY)
   2907 {
   2908     RenderLayer* layer = nodeRenderer->enclosingLayer();
   2909     RenderLayerBacking* back = layer->backing();
   2910     if (!back)
   2911         return;
   2912     GraphicsLayer* grLayer = back->graphicsLayer();
   2913     if (back->hasContentsLayer())
   2914         grLayer = back->foregroundLayer();
   2915     if (!grLayer)
   2916         return;
   2917     LayerAndroid* aLayer = grLayer->platformLayer();
   2918     if (!aLayer)
   2919         return;
   2920     IntPoint scroll(layer->scrollXOffset(), layer->scrollYOffset());
   2921 #if ENABLE(ANDROID_OVERFLOW_SCROLL)
   2922     // If this is an overflow element, track the content layer.
   2923     if (layer->hasOverflowScroll() && aLayer->getChild(0))
   2924         aLayer = aLayer->getChild(0)->getChild(0);
   2925     if (!aLayer)
   2926         return;
   2927     // Prevent a crash when scrolling a layer that does not have a parent.
   2928     if (layer->stackingContext())
   2929         layer->scrollToOffset(0, 0);
   2930 #endif
   2931     layerTracker.grow(layerTracker.size() + 1);
   2932     LayerTracker& indexTracker = layerTracker.last();
   2933     indexTracker.mLayer = aLayer;
   2934     indexTracker.mRenderLayer = layer;
   2935     indexTracker.mBounds = enclosingIntRect(aLayer->bounds());
   2936     // Use the absolute location of the layer as the bounds location.  This
   2937     // provides the original offset of nodes in the layer so that we can
   2938     // translate nodes between their original location and the layer's new
   2939     // location.
   2940     indexTracker.mBounds.setLocation(layer->absoluteBoundingBox().location());
   2941     indexTracker.mBounds.move(offsetX, offsetY);
   2942     indexTracker.mScroll = scroll;
   2943     indexTracker.mLastChild = OneAfter(lastChild);
   2944     DBG_NAV_LOGD("layer=%p [%d] bounds=(%d,%d,w=%d,h=%d)", aLayer,
   2945         aLayer->uniqueId(), indexTracker.mBounds.x(), indexTracker.mBounds.y(),
   2946         indexTracker.mBounds.width(), indexTracker.mBounds.height());
   2947 }
   2948 #endif
   2949 
   2950 bool CacheBuilder::validNode(Frame* startFrame, void* matchFrame,
   2951         void* matchNode)
   2952 {
   2953     if (matchFrame == startFrame) {
   2954         if (matchNode == NULL)
   2955             return true;
   2956         Node* node = startFrame->document();
   2957         while (node != NULL) {
   2958             if (node == matchNode) {
   2959                 const IntRect& rect = node->hasTagName(HTMLNames::areaTag) ?
   2960                     getAreaRect(static_cast<HTMLAreaElement*>(node)) : node->getRect();
   2961                 // Consider nodes with empty rects that are not at the origin
   2962                 // to be valid, since news.google.com has valid nodes like this
   2963                 if (rect.x() == 0 && rect.y() == 0 && rect.isEmpty())
   2964                     return false;
   2965                 return true;
   2966             }
   2967             node = node->traverseNextNode();
   2968         }
   2969         DBG_NAV_LOGD("frame=%p valid node=%p invalid\n", matchFrame, matchNode);
   2970         return false;
   2971     }
   2972     Frame* child = startFrame->tree()->firstChild();
   2973     while (child) {
   2974         bool result = validNode(child, matchFrame, matchNode);
   2975         if (result)
   2976             return result;
   2977         child = child->tree()->nextSibling();
   2978     }
   2979 #if DEBUG_NAV_UI
   2980     if (startFrame->tree()->parent() == NULL)
   2981         DBG_NAV_LOGD("frame=%p node=%p false\n", matchFrame, matchNode);
   2982 #endif
   2983     return false;
   2984 }
   2985 
   2986 static int Area(const IntRect& rect)
   2987 {
   2988     return rect.width() * rect.height();
   2989 }
   2990 
   2991 bool CacheBuilder::AddPartRect(IntRect& bounds, int x, int y,
   2992     WTF::Vector<IntRect>* result, IntRect* focusBounds)
   2993 {
   2994     if (bounds.isEmpty())
   2995         return true;
   2996     bounds.move(x, y);
   2997     if (bounds.maxX() <= 0 || bounds.maxY() <= 0)
   2998         return true;
   2999     IntRect* work = result->begin() - 1;
   3000     IntRect* end = result->end();
   3001     while (++work < end) {
   3002         if (work->contains(bounds))
   3003             return true;
   3004         if (bounds.contains(*work)) {
   3005             *work = bounds;
   3006             focusBounds->unite(bounds);
   3007             return true;
   3008         }
   3009         if ((bounds.x() != work->x() || bounds.width() != work->width()) &&
   3010                (bounds.y() != work->y() || bounds.height() != work->height()))
   3011             continue;
   3012         IntRect test = *work;
   3013         test.unite(bounds);
   3014         if (Area(test) > Area(*work) + Area(bounds))
   3015             continue;
   3016         *work = test;
   3017         focusBounds->unite(bounds);
   3018         return true;
   3019     }
   3020     if (result->size() >= MAXIMUM_FOCUS_RING_COUNT)
   3021         return false;
   3022     result->append(bounds);
   3023     if (focusBounds->isEmpty())
   3024         *focusBounds = bounds;
   3025     else
   3026         focusBounds->unite(bounds);
   3027     return true;
   3028 }
   3029 
   3030 bool CacheBuilder::ConstructPartRects(Node* node, const IntRect& bounds,
   3031     IntRect* focusBounds, int x, int y, WTF::Vector<IntRect>* result,
   3032     int* imageCountPtr)
   3033 {
   3034     WTF::Vector<ClipColumnTracker> clipTracker(1);
   3035     ClipColumnTracker* baseTracker = clipTracker.data(); // sentinel
   3036     bzero(baseTracker, sizeof(ClipColumnTracker));
   3037     if (node->hasChildNodes() && node->hasTagName(HTMLNames::buttonTag) == false
   3038             && node->hasTagName(HTMLNames::selectTag) == false) {
   3039         // collect all text rects from first to last child
   3040         Node* test = node->firstChild();
   3041         Node* last = NULL;
   3042         Node* prior = node;
   3043         while ((prior = prior->lastChild()) != NULL)
   3044             last = prior;
   3045         ASSERT(last != NULL);
   3046         bool nodeIsAnchor = node->hasTagName(HTMLNames::aTag);
   3047         do {
   3048             do {
   3049                 const ClipColumnTracker* lastClip = &clipTracker.last();
   3050                 if (test != lastClip->mLastChild)
   3051                     break;
   3052                 clipTracker.removeLast();
   3053             } while (true);
   3054             RenderObject* renderer = test->renderer();
   3055             if (renderer == NULL)
   3056                 continue;
   3057             EVisibility vis = renderer->style()->visibility();
   3058             if (vis == HIDDEN)
   3059                 continue;
   3060             bool hasClip = renderer->hasOverflowClip();
   3061             size_t clipIndex = clipTracker.size();
   3062             IntRect clipBounds = IntRect(0, 0, INT_MAX, INT_MAX);
   3063             if (hasClip || --clipIndex > 0) {
   3064                 clipBounds = hasClip ? renderer->absoluteBoundingBoxRect() :
   3065                     clipTracker.at(clipIndex).mBounds; // x, y fixup done by ConstructTextRect
   3066             }
   3067             if (test->isTextNode()) {
   3068                 RenderText* renderText = (RenderText*) renderer;
   3069                 InlineTextBox *textBox = renderText->firstTextBox();
   3070                 if (textBox == NULL)
   3071                     continue;
   3072                 if (ConstructTextRect((Text*) test, textBox, 0, INT_MAX,
   3073                         x, y, focusBounds, clipBounds, result) == false) {
   3074                     return false;
   3075                 }
   3076                 continue;
   3077             }
   3078             if (test->hasTagName(HTMLNames::imgTag)) {
   3079                 IntRect bounds = test->getRect();
   3080                 bounds.intersect(clipBounds);
   3081                 if (AddPartRect(bounds, x, y, result, focusBounds) == false)
   3082                     return false;
   3083                 *imageCountPtr += 1;
   3084                 continue;
   3085             }
   3086             if (hasClip == false) {
   3087                 if (nodeIsAnchor && test->hasTagName(HTMLNames::divTag)) {
   3088                     IntRect bounds = renderer->absoluteBoundingBoxRect();  // x, y fixup done by AddPartRect
   3089                     RenderBox* renderBox = static_cast<RenderBox*>(renderer);
   3090                     int left = bounds.x() + renderBox->paddingLeft() + renderBox->borderLeft();
   3091                     int top = bounds.y() + renderBox->paddingTop() + renderBox->borderTop();
   3092                     int right = bounds.maxX() - renderBox->paddingRight() - renderBox->borderRight();
   3093                     int bottom = bounds.maxY() - renderBox->paddingBottom() - renderBox->borderBottom();
   3094                     if (left >= right || top >= bottom)
   3095                         continue;
   3096                     bounds = IntRect(left, top, right - left, bottom - top);
   3097                     if (AddPartRect(bounds, x, y, result, focusBounds) == false)
   3098                         return false;
   3099                 }
   3100                 continue;
   3101             }
   3102             Node* lastChild = test->lastChild();
   3103             if (lastChild == NULL)
   3104                 continue;
   3105             clipTracker.grow(clipTracker.size() + 1);
   3106             ClipColumnTracker& clip = clipTracker.last();
   3107             clip.mBounds = renderer->absoluteBoundingBoxRect(); // x, y fixup done by ConstructTextRect
   3108             clip.mLastChild = OneAfter(lastChild);
   3109             clip.mNode = test;
   3110         } while (test != last && (test = test->traverseNextNode()) != NULL);
   3111     }
   3112     if (result->size() == 0 || focusBounds->width() < MINIMUM_FOCUSABLE_WIDTH
   3113             || focusBounds->height() < MINIMUM_FOCUSABLE_HEIGHT) {
   3114         if (bounds.width() < MINIMUM_FOCUSABLE_WIDTH)
   3115             return false;
   3116         if (bounds.height() < MINIMUM_FOCUSABLE_HEIGHT)
   3117             return false;
   3118         result->append(bounds);
   3119         *focusBounds = bounds;
   3120     }
   3121     return true;
   3122 }
   3123 
   3124 static inline bool isNotSpace(UChar c)
   3125 {
   3126     return c <= 0xA0 ? isUnicodeSpace(c) == false :
   3127         WTF::Unicode::direction(c) != WTF::Unicode::WhiteSpaceNeutral;
   3128 }
   3129 
   3130 bool CacheBuilder::ConstructTextRect(Text* textNode,
   3131     InlineTextBox* textBox, int start, int relEnd, int x, int y,
   3132     IntRect* focusBounds, const IntRect& clipBounds, WTF::Vector<IntRect>* result)
   3133 {
   3134     RenderText* renderText = (RenderText*) textNode->renderer();
   3135     EVisibility vis = renderText->style()->visibility();
   3136     StringImpl* string = textNode->dataImpl();
   3137     const UChar* chars = string->characters();
   3138     FloatPoint pt = renderText->localToAbsolute();
   3139     do {
   3140         int textBoxStart = textBox->start();
   3141         int textBoxEnd = textBoxStart + textBox->len();
   3142         if (textBoxEnd <= start)
   3143             continue;
   3144         if (textBoxEnd > relEnd)
   3145             textBoxEnd = relEnd;
   3146         IntRect bounds = textBox->selectionRect((int) pt.x(), (int) pt.y(),
   3147             start, textBoxEnd);
   3148         bounds.intersect(clipBounds);
   3149         if (bounds.isEmpty())
   3150             continue;
   3151         bool drawable = false;
   3152         for (int index = start; index < textBoxEnd; index++)
   3153             if ((drawable |= isNotSpace(chars[index])) != false)
   3154                 break;
   3155         if (drawable && vis != HIDDEN) {
   3156             if (AddPartRect(bounds, x, y, result, focusBounds) == false)
   3157                 return false;
   3158         }
   3159         if (textBoxEnd == relEnd)
   3160             break;
   3161     } while ((textBox = textBox->nextTextBox()) != NULL);
   3162     return true;
   3163 }
   3164 
   3165 bool CacheBuilder::ConstructTextRects(Text* node, int start,
   3166     Text* last, int end, int x, int y, IntRect* focusBounds,
   3167     const IntRect& clipBounds, WTF::Vector<IntRect>* result)
   3168 {
   3169     result->clear();
   3170     *focusBounds = IntRect(0, 0, 0, 0);
   3171     do {
   3172         RenderText* renderText = (RenderText*) node->renderer();
   3173         int relEnd = node == last ? end : renderText->textLength();
   3174         InlineTextBox *textBox = renderText->firstTextBox();
   3175         if (textBox != NULL) {
   3176             do {
   3177                 if ((int) textBox->end() >= start)
   3178                     break;
   3179             } while ((textBox = textBox->nextTextBox()) != NULL);
   3180             if (textBox && ConstructTextRect(node, textBox, start, relEnd,
   3181                     x, y, focusBounds, clipBounds, result) == false)
   3182                 return false;
   3183         }
   3184         start = 0;
   3185         do {
   3186             if (node == last)
   3187                 return true;
   3188             node = (Text*) node->traverseNextNode();
   3189             ASSERT(node != NULL);
   3190         } while (node->isTextNode() == false || node->renderer() == NULL);
   3191     } while (true);
   3192 }
   3193 
   3194 }
   3195