summaryrefslogtreecommitdiffstats
path: root/WebKit/android/nav
diff options
context:
space:
mode:
Diffstat (limited to 'WebKit/android/nav')
-rw-r--r--WebKit/android/nav/CacheBuilder.cpp209
-rw-r--r--WebKit/android/nav/CacheBuilder.h17
-rw-r--r--WebKit/android/nav/CachedColor.cpp58
-rw-r--r--WebKit/android/nav/CachedColor.h87
-rw-r--r--WebKit/android/nav/CachedFrame.cpp56
-rw-r--r--WebKit/android/nav/CachedFrame.h11
-rw-r--r--WebKit/android/nav/CachedInput.cpp9
-rw-r--r--WebKit/android/nav/CachedInput.h17
-rw-r--r--WebKit/android/nav/CachedLayer.cpp94
-rw-r--r--WebKit/android/nav/CachedLayer.h13
-rw-r--r--WebKit/android/nav/CachedNode.cpp12
-rw-r--r--WebKit/android/nav/CachedNode.h18
-rw-r--r--WebKit/android/nav/CachedNodeType.h4
-rw-r--r--WebKit/android/nav/CachedPrefix.h7
-rw-r--r--WebKit/android/nav/CachedRoot.cpp617
-rw-r--r--WebKit/android/nav/CachedRoot.h11
-rw-r--r--WebKit/android/nav/FindCanvas.cpp82
-rw-r--r--WebKit/android/nav/FindCanvas.h1
-rw-r--r--WebKit/android/nav/SelectText.cpp19
-rw-r--r--WebKit/android/nav/WebView.cpp507
20 files changed, 1416 insertions, 433 deletions
diff --git a/WebKit/android/nav/CacheBuilder.cpp b/WebKit/android/nav/CacheBuilder.cpp
index f69b23d..1d53721 100644
--- a/WebKit/android/nav/CacheBuilder.cpp
+++ b/WebKit/android/nav/CacheBuilder.cpp
@@ -26,6 +26,7 @@
#include "CachedPrefix.h"
#include "CachedNode.h"
#include "CachedRoot.h"
+#include "ColumnInfo.h"
#include "Document.h"
#include "EventListener.h"
#include "EventNames.h"
@@ -412,7 +413,7 @@ void CacheBuilder::Debug::groups() {
comma(scratch);
Element* element = static_cast<Element*>(node);
if (node->isElementNode() && element->hasID())
- wideString(element->getIDAttribute());
+ wideString(element->getIdAttribute());
else if (node->isTextNode()) {
#if 01 // set to one to abbreviate text that can be omitted from the address detection code
if (rect.isEmpty() && node->textContent().length() > 100) {
@@ -469,22 +470,50 @@ void CacheBuilder::Debug::groups() {
}
}
}
- count++;
- newLine();
-#if USE(ACCELERATED_COMPOSITING)
- if (renderer && layer) {
+ if (renderer) {
+ RenderStyle* style = renderer->style();
+ snprintf(scratch, sizeof(scratch), "// renderStyle:"
+ " visibility=%s hasBackGround=%d"
+ " tapHighlightColor().alpha()=0x%02x"
+ " isTransparent()=%s",
+ style->visibility() == HIDDEN ? "HIDDEN" : "VISIBLE",
+ renderer->hasBackground(), style->tapHighlightColor().alpha(),
+ renderer->isTransparent() ? "true" : "false");
+ newLine();
+ print(scratch);
+ RenderBlock* renderBlock = static_cast<RenderBlock*>(renderer);
+ if (renderer->isRenderBlock() && renderBlock->hasColumns()) {
+ const RenderBox* box = static_cast<RenderBox*>(renderer);
+ const IntRect& oRect = box->visibleOverflowRect();
+ snprintf(scratch, sizeof(scratch), "// renderBlock:"
+ " columnCount=%d columnGap=%d direction=%d"
+ " hasOverflowClip=%d overflow=(%d,%d,w=%d,h=%d)",
+ renderBlock->columnInfo()->columnCount(), renderBlock->columnGap(),
+ renderBlock->style()->direction(), renderer->hasOverflowClip(),
+ oRect.x(), oRect.y(), oRect.width(), oRect.height());
+ newLine();
+ print(scratch);
+ }
+ }
+ #if USE(ACCELERATED_COMPOSITING)
+ if (renderer && renderer->hasLayer()) {
+ RenderLayer* layer = toRenderBoxModelObject(renderer)->layer();
RenderLayerBacking* back = layer->backing();
GraphicsLayerAndroid* grLayer = static_cast
<GraphicsLayerAndroid*>(back ? back->graphicsLayer() : 0);
LayerAndroid* aLayer = grLayer ? grLayer->contentLayer() : 0;
const SkPicture* pict = aLayer ? aLayer->picture() : 0;
+ const IntRect& r = renderer->absoluteBoundingBoxRect();
snprintf(scratch, sizeof(scratch), "// layer:%p back:%p"
- " gLayer:%p aLayer:%p pict:%p", layer, back, grLayer,
- aLayer, pict);
- print(scratch);
+ " gLayer:%p aLayer:%p pict:%p r:(%d,%d,w=%d,h=%d)",
+ layer, back, grLayer, aLayer, pict, r.x(), r.y(),
+ r.width(), r.height());
newLine();
- }
-#endif
+ print(scratch);
+ }
+ #endif
+ count++;
+ newLine();
} while ((node = node->traverseNextNode()) != NULL);
DUMP_NAV_LOGD("}; // focusables = %d\n", count - 1);
DUMP_NAV_LOGD("\n");
@@ -553,7 +582,7 @@ void CacheBuilder::Debug::groups() {
mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex, ", %d, %d, %d",
0 /*textBox->spaceAdd()*/, textBox->start(), 0 /*textBox->textPos()*/);
mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex, ", %d, %d, %d, %d",
- textBox->x(), textBox->y(), textBox->width(), textBox->height());
+ textBox->x(), textBox->y(), textBox->logicalWidth(), textBox->logicalHeight());
int baseline = textBox->renderer()->style(textBox->isFirstLineStyle())->font().ascent();
mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex, ", %d }, // %d ",
baseline, ++rectIndex);
@@ -754,16 +783,18 @@ CacheBuilder::CacheBuilder()
}
void CacheBuilder::adjustForColumns(const ClipColumnTracker& track,
- CachedNode* node, IntRect* bounds)
+ CachedNode* node, IntRect* bounds, RenderBlock* renderer)
{
+ if (!renderer->hasColumns())
+ return;
int x = 0;
int y = 0;
int tx = track.mBounds.x();
int ty = track.mBounds.y();
int columnGap = track.mColumnGap;
- size_t limit = track.mColumns->size();
+ size_t limit = track.mColumnInfo->columnCount();
for (size_t index = 0; index < limit; index++) {
- IntRect column = track.mColumns->at(index);
+ IntRect column = renderer->columnRectAt(track.mColumnInfo, index);
column.move(tx, ty);
IntRect test = *bounds;
test.move(x, y);
@@ -841,6 +872,7 @@ bool CacheBuilder::AnyIsClick(Node* node)
void CacheBuilder::buildCache(CachedRoot* root)
{
Frame* frame = FrameAnd(this);
+ mPictureSetDisabled = false;
BuildFrame(frame, frame, root, (CachedFrame*) root);
root->finishInit(); // set up frame parent pointers, child pointers
setData((CachedFrame*) root);
@@ -878,7 +910,7 @@ static Node* OneAfter(Node* node)
static bool checkForPluginViewThatWantsFocus(RenderObject* renderer) {
if (renderer->isWidget()) {
Widget* widget = static_cast<RenderWidget*>(renderer)->widget();
- if (widget && (widget->isPluginView() || widget->isPluginWidget())) {
+ if (widget && (widget->isPluginView() || widget->isPluginViewBase())) {
// check if this plugin really wants key events (TODO)
return true;
}
@@ -888,7 +920,7 @@ static bool checkForPluginViewThatWantsFocus(RenderObject* renderer) {
#if USE(ACCELERATED_COMPOSITING)
static void AddLayer(CachedFrame* frame, size_t index, const IntPoint& location,
- int id)
+ const IntPoint& scroll, int id)
{
DBG_NAV_LOGD("frame=%p index=%d loc=(%d,%d) id=%d", frame, index,
location.x(), location.y(), id);
@@ -896,11 +928,41 @@ static void AddLayer(CachedFrame* frame, size_t index, const IntPoint& location,
cachedLayer.reset();
cachedLayer.setCachedNodeIndex(index);
cachedLayer.setOffset(location);
+ cachedLayer.setScrollOffset(scroll);
cachedLayer.setUniqueId(id);
frame->add(cachedLayer);
}
#endif
+static int FindColorIndex(WTF::Vector<CachedColor>& colorTracker,
+ const CachedColor& cachedColor)
+{
+ CachedColor* work = colorTracker.begin() - 1;
+ CachedColor* end = colorTracker.end();
+ while (++work < end) {
+ if (*work == cachedColor)
+ return work - colorTracker.begin();
+ }
+ int result = colorTracker.size();
+ colorTracker.grow(result + 1);
+ CachedColor& newColor = colorTracker.last();
+ newColor = cachedColor;
+ return result;
+}
+
+static void InitColor(CachedColor* color)
+{
+ color->setFillColor(RenderStyle::initialRingFillColor());
+ color->setInnerWidth(RenderStyle::initialRingInnerWidth());
+ color->setOuterWidth(RenderStyle::initialRingOuterWidth());
+ color->setOutset(RenderStyle::initialRingOutset());
+ color->setPressedInnerColor(RenderStyle::initialRingPressedInnerColor());
+ color->setPressedOuterColor(RenderStyle::initialRingPressedOuterColor());
+ color->setRadius(RenderStyle::initialRingRadius());
+ color->setSelectedInnerColor(RenderStyle::initialRingSelectedInnerColor());
+ color->setSelectedOuterColor(RenderStyle::initialRingSelectedOuterColor());
+}
+
// when new focus is found, push it's parent on a stack
// as long as more focii are found with the same (grand) parent, note it
// (which only requires retrieving the last parent on the stack)
@@ -928,6 +990,8 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame,
bzero(clipTracker.data(), sizeof(ClipColumnTracker));
WTF::Vector<TabIndexTracker> tabIndexTracker(1); // sentinel
bzero(tabIndexTracker.data(), sizeof(TabIndexTracker));
+ WTF::Vector<CachedColor> colorTracker(1);
+ InitColor(colorTracker.data());
#if DUMP_NAV_CACHE
char* frameNamePtr = cachedFrame->mDebug.mFrameName;
Builder(frame)->mDebug.frameName(frameNamePtr, frameNamePtr +
@@ -943,16 +1007,18 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame,
#if DUMP_NAV_CACHE
cachedParentNode.mDebug.mNodeIndex = nodeIndex;
#endif
+ cachedFrame->add(colorTracker[0]);
cachedFrame->add(cachedParentNode);
Node* node = parent;
int cacheIndex = 1;
+ int colorIndex = 0; // assume no special css ring colors
+ const void* lastStyleDataPtr = 0;
int textInputIndex = 0;
Node* focused = doc->focusedNode();
if (focused)
cachedRoot->setFocusBounds(focused->getRect());
int globalOffsetX, globalOffsetY;
GetGlobalOffset(frame, &globalOffsetX, &globalOffsetY);
- IntPoint bodyPos = IntPoint(0, 0);
while (walk.mMore || (node = node->traverseNextNode()) != NULL) {
#if DUMP_NAV_CACHE
nodeIndex++;
@@ -1028,21 +1094,25 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame,
RenderStyle* style = nodeRenderer->style();
if (style->visibility() == HIDDEN)
continue;
- isTransparent = style->hasBackground() == false;
+ isTransparent = nodeRenderer->hasBackground() == false;
#ifdef ANDROID_CSS_TAP_HIGHLIGHT_COLOR
hasCursorRing = style->tapHighlightColor().alpha() > 0;
#endif
#if USE(ACCELERATED_COMPOSITING)
if (nodeRenderer->hasLayer()) {
TrackLayer(layerTracker, nodeRenderer, lastChild,
- globalOffsetX - bodyPos.x(), globalOffsetY - bodyPos.y());
+ globalOffsetX, globalOffsetY);
size_t size = tracker.size();
- const LayerAndroid* layer = layerTracker.last().mLayer;
+ LayerAndroid* layer = layerTracker.last().mLayer;
if (layer) {
int id = layer->uniqueId();
- IntPoint loc = nodeRenderer->
- absoluteBoundingBoxRect().location();
+ const RenderLayer* renderLayer =
+ layerTracker.last().mRenderLayer;
+ IntPoint loc(SkScalarRound(layer->getPosition().fX),
+ SkScalarRound(layer->getPosition().fY));
loc.move(globalOffsetX, globalOffsetY);
+ IntPoint scroll(renderLayer->scrollXOffset(),
+ renderLayer->scrollYOffset());
// if this is a child of a CachedNode, add a layer
size_t limit = cachedFrame->layerCount() == 0 ? 0 :
cachedFrame->lastLayer()->cachedNodeIndex();
@@ -1058,7 +1128,7 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame,
CachedNode* trackedNode = cachedFrame->getIndex(index);
trackedNode->setIsInLayer(true);
trackedNode->setIsUnclipped(true);
- AddLayer(cachedFrame, index, loc, id);
+ AddLayer(cachedFrame, index, loc, scroll, id);
}
}
}
@@ -1077,11 +1147,12 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame,
TextDirection direction = LTR;
String exported;
CachedNodeType type = NORMAL_CACHEDNODETYPE;
+ CachedColor cachedColor;
CachedInput cachedInput;
IntRect bounds;
IntRect absBounds;
IntRect originalAbsBounds;
- WTF::Vector<IntRect>* columns = NULL;
+ ColumnInfo* columnInfo = NULL;
if (node->hasTagName(HTMLNames::areaTag)) {
type = AREA_CACHEDNODETYPE;
HTMLAreaElement* area = static_cast<HTMLAreaElement*>(node);
@@ -1102,9 +1173,16 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame,
originalAbsBounds = absBounds;
absBounds.move(globalOffsetX, globalOffsetY);
hasClip = nodeRenderer->hasOverflowClip();
+#if ENABLE(ANDROID_OVERFLOW_SCROLL)
+ if (nodeRenderer->hasLayer()) {
+ const LayerAndroid* layer = layerTracker.last().mLayer;
+ if (layer && layer->contentIsScrollable())
+ hasClip = false;
+ }
+#endif
- if (node->hasTagName(HTMLNames::bodyTag))
- bodyPos = originalAbsBounds.location();
+ if (node->hasTagName(HTMLNames::canvasTag))
+ mPictureSetDisabled = true;
if (checkForPluginViewThatWantsFocus(nodeRenderer)) {
bounds = absBounds;
isUnclipped = true;
@@ -1112,27 +1190,32 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame,
type = PLUGIN_CACHEDNODETYPE;
goto keepNode;
}
+ // Only use the root contentEditable element
+ if (node->isContentEditable() && !node->parent()->isContentEditable()) {
+ bounds = absBounds;
+ takesFocus = true;
+ type = CONTENT_EDITABLE_CACHEDNODETYPE;
+ goto keepNode;
+ }
if (nodeRenderer->isRenderBlock()) {
RenderBlock* renderBlock = (RenderBlock*) nodeRenderer;
if (renderBlock->hasColumns()) {
- columns = renderBlock->columnRects();
-#ifdef ANDROID_EXPOSE_COLUMN_GAP
+ columnInfo = renderBlock->columnInfo();
columnGap = renderBlock->columnGap();
-#endif
direction = renderBlock->style()->direction();
}
}
- if ((hasClip != false || columns != NULL) && lastChild) {
+ if ((hasClip != false || columnInfo != NULL) && lastChild) {
clipTracker.grow(clipTracker.size() + 1);
ClipColumnTracker& clip = clipTracker.last();
clip.mBounds = absBounds;
clip.mLastChild = OneAfter(lastChild);
clip.mNode = node;
- clip.mColumns = columns;
+ clip.mColumnInfo = columnInfo;
clip.mColumnGap = columnGap;
clip.mHasClip = hasClip;
clip.mDirection = direction;
- if (columns != NULL) {
+ if (columnInfo != NULL) {
const IntRect& oRect = ((RenderBox*)nodeRenderer)->visibleOverflowRect();
clip.mBounds.move(oRect.x(), oRect.y());
}
@@ -1177,7 +1260,7 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame,
}
if (node->hasTagName(WebCore::HTMLNames::inputTag)) {
HTMLInputElement* input = static_cast<HTMLInputElement*>(node);
- HTMLInputElement::InputType inputType = input->inputType();
+ HTMLInputElement::DeprecatedInputType inputType = input->deprecatedInputType();
if (input->isTextField()) {
type = TEXT_INPUT_CACHEDNODETYPE;
cachedInput.init();
@@ -1216,6 +1299,8 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame,
if (!href.isEmpty() && !WebCore::protocolIsJavaScript(href.string()))
// Set the exported string for all non-javascript anchors.
exported = href.string().threadsafeCopy();
+ } else if (node->hasTagName(HTMLNames::selectTag)) {
+ type = SELECT_CACHEDNODETYPE;
}
if (type == TEXT_INPUT_CACHEDNODETYPE) {
RenderTextControl* renderText =
@@ -1262,6 +1347,28 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame,
globalOffsetX, globalOffsetY, &cachedNode.mCursorRing) == false)
continue;
keepTextNode:
+ if (nodeRenderer) { // area tags' node->renderer() == 0
+ RenderStyle* style = nodeRenderer->style();
+ const void* styleDataPtr = style->ringData();
+ // to save time, see if we're pointing to the same style data as before
+ if (lastStyleDataPtr != styleDataPtr) {
+ lastStyleDataPtr = styleDataPtr;
+ cachedColor.setFillColor(style->ringFillColor());
+ cachedColor.setInnerWidth(style->ringInnerWidth());
+ cachedColor.setOuterWidth(style->ringOuterWidth());
+ cachedColor.setOutset(style->ringOutset());
+ cachedColor.setPressedInnerColor(style->ringPressedInnerColor());
+ cachedColor.setPressedOuterColor(style->ringPressedOuterColor());
+ cachedColor.setRadius(style->ringRadius());
+ cachedColor.setSelectedInnerColor(style->ringSelectedInnerColor());
+ cachedColor.setSelectedOuterColor(style->ringSelectedOuterColor());
+ int oldSize = colorTracker.size();
+ colorIndex = FindColorIndex(colorTracker, cachedColor);
+ if (colorIndex == oldSize)
+ cachedFrame->add(cachedColor);
+ }
+ } else
+ colorIndex = 0;
IntRect clip = hasClip ? bounds : absBounds;
size_t clipIndex = clipTracker.size();
if (clipTracker.last().mNode == node)
@@ -1269,7 +1376,7 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame,
while (--clipIndex > 0) {
const ClipColumnTracker& clipTrack = clipTracker.at(clipIndex);
if (clipTrack.mHasClip == false) {
- adjustForColumns(clipTrack, &cachedNode, &absBounds);
+ adjustForColumns(clipTrack, &cachedNode, &absBounds, static_cast<RenderBlock*>(nodeRenderer));
continue;
}
const IntRect& parentClip = clipTrack.mBounds;
@@ -1291,17 +1398,22 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame,
LayerAndroid* layer = layerTracker.last().mLayer;
if (layer) {
const IntRect& layerClip = layerTracker.last().mBounds;
- if (!layerClip.isEmpty() && !cachedNode.clip(layerClip)) {
+ const RenderLayer* renderLayer = layerTracker.last().mRenderLayer;
+ if (!layer->contentIsScrollable() && !layerClip.isEmpty() &&
+ !cachedNode.clip(layerClip)) {
DBG_NAV_LOGD("skipped on layer clip %d", cacheIndex);
continue; // skip this node if outside of the clip
}
isInLayer = true;
isUnclipped = true; // assume that layers do not have occluded nodes
+ IntPoint scroll(renderLayer->scrollXOffset(),
+ renderLayer->scrollYOffset());
AddLayer(cachedFrame, cachedFrame->size(), layerClip.location(),
- layer->uniqueId());
+ scroll, layer->uniqueId());
}
#endif
cachedNode.setNavableRects();
+ cachedNode.setColorIndex(colorIndex);
cachedNode.setExport(exported);
cachedNode.setHasCursorRing(hasCursorRing);
cachedNode.setHasMouseOver(hasMouseOver);
@@ -2680,7 +2792,8 @@ bool CacheBuilder::isFocusableText(NodeWalk* walk, bool more, Node* node,
do {
do {
do {
- node = node->traverseNextNode();
+ if (node)
+ node = node->traverseNextNode();
if (node == NULL || node->hasTagName(HTMLNames::aTag)
|| node->hasTagName(HTMLNames::inputTag)
|| node->hasTagName(HTMLNames::textareaTag)) {
@@ -2727,10 +2840,10 @@ tryNextCheckType:
exported->replace(index, 1, escapedComma);
} break;
case EMAIL_CACHEDNODETYPE:
- exported->insert(WebCore::String("mailto:"), 0);
+ exported->insert(WTF::String("mailto:"), 0);
break;
case PHONE_CACHEDNODETYPE:
- exported->insert(WebCore::String("tel:"), 0);
+ exported->insert(WTF::String("tel:"), 0);
break;
default:
break;
@@ -2803,7 +2916,8 @@ void CacheBuilder::TrackLayer(WTF::Vector<LayerTracker>& layerTracker,
layerTracker.grow(layerTracker.size() + 1);
LayerTracker& indexTracker = layerTracker.last();
indexTracker.mLayer = aLayer;
- indexTracker.mBounds = nodeRenderer->absoluteBoundingBoxRect();
+ indexTracker.mRenderLayer = layer;
+ indexTracker.mBounds = IntRect(FloatRect(aLayer->bounds()));
indexTracker.mBounds.move(offsetX, offsetY);
indexTracker.mLastChild = lastChild ? OneAfter(lastChild) : 0;
DBG_NAV_LOGD("layer=%p [%d] bounds=(%d,%d,w=%d,h=%d)", aLayer,
@@ -2921,18 +3035,18 @@ bool CacheBuilder::ConstructPartRects(Node* node, const IntRect& bounds,
EVisibility vis = renderer->style()->visibility();
if (vis == HIDDEN)
continue;
+ bool hasClip = renderer->hasOverflowClip();
+ size_t clipIndex = clipTracker.size();
+ IntRect clipBounds = IntRect(0, 0, INT_MAX, INT_MAX);
+ if (hasClip || --clipIndex > 0) {
+ clipBounds = hasClip ? renderer->absoluteBoundingBoxRect() :
+ clipTracker.at(clipIndex).mBounds; // x, y fixup done by ConstructTextRect
+ }
if (test->isTextNode()) {
RenderText* renderText = (RenderText*) renderer;
InlineTextBox *textBox = renderText->firstTextBox();
if (textBox == NULL)
continue;
- bool hasClip = renderer->hasOverflowClip();
- size_t clipIndex = clipTracker.size();
- IntRect clipBounds = IntRect(0, 0, INT_MAX, INT_MAX);
- if (hasClip || --clipIndex > 0) {
- clipBounds = hasClip ? renderer->absoluteBoundingBoxRect() :
- clipTracker.at(clipIndex).mBounds; // x, y fixup done by ConstructTextRect
- }
if (ConstructTextRect((Text*) test, textBox, 0, INT_MAX,
x, y, focusBounds, clipBounds, result) == false) {
return false;
@@ -2941,6 +3055,7 @@ bool CacheBuilder::ConstructPartRects(Node* node, const IntRect& bounds,
}
if (test->hasTagName(HTMLNames::imgTag)) {
IntRect bounds = test->getRect();
+ bounds.intersect(clipBounds);
if (AddPartRect(bounds, x, y, result, focusBounds) == false)
return false;
continue;
diff --git a/WebKit/android/nav/CacheBuilder.h b/WebKit/android/nav/CacheBuilder.h
index 407d590..9832865 100644
--- a/WebKit/android/nav/CacheBuilder.h
+++ b/WebKit/android/nav/CacheBuilder.h
@@ -31,7 +31,8 @@
#include "IntRect.h"
#include "PlatformString.h"
#include "TextDirection.h"
-#include "wtf/Vector.h"
+#include <wtf/Forward.h>
+#include <wtf/Vector.h>
#define NAVIGATION_MAX_PHONE_LENGTH 14
@@ -39,7 +40,7 @@ using namespace WebCore;
namespace WebCore {
-class AtomicString;
+class ColumnInfo;
class Document;
class Frame;
class HTMLAreaElement;
@@ -47,9 +48,10 @@ class InlineTextBox;
class LayerAndroid;
class Node;
class PlatformGraphicsContext;
+class RenderBlock;
class RenderFlow;
-class RenderObject;
class RenderLayer;
+class RenderObject;
class Text;
}
@@ -94,6 +96,7 @@ public:
static IntRect getAreaRect(const HTMLAreaElement* area);
static void GetGlobalOffset(Frame* , int* x, int * y);
static void GetGlobalOffset(Node* , int* x, int * y);
+ bool pictureSetDisabled() { return mPictureSetDisabled; }
static bool validNode(Frame* startFrame, void* framePtr, void* nodePtr);
private:
enum AddressProgress {
@@ -190,13 +193,14 @@ private:
struct ClipColumnTracker : Tracker {
Node* mNode;
IntRect mBounds;
- WTF::Vector<IntRect>* mColumns;
+ ColumnInfo* mColumnInfo;
int mColumnGap;
TextDirection mDirection;
bool mHasClip;
};
struct LayerTracker : Tracker {
LayerAndroid* mLayer;
+ RenderLayer* mRenderLayer;
IntRect mBounds;
};
struct TabIndexTracker : Tracker {
@@ -207,7 +211,7 @@ private:
bool mSomeParentTakesFocus;
};
void adjustForColumns(const ClipColumnTracker& track,
- CachedNode* node, IntRect* bounds);
+ CachedNode* node, IntRect* bounds, RenderBlock*);
static bool AddPartRect(IntRect& bounds, int x, int y,
WTF::Vector<IntRect>* result, IntRect* focusBounds);
static bool AnyIsClick(Node* node);
@@ -215,7 +219,7 @@ private:
static bool NodeHasEventListeners(Node* node, AtomicString* eventTypes, int length);
void BuildFrame(Frame* root, Frame* frame,
CachedRoot* cachedRoot, CachedFrame* cachedFrame);
- bool CleanUpContainedNodes(CachedRoot* cachedRoot, CachedFrame* cachedFrame,
+ bool CleanUpContainedNodes(CachedRoot* cachedRoot, CachedFrame* cachedFrame,
const FocusTracker* last, int lastChildIndex);
static bool ConstructTextRect(Text* textNode,
InlineTextBox* textBox, int start, int relEnd, int x, int y,
@@ -249,6 +253,7 @@ private:
Node* tryFocus(Direction direction);
Node* trySegment(Direction direction, int mainStart, int mainEnd);
CachedNodeBits mAllowableTypes;
+ bool mPictureSetDisabled;
#if DUMP_NAV_CACHE
public:
class Debug {
diff --git a/WebKit/android/nav/CachedColor.cpp b/WebKit/android/nav/CachedColor.cpp
new file mode 100644
index 0000000..c610022
--- /dev/null
+++ b/WebKit/android/nav/CachedColor.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2010, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "CachedPrefix.h"
+#include "CachedColor.h"
+
+namespace android {
+
+#if DUMP_NAV_CACHE
+
+#define DEBUG_PRINT_COLOR(field) \
+ DUMP_NAV_LOGD("// SkColor " #field "=0x%08x;\n", b->field)
+
+CachedColor* CachedColor::Debug::base() const {
+ CachedColor* nav = (CachedColor*) ((char*) this - OFFSETOF(CachedColor, mDebug));
+ return nav;
+}
+
+void CachedColor::Debug::print() const
+{
+ CachedColor* b = base();
+ DEBUG_PRINT_COLOR(mFillColor);
+ DUMP_NAV_LOGD("// int mInnerWidth=%d;\n", b->mInnerWidth);
+ DUMP_NAV_LOGD("// int mOuterWidth=%d;\n", b->mOuterWidth);
+ DUMP_NAV_LOGD("// int mOutset=%d;\n", b->mOutset);
+ DEBUG_PRINT_COLOR(mPressedInnerColor);
+ DEBUG_PRINT_COLOR(mPressedOuterColor);
+ DUMP_NAV_LOGD("// int mRadius=%d;\n", b->mRadius);
+ DEBUG_PRINT_COLOR(mSelectedInnerColor);
+ DEBUG_PRINT_COLOR(mSelectedOuterColor);
+}
+
+#endif
+
+}
+
diff --git a/WebKit/android/nav/CachedColor.h b/WebKit/android/nav/CachedColor.h
new file mode 100644
index 0000000..4b39810
--- /dev/null
+++ b/WebKit/android/nav/CachedColor.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2010, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef CachedColor_H
+#define CachedColor_H
+
+#include "CachedDebug.h"
+#include "Color.h"
+#include "Length.h"
+#include "SkColor.h"
+
+using namespace WebCore;
+
+namespace android {
+
+class CachedColor {
+public:
+ CachedColor() {
+ // Initiaized to 0 in its array, so nothing to do in the
+ // constructor
+ }
+ bool operator==(const CachedColor& o) const {
+ return memcmp(&o, this, sizeof(this)) == 0; }
+ SkColor fillColor() const { return mFillColor; }
+ void init();
+ int innerWidth() const { return mInnerWidth; }
+ int outerWidth() const { return mOuterWidth; }
+ int outset() const { return mOutset; }
+ SkColor pressedInnerColor() const { return mPressedInnerColor; }
+ SkColor pressedOuterColor() const { return mPressedOuterColor; }
+ int radius() const { return mRadius; }
+ SkColor selectedInnerColor() const { return mSelectedInnerColor; }
+ SkColor selectedOuterColor() const { return mSelectedOuterColor; }
+ void setFillColor(const Color& c) { mFillColor = c.rgb(); }
+ void setInnerWidth(Length l) { mInnerWidth = l.value(); }
+ void setOuterWidth(Length l) { mOuterWidth = l.value(); }
+ void setOutset(Length l) { mOutset = l.value(); }
+ void setPressedInnerColor(const Color& c) { mPressedInnerColor = c.rgb(); }
+ void setPressedOuterColor(const Color& c) { mPressedOuterColor = c.rgb(); }
+ void setRadius(Length l) { mRadius = l.value(); }
+ void setSelectedInnerColor(const Color& c) { mSelectedInnerColor = c.rgb(); }
+ void setSelectedOuterColor(const Color& c) { mSelectedOuterColor = c.rgb(); }
+private:
+ SkColor mFillColor;
+ int mInnerWidth;
+ int mOuterWidth;
+ int mOutset;
+ SkColor mPressedInnerColor;
+ SkColor mPressedOuterColor;
+ int mRadius;
+ SkColor mSelectedInnerColor;
+ SkColor mSelectedOuterColor;
+#if DUMP_NAV_CACHE
+public:
+ class Debug {
+public:
+ CachedColor* base() const;
+ void print() const;
+ } mDebug;
+#endif
+};
+
+}
+
+#endif
diff --git a/WebKit/android/nav/CachedFrame.cpp b/WebKit/android/nav/CachedFrame.cpp
index ce5600b..81ef299 100644
--- a/WebKit/android/nav/CachedFrame.cpp
+++ b/WebKit/android/nav/CachedFrame.cpp
@@ -48,6 +48,19 @@ WebCore::IntRect CachedFrame::adjustBounds(const CachedNode* node,
#endif
}
+// This is for nodes inside a layer. It takes an IntRect that has been
+// adjusted by the layer's position and removes the adjustment made by the
+// layer.
+WebCore::IntRect CachedFrame::unadjustBounds(const CachedNode* node,
+ const WebCore::IntRect& rect) const
+{
+#if USE(ACCELERATED_COMPOSITING)
+ if (node->isInLayer())
+ return layer(node)->unadjustBounds(mRoot->rootLayer(), rect);
+#endif
+ return rect;
+}
+
bool CachedFrame::CheckBetween(Direction direction, const WebCore::IntRect& bestRect,
const WebCore::IntRect& prior, WebCore::IntRect* result)
{
@@ -119,9 +132,10 @@ bool CachedFrame::checkBetween(BestData* best, Direction direction)
bool CachedFrame::checkRings(const CachedNode* node,
const WTF::Vector<WebCore::IntRect>& rings,
- const WebCore::IntRect& bounds) const
+ const WebCore::IntRect& nodeBounds,
+ const WebCore::IntRect& testBounds) const
{
- return mRoot->checkRings(picture(node), rings, bounds);
+ return mRoot->checkRings(picture(node), rings, nodeBounds, testBounds);
}
bool CachedFrame::checkVisited(const CachedNode* node, Direction direction) const
@@ -394,8 +408,10 @@ const CachedNode* CachedFrame::findBestAt(const WebCore::IntRect& rect,
if (*directHit == NULL) {
*directHit = test;
*directHitFramePtr = this;
- *x = center.x();
- *y = center.y();
+ IntRect r(center, IntSize(0, 0));
+ r = unadjustBounds(test, r);
+ *x = r.x();
+ *y = r.y();
} else {
// We have hit another one before
const CachedNode* d = *directHit;
@@ -436,6 +452,7 @@ const CachedNode* CachedFrame::findBestAt(const WebCore::IntRect& rect,
*inside = testInside;
result = test;
*framePtr = this;
+ both = unadjustBounds(test, both);
*x = both.x() + (both.width() >> 1);
*y = both.y() + (both.height() >> 1);
}
@@ -495,17 +512,30 @@ const CachedNode* CachedFrame::findBestHitAt(const WebCore::IntRect& rect,
testData.setNodeBounds(testRect);
if (mRoot->maskIfHidden(&testData) == true)
continue;
+ DBG_NAV_LOGD("candidate %d rect=(%d,%d,r=%d,b=%d)"
+ " testRect=(%d,%d,r=%d,b=%d)",
+ test->index(), rect.x(), rect.y(), rect.right(), rect.bottom(),
+ testRect.x(), testRect.y(), testRect.right(), testRect.bottom());
for (int i = 0; i < test->navableRects(); i++) {
WebCore::IntRect cursorRect = test->ring(this, i);
+ DBG_NAV_LOGD("candidate %d cursorRect=(%d,%d,r=%d,b=%d)",
+ i, cursorRect.x(), cursorRect.y(), cursorRect.right(),
+ cursorRect.bottom());
if (cursorRect.intersects(rect)) {
WebCore::IntRect intersection(cursorRect);
intersection.intersect(rect);
+ intersection = unadjustBounds(test, intersection);
*x = intersection.x() + (intersection.width() >> 1);
*y = intersection.y() + (intersection.height() >> 1);
*framePtr = this;
return test;
}
}
+ testRect.intersect(rect);
+ *x = testRect.x() + (testRect.width() >> 1);
+ *y = testRect.y() + (testRect.height() >> 1);
+ *framePtr = this;
+ return test;
}
return NULL;
}
@@ -696,12 +726,17 @@ int CachedFrame::frameNodeCommon(BestData& testData, const CachedNode* test,
testData.mNode->setCondition(CachedNode::DISABLED);
return REJECT_TEST;
}
- if (mRoot->scrolledBounds().intersects(test->bounds(this)) == false) {
+ WebCore::IntRect bounds = test->bounds(this);
+ if (bounds.isEmpty()) {
+ testData.mNode->setCondition(CachedNode::NAVABLE);
+ return REJECT_TEST;
+ }
+ if (mRoot->scrolledBounds().intersects(bounds) == false) {
testData.mNode->setCondition(CachedNode::NAVABLE);
return REJECT_TEST;
}
if (mRoot->rootLayer() && !test->isInLayer()
- && !mRoot->baseUncovered().intersects(test->bounds(this))) {
+ && !mRoot->baseUncovered().intersects(bounds)) {
testData.mNode->setCondition(CachedNode::UNDER_LAYER);
return REJECT_TEST;
}
@@ -901,7 +936,7 @@ WebCore::IntRect CachedFrame::localBounds(const CachedNode* node,
DBG_NAV_LOGD("node=%p [%d] rect=(%d,%d,w=%d,h=%d)",
node, node->index(), rect.x(), rect.y(), rect.width(), rect.height());
#if USE(ACCELERATED_COMPOSITING)
- return layer(node)->localBounds(rect);
+ return layer(node)->localBounds(mRoot->rootLayer(), rect);
#else
return rect;
#endif
@@ -1390,6 +1425,7 @@ void CachedFrame::Debug::print() const
const CachedInput* input = b->textInput(node);
if (input)
input->mDebug.print();
+ DUMP_NAV_LOGD("\n");
}
DUMP_NAV_LOGD("// }; // end of nodes\n");
#if USE(ACCELERATED_COMPOSITING)
@@ -1400,6 +1436,12 @@ void CachedFrame::Debug::print() const
}
DUMP_NAV_LOGD("// }; // end of layers\n");
#endif // USE(ACCELERATED_COMPOSITING)
+ DUMP_NAV_LOGD("// CachedColor mCachedColors={ // count=%d\n", b->mCachedColors.size());
+ for (CachedColor* color = b->mCachedColors.begin();
+ color != b->mCachedColors.end(); color++) {
+ color->mDebug.print();
+ }
+ DUMP_NAV_LOGD("// }; // end of colors\n");
DUMP_NAV_LOGD("// CachedFrame mCachedFrames={ // count=%d\n", b->mCachedFrames.size());
for (CachedFrame* child = b->mCachedFrames.begin();
child != b->mCachedFrames.end(); child++)
diff --git a/WebKit/android/nav/CachedFrame.h b/WebKit/android/nav/CachedFrame.h
index 9334707..bd47421 100644
--- a/WebKit/android/nav/CachedFrame.h
+++ b/WebKit/android/nav/CachedFrame.h
@@ -26,6 +26,7 @@
#ifndef CachedFrame_H
#define CachedFrame_H
+#include "CachedColor.h"
#include "CachedInput.h"
#include "CachedLayer.h"
#include "CachedNode.h"
@@ -70,6 +71,7 @@ public:
CURSOR_SET = 0
};
CachedFrame() {}
+ void add(CachedColor& color) { mCachedColors.append(color); }
void add(CachedInput& input) { mCachedTextInputs.append(input); }
#if USE(ACCELERATED_COMPOSITING)
void add(CachedLayer& layer) { mCachedLayers.append(layer); }
@@ -78,12 +80,18 @@ public:
void addFrame(CachedFrame& child) { mCachedFrames.append(child); }
WebCore::IntRect adjustBounds(const CachedNode* ,
const WebCore::IntRect& ) const;
+ WebCore::IntRect unadjustBounds(const CachedNode*,
+ const WebCore::IntRect& ) const;
bool checkRings(const CachedNode* node,
const WTF::Vector<WebCore::IntRect>& rings,
- const WebCore::IntRect& bounds) const;
+ const WebCore::IntRect& nodeBounds,
+ const WebCore::IntRect& testBounds) const;
bool checkVisited(const CachedNode* , CachedFrame::Direction ) const;
size_t childCount() { return mCachedFrames.size(); }
void clearCursor();
+ const CachedColor& color(const CachedNode* node) const {
+ return mCachedColors[node->colorIndex()];
+ }
const CachedNode* currentCursor() const { return currentCursor(NULL); }
const CachedNode* currentCursor(const CachedFrame** ) const;
const CachedNode* currentFocus() const { return currentFocus(NULL); }
@@ -224,6 +232,7 @@ private: // since computing these is complicated, protect them so that the
WebCore::IntRect mContents;
WebCore::IntRect mLocalViewBounds;
WebCore::IntRect mViewBounds;
+ WTF::Vector<CachedColor> mCachedColors;
WTF::Vector<CachedNode> mCachedNodes;
WTF::Vector<CachedFrame> mCachedFrames;
WTF::Vector<CachedInput> mCachedTextInputs;
diff --git a/WebKit/android/nav/CachedInput.cpp b/WebKit/android/nav/CachedInput.cpp
index cba5820..7c9beba 100644
--- a/WebKit/android/nav/CachedInput.cpp
+++ b/WebKit/android/nav/CachedInput.cpp
@@ -28,6 +28,11 @@
namespace android {
+void CachedInput::init() {
+ bzero(this, sizeof(CachedInput));
+ mName = WTF::String();
+}
+
#if DUMP_NAV_CACHE
#define DEBUG_PRINT_BOOL(field) \
@@ -39,7 +44,7 @@ CachedInput* CachedInput::Debug::base() const {
}
static void printWebCoreString(const char* label,
- const WebCore::String& string) {
+ const WTF::String& string) {
char scratch[256];
size_t index = snprintf(scratch, sizeof(scratch), label);
const UChar* ch = string.characters();
@@ -55,7 +60,7 @@ void CachedInput::Debug::print() const
{
CachedInput* b = base();
printWebCoreString("// char* mName=\"", b->mName);
- DUMP_NAV_LOGD("// void* mForm=%p;", b->mForm);
+ DUMP_NAV_LOGD("// void* mForm=%p;\n", b->mForm);
DUMP_NAV_LOGD("// int mMaxLength=%d;\n", b->mMaxLength);
DUMP_NAV_LOGD("// int mTextSize=%d;\n", b->mTextSize);
DUMP_NAV_LOGD("// int mInputType=%d;\n", b->mInputType);
diff --git a/WebKit/android/nav/CachedInput.h b/WebKit/android/nav/CachedInput.h
index 01b40f9..0809208 100644
--- a/WebKit/android/nav/CachedInput.h
+++ b/WebKit/android/nav/CachedInput.h
@@ -39,25 +39,22 @@ public:
// constructor
}
void* formPointer() const { return mForm; }
- void init() {
- bzero(this, sizeof(CachedInput));
- mName = WebCore::String();
- }
- WebCore::HTMLInputElement::InputType inputType() const { return mInputType; }
+ void init();
+ WebCore::HTMLInputElement::DeprecatedInputType inputType() const { return mInputType; }
bool isRtlText() const { return mIsRtlText; }
bool isTextField() const { return mIsTextField; }
int maxLength() const { return mMaxLength; };
- const WebCore::String& name() const { return mName; }
+ const WTF::String& name() const { return mName; }
int paddingBottom() const { return mPaddingBottom; }
int paddingLeft() const { return mPaddingLeft; }
int paddingRight() const { return mPaddingRight; }
int paddingTop() const { return mPaddingTop; }
void setFormPointer(void* form) { mForm = form; }
- void setInputType(WebCore::HTMLInputElement::InputType type) { mInputType = type; }
+ void setInputType(WebCore::HTMLInputElement::DeprecatedInputType type) { mInputType = type; }
void setIsRtlText(bool isRtlText) { mIsRtlText = isRtlText; }
void setIsTextField(bool isTextField) { mIsTextField = isTextField; }
void setMaxLength(int maxLength) { mMaxLength = maxLength; }
- void setName(const WebCore::String& name) { mName = name; }
+ void setName(const WTF::String& name) { mName = name; }
void setPaddingBottom(int bottom) { mPaddingBottom = bottom; }
void setPaddingLeft(int left) { mPaddingLeft = left; }
void setPaddingRight(int right) { mPaddingRight = right; }
@@ -66,14 +63,14 @@ public:
int textSize() const { return mTextSize; }
private:
void* mForm;
- WebCore::HTMLInputElement::InputType mInputType;
+ WTF::String mName;
int mMaxLength;
- WebCore::String mName;
int mPaddingBottom;
int mPaddingLeft;
int mPaddingRight;
int mPaddingTop;
int mTextSize;
+ WebCore::HTMLInputElement::DeprecatedInputType mInputType;
bool mIsRtlText : 1;
bool mIsTextField : 1;
#if DUMP_NAV_CACHE
diff --git a/WebKit/android/nav/CachedLayer.cpp b/WebKit/android/nav/CachedLayer.cpp
index 2f6e20a..c4293a5 100644
--- a/WebKit/android/nav/CachedLayer.cpp
+++ b/WebKit/android/nav/CachedLayer.cpp
@@ -46,23 +46,79 @@ IntRect CachedLayer::adjustBounds(const LayerAndroid* root,
return bounds;
}
FloatRect temp = bounds;
+ // First, remove the original offset from the bounds.
+ temp.move(-mOffset.x(), -mOffset.y());
+
+ // Now, add in the original scroll position. This moves the node to the
+ // original location within the layer.
+ temp.move(mScrollOffset.x(), mScrollOffset.y());
+
+ // Next, add in the new position of the layer (could be different due to a
+ // fixed position layer).
const FloatPoint& position = aLayer->getPosition();
temp.move(position.x(), position.y());
+
+ // Add in any layer translation.
const FloatPoint& translation = aLayer->translation();
temp.move(translation.x(), translation.y());
+
+ // Move the bounds by the layer's internal scroll position.
+ const SkPoint& scroll = aLayer->scrollPosition();
+ temp.move(SkScalarToFloat(-scroll.fX), SkScalarToFloat(-scroll.fY));
+
IntRect result = enclosingIntRect(temp);
+
+ // Finally, clip the result to the foreground (this includes the object's
+ // border which does not scroll).
+ IntRect clip(aLayer->foregroundClip());
+ clip.move(position.x(), position.y());
+ result.intersect(clip);
+
DBG_NAV_LOGD("root=%p aLayer=%p [%d]"
- " bounds=(%d,%d,w=%d,h=%d) pos=(%g,%g) trans=(%g,%g)"
- " result=(%d,%d,w=%d,h=%d) offset=(%d,%d)",
+ " bounds=(%d,%d,w=%d,h=%d) trans=(%g,%g)"
+ " pos=(%f,%f)"
+ " offset=(%d,%d) clip=(%d,%d,w=%d,h=%d)"
+ " scroll=(%d,%d) origScroll=(%d,%d)"
+ " result=(%d,%d,w=%d,h=%d)",
root, aLayer, aLayer->uniqueId(),
bounds.x(), bounds.y(), bounds.width(), bounds.height(),
- position.x(), position.y(), translation.x(), translation.y(),
- result.x(), result.y(), result.width(), result.height(),
- mOffset.x(), mOffset.y());
- result.move(-mOffset.x(), -mOffset.y());
+ translation.x(), translation.y(), position.x(), position.y(),
+ mOffset.x(), mOffset.y(),
+ clip.x(), clip.y(), clip.width(), clip.height(),
+ SkScalarRound(scroll.fX), SkScalarRound(scroll.fY),
+ mScrollOffset.x(), mScrollOffset.y(),
+ result.x(), result.y(), result.width(), result.height());
return result;
}
+IntRect CachedLayer::unadjustBounds(const LayerAndroid* root,
+ const IntRect& bounds) const
+{
+ const LayerAndroid* aLayer = layer(root);
+ if (!aLayer)
+ return bounds;
+
+ IntRect temp = bounds;
+ // Remove the new position (i.e. fixed position elements).
+ const FloatPoint& position = aLayer->getPosition();
+ temp.move(-position.x(), -position.y());
+
+ // Remove any layer translation.
+ const FloatPoint& translation = aLayer->translation();
+ temp.move(-translation.x(), -translation.y());
+
+ // Move the bounds by the internal scroll position.
+ const SkPoint& scroll = aLayer->scrollPosition();
+ temp.move(SkScalarRound(scroll.fX), SkScalarRound(scroll.fY));
+
+ // Move it back to the original offset.
+ temp.move(mOffset.x(), mOffset.y());
+
+ // Move the bounds by the original scroll.
+ temp.move(-mScrollOffset.x(), -mScrollOffset.y());
+ return temp;
+}
+
const LayerAndroid* CachedLayer::layer(const LayerAndroid* root) const
{
if (!root || mLayer)
@@ -71,10 +127,34 @@ const LayerAndroid* CachedLayer::layer(const LayerAndroid* root) const
}
// return bounds relative to enclosing layer as recorded when walking the dom
-IntRect CachedLayer::localBounds(const IntRect& bounds) const
+IntRect CachedLayer::localBounds(const LayerAndroid* root,
+ const IntRect& bounds) const
{
IntRect temp = bounds;
+ // Remove the original offset from the bounds.
temp.move(-mOffset.x(), -mOffset.y());
+
+ // We add in the original scroll position in order to position the node
+ // relative to the current internal scroll position.
+ temp.move(mScrollOffset.x(), mScrollOffset.y());
+
+ const LayerAndroid* aLayer = layer(root);
+ if (aLayer) {
+ // Move the bounds by the scroll position of the layer.
+ const SkPoint& scroll = aLayer->scrollPosition();
+ temp.move(SkScalarToFloat(-scroll.fX), SkScalarToFloat(-scroll.fY));
+
+ // Clip by the layer's foreground bounds. Since the bounds have
+ // already be moved local to the layer, no need to move the foreground
+ // clip.
+ temp.intersect(IntRect(aLayer->foregroundClip()));
+ }
+
+ DBG_NAV_LOGD("bounds=(%d,%d,w=%d,h=%d) offset=(%d,%d)"
+ " result=(%d,%d,w=%d,h=%d)", bounds.x(), bounds.y(),
+ bounds.width(), bounds.height(), mOffset.x(), mOffset.y(),
+ temp.x(), temp.y(), temp.width(), temp.height());
+
return temp;
}
diff --git a/WebKit/android/nav/CachedLayer.h b/WebKit/android/nav/CachedLayer.h
index c802407..0a56ea1 100644
--- a/WebKit/android/nav/CachedLayer.h
+++ b/WebKit/android/nav/CachedLayer.h
@@ -47,20 +47,29 @@ public:
}
// FIXME: adjustBounds should be renamed globalBounds or toGlobal
IntRect adjustBounds(const LayerAndroid* root, const IntRect& bounds) const;
+ // Moves the bounds by the layer's scroll position. Assumes the incoming
+ // bounds have been adjusted by adjustBounds.
+ IntRect unadjustBounds(const LayerAndroid* root,
+ const IntRect& bounds) const;
int cachedNodeIndex() const { return mCachedNodeIndex; }
- const IntPoint& getOffset() const { return mOffset; }
const LayerAndroid* layer(const LayerAndroid* root) const;
- IntRect localBounds(const IntRect& bounds) const;
+ IntRect localBounds(const LayerAndroid* root, const IntRect& bounds) const;
SkPicture* picture(const LayerAndroid* root) const;
void reset() { mLayer = 0; }
void setCachedNodeIndex(int index) { mCachedNodeIndex = index; }
void setOffset(const IntPoint& offset) { mOffset = offset; }
+ void setScrollOffset(const IntPoint& scrollOffset) {
+ mScrollOffset = scrollOffset;
+ }
void setUniqueId(int uniqueId) { mUniqueId = uniqueId; }
int uniqueId() const { return mUniqueId; }
private:
int mCachedNodeIndex;
mutable const LayerAndroid* mLayer;
+ // mOffset and mScrollOffset are the position and scroll offset of the
+ // layer when recorded by the nav cache.
IntPoint mOffset;
+ IntPoint mScrollOffset;
int mUniqueId;
#if DUMP_NAV_CACHE
diff --git a/WebKit/android/nav/CachedNode.cpp b/WebKit/android/nav/CachedNode.cpp
index 0c9d541..4ba7b48 100644
--- a/WebKit/android/nav/CachedNode.cpp
+++ b/WebKit/android/nav/CachedNode.cpp
@@ -110,7 +110,7 @@ void CachedNode::fixUpCursorRects(const CachedFrame* frame)
mFixedUpCursorRects = true;
// if the hit-test rect doesn't intersect any other rect, use it
if (mHitBounds != mBounds && mHitBounds.contains(mBounds) &&
- frame->checkRings(this, mCursorRing, mHitBounds)) {
+ frame->checkRings(this, mCursorRing, mBounds, mHitBounds)) {
DBG_NAV_LOGD("use mHitBounds (%d,%d,%d,%d)", mHitBounds.x(),
mHitBounds.y(), mHitBounds.width(), mHitBounds.height());
mUseHitBounds = true;
@@ -120,7 +120,9 @@ void CachedNode::fixUpCursorRects(const CachedFrame* frame)
return;
// if there is more than 1 rect, and the bounds doesn't intersect
// any other cursor ring bounds, use it
- if (frame->checkRings(this, mCursorRing, mBounds)) {
+ IntRect sloppyBounds = mBounds;
+ sloppyBounds.inflate(2); // give it a couple of extra pixels
+ if (frame->checkRings(this, mCursorRing, mBounds, sloppyBounds)) {
DBG_NAV_LOGD("use mBounds (%d,%d,%d,%d)", mBounds.x(),
mBounds.y(), mBounds.width(), mBounds.height());
mUseBounds = true;
@@ -237,7 +239,7 @@ WebCore::IntRect CachedNode::hitBounds(const CachedFrame* frame) const
void CachedNode::init(WebCore::Node* node)
{
bzero(this, sizeof(CachedNode));
- mExport = WebCore::String();
+ mExport = WTF::String();
mNode = node;
mParentIndex = mDataIndex = -1;
mType = android::NORMAL_CACHEDNODETYPE;
@@ -367,6 +369,8 @@ const char* CachedNode::Debug::type(android::CachedNodeType t) const
case FRAME_CACHEDNODETYPE: return "FRAME"; break;
case PLUGIN_CACHEDNODETYPE: return "PLUGIN"; break;
case TEXT_INPUT_CACHEDNODETYPE: return "INPUT"; break;
+ case SELECT_CACHEDNODETYPE: return "SELECT"; break;
+ case CONTENT_EDITABLE_CACHEDNODETYPE: return "CONTENT_EDITABLE"; break;
default: return "???";
}
}
@@ -402,6 +406,7 @@ void CachedNode::Debug::print() const
DUMP_NAV_LOGD("// int mNavableRects=%d;\n", b->mNavableRects);
DUMP_NAV_LOGD("// int mParentIndex=%d;\n", b->mParentIndex);
DUMP_NAV_LOGD("// int mTabIndex=%d;\n", b->mTabIndex);
+ DUMP_NAV_LOGD("// int mColorIndex=%d;\n", b->mColorIndex);
DUMP_NAV_LOGD("// Condition mCondition=%s;\n", condition(b->mCondition));
DUMP_NAV_LOGD("// Type mType=%s;\n", type(b->mType));
DEBUG_PRINT_BOOL(mClippedOut);
@@ -419,7 +424,6 @@ void CachedNode::Debug::print() const
DEBUG_PRINT_BOOL(mLast);
DEBUG_PRINT_BOOL(mUseBounds);
DEBUG_PRINT_BOOL(mUseHitBounds);
- DUMP_NAV_LOGD("\n");
}
#endif
diff --git a/WebKit/android/nav/CachedNode.h b/WebKit/android/nav/CachedNode.h
index f3cfd98..db48a66 100644
--- a/WebKit/android/nav/CachedNode.h
+++ b/WebKit/android/nav/CachedNode.h
@@ -26,12 +26,13 @@
#ifndef CachedNode_H
#define CachedNode_H
-#include "AtomicString.h"
#include "CachedDebug.h"
#include "CachedNodeType.h"
#include "IntRect.h"
#include "PlatformString.h"
-#include "wtf/Vector.h"
+
+#include <wtf/Vector.h>
+#include <wtf/text/AtomicString.h>
class SkPicture;
@@ -95,12 +96,13 @@ public:
WTF::Vector<WebCore::IntRect>* rings);
bool clip(const WebCore::IntRect& );
bool clippedOut() { return mClippedOut; }
+ int colorIndex() const { return mColorIndex; }
WebCore::IntRect cursorRingBounds(const CachedFrame* ) const;
void cursorRings(const CachedFrame* , WTF::Vector<WebCore::IntRect>* ) const;
bool disabled() const { return mDisabled; }
const CachedNode* document() const { return &this[-mIndex]; }
void fixUpCursorRects(const CachedFrame* frame);
- const WebCore::String& getExport() const { return mExport; }
+ const WTF::String& getExport() const { return mExport; }
bool hasCursorRing() const { return mHasCursorRing; }
bool hasMouseOver() const { return mHasMouseOver; }
void hideCursor(CachedFrame* );
@@ -108,6 +110,7 @@ public:
int index() const { return mIndex; }
void init(WebCore::Node* node);
bool isAnchor() const { return mType == ANCHOR_CACHEDNODETYPE; }
+ bool isContentEditable() const { return mType == CONTENT_EDITABLE_CACHEDNODETYPE; }
bool isCursor() const { return mIsCursor; }
bool isArea() const { return mType == AREA_CACHEDNODETYPE; }
bool isFocus() const { return mIsFocus; }
@@ -118,6 +121,7 @@ public:
return clip.intersects(bounds(frame));
}
bool isPlugin() const { return mType == PLUGIN_CACHEDNODETYPE; }
+ bool isSelect() const { return mType == SELECT_CACHEDNODETYPE; }
bool isSyntheticLink() const {
return mType >= ADDRESS_CACHEDNODETYPE && mType <= PHONE_CACHEDNODETYPE;
}
@@ -145,10 +149,11 @@ public:
WebCore::IntRect ring(const CachedFrame* , size_t part) const;
void setBounds(const WebCore::IntRect& bounds) { mBounds = bounds; }
void setClippedOut(bool clipped) { mClippedOut = clipped; }
+ void setColorIndex(int index) { mColorIndex = index; }
void setCondition(Condition condition) const { mCondition = condition; }
void setDataIndex(int index) { mDataIndex = index; }
void setDisabled(bool disabled) { mDisabled = disabled; }
- void setExport(const WebCore::String& exported) { mExport = exported; }
+ void setExport(const WTF::String& exported) { mExport = exported; }
void setHasCursorRing(bool hasRing) { mHasCursorRing = hasRing; }
void setHasMouseOver(bool hasMouseOver) { mHasMouseOver = hasMouseOver; }
void setHitBounds(const WebCore::IntRect& bounds) { mHitBounds = bounds; }
@@ -173,10 +178,10 @@ public:
const CachedNode* traverseNextNode() const { return mLast ? NULL : &this[1]; }
bool useBounds() const { return mUseBounds; }
bool useHitBounds() const { return mUseHitBounds; }
- bool wantsKeyEvents() const { return isTextInput() || isPlugin(); }
+ bool wantsKeyEvents() const { return isTextInput() || isPlugin() || isContentEditable(); }
private:
friend class CacheBuilder;
- WebCore::String mExport;
+ WTF::String mExport;
WebCore::IntRect mBounds;
WebCore::IntRect mHitBounds;
WebCore::IntRect mOriginalAbsoluteBounds;
@@ -188,6 +193,7 @@ private:
int mNavableRects; // FIXME: could be bitfield once I limit max number of rects
int mParentIndex;
int mTabIndex;
+ int mColorIndex; // index to ring color and other stylable properties
mutable Condition mCondition : 5; // why the node was not chosen on the first pass
CachedNodeType mType : 4;
bool mClippedOut : 1;
diff --git a/WebKit/android/nav/CachedNodeType.h b/WebKit/android/nav/CachedNodeType.h
index 21e2d40..8bc9328 100644
--- a/WebKit/android/nav/CachedNodeType.h
+++ b/WebKit/android/nav/CachedNodeType.h
@@ -37,7 +37,9 @@ enum CachedNodeType {
AREA_CACHEDNODETYPE,
FRAME_CACHEDNODETYPE,
PLUGIN_CACHEDNODETYPE,
- TEXT_INPUT_CACHEDNODETYPE
+ TEXT_INPUT_CACHEDNODETYPE,
+ SELECT_CACHEDNODETYPE,
+ CONTENT_EDITABLE_CACHEDNODETYPE
};
enum CachedNodeBits {
diff --git a/WebKit/android/nav/CachedPrefix.h b/WebKit/android/nav/CachedPrefix.h
index b682288..73a5c2c 100644
--- a/WebKit/android/nav/CachedPrefix.h
+++ b/WebKit/android/nav/CachedPrefix.h
@@ -43,4 +43,11 @@
#define OFFSETOF(type, field) ((char*)&(((type*)1)->field) - (char*)1) // avoids gnu warning
+#ifndef BZERO_DEFINED
+#define BZERO_DEFINED
+// http://www.opengroup.org/onlinepubs/000095399/functions/bzero.html
+// For maximum portability, it is recommended to replace the function call to bzero() as follows:
+#define bzero(b,len) (memset((b), '\0', (len)), (void) 0)
+#endif
+
#endif
diff --git a/WebKit/android/nav/CachedRoot.cpp b/WebKit/android/nav/CachedRoot.cpp
index 2d37a2a..e86999c 100644
--- a/WebKit/android/nav/CachedRoot.cpp
+++ b/WebKit/android/nav/CachedRoot.cpp
@@ -38,6 +38,10 @@
#include "CachedRoot.h"
+#if DEBUG_NAV_UI
+#include "wtf/text/CString.h"
+#endif
+
using std::min;
using std::max;
@@ -62,7 +66,10 @@ public:
kDrawRect_Type,
kDrawSprite_Type,
kDrawText_Type,
- kDrawTextOnPath_Type
+ kDrawTextOnPath_Type,
+ kPopLayer_Type,
+ kPushLayer_Type,
+ kPushSave_Type
};
static bool isTextType(Type t) {
@@ -110,7 +117,10 @@ public:
"kDrawRect_Type",
"kDrawSprite_Type",
"kDrawText_Type",
- "kDrawTextOnPath_Type"
+ "kDrawTextOnPath_Type",
+ "kPopLayer_Type",
+ "kPushLayer_Type",
+ "kPushSave_Type"
};
#endif
@@ -147,8 +157,9 @@ public:
virtual bool onIRect(const SkIRect& rect) {
if (joinGlyphs(rect))
return false;
- bool interestingType = mType == kDrawBitmap_Type ||
- mType == kDrawRect_Type || isTextType(mType);
+ bool interestingType = mType == kDrawBitmap_Type
+ || mType == kDrawSprite_Type
+ || mType == kDrawRect_Type || isTextType(mType);
if (SkIRect::Intersects(mBounds, rect) == false) {
DBG_NAV_LOGD("BoundsCheck (no intersect) rect={%d,%d,%d,%d}"
" mType=%s", rect.fLeft, rect.fTop, rect.fRight, rect.fBottom,
@@ -255,9 +266,10 @@ public:
}
virtual void drawSprite(const SkBitmap& bitmap, int left, int top,
- const SkPaint* paint = NULL) {
+ const SkPaint* paint) {
mBounder.setType(CommonCheck::kDrawSprite_Type);
- mBounder.setIsOpaque(bitmap.isOpaque());
+ mBounder.setIsOpaque(bitmap.isOpaque() &&
+ (!paint || paint->getAlpha() == 255));
SkCanvas::drawSprite(bitmap, left, top, paint);
}
@@ -283,8 +295,10 @@ public:
mBounder.setEmpty();
mBounder.setType(CommonCheck::kDrawGlyph_Type);
SkCanvas::drawPosTextH(text, byteLength, xpos, constY, paint);
- if (mBounder.mUnion.isEmpty())
+ if (mBounder.mUnion.isEmpty()) {
+ DBG_NAV_LOGD("empty constY=%g", SkScalarToFloat(constY));
return;
+ }
SkPaint::FontMetrics metrics;
paint.getFontMetrics(&metrics);
SkPoint upDown[2] = { {xpos[0], constY + metrics.fAscent},
@@ -314,7 +328,7 @@ public:
virtual int saveLayer(const SkRect* bounds, const SkPaint* paint,
SaveFlags flags) {
- int depth = SkCanvas::saveLayer(bounds, paint, flags);
+ int depth = SkCanvas::save(flags);
if (mTransparentLayer == 0 && paint && paint->getAlpha() < 255) {
mTransparentLayer = depth;
mBounder.setAllOpaque(false);
@@ -323,6 +337,7 @@ public:
}
virtual void restore() {
+ mBounder.setType(CommonCheck::kDrawSprite_Type); // for layer draws
int depth = getSaveCount();
if (depth == mTransparentLayer) {
mTransparentLayer = 0;
@@ -653,32 +668,404 @@ public:
class RingCheck : public CommonCheck {
public:
RingCheck(const WTF::Vector<WebCore::IntRect>& rings,
- const WebCore::IntPoint& location) : mSuccess(true) {
+ const WebCore::IntRect& bitBounds, const WebCore::IntRect& testBounds)
+ : mTestBounds(testBounds)
+ , mBitBounds(bitBounds)
+ {
const WebCore::IntRect* r;
for (r = rings.begin(); r != rings.end(); r++) {
SkIRect fatter = {r->x(), r->y(), r->right(), r->bottom()};
fatter.inset(-CURSOR_RING_HIT_TEST_RADIUS, -CURSOR_RING_HIT_TEST_RADIUS);
- DBG_NAV_LOGD("fat=(%d,%d,r=%d,b=%d)", fatter.fLeft, fatter.fTop,
+ DBG_NAV_LOGD("RingCheck fat=(%d,%d,r=%d,b=%d)", fatter.fLeft, fatter.fTop,
fatter.fRight, fatter.fBottom);
- mRings.op(fatter, SkRegion::kUnion_Op);
+ mTextSlop.op(fatter, SkRegion::kUnion_Op);
+ mTextTest.op(*r, SkRegion::kUnion_Op);
}
- DBG_NAV_LOGD("translate=(%d,%d)", -location.x(), -location.y());
- mRings.translate(-location.x(), -location.y());
+ int dx = -bitBounds.x();
+ int dy = -bitBounds.y();
+ DBG_NAV_LOGD("RingCheck translate=(%d,%d)", dx, dy);
+ mTextSlop.translate(dx, dy);
+ mTextTest.translate(dx, dy);
+ mTestBounds.translate(dx, dy);
+ mEmpty.setEmpty();
}
- virtual bool onIRect(const SkIRect& rect) {
- if (mSuccess && mType == kDrawGlyph_Type) {
- DBG_NAV_LOGD("contains (%d,%d,r=%d,b=%d) == %s",
- rect.fLeft, rect.fTop, rect.fRight, rect.fBottom,
- mRings.contains(rect) ? "true" : "false");
- mSuccess &= mRings.contains(rect);
+ bool hiddenRings(SkRegion* clipped)
+ {
+ findBestLayer();
+ if (!mBestLayer) {
+ DBG_NAV_LOG("RingCheck empty");
+ clipped->setEmpty();
+ return true;
}
+ const SkRegion* layersEnd = mLayers.end();
+ const Type* layerTypes = &mLayerTypes[mBestLayer - mLayers.begin()];
+ bool collectGlyphs = true;
+ bool collectOvers = false;
+ SkRegion over;
+ for (const SkRegion* layers = mBestLayer; layers != layersEnd; layers++) {
+ Type layerType = *layerTypes++;
+ DBG_NAV_LOGD("RingCheck #%d %s (%d,%d,r=%d,b=%d)",
+ layers - mLayers.begin(), TypeNames[layerType],
+ layers->getBounds().fLeft, layers->getBounds().fTop,
+ layers->getBounds().fRight, layers->getBounds().fBottom);
+ if (collectGlyphs && layerType == kDrawGlyph_Type) {
+ DBG_NAV_LOGD("RingCheck #%d collectOvers", layers - mLayers.begin());
+ collectOvers = true;
+ clipped->op(*layers, SkRegion::kUnion_Op);
+ }
+ collectGlyphs &= layerType != kPushLayer_Type;
+ if (collectOvers && (layerType == kDrawRect_Type
+ || (!collectGlyphs && layerType == kDrawSprite_Type)))
+ {
+ DBG_NAV_LOGD("RingCheck #%d over.op", layers - mLayers.begin());
+ over.op(*layers, SkRegion::kUnion_Op);
+ }
+ }
+ bool result = !collectOvers || clipped->intersects(over);
+ const SkIRect t = clipped->getBounds();
+ const SkIRect o = over.getBounds();
+ clipped->op(over, SkRegion::kDifference_Op);
+ clipped->translate(mBitBounds.x(), mBitBounds.y());
+ const SkIRect c = clipped->getBounds();
+ DBG_NAV_LOGD("RingCheck intersects=%s text=(%d,%d,r=%d,b=%d)"
+ " over=(%d,%d,r=%d,b=%d) clipped=(%d,%d,r=%d,b=%d)",
+ result ? "true" : "false",
+ t.fLeft, t.fTop, t.fRight, t.fBottom,
+ o.fLeft, o.fTop, o.fRight, o.fBottom,
+ c.fLeft, c.fTop, c.fRight, c.fBottom);
+ return result;
+ }
+
+ void push(Type type, const SkIRect& bounds)
+ {
+#if DEBUG_NAV_UI
+ // this caches the push string and subquently ignores if pushSave
+ // is immediately followed by popLayer. Push/pop pairs happen
+ // frequently and just add noise to the log.
+ static String lastLog;
+ String currentLog = String("RingCheck append #")
+ + String::number(mLayers.size())
+ + " type=" + TypeNames[type] + " bounds=("
+ + String::number(bounds.fLeft)
+ + "," + String::number(bounds.fTop) + ","
+ + String::number(bounds.fRight) + ","
+ + String::number(bounds.fBottom) + ")";
+ if (lastLog.length() == 0 || type != kPopLayer_Type) {
+ if (lastLog.length() != 0)
+ DBG_NAV_LOGD("%s", lastLog.latin1().data());
+ if (type == kPushSave_Type)
+ lastLog = currentLog;
+ else
+ DBG_NAV_LOGD("%s", currentLog.latin1().data());
+ } else
+ lastLog = "";
+#endif
+ popEmpty();
+ if (type == kPopLayer_Type) {
+ Type last = mLayerTypes.last();
+ // remove empty brackets
+ if (last == kPushLayer_Type || last == kPushSave_Type) {
+ mLayers.removeLast();
+ mLayerTypes.removeLast();
+ return;
+ }
+ // remove non-layer brackets
+ int stack = 0;
+ Type* types = mLayerTypes.end();
+ while (types != mLayerTypes.begin()) {
+ Type type = *--types;
+ if (type == kPopLayer_Type) {
+ stack++;
+ continue;
+ }
+ if (type != kPushLayer_Type && type != kPushSave_Type)
+ continue;
+ if (--stack >= 0)
+ continue;
+ if (type == kPushLayer_Type)
+ break;
+ int remove = types - mLayerTypes.begin();
+ DBG_NAV_LOGD("RingCheck remove=%d mLayers.size=%d"
+ " mLayerTypes.size=%d", remove, mLayers.size(),
+ mLayerTypes.size());
+ mLayers.remove(remove);
+ mLayerTypes.remove(remove);
+ return;
+ }
+ }
+ mLayers.append(bounds);
+ mLayerTypes.append(type);
+ }
+
+ void startText(const SkPaint& paint)
+ {
+ mPaint = &paint;
+ if (!mLayerTypes.isEmpty() && mLayerTypes.last() == kDrawGlyph_Type
+ && !mLayers.last().isEmpty()) {
+ push(kDrawGlyph_Type, mEmpty);
+ }
+ }
+
+ bool textOutsideRings()
+ {
+ findBestLayer();
+ if (!mBestLayer) {
+ DBG_NAV_LOG("RingCheck empty");
+ return false;
+ }
+ const SkRegion* layers = mBestLayer;
+ const Type* layerTypes = &mLayerTypes[layers - mLayers.begin()];
+ // back up to include text drawn before the best layer
+ SkRegion active = SkRegion(mBitBounds);
+ active.translate(-mBitBounds.x(), -mBitBounds.y());
+ while (layers != mLayers.begin()) {
+ --layers;
+ Type layerType = *--layerTypes;
+ DBG_NAV_LOGD("RingCheck #%d %s"
+ " mTestBounds=(%d,%d,r=%d,b=%d) layers=(%d,%d,r=%d,b=%d)"
+ " active=(%d,%d,r=%d,b=%d)",
+ layers - mLayers.begin(), TypeNames[layerType],
+ mTestBounds.getBounds().fLeft, mTestBounds.getBounds().fTop,
+ mTestBounds.getBounds().fRight, mTestBounds.getBounds().fBottom,
+ layers->getBounds().fLeft, layers->getBounds().fTop,
+ layers->getBounds().fRight, layers->getBounds().fBottom,
+ active.getBounds().fLeft, active.getBounds().fTop,
+ active.getBounds().fRight, active.getBounds().fBottom);
+ if (layerType == kDrawRect_Type) {
+ SkRegion temp = *layers;
+ temp.op(mTestBounds, SkRegion::kIntersect_Op);
+ active.op(temp, SkRegion::kDifference_Op);
+ if (active.isEmpty()) {
+ DBG_NAV_LOGD("RingCheck #%d empty", layers - mLayers.begin());
+ break;
+ }
+ } else if (layerType == kDrawGlyph_Type) {
+ SkRegion temp = *layers;
+ temp.op(active, SkRegion::kIntersect_Op);
+ if (!mTestBounds.intersects(temp))
+ continue;
+ if (!mTestBounds.contains(temp))
+ return false;
+ } else
+ break;
+ }
+ layers = mBestLayer;
+ layerTypes = &mLayerTypes[layers - mLayers.begin()];
+ bool foundGlyph = false;
+ bool collectGlyphs = true;
+ do {
+ Type layerType = *layerTypes++;
+ DBG_NAV_LOGD("RingCheck #%d %s mTestBounds=(%d,%d,r=%d,b=%d)"
+ " layers=(%d,%d,r=%d,b=%d) collects=%s intersects=%s contains=%s",
+ layers - mLayers.begin(), TypeNames[layerType],
+ mTestBounds.getBounds().fLeft, mTestBounds.getBounds().fTop,
+ mTestBounds.getBounds().fRight, mTestBounds.getBounds().fBottom,
+ layers->getBounds().fLeft, layers->getBounds().fTop,
+ layers->getBounds().fRight, layers->getBounds().fBottom,
+ collectGlyphs ? "true" : "false",
+ mTestBounds.intersects(*layers) ? "true" : "false",
+ mTestBounds.contains(*layers) ? "true" : "false");
+ if (collectGlyphs && layerType == kDrawGlyph_Type) {
+ if (!mTestBounds.intersects(*layers))
+ continue;
+ if (!mTestBounds.contains(*layers))
+ return false;
+ foundGlyph = true;
+ }
+ collectGlyphs &= layerType != kPushLayer_Type;
+ } while (++layers != mLayers.end());
+ DBG_NAV_LOGD("RingCheck foundGlyph=%s", foundGlyph ? "true" : "false");
+ return foundGlyph;
+ }
+
+protected:
+ virtual bool onIRect(const SkIRect& rect)
+ {
+ joinGlyphs(rect);
+ if (mType != kDrawGlyph_Type && mType != kDrawRect_Type
+ && mType != kDrawSprite_Type)
+ return false;
+ if (mLayerTypes.isEmpty() || mLayerTypes.last() != mType)
+ push(mType, mEmpty);
+ DBG_NAV_LOGD("RingCheck join %s (%d,%d,r=%d,b=%d) '%c'",
+ TypeNames[mType], rect.fLeft, rect.fTop, rect.fRight, rect.fBottom,
+ mCh);
+ mLayers.last().op(rect, SkRegion::kUnion_Op);
return false;
}
- bool success() { return mSuccess; }
- SkRegion mRings;
- bool mSuccess;
+ virtual bool onIRectGlyph(const SkIRect& rect,
+ const SkBounder::GlyphRec& rec)
+ {
+ mCh = ' ';
+ if (mPaint) {
+ SkUnichar unichar;
+ SkPaint utfPaint = *mPaint;
+ utfPaint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
+ utfPaint.glyphsToUnichars(&rec.fGlyphID, 1, &unichar);
+ mCh = unichar < 0x7f ? unichar : '?';
+ }
+ return onIRect(rect);
+ }
+
+private:
+ int calcOverlap(SkRegion& testRegion)
+ {
+ if (testRegion.isEmpty())
+ return INT_MAX;
+ testRegion.op(mTextTest, SkRegion::kXOR_Op);
+ SkRegion::Iterator iter(testRegion);
+ int area = 0;
+ while (!iter.done()) {
+ const SkIRect& cr = iter.rect();
+ area += cr.width() * cr.height();
+ iter.next();
+ }
+ DBG_NAV_LOGD("RingCheck area=%d", area);
+ return area;
+ }
+
+ void findBestLayer()
+ {
+ popEmpty();
+ mBestLayer = 0;
+ const SkRegion* layers = mLayers.begin();
+ const SkRegion* layersEnd = mLayers.end();
+ if (layers == layersEnd) {
+ DBG_NAV_LOG("RingCheck empty");
+ return;
+ }
+ // find text most like focus rings by xoring found with original
+ int bestArea = INT_MAX;
+ const SkRegion* testLayer = 0;
+ SkRegion testRegion;
+ const Type* layerTypes = &mLayerTypes[layers - mLayers.begin()];
+ for (; layers != mLayers.end(); layers++) {
+ Type layerType = *layerTypes++;
+#if DEBUG_NAV_UI
+ const SkIRect& gb = layers->getBounds();
+ const SkIRect& tb = mTextSlop.getBounds();
+ DBG_NAV_LOGD("RingCheck #%d %s mTextSlop=(%d,%d,%d,%d)"
+ " contains=%s bounds=(%d,%d,%d,%d)",
+ layers - mLayers.begin(), TypeNames[layerType],
+ tb.fLeft, tb.fTop, tb.fRight, tb.fBottom,
+ mTextSlop.contains(*layers) ? "true" : "false",
+ gb.fLeft, gb.fTop, gb.fRight, gb.fBottom);
+#endif
+ if (layerType == kDrawGlyph_Type) {
+ if (!testLayer)
+ testLayer = layers;
+ if (mTextSlop.contains(*layers)) {
+ testRegion.op(*layers, SkRegion::kUnion_Op);
+ continue;
+ }
+ }
+ if (testLayer) {
+ int area = calcOverlap(testRegion);
+ if (bestArea > area) {
+ bestArea = area;
+ mBestLayer = testLayer;
+ }
+ DBG_NAV_LOGD("RingCheck #%d push test=%d best=%d",
+ layers - mLayers.begin(), testLayer - mLayers.begin(),
+ mBestLayer ? mBestLayer - mLayers.begin() : -1);
+ testRegion.setEmpty();
+ testLayer = 0;
+ }
+ }
+ if (testLayer && bestArea > calcOverlap(testRegion)) {
+ DBG_NAV_LOGD("RingCheck last best=%d", testLayer - mLayers.begin());
+ mBestLayer = testLayer;
+ }
+ }
+
+ void popEmpty()
+ {
+ if (mLayerTypes.size() == 0)
+ return;
+ Type last = mLayerTypes.last();
+ if (last >= kPopLayer_Type)
+ return;
+ const SkRegion& area = mLayers.last();
+ if (!area.isEmpty())
+ return;
+ DBG_NAV_LOGD("RingCheck #%d %s", mLayers.size() - 1, TypeNames[last]);
+ mLayers.removeLast();
+ mLayerTypes.removeLast();
+ }
+
+ SkRegion mTestBounds;
+ IntRect mBitBounds;
+ SkIRect mEmpty;
+ const SkRegion* mBestLayer;
+ SkRegion mTextSlop; // outset rects for inclusion test
+ SkRegion mTextTest; // exact rects for xor area test
+ Type mLastType;
+ Vector<SkRegion> mLayers;
+ Vector<Type> mLayerTypes;
+ const SkPaint* mPaint;
+ char mCh;
+};
+
+class RingCanvas : public BoundsCanvas {
+public:
+ RingCanvas(RingCheck* bounder)
+ : INHERITED(bounder)
+ {
+ }
+
+protected:
+ virtual void drawText(const void* text, size_t byteLength, SkScalar x,
+ SkScalar y, const SkPaint& paint) {
+ static_cast<RingCheck&>(mBounder).startText(paint);
+ INHERITED::drawText(text, byteLength, x, y, paint);
+ }
+
+ virtual void drawPosText(const void* text, size_t byteLength,
+ const SkPoint pos[], const SkPaint& paint) {
+ static_cast<RingCheck&>(mBounder).startText(paint);
+ INHERITED::drawPosText(text, byteLength, pos, paint);
+ }
+
+ virtual void drawTextOnPath(const void* text, size_t byteLength,
+ const SkPath& path, const SkMatrix* matrix,
+ const SkPaint& paint) {
+ static_cast<RingCheck&>(mBounder).startText(paint);
+ INHERITED::drawTextOnPath(text, byteLength, path, matrix, paint);
+ }
+
+ virtual void drawPosTextH(const void* text, size_t byteLength,
+ const SkScalar xpos[], SkScalar constY,
+ const SkPaint& paint) {
+ static_cast<RingCheck&>(mBounder).startText(paint);
+ INHERITED::drawPosTextH(text, byteLength, xpos, constY, paint);
+ }
+
+ virtual int save(SaveFlags flags)
+ {
+ RingCheck& bounder = static_cast<RingCheck&>(mBounder);
+ bounder.push(CommonCheck::kPushSave_Type, getTotalClip().getBounds());
+ return INHERITED::save(flags);
+ }
+
+ virtual int saveLayer(const SkRect* bounds, const SkPaint* paint,
+ SaveFlags flags)
+ {
+ RingCheck& bounder = static_cast<RingCheck&>(mBounder);
+ bounder.push(CommonCheck::kPushLayer_Type, getTotalClip().getBounds());
+ return INHERITED::save(flags);
+ }
+
+ virtual void restore()
+ {
+ RingCheck& bounder = static_cast<RingCheck&>(mBounder);
+ bounder.push(CommonCheck::kPopLayer_Type, getTotalClip().getBounds());
+ INHERITED::restore();
+ }
+
+private:
+ typedef BoundsCanvas INHERITED;
};
bool CachedRoot::adjustForScroll(BestData* best, CachedFrame::Direction direction,
@@ -709,6 +1096,29 @@ bool CachedRoot::adjustForScroll(BestData* best, CachedFrame::Direction directio
return false;
}
+void CachedRoot::calcBitBounds(const IntRect& nodeBounds, IntRect* bitBounds) const
+{
+ IntRect contentBounds = IntRect(0, 0, mPicture->width(), mPicture->height());
+ IntRect overBounds = nodeBounds;
+ overBounds.inflate(kMargin);
+ *bitBounds = mScrolledBounds;
+ bitBounds->unite(mViewBounds);
+ bitBounds->intersect(contentBounds);
+ bitBounds->intersect(overBounds);
+ DBG_NAV_LOGD("contentBounds=(%d,%d,r=%d,b=%d) overBounds=(%d,%d,r=%d,b=%d)"
+ " mScrolledBounds=(%d,%d,r=%d,b=%d) mViewBounds=(%d,%d,r=%d,b=%d)"
+ " bitBounds=(%d,%d,r=%d,b=%d)",
+ contentBounds.x(), contentBounds.y(), contentBounds.right(),
+ contentBounds.bottom(),
+ overBounds.x(), overBounds.y(), overBounds.right(), overBounds.bottom(),
+ mScrolledBounds.x(), mScrolledBounds.y(), mScrolledBounds.right(),
+ mScrolledBounds.bottom(),
+ mViewBounds.x(), mViewBounds.y(), mViewBounds.right(),
+ mViewBounds.bottom(),
+ bitBounds->x(), bitBounds->y(), bitBounds->right(),
+ bitBounds->bottom());
+}
+
int CachedRoot::checkForCenter(int x, int y) const
{
@@ -745,22 +1155,30 @@ void CachedRoot::checkForJiggle(int* xDeltaPtr) const
bool CachedRoot::checkRings(SkPicture* picture,
const WTF::Vector<WebCore::IntRect>& rings,
- const WebCore::IntRect& bounds) const
+ const WebCore::IntRect& nodeBounds,
+ const WebCore::IntRect& testBounds) const
{
if (!picture)
return false;
- RingCheck ringCheck(rings, bounds.location());
- BoundsCanvas checker(&ringCheck);
+ IntRect bitBounds;
+ calcBitBounds(nodeBounds, &bitBounds);
+ RingCheck ringCheck(rings, bitBounds, testBounds);
+ RingCanvas checker(&ringCheck);
SkBitmap bitmap;
- bitmap.setConfig(SkBitmap::kARGB_8888_Config, bounds.width(),
- bounds.height());
+ bitmap.setConfig(SkBitmap::kARGB_8888_Config, bitBounds.width(),
+ bitBounds.height());
checker.setBitmapDevice(bitmap);
- checker.translate(SkIntToScalar(-bounds.x()), SkIntToScalar(-bounds.y()));
+ checker.translate(SkIntToScalar(-bitBounds.x()),
+ SkIntToScalar(-bitBounds.y()));
checker.drawPicture(*picture);
- DBG_NAV_LOGD("bounds=(%d,%d,r=%d,b=%d) success=%s",
- bounds.x(), bounds.y(), bounds.right(), bounds.bottom(),
- ringCheck.success() ? "true" : "false");
- return ringCheck.success();
+ bool result = ringCheck.textOutsideRings();
+ DBG_NAV_LOGD("bitBounds=(%d,%d,r=%d,b=%d) nodeBounds=(%d,%d,r=%d,b=%d)"
+ " testBounds=(%d,%d,r=%d,b=%d) success=%s",
+ bitBounds.x(), bitBounds.y(), bitBounds.right(), bitBounds.bottom(),
+ nodeBounds.x(), nodeBounds.y(), nodeBounds.right(), nodeBounds.bottom(),
+ testBounds.x(), testBounds.y(), testBounds.right(), testBounds.bottom(),
+ result ? "true" : "false");
+ return result;
}
void CachedRoot::draw(FindCanvas& canvas) const
@@ -999,7 +1417,9 @@ void CachedRoot::innerMove(const CachedNode* node, BestData* bestData,
if (bestData->mNode != NULL) {
mHistory->addToVisited(bestData->mNode, direction);
mHistory->mNavBounds = bestData->bounds();
- mHistory->mMouseBounds = bestData->mouseBounds();
+ mHistory->mMouseBounds =
+ cursorFrame->unadjustBounds(bestData->mNode,
+ bestData->mouseBounds());
} else if (scroll->x() != 0 || scroll->y() != 0) {
WebCore::IntRect newBounds = mHistory->mNavBounds;
int offsetX = scroll->x();
@@ -1068,7 +1488,7 @@ bool CachedRoot::innerUp(const CachedNode* test, BestData* bestData) const
return true;
}
-WebCore::String CachedRoot::imageURI(int x, int y) const
+WTF::String CachedRoot::imageURI(int x, int y) const
{
ImageCheck imageCheck;
ImageCanvas checker(&imageCheck);
@@ -1077,13 +1497,13 @@ WebCore::String CachedRoot::imageURI(int x, int y) const
checker.setBitmapDevice(bitmap);
checker.translate(SkIntToScalar(-x), SkIntToScalar(-y));
checker.drawPicture(*pictureAt(x, y));
- return WebCore::String(checker.mURI);
+ return WTF::String(checker.mURI);
}
bool CachedRoot::maskIfHidden(BestData* best) const
{
const CachedNode* bestNode = best->mNode;
- if (bestNode->isUnclipped() || bestNode->isTransparent())
+ if (bestNode->isUnclipped())
return false;
const CachedFrame* frame = best->mFrame;
SkPicture* picture = frame->picture(bestNode);
@@ -1091,115 +1511,42 @@ bool CachedRoot::maskIfHidden(BestData* best) const
DBG_NAV_LOG("missing picture");
return false;
}
- // given the picture matching this nav cache
- // create an SkBitmap with dimensions of the cursor intersected w/ extended view
- const WebCore::IntRect& nodeBounds = bestNode->bounds(frame);
- WebCore::IntRect bounds = nodeBounds;
- bounds.intersect(mScrolledBounds);
- int leftMargin = bounds.x() == nodeBounds.x() ? kMargin : 0;
- int topMargin = bounds.y() == nodeBounds.y() ? kMargin : 0;
- int rightMargin = bounds.right() == nodeBounds.right() ? kMargin : 0;
- int bottomMargin = bounds.bottom() == nodeBounds.bottom() ? kMargin : 0;
- bool unclipped = (leftMargin & topMargin & rightMargin & bottomMargin) != 0;
- WebCore::IntRect marginBounds = nodeBounds;
- marginBounds.inflate(kMargin);
- marginBounds.intersect(mScrolledBounds);
- SkScalar offsetX = SkIntToScalar(leftMargin - bounds.x());
- SkScalar offsetY = SkIntToScalar(topMargin - bounds.y());
-#if USE(ACCELERATED_COMPOSITING)
- // When cached nodes are constructed in CacheBuilder.cpp, their
- // unclipped attribute is set so this condition won't be reached.
- // In the future, layers may contain nodes that can be clipped.
- // So to be safe, adjust the layer picture by its offset.
- if (bestNode->isInLayer()) {
- const CachedLayer* cachedLayer = frame->layer(bestNode);
- const LayerAndroid* layer = cachedLayer->layer(mRootLayer);
- SkMatrix pictMatrix;
- layer->localToGlobal(&pictMatrix);
- // FIXME: ignore scale, rotation for now
- offsetX += pictMatrix.getTranslateX();
- offsetY += pictMatrix.getTranslateY();
- DBG_NAV_LOGD("layer picture=%p (%g,%g)", picture,
- pictMatrix.getTranslateX(), pictMatrix.getTranslateY());
- }
-#endif
- BoundsCheck boundsCheck;
- BoundsCanvas checker(&boundsCheck);
- boundsCheck.mBounds.set(leftMargin, topMargin,
- leftMargin + bounds.width(), topMargin + bounds.height());
- boundsCheck.mBoundsSlop = boundsCheck.mBounds;
- boundsCheck.mBoundsSlop.inset(-kSlop, -kSlop);
+ Vector<IntRect> rings;
+ bestNode->cursorRings(frame, &rings);
+ const WebCore::IntRect& bounds = bestNode->bounds(frame);
+ IntRect bitBounds;
+ calcBitBounds(bounds, &bitBounds);
+ RingCheck ringCheck(rings, bitBounds, bounds);
+ RingCanvas checker(&ringCheck);
SkBitmap bitmap;
- bitmap.setConfig(SkBitmap::kARGB_8888_Config, marginBounds.width(),
- marginBounds.height());
+ bitmap.setConfig(SkBitmap::kARGB_8888_Config, bitBounds.width(),
+ bitBounds.height());
checker.setBitmapDevice(bitmap);
- // insert probes to be called when the data corresponding to this ring is drawn
- // need to know if ring was generated by text, image, or parent (like div)
- // ? need to know (like imdb menu bar) to give up sometimes (when?)
- checker.translate(offsetX, offsetY);
+ checker.translate(SkIntToScalar(-bitBounds.x()),
+ SkIntToScalar(-bitBounds.y()));
checker.drawPicture(*picture);
- boundsCheck.checkLast();
- // was it not drawn or clipped out?
+ SkRegion clipRgn;
+ bool clipped = ringCheck.hiddenRings(&clipRgn);
CachedNode* node = const_cast<CachedNode*>(best->mNode);
- if (boundsCheck.hidden()) { // if hidden, return false so that nav can try again
-#if DEBUG_NAV_UI
- const SkIRect& m = boundsCheck.mBounds;
- const SkIRect& s = boundsCheck.mBoundsSlop;
- DBG_NAV_LOGD("hidden node:%p (%d) mBounds={%d,%d,%d,%d} mBoundsSlop="
- "{%d,%d,%d,%d}", node, node->index(),
- m.fLeft, m.fTop, m.fRight, m.fBottom,
- s.fLeft, s.fTop, s.fRight, s.fBottom);
- const SkIRect& o = boundsCheck.mDrawnOver.getBounds();
- const SkIRect& l = boundsCheck.mLastAll;
- const SkIRect& u = boundsCheck.mUnion;
- DBG_NAV_LOGD("hidden mDrawnOver={%d,%d,%d,%d} mLastAll={%d,%d,%d,%d}"
- " mUnion={%d,%d,%d,%d}",
- o.fLeft, o.fTop, o.fRight, o.fBottom,
- l.fLeft, l.fTop, l.fRight, l.fBottom,
- u.fLeft, u.fTop, u.fRight, u.fBottom);
- const SkIRect& a = boundsCheck.mAllDrawnIn;
- const WebCore::IntRect& c = mScrolledBounds;
- const WebCore::IntRect& b = nodeBounds;
- DBG_NAV_LOGD("hidden mAllDrawnIn={%d,%d,%d,%d}"
- " mScrolledBounds={%d,%d,%d,%d} nodeBounds={%d,%d,%d,%d}",
- a.fLeft, a.fTop, a.fRight, a.fBottom,
- c.x(), c.y(), c.right(), c.bottom(),
- b.x(), b.y(), b.right(), b.bottom());
- DBG_NAV_LOGD("bits.mWidth=%d bits.mHeight=%d transX=%d transY=%d",
- marginBounds.width(),marginBounds.height(),
- kMargin - bounds.x(), kMargin - bounds.y());
-#endif
+ DBG_NAV_LOGD("clipped=%s clipRgn.isEmpty=%s", clipped ? "true" : "false",
+ clipRgn.isEmpty() ? "true" : "false");
+ if (clipped && clipRgn.isEmpty()) {
node->setDisabled(true);
- node->setClippedOut(unclipped == false);
+ IntRect clippedBounds = bounds;
+ clippedBounds.intersect(bitBounds);
+ node->setClippedOut(clippedBounds != bounds);
return true;
}
// was it partially occluded by later drawing?
// if partially occluded, modify the bounds so that the mouse click has a better x,y
- const SkIRect& over = boundsCheck.mDrawnOver.getBounds();
- if (over.isEmpty() == false) {
-#if DEBUG_NAV_UI
- SkIRect orig = boundsCheck.mBounds;
-#endif
- SkIRect& base = boundsCheck.mBounds;
- if (base.fLeft < over.fRight && base.fRight > over.fRight)
- base.fLeft = over.fRight;
- else if (base.fRight > over.fLeft && base.fLeft < over.fLeft)
- base.fRight = over.fLeft;
- if (base.fTop < over.fBottom && base.fBottom > over.fBottom)
- base.fTop = over.fBottom;
- else if (base.fBottom > over.fTop && base.fTop < over.fTop)
- base.fBottom = over.fTop;
-#if DEBUG_NAV_UI
- const SkIRect& modded = boundsCheck.mBounds;
- DBG_NAV_LOGD("partially occluded node:%p (%d) old:{%d,%d,%d,%d}"
- " new:{%d,%d,%d,%d}", node, node->index(),
- orig.fLeft, orig.fTop, orig.fRight, orig.fBottom,
- base.fLeft, base.fTop, base.fRight, base.fBottom);
-#endif
- best->setMouseBounds(WebCore::IntRect(bounds.x() + base.fLeft - kMargin,
- bounds.y() + base.fTop - kMargin, base.width(), base.height()));
+ if (clipped) {
+ DBG_NAV_LOGD("clipped clipRgn={%d,%d,r=%d,b=%d}",
+ clipRgn.getBounds().fLeft, clipRgn.getBounds().fTop,
+ clipRgn.getBounds().fRight, clipRgn.getBounds().fBottom);
+ best->setMouseBounds(clipRgn.getBounds());
node->clip(best->mouseBounds());
- }
+ } else
+ node->fixUpCursorRects(frame);
return false;
}
diff --git a/WebKit/android/nav/CachedRoot.h b/WebKit/android/nav/CachedRoot.h
index 6e9fff0..8c263f8 100644
--- a/WebKit/android/nav/CachedRoot.h
+++ b/WebKit/android/nav/CachedRoot.h
@@ -49,10 +49,12 @@ public:
bool adjustForScroll(BestData* , Direction , WebCore::IntPoint* scrollPtr,
bool findClosest);
const SkRegion& baseUncovered() const { return mBaseUncovered; }
+ void calcBitBounds(const IntRect& , IntRect* ) const;
int checkForCenter(int x, int y) const;
void checkForJiggle(int* ) const;
bool checkRings(SkPicture* , const WTF::Vector<WebCore::IntRect>& rings,
- const WebCore::IntRect& bounds) const;
+ const WebCore::IntRect& nodeBounds,
+ const WebCore::IntRect& testBounds) const;
WebCore::IntPoint cursorLocation() const;
int documentHeight() { return mContents.height(); }
int documentWidth() { return mContents.width(); }
@@ -72,7 +74,7 @@ public:
WebCore::IntPoint* scroll, bool firstCall);
bool innerRight(const CachedNode* , BestData* ) const;
bool innerUp(const CachedNode* , BestData* ) const;
- WebCore::String imageURI(int x, int y) const;
+ WTF::String imageURI(int x, int y) const;
bool maskIfHidden(BestData* ) const;
const CachedNode* moveCursor(Direction , const CachedFrame** , WebCore::IntPoint* scroll);
/**
@@ -96,7 +98,10 @@ public:
void setTextGeneration(int textGeneration) { mTextGeneration = textGeneration; }
void setMaxScroll(int x, int y) { mMaxXScroll = x; mMaxYScroll = y; }
void setPicture(SkPicture* picture) { mPicture = picture; }
- void setRootLayer(WebCore::LayerAndroid* layer) { mRootLayer = layer; }
+ void setRootLayer(WebCore::LayerAndroid* layer) {
+ mRootLayer = layer;
+ resetLayers();
+ }
void setScrollOnly(bool state) { mScrollOnly = state; }
void setSelection(int start, int end) { mSelectionStart = start; mSelectionEnd = end; }
void setupScrolledBounds() const { mScrolledBounds = mViewBounds; }
diff --git a/WebKit/android/nav/FindCanvas.cpp b/WebKit/android/nav/FindCanvas.cpp
index d8e908b..d60fffd 100644
--- a/WebKit/android/nav/FindCanvas.cpp
+++ b/WebKit/android/nav/FindCanvas.cpp
@@ -98,7 +98,7 @@ GlyphSet::~GlyphSet() {
// part of mLowerGlyphs
}
-GlyphSet::GlyphSet& GlyphSet::operator=(GlyphSet& src) {
+GlyphSet& GlyphSet::operator=(GlyphSet& src) {
mTypeface = src.mTypeface;
mCount = src.mCount;
if (mCount > MAX_STORAGE_COUNT) {
@@ -361,48 +361,40 @@ void FindCanvas::findHelper(const void* text, size_t byteLength,
// We need an SkIRect for SkRegion operations.
SkIRect iRect;
rect.roundOut(&iRect);
- // If the rectangle is partially clipped, assume that the text is
- // not visible, so skip this match.
- if (getTotalClip().contains(iRect)) {
- // Want to outset the drawn rectangle by the same amount as
- // mOutset
- iRect.inset(-INTEGER_OUTSET, -INTEGER_OUTSET);
- SkRegion regionToAdd(iRect);
- if (!mWorkingRegion.isEmpty()) {
- // If this is on the same line as our working region, make
- // sure that they are close enough together that they are
- // supposed to be part of the same text string.
- // The width of two spaces has arbitrarily been chosen.
- const SkIRect& workingBounds = mWorkingRegion.getBounds();
- if (workingBounds.fTop <= iRect.fBottom &&
- workingBounds.fBottom >= iRect.fTop &&
- SkIntToScalar(iRect.fLeft - workingBounds.fRight) >
- approximateSpaceWidth(paint)) {
- index = -1; // Will increase to 0 on next run
- // In this case, we need to start from the beginning of
- // the text being searched and our search term.
- j = 0;
- mWorkingIndex = 0;
- mWorkingRegion.setEmpty();
- continue;
- }
- // Add the mWorkingRegion, which contains rectangles from
- // the previous line(s).
- regionToAdd.op(mWorkingRegion, SkRegion::kUnion_Op);
+ // Want to outset the drawn rectangle by the same amount as
+ // mOutset
+ iRect.inset(-INTEGER_OUTSET, -INTEGER_OUTSET);
+ SkRegion regionToAdd(iRect);
+ if (!mWorkingRegion.isEmpty()) {
+ // If this is on the same line as our working region, make
+ // sure that they are close enough together that they are
+ // supposed to be part of the same text string.
+ // The width of two spaces has arbitrarily been chosen.
+ const SkIRect& workingBounds = mWorkingRegion.getBounds();
+ if (workingBounds.fTop <= iRect.fBottom &&
+ workingBounds.fBottom >= iRect.fTop &&
+ SkIntToScalar(iRect.fLeft - workingBounds.fRight) >
+ approximateSpaceWidth(paint)) {
+ index = -1; // Will increase to 0 on next run
+ // In this case, we need to start from the beginning of
+ // the text being searched and our search term.
+ j = 0;
+ mWorkingIndex = 0;
+ mWorkingRegion.setEmpty();
+ continue;
}
- insertMatchInfo(regionToAdd);
+ // Add the mWorkingRegion, which contains rectangles from
+ // the previous line(s).
+ regionToAdd.op(mWorkingRegion, SkRegion::kUnion_Op);
+ }
+ insertMatchInfo(regionToAdd);
#if INCLUDE_SUBSTRING_MATCHES
- // Reset index to the location of the match and reset j to the
- // beginning, so that on the next iteration of the loop, index
- // will advance by 1 and we will compare the next character in
- // chars to the first character in the GlyphSet.
- index = matchIndex;
+ // Reset index to the location of the match and reset j to the
+ // beginning, so that on the next iteration of the loop, index
+ // will advance by 1 and we will compare the next character in
+ // chars to the first character in the GlyphSet.
+ index = matchIndex;
#endif
- } else {
- // This match was clipped out, so begin looking at the next
- // character from our hidden match
- index = matchIndex;
- }
// Whether the clip contained it or not, we need to start over
// with our recording canvas
resetWorkingCanvas();
@@ -443,12 +435,9 @@ void FindCanvas::findHelper(const void* text, size_t byteLength,
partial.inset(mOutset, mOutset);
SkIRect dest;
partial.roundOut(&dest);
- // Only save a partial if it is in the current clip.
- if (getTotalClip().contains(dest)) {
- mWorkingRegion.op(dest, SkRegion::kUnion_Op);
- mWorkingIndex = j;
- return;
- }
+ mWorkingRegion.op(dest, SkRegion::kUnion_Op);
+ mWorkingIndex = j;
+ return;
}
// This string doesn't go into the next drawText, so reset our working
// variables
@@ -675,4 +664,3 @@ void FindOnPage::setMatches(WTF::Vector<MatchInfo>* matches)
}
}
-
diff --git a/WebKit/android/nav/FindCanvas.h b/WebKit/android/nav/FindCanvas.h
index 34929ec..903279c 100644
--- a/WebKit/android/nav/FindCanvas.h
+++ b/WebKit/android/nav/FindCanvas.h
@@ -224,6 +224,7 @@ public:
bool currentMatchIsInLayer() const;
virtual void draw(SkCanvas* , LayerAndroid* );
void findNext(bool forward);
+ bool isCurrentLocationValid() { return m_hasCurrentLocation; }
void setMatches(WTF::Vector<MatchInfo>* matches);
private:
void drawMatch(const SkRegion& region, SkCanvas* canvas, bool focused);
diff --git a/WebKit/android/nav/SelectText.cpp b/WebKit/android/nav/SelectText.cpp
index 25f9482..f691d47 100644
--- a/WebKit/android/nav/SelectText.cpp
+++ b/WebKit/android/nav/SelectText.cpp
@@ -44,7 +44,7 @@
#include "TextRun.h"
#ifdef DEBUG_NAV_UI
-#include "CString.h"
+#include <wtf/text/CString.h>
#endif
#define VERBOSE_LOGGING 0
@@ -961,7 +961,7 @@ public:
return false;
}
- WebCore::String text() {
+ WTF::String text() {
if (mFlipped)
finish();
// the text has been copied in visual order. Reverse as needed if
@@ -977,7 +977,7 @@ public:
break;
}
}
- return WebCore::String(mSelectText.begin(), mSelectText.count());
+ return WTF::String(mSelectText.begin(), mSelectText.count());
}
protected:
@@ -1166,7 +1166,7 @@ static SkIRect findRight(const SkPicture& picture, const SkIRect& area,
return findEdge(picture, area, x, y, false, base);
}
-static WebCore::String text(const SkPicture& picture, const SkIRect& area,
+static WTF::String text(const SkPicture& picture, const SkIRect& area,
const SkIRect& start, int startBase, const SkIRect& end,
int endBase, bool flipped)
{
@@ -1275,12 +1275,6 @@ SelectText::SelectText()
void SelectText::draw(SkCanvas* canvas, LayerAndroid* layer)
{
- // Gmail makes layers appear dynamically the page scrolls. The picture
- // recorded when the selection begins is confused by the pictures seen
- // in subsequent layers. To work around this, only allow text selection
- // in the main picture.
- if (layer->uniqueId() != -1)
- return;
// FIXME: layer may not own the original selected picture
m_picture = layer->picture();
if (!m_picture)
@@ -1463,10 +1457,7 @@ bool SelectText::hitSelection(int x, int y) const
int bottom = m_selEnd.fBottom + CONTROL_HEIGHT / 2;
if (hitCorner(right, bottom, x, y))
return true;
- SkIRect test;
- test.set(x - CONTROL_WIDTH, y - CONTROL_HEIGHT, x + CONTROL_WIDTH,
- y + CONTROL_HEIGHT);
- return m_selRegion.intersects(test);
+ return m_selRegion.contains(x, y);
}
void SelectText::moveSelection(const SkPicture* picture, int x, int y)
diff --git a/WebKit/android/nav/WebView.cpp b/WebKit/android/nav/WebView.cpp
index 913c4ba..a9e5e10 100644
--- a/WebKit/android/nav/WebView.cpp
+++ b/WebKit/android/nav/WebView.cpp
@@ -29,11 +29,10 @@
#include "AndroidAnimation.h"
#include "AndroidLog.h"
-#include "AtomicString.h"
+#include "BaseLayerAndroid.h"
#include "CachedFrame.h"
#include "CachedNode.h"
#include "CachedRoot.h"
-#include "CString.h"
#include "DrawExtra.h"
#include "FindCanvas.h"
#include "Frame.h"
@@ -54,7 +53,9 @@
#ifdef ANDROID_INSTRUMENT
#include "TimeCounter.h"
#endif
+#include "TilesManager.h"
#include "WebCoreJni.h"
+#include "WebRequestContext.h"
#include "WebViewCore.h"
#include "android_graphics.h"
@@ -68,6 +69,8 @@
#include <JNIHelp.h>
#include <jni.h>
#include <ui/KeycodeLabels.h>
+#include <wtf/text/AtomicString.h>
+#include <wtf/text/CString.h>
namespace android {
@@ -104,7 +107,6 @@ enum DrawExtras { // keep this in sync with WebView.java
struct JavaGlue {
jweak m_obj;
jmethodID m_calcOurContentVisibleRectF;
- jmethodID m_clearTextEntry;
jmethodID m_overrideLoading;
jmethodID m_scrollBy;
jmethodID m_sendMoveFocus;
@@ -140,7 +142,6 @@ WebView(JNIEnv* env, jobject javaWebView, int viewImpl) :
m_javaGlue.m_obj = env->NewWeakGlobalRef(javaWebView);
m_javaGlue.m_scrollBy = GetJMethod(env, clazz, "setContentScrollBy", "(IIZ)Z");
m_javaGlue.m_calcOurContentVisibleRectF = GetJMethod(env, clazz, "calcOurContentVisibleRectF", "(Landroid/graphics/RectF;)V");
- m_javaGlue.m_clearTextEntry = GetJMethod(env, clazz, "clearTextEntry", "(Z)V");
m_javaGlue.m_overrideLoading = GetJMethod(env, clazz, "overrideLoading", "(Ljava/lang/String;)V");
m_javaGlue.m_sendMoveFocus = GetJMethod(env, clazz, "sendMoveFocus", "(II)V");
m_javaGlue.m_sendMoveMouse = GetJMethod(env, clazz, "sendMoveMouse", "(IIII)V");
@@ -173,11 +174,10 @@ WebView(JNIEnv* env, jobject javaWebView, int viewImpl) :
m_navPictureUI = 0;
m_generation = 0;
m_heightCanMeasure = false;
- m_ring.m_followedLink = false;
m_lastDx = 0;
m_lastDxTime = 0;
m_ringAnimationEnd = 0;
- m_rootLayer = 0;
+ m_baseLayer = 0;
}
~WebView()
@@ -190,7 +190,7 @@ WebView(JNIEnv* env, jobject javaWebView, int viewImpl) :
}
delete m_frameCacheUI;
delete m_navPictureUI;
- delete m_rootLayer;
+ delete m_baseLayer;
}
WebViewCore* getWebViewCore() const {
@@ -221,15 +221,6 @@ void hideCursor()
viewInvalidate();
}
-void clearTextEntry()
-{
- DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
- JNIEnv* env = JSC::Bindings::getJNIEnv();
- env->CallVoidMethod(m_javaGlue.object(env).get(),
- m_javaGlue.m_clearTextEntry, true);
- checkException(env);
-}
-
#if DUMP_NAV_CACHE
void debugDump()
{
@@ -276,7 +267,7 @@ void nativeRecordButtons(bool hasFocus, bool pressed, bool invalidate)
// button
if (!hasFocus) {
state = WebCore::RenderSkinAndroid::kNormal;
- } else if (m_ring.m_followedLink || pressed) {
+ } else if (pressed || m_ring.m_isPressed) {
state = WebCore::RenderSkinAndroid::kPressed;
} else {
state = WebCore::RenderSkinAndroid::kFocused;
@@ -303,10 +294,11 @@ void scrollRectOnScreen(const IntRect& rect)
SkRect visible;
calcOurContentVisibleRect(&visible);
#if USE(ACCELERATED_COMPOSITING)
- if (m_rootLayer) {
- m_rootLayer->updateFixedLayersPositions(visible);
- m_rootLayer->updatePositions();
- visible = m_rootLayer->subtractLayers(visible);
+ LayerAndroid* root = compositeRoot();
+ if (root) {
+ root->updateFixedLayersPositions(visible);
+ root->updatePositions();
+ visible = root->subtractLayers(visible);
}
#endif
int dx = 0;
@@ -350,7 +342,7 @@ void calcOurContentVisibleRect(SkRect* r)
void resetCursorRing()
{
- m_ring.m_followedLink = false;
+ m_ringAnimationEnd = 0;
m_viewImpl->m_hasCursorBounds = false;
}
@@ -372,36 +364,101 @@ bool drawCursorPreamble(CachedRoot* root)
m_ring.m_root = root;
m_ring.m_frame = frame;
m_ring.m_node = node;
+ SkMSec time = SkTime::GetMSecs();
+ m_ring.m_isPressed = time < m_ringAnimationEnd
+ && m_ringAnimationEnd != UINT_MAX;
return true;
}
void drawCursorPostamble()
{
- if (!m_ring.m_isButton && m_ring.m_flavor < CursorRing::NORMAL_ANIMATING)
+ if (m_ringAnimationEnd == UINT_MAX)
return;
SkMSec time = SkTime::GetMSecs();
if (time < m_ringAnimationEnd) {
// views assume that inval bounds coordinates are non-negative
WebCore::IntRect invalBounds(0, 0, INT_MAX, INT_MAX);
- invalBounds.intersect(m_ring.m_bounds);
+ invalBounds.intersect(m_ring.m_absBounds);
postInvalidateDelayed(m_ringAnimationEnd - time, invalBounds);
} else {
- if (m_ring.m_followedLink)
- hideCursor();
- m_ring.m_followedLink = false;
- m_ring.m_flavor = static_cast<CursorRing::Flavor>
- (m_ring.m_flavor - CursorRing::NORMAL_ANIMATING);
+ hideCursor();
}
}
-void drawExtras(SkCanvas* canvas, int extras)
+bool drawGL(WebCore::IntRect& viewRect, float scale, int extras)
{
+#if USE(ACCELERATED_COMPOSITING)
+ if (!m_baseLayer)
+ return false;
+
+ m_glWebViewState.resetExtra(false);
CachedRoot* root = getFrameCache(AllowNewer);
if (!root) {
DBG_NAV_LOG("!root");
if (extras == DrawExtrasCursorRing)
resetCursorRing();
- return;
+ return false;
+ }
+ DrawExtra* extra = 0;
+ switch (extras) {
+ case DrawExtrasFind:
+ extra = &m_findOnPage;
+ break;
+ case DrawExtrasSelection:
+ extra = &m_selectText;
+ break;
+ case DrawExtrasCursorRing:
+ if (drawCursorPreamble(root) && m_ring.setup()) {
+ if (!m_ring.m_isButton)
+ extra = &m_ring;
+ drawCursorPostamble();
+ }
+ break;
+ default:
+ ;
+ }
+
+ unsigned int pic = m_glWebViewState.currentPictureCounter();
+ if (extra) {
+ LayerAndroid* mainPicture = new LayerAndroid(m_navPictureUI);
+ m_glWebViewState.setExtra(extra, mainPicture);
+ } else {
+ m_glWebViewState.resetExtra(true);
+ }
+
+ SkRect visibleRect;
+ calcOurContentVisibleRect(&visibleRect);
+ bool ret = m_baseLayer->drawGL(viewRect, visibleRect, scale);
+ if (ret || m_glWebViewState.currentPictureCounter() != pic)
+ return true;
+#endif
+ return false;
+}
+
+PictureSet* draw(SkCanvas* canvas, SkColor bgColor, int extras, bool split)
+{
+ PictureSet* ret = 0;
+ if (!m_baseLayer) {
+ canvas->drawColor(bgColor);
+ return ret;
+ }
+
+ // draw the content of the base layer first
+ PictureSet* content = m_baseLayer->content();
+ int sc = canvas->save(SkCanvas::kClip_SaveFlag);
+ canvas->clipRect(SkRect::MakeLTRB(0, 0, content->width(),
+ content->height()), SkRegion::kDifference_Op);
+ canvas->drawColor(bgColor);
+ canvas->restoreToCount(sc);
+ if (content->draw(canvas))
+ ret = split ? new PictureSet(*content) : 0;
+
+ CachedRoot* root = getFrameCache(AllowNewer);
+ if (!root) {
+ DBG_NAV_LOG("!root");
+ if (extras == DrawExtrasCursorRing)
+ resetCursorRing();
+ return ret;
}
LayerAndroid mainPicture(m_navPictureUI);
DrawExtra* extra = 0;
@@ -425,22 +482,24 @@ void drawExtras(SkCanvas* canvas, int extras)
if (extra)
extra->draw(canvas, &mainPicture);
#if USE(ACCELERATED_COMPOSITING)
- if (!m_rootLayer)
- return;
- m_rootLayer->setExtra(extra);
+ LayerAndroid* compositeLayer = compositeRoot();
+ if (!compositeLayer)
+ return ret;
+ compositeLayer->setExtra(extra);
SkRect visible;
calcOurContentVisibleRect(&visible);
// call this to be sure we've adjusted for any scrolling or animations
// before we actually draw
- m_rootLayer->updateFixedLayersPositions(visible);
- m_rootLayer->updatePositions();
- // We have to set the canvas' matrix on the root layer
+ compositeLayer->updateFixedLayersPositions(visible);
+ compositeLayer->updatePositions();
+ // We have to set the canvas' matrix on the base layer
// (to have fixed layers work as intended)
SkAutoCanvasRestore restore(canvas, true);
- m_rootLayer->setMatrix(canvas->getTotalMatrix());
+ m_baseLayer->setMatrix(canvas->getTotalMatrix());
canvas->resetMatrix();
- m_rootLayer->draw(canvas);
+ m_baseLayer->draw(canvas);
#endif
+ return ret;
}
@@ -487,7 +546,7 @@ void fixCursor()
return;
int x, y;
const CachedFrame* frame;
- const CachedNode* node = m_frameCacheUI->findAt(bounds, &frame, &x, &y, false);
+ const CachedNode* node = m_frameCacheUI->findAt(bounds, &frame, &x, &y, true);
if (!node)
return;
// require that node have approximately the same bounds (+/- 4) and the same
@@ -565,7 +624,7 @@ CachedRoot* getFrameCache(FrameCachePermission allowNewer)
m_viewImpl->m_navPictureKit = 0;
m_viewImpl->gFrameCacheMutex.unlock();
if (m_frameCacheUI)
- m_frameCacheUI->setRootLayer(m_rootLayer);
+ m_frameCacheUI->setRootLayer(compositeRoot());
#if USE(ACCELERATED_COMPOSITING)
if (layerId >= 0) {
SkRect visible;
@@ -658,10 +717,10 @@ static CachedFrame::Direction KeyToDirection(int32_t keyCode)
}
}
-WebCore::String imageURI(int x, int y)
+WTF::String imageURI(int x, int y)
{
const CachedRoot* root = getFrameCache(DontAllowNewer);
- return root ? root->imageURI(x, y) : WebCore::String();
+ return root ? root->imageURI(x, y) : WTF::String();
}
bool cursorWantsKeyEvents()
@@ -701,8 +760,6 @@ bool moveCursor(int keyCode, int count, bool ignoreScroll)
int dx = 0;
int dy = 0;
int counter = count;
- if (!cursor || !m_ring.m_followedLink)
- root->setScrollOnly(m_ring.m_followedLink);
while (--counter >= 0) {
WebCore::IntPoint scroll = WebCore::IntPoint(0, 0);
cachedNode = root->moveCursor(direction, &cachedFrame, &scroll);
@@ -734,13 +791,13 @@ bool moveCursor(int keyCode, int count, bool ignoreScroll)
}
bool result = false;
if (cachedNode) {
+ showCursorUntimed();
m_viewImpl->updateCursorBounds(root, cachedFrame, cachedNode);
root->setCursor(const_cast<CachedFrame*>(cachedFrame),
const_cast<CachedNode*>(cachedNode));
bool disableFocusController = cachedNode != root->currentFocus()
&& cachedNode->wantsKeyEvents();
sendMoveMouseIfLatest(disableFocusController);
- viewInvalidate();
} else {
int docHeight = root->documentHeight();
int docWidth = root->documentWidth();
@@ -807,34 +864,19 @@ void selectBestAt(const WebCore::IntRect& rect)
m_viewImpl->m_hasCursorBounds = false;
if (root)
root->setCursor(0, 0);
+ viewInvalidate();
} else {
DBG_NAV_LOGD("CachedNode:%p (%d)", node, node->index());
- root->rootHistory()->setMouseBounds(node->bounds(frame));
+ WebCore::IntRect bounds = node->bounds(frame);
+ root->rootHistory()->setMouseBounds(frame->unadjustBounds(node, bounds));
m_viewImpl->updateCursorBounds(root, frame, node);
+ showCursorTimed();
root->setCursor(const_cast<CachedFrame*>(frame),
const_cast<CachedNode*>(node));
}
sendMoveMouseIfLatest(false);
- viewInvalidate();
-}
-
-WebCore::IntRect getNavBounds()
-{
- CachedRoot* root = getFrameCache(DontAllowNewer);
- return root ? root->rootHistory()->navBounds() :
- WebCore::IntRect(0, 0, 0, 0);
}
-void setNavBounds(const WebCore::IntRect& rect)
-{
- CachedRoot* root = getFrameCache(DontAllowNewer);
- if (!root)
- return;
- root->rootHistory()->setNavBounds(rect);
-}
-
-
-
const CachedNode* m_cacheHitNode;
const CachedFrame* m_cacheHitFrame;
@@ -851,7 +893,6 @@ bool pointInNavCache(int x, int y, int slop)
bool motionUp(int x, int y, int slop)
{
bool pageScrolled = false;
- m_ring.m_followedLink = false;
IntRect rect = IntRect(x - slop, y - slop, slop * 2, slop * 2);
int rx, ry;
CachedRoot* root = getFrameCache(AllowNewer);
@@ -859,9 +900,10 @@ bool motionUp(int x, int y, int slop)
return 0;
const CachedFrame* frame = 0;
const CachedNode* result = findAt(root, rect, &frame, &rx, &ry);
+ CachedHistory* history = root->rootHistory();
if (!result) {
DBG_NAV_LOGD("no nodes found root=%p", root);
- setNavBounds(rect);
+ history->setNavBounds(rect);
m_viewImpl->m_hasCursorBounds = false;
root->hideCursor();
int dx = root->checkForCenter(x, y);
@@ -872,33 +914,46 @@ bool motionUp(int x, int y, int slop)
sendMotionUp(frame ? (WebCore::Frame*) frame->framePointer() : 0,
0, x, y);
viewInvalidate();
- clearTextEntry();
return pageScrolled;
}
DBG_NAV_LOGD("CachedNode:%p (%d) x=%d y=%d rx=%d ry=%d", result,
result->index(), x, y, rx, ry);
+ // No need to call unadjustBounds below. rx and ry are already adjusted to
+ // the absolute position of the node.
WebCore::IntRect navBounds = WebCore::IntRect(rx, ry, 1, 1);
- setNavBounds(navBounds);
- root->rootHistory()->setMouseBounds(navBounds);
+ history->setNavBounds(navBounds);
+ history->setMouseBounds(navBounds);
m_viewImpl->updateCursorBounds(root, frame, result);
root->setCursor(const_cast<CachedFrame*>(frame),
const_cast<CachedNode*>(result));
- bool syntheticLink = result->isSyntheticLink();
- if (!syntheticLink) {
+ if (result->isSyntheticLink())
+ overrideUrlLoading(result->getExport());
+ else {
sendMotionUp(
(WebCore::Frame*) frame->framePointer(),
(WebCore::Node*) result->nodePointer(), rx, ry);
}
- viewInvalidate();
- if (!result->isTextInput()) {
- clearTextEntry();
- setFollowedLink(true);
- if (syntheticLink)
- overrideUrlLoading(result->getExport());
- }
+ if (result->isTextInput() || result->isSelect()
+ || result->isContentEditable()) {
+ showCursorUntimed();
+ } else
+ showCursorTimed();
return pageScrolled;
}
+const LayerAndroid* scrollableLayer(int x, int y)
+{
+#if ENABLE(ANDROID_OVERFLOW_SCROLL) && USE(ACCELERATED_COMPOSITING)
+ const LayerAndroid* root = compositeRoot();
+ if (!root)
+ return 0;
+ const LayerAndroid* result = root->find(x, y);
+ if (result != 0 && result->contentIsScrollable())
+ return result;
+#endif
+ return 0;
+}
+
int getBlockLeftEdge(int x, int y, float scale)
{
CachedRoot* root = getFrameCache(AllowNewer);
@@ -907,7 +962,7 @@ int getBlockLeftEdge(int x, int y, float scale)
return -1;
}
-void overrideUrlLoading(const WebCore::String& url)
+void overrideUrlLoading(const WTF::String& url)
{
JNIEnv* env = JSC::Bindings::getJNIEnv();
jstring jName = env->NewString((jchar*) url.characters(), url.length());
@@ -928,12 +983,19 @@ void setFindIsEmpty()
m_findOnPage.clearCurrentLocation();
}
-void setFollowedLink(bool followed)
+void showCursorTimed()
{
- if ((m_ring.m_followedLink = followed) != false) {
- m_ringAnimationEnd = SkTime::GetMSecs() + 500;
- viewInvalidate();
- }
+ DBG_NAV_LOG("");
+ m_ringAnimationEnd = SkTime::GetMSecs() + 500;
+ viewInvalidate();
+}
+
+void showCursorUntimed()
+{
+ DBG_NAV_LOG("");
+ m_ring.m_isPressed = false;
+ m_ringAnimationEnd = UINT_MAX;
+ viewInvalidate();
}
void setHeightCanMeasure(bool measure)
@@ -1082,11 +1144,27 @@ void findNext(bool forward)
// With this call, WebView takes ownership of matches, and is responsible for
// deleting it.
-void setMatches(WTF::Vector<MatchInfo>* matches)
-{
+void setMatches(WTF::Vector<MatchInfo>* matches, jboolean sameAsLastSearch)
+{
+ // If this search is the same as the last one, check against the old
+ // location to determine whether to scroll. If the same word is found
+ // in the same place, then do not scroll.
+ IntRect oldLocation;
+ bool checkAgainstOldLocation;
+ if (sameAsLastSearch && m_findOnPage.isCurrentLocationValid()) {
+ oldLocation = m_findOnPage.currentMatchBounds();
+ checkAgainstOldLocation = true;
+ } else
+ checkAgainstOldLocation = false;
+
m_findOnPage.setMatches(matches);
- if (!m_findOnPage.currentMatchIsInLayer())
- scrollRectOnScreen(m_findOnPage.currentMatchBounds());
+
+ if (!checkAgainstOldLocation
+ || oldLocation != m_findOnPage.currentMatchBounds()) {
+ // FIXME: Need to scroll if the match is in a layer.
+ if (!m_findOnPage.currentMatchIsInLayer())
+ scrollRectOnScreen(m_findOnPage.currentMatchBounds());
+ }
viewInvalidate();
}
@@ -1169,20 +1247,74 @@ int moveGeneration()
return m_viewImpl->m_moveGeneration;
}
-LayerAndroid* rootLayer() const
+LayerAndroid* compositeRoot() const
{
- return m_rootLayer;
+ LOG_ASSERT(!m_baseLayer || m_baseLayer->countChildren() == 1,
+ "base layer can't have more than one child %s", __FUNCTION__);
+ if (m_baseLayer && m_baseLayer->countChildren() == 1)
+ return static_cast<LayerAndroid*>(m_baseLayer->getChild(0));
+ else
+ return 0;
}
-void setRootLayer(LayerAndroid* layer)
+static void copyScrollPositionRecursive(const LayerAndroid* from,
+ LayerAndroid* root)
{
- delete m_rootLayer;
- m_rootLayer = layer;
+ if (!from || !root)
+ return;
+ for (int i = 0; i < from->countChildren(); i++) {
+ const LayerAndroid* l = from->getChild(i);
+ if (l->contentIsScrollable()) {
+ LayerAndroid* match =
+ const_cast<LayerAndroid*>(root->findById(l->uniqueId()));
+ if (match != 0)
+ match->setScrollPosition(l->scrollPosition());
+ }
+ copyScrollPositionRecursive(l, root);
+ }
+}
+
+void setBaseLayer(BaseLayerAndroid* layer, WebCore::IntRect& rect)
+{
+#if USE(ACCELERATED_COMPOSITING)
+ m_glWebViewState.setBaseLayer(layer, rect);
+#endif
+
+ if (layer) {
+ copyScrollPositionRecursive(compositeRoot(),
+ static_cast<LayerAndroid*>(layer->getChild(0)));
+ }
+ delete m_baseLayer;
+ m_baseLayer = layer;
CachedRoot* root = getFrameCache(DontAllowNewer);
if (!root)
return;
root->resetLayers();
- root->setRootLayer(m_rootLayer);
+ root->setRootLayer(compositeRoot());
+}
+
+void replaceBaseContent(PictureSet* set)
+{
+ if (!m_baseLayer)
+ return;
+ m_baseLayer->setContent(*set);
+ delete set;
+}
+
+void copyBaseContentToPicture(SkPicture* picture)
+{
+ if (!m_baseLayer)
+ return;
+ PictureSet* content = m_baseLayer->content();
+ content->draw(picture->beginRecording(content->width(), content->height(),
+ SkPicture::kUsePathBoundsForClip_RecordingFlag));
+ picture->endRecording();
+}
+
+bool hasContent() {
+ if (!m_baseLayer)
+ return false;
+ return !m_baseLayer->content()->isEmpty();
}
private: // local state for WebView
@@ -1199,13 +1331,16 @@ private: // local state for WebView
SelectText m_selectText;
FindOnPage m_findOnPage;
CursorRing m_ring;
- LayerAndroid* m_rootLayer;
+ BaseLayerAndroid* m_baseLayer;
+#if USE(ACCELERATED_COMPOSITING)
+ GLWebViewState m_glWebViewState;
+#endif
}; // end of WebView class
/*
* Native JNI methods
*/
-static jstring WebCoreStringToJString(JNIEnv *env, WebCore::String string)
+static jstring WebCoreStringToJString(JNIEnv *env, WTF::String string)
{
int length = string.length();
if (!length)
@@ -1332,6 +1467,19 @@ static const CachedInput* getInputCandidate(JNIEnv *env, jobject obj)
return cursor ? frame->textInput(cursor) : 0;
}
+static jboolean nativePageShouldHandleShiftAndArrows(JNIEnv *env, jobject obj)
+{
+ const CachedNode* focus = getFocusNode(env, obj);
+ if (!focus) return false;
+ // Plugins handle shift and arrows whether or not they have focus.
+ if (focus->isPlugin()) return true;
+ const CachedNode* cursor = getCursorNode(env, obj);
+ // ContentEditable nodes should only receive shift and arrows if they have
+ // both the cursor and the focus.
+ return cursor && cursor->nodePointer() == focus->nodePointer()
+ && cursor->isContentEditable();
+}
+
static jboolean nativeCursorMatchesFocus(JNIEnv *env, jobject obj)
{
const CachedNode* cursor = getCursorNode(env, obj);
@@ -1403,7 +1551,7 @@ static jobject nativeCursorText(JNIEnv *env, jobject obj)
const CachedNode* node = getCursorNode(env, obj);
if (!node)
return 0;
- WebCore::String value = node->getExport();
+ WTF::String value = node->getExport();
return !value.isEmpty() ? env->NewString((jchar *)value.characters(),
value.length()) : 0;
}
@@ -1417,35 +1565,58 @@ static void nativeDebugDump(JNIEnv *env, jobject obj)
#endif
}
-static void nativeDrawExtras(JNIEnv *env, jobject obj, jobject canv, jint extras)
-{
+static jint nativeDraw(JNIEnv *env, jobject obj, jobject canv, jint color,
+ jint extras, jboolean split) {
SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv);
- GET_NATIVE_VIEW(env, obj)->drawExtras(canvas, extras);
+ return reinterpret_cast<jint>(GET_NATIVE_VIEW(env, obj)->draw(canvas, color, extras, split));
+}
+
+static bool nativeDrawGL(JNIEnv *env, jobject obj, jobject jrect,
+ jfloat scale, jint extras)
+{
+ WebCore::IntRect viewRect = jrect_to_webrect(env, jrect);
+ return GET_NATIVE_VIEW(env, obj)->drawGL(viewRect, scale, extras);
}
static bool nativeEvaluateLayersAnimations(JNIEnv *env, jobject obj)
{
#if USE(ACCELERATED_COMPOSITING)
- const LayerAndroid* root = GET_NATIVE_VIEW(env, obj)->rootLayer();
+ const LayerAndroid* root = GET_NATIVE_VIEW(env, obj)->compositeRoot();
if (root)
return root->evaluateAnimations();
#endif
return false;
}
-static void nativeSetRootLayer(JNIEnv *env, jobject obj, jint layer)
+static void nativeSetBaseLayer(JNIEnv *env, jobject obj, jint layer, jobject jrect)
{
-#if USE(ACCELERATED_COMPOSITING)
- LayerAndroid* layerImpl = reinterpret_cast<LayerAndroid*>(layer);
- GET_NATIVE_VIEW(env, obj)->setRootLayer(layerImpl);
-#endif
+ BaseLayerAndroid* layerImpl = reinterpret_cast<BaseLayerAndroid*>(layer);
+ WebCore::IntRect rect = jrect_to_webrect(env, jrect);
+ GET_NATIVE_VIEW(env, obj)->setBaseLayer(layerImpl, rect);
+}
+
+static void nativeReplaceBaseContent(JNIEnv *env, jobject obj, jint content)
+{
+ PictureSet* set = reinterpret_cast<PictureSet*>(content);
+ GET_NATIVE_VIEW(env, obj)->replaceBaseContent(set);
+}
+
+static void nativeCopyBaseContentToPicture(JNIEnv *env, jobject obj, jobject pict)
+{
+ SkPicture* picture = GraphicsJNI::getNativePicture(env, pict);
+ GET_NATIVE_VIEW(env, obj)->copyBaseContentToPicture(picture);
+}
+
+static bool nativeHasContent(JNIEnv *env, jobject obj)
+{
+ return GET_NATIVE_VIEW(env, obj)->hasContent();
}
static jobject nativeImageURI(JNIEnv *env, jobject obj, jint x, jint y)
{
WebView* view = GET_NATIVE_VIEW(env, obj);
LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
- WebCore::String uri = view->imageURI(x, y);
+ WTF::String uri = view->imageURI(x, y);
jstring ret = 0;
unsigned len = uri.length();
if (len) {
@@ -1497,7 +1668,7 @@ static jobject nativeFocusCandidateName(JNIEnv *env, jobject obj)
const CachedInput* input = getInputCandidate(env, obj);
if (!input)
return 0;
- const WebCore::String& name = input->name();
+ const WTF::String& name = input->name();
return env->NewString((jchar*)name.characters(), name.length());
}
@@ -1540,7 +1711,7 @@ static jobject nativeFocusCandidateText(JNIEnv *env, jobject obj)
const CachedNode* node = getFocusCandidate(env, obj, 0);
if (!node)
return 0;
- WebCore::String value = node->getExport();
+ WTF::String value = node->getExport();
return !value.isEmpty() ? env->NewString((jchar *)value.characters(),
value.length()) : 0;
}
@@ -1643,7 +1814,7 @@ static jobject nativeSubtractLayers(JNIEnv* env, jobject obj, jobject jrect)
{
SkIRect irect = jrect_to_webrect(env, jrect);
#if USE(ACCELERATED_COMPOSITING)
- LayerAndroid* root = GET_NATIVE_VIEW(env, obj)->rootLayer();
+ LayerAndroid* root = GET_NATIVE_VIEW(env, obj)->compositeRoot();
if (root) {
SkRect rect;
rect.set(irect);
@@ -1717,11 +1888,9 @@ static void nativeSetFindIsEmpty(JNIEnv *env, jobject obj)
GET_NATIVE_VIEW(env, obj)->setFindIsEmpty();
}
-static void nativeSetFollowedLink(JNIEnv *env, jobject obj, bool followed)
+static void nativeShowCursorTimed(JNIEnv *env, jobject obj)
{
- WebView* view = GET_NATIVE_VIEW(env, obj);
- LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
- view->setFollowedLink(followed);
+ GET_NATIVE_VIEW(env, obj)->showCursorTimed();
}
static void nativeSetHeightCanMeasure(JNIEnv *env, jobject obj, bool measure)
@@ -1747,7 +1916,7 @@ static jobject nativeGetCursorRingBounds(JNIEnv *env, jobject obj)
}
static int nativeFindAll(JNIEnv *env, jobject obj, jstring findLower,
- jstring findUpper)
+ jstring findUpper, jboolean sameAsLastSearch)
{
// If one or the other is null, do not search.
if (!(findLower && findUpper))
@@ -1795,7 +1964,7 @@ static int nativeFindAll(JNIEnv *env, jobject obj, jstring findLower,
root->draw(canvas);
WTF::Vector<MatchInfo>* matches = canvas.detachMatches();
// With setMatches, the WebView takes ownership of matches
- view->setMatches(matches);
+ view->setMatches(matches, sameAsLastSearch);
env->ReleaseStringChars(findLower, findLowerChars);
env->ReleaseStringChars(findUpper, findUpperChars);
@@ -1827,7 +1996,7 @@ static void nativeUpdateCachedTextfield(JNIEnv *env, jobject obj, jstring update
const CachedNode* cachedFocusNode = root->currentFocus();
if (!cachedFocusNode || !cachedFocusNode->isTextInput())
return;
- WebCore::String webcoreString = to_string(env, updatedText);
+ WTF::String webcoreString = jstringToWtfString(env, updatedText);
(const_cast<CachedNode*>(cachedFocusNode))->setExport(webcoreString);
root->setTextGeneration(generation);
checkException(env);
@@ -1867,8 +2036,9 @@ static bool nativeMoveCursorToNextTextInput(JNIEnv *env, jobject obj)
if (!next)
return false;
const WebCore::IntRect& bounds = next->bounds(frame);
- root->rootHistory()->setMouseBounds(bounds);
+ root->rootHistory()->setMouseBounds(frame->unadjustBounds(next, bounds));
view->getWebViewCore()->updateCursorBounds(root, frame, next);
+ view->showCursorUntimed();
root->setCursor(const_cast<CachedFrame*>(frame),
const_cast<CachedNode*>(next));
view->sendMoveFocus(static_cast<WebCore::Frame*>(frame->framePointer()),
@@ -1892,6 +2062,24 @@ static void nativeMoveSelection(JNIEnv *env, jobject obj, int x, int y)
GET_NATIVE_VIEW(env, obj)->moveSelection(x, y);
}
+static jboolean nativeCleanupPrivateBrowsingFiles(
+ JNIEnv *env, jobject obj, jstring databaseDirectoryJString, jstring cacheDirectoryJString) {
+#if USE(CHROME_NETWORK_STACK)
+ jboolean isCopy;
+ const char* cString = env->GetStringUTFChars(databaseDirectoryJString, &isCopy);
+ std::string databaseDirectory(cString);
+ if (isCopy == JNI_TRUE)
+ env->ReleaseStringUTFChars(databaseDirectoryJString, cString);
+ cString = env->GetStringUTFChars(cacheDirectoryJString, &isCopy);
+ std::string cacheDirectory(cString);
+ if (isCopy == JNI_TRUE)
+ env->ReleaseStringUTFChars(cacheDirectoryJString, cString);
+ return WebRequestContext::CleanupPrivateBrowsingFiles(databaseDirectory, cacheDirectory);
+#else
+ return JNI_FALSE;
+#endif
+}
+
static void nativeResetSelection(JNIEnv *env, jobject obj)
{
return GET_NATIVE_VIEW(env, obj)->resetSelection();
@@ -1979,26 +2167,13 @@ static void nativeDumpDisplayTree(JNIEnv* env, jobject jwebview, jstring jurl)
SkDumpCanvas canvas(&dumper);
// this will playback the picture into the canvas, which will
// spew its contents to the dumper
- view->getWebViewCore()->drawContent(&canvas, 0);
-#if USE(ACCELERATED_COMPOSITING)
- if (true) {
- LayerAndroid* rootLayer = view->rootLayer();
- if (rootLayer) {
- // We have to set the canvas' matrix on the root layer
- // (to have fixed layers work as intended)
- SkAutoCanvasRestore restore(&canvas, true);
- rootLayer->setMatrix(canvas.getTotalMatrix());
- canvas.resetMatrix();
- rootLayer->draw(&canvas);
- }
- }
-#endif
+ view->draw(&canvas, 0, 0, false);
// we're done with the file now
fwrite("\n", 1, 1, file);
fclose(file);
}
#if USE(ACCELERATED_COMPOSITING)
- const LayerAndroid* rootLayer = view->rootLayer();
+ const LayerAndroid* rootLayer = view->compositeRoot();
if (rootLayer) {
FILE* file = fopen(LAYERS_TREE_LOG_FILE,"w");
if (file) {
@@ -2011,6 +2186,40 @@ static void nativeDumpDisplayTree(JNIEnv* env, jobject jwebview, jstring jurl)
#endif
}
+static int nativeScrollableLayer(JNIEnv* env, jobject jwebview, jint x, jint y)
+{
+ WebView* view = GET_NATIVE_VIEW(env, jwebview);
+ LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
+ return (int) view->scrollableLayer(x, y);
+}
+
+static bool validLayer(const LayerAndroid* root, const LayerAndroid* layer) {
+ if (root == layer)
+ return true;
+ for (int i = 0; i < root->countChildren(); i++) {
+ const LayerAndroid* l = root->getChild(i);
+ if (validLayer(l, layer))
+ return true;
+ }
+ return false;
+}
+
+static bool nativeScrollLayer(JNIEnv* env, jobject obj, jint pLayer, jint dx,
+ jint dy)
+{
+#if ENABLE(ANDROID_OVERFLOW_SCROLL)
+ WebView* view = GET_NATIVE_VIEW(env, obj);
+ const LayerAndroid* root = view->compositeRoot();
+ LayerAndroid* layer = (LayerAndroid*) pLayer;
+ if (!validLayer(root, layer)) {
+ return false;
+ }
+ LOG_ASSERT(layer, "layer not set in %s", __FUNCTION__);
+ return layer->scrollBy(dx, dy);
+#endif
+ return false;
+}
+
/*
* JNI registration
*/
@@ -2027,6 +2236,8 @@ static JNINativeMethod gJavaWebViewMethods[] = {
(void*) nativeCreate },
{ "nativeCursorFramePointer", "()I",
(void*) nativeCursorFramePointer },
+ { "nativePageShouldHandleShiftAndArrows", "()Z",
+ (void*) nativePageShouldHandleShiftAndArrows },
{ "nativeCursorMatchesFocus", "()Z",
(void*) nativeCursorMatchesFocus },
{ "nativeCursorNodeBounds", "()Landroid/graphics/Rect;",
@@ -2049,15 +2260,17 @@ static JNINativeMethod gJavaWebViewMethods[] = {
(void*) nativeDebugDump },
{ "nativeDestroy", "()V",
(void*) nativeDestroy },
- { "nativeDrawExtras", "(Landroid/graphics/Canvas;I)V",
- (void*) nativeDrawExtras },
+ { "nativeDraw", "(Landroid/graphics/Canvas;IIZ)I",
+ (void*) nativeDraw },
+ { "nativeDrawGL", "(Landroid/graphics/Rect;FI)Z",
+ (void*) nativeDrawGL },
{ "nativeDumpDisplayTree", "(Ljava/lang/String;)V",
(void*) nativeDumpDisplayTree },
{ "nativeEvaluateLayersAnimations", "()Z",
(void*) nativeEvaluateLayersAnimations },
{ "nativeExtendSelection", "(II)V",
(void*) nativeExtendSelection },
- { "nativeFindAll", "(Ljava/lang/String;Ljava/lang/String;)I",
+ { "nativeFindAll", "(Ljava/lang/String;Ljava/lang/String;Z)I",
(void*) nativeFindAll },
{ "nativeFindNext", "(Z)V",
(void*) nativeFindNext },
@@ -2121,6 +2334,8 @@ static JNINativeMethod gJavaWebViewMethods[] = {
(void*) nativeMoveGeneration },
{ "nativeMoveSelection", "(II)V",
(void*) nativeMoveSelection },
+ { "nativeCleanupPrivateBrowsingFiles", "(Ljava/lang/String;Ljava/lang/String;)Z",
+ (void*) nativeCleanupPrivateBrowsingFiles },
{ "nativePointInNavCache", "(III)Z",
(void*) nativePointInNavCache },
{ "nativeRecordButtons", "(ZZZ)V",
@@ -2141,14 +2356,20 @@ static JNINativeMethod gJavaWebViewMethods[] = {
(void*) nativeSetFindIsEmpty },
{ "nativeSetFindIsUp", "(Z)V",
(void*) nativeSetFindIsUp },
- { "nativeSetFollowedLink", "(Z)V",
- (void*) nativeSetFollowedLink },
{ "nativeSetHeightCanMeasure", "(Z)V",
(void*) nativeSetHeightCanMeasure },
- { "nativeSetRootLayer", "(I)V",
- (void*) nativeSetRootLayer },
+ { "nativeSetBaseLayer", "(ILandroid/graphics/Rect;)V",
+ (void*) nativeSetBaseLayer },
+ { "nativeReplaceBaseContent", "(I)V",
+ (void*) nativeReplaceBaseContent },
+ { "nativeCopyBaseContentToPicture", "(Landroid/graphics/Picture;)V",
+ (void*) nativeCopyBaseContentToPicture },
+ { "nativeHasContent", "()Z",
+ (void*) nativeHasContent },
{ "nativeSetSelectionPointer", "(ZFII)V",
(void*) nativeSetSelectionPointer },
+ { "nativeShowCursorTimed", "()V",
+ (void*) nativeShowCursorTimed },
{ "nativeStartSelection", "(II)Z",
(void*) nativeStartSelection },
{ "nativeSubtractLayers", "(Landroid/graphics/Rect;)Landroid/graphics/Rect;",
@@ -2161,6 +2382,10 @@ static JNINativeMethod gJavaWebViewMethods[] = {
(void*) nativeWordSelection },
{ "nativeGetBlockLeftEdge", "(IIF)I",
(void*) nativeGetBlockLeftEdge },
+ { "nativeScrollableLayer", "(II)I",
+ (void*) nativeScrollableLayer },
+ { "nativeScrollLayer", "(III)Z",
+ (void*) nativeScrollLayer },
};
int register_webview(JNIEnv* env)