#endif
#endif
-#if PLATFORM(ANDROID)
-#define WTF_USE_ACCELERATED_COMPOSITING 0
+#if PLATFORM(ANDROID) && !defined WTF_USE_ACCELERATED_COMPOSITING
+#define WTF_USE_ACCELERATED_COMPOSITING 1
#endif
#if PLATFORM(IPHONE)
#if USE(ACCELERATED_COMPOSITING)
#include "AndroidAnimation.h"
-#include "CString.h"
-#include "GraphicsLayerAndroid.h"
-#include "PlatformGraphicsContext.h"
-#include "RenderLayer.h"
-#include "RenderLayerBacking.h"
-#include "RenderView.h"
-#include "SkDevice.h"
+#include "FindCanvas.h"
#include "SkDrawFilter.h"
#include <wtf/CurrentTime.h>
namespace WebCore {
static int gDebugLayerAndroidInstances;
+static int gUniqueId;
+
inline int LayerAndroid::instancesCount()
{
return gDebugLayerAndroidInstances;
m_drawsContent(true),
m_haveImage(false),
m_haveClip(false),
- m_recordingPicture(0)
+ m_recordingPicture(0),
+ m_findOnPage(0),
+ m_uniqueId(++gUniqueId)
{
gDebugLayerAndroidInstances++;
}
m_haveContents(layer.m_haveContents),
m_drawsContent(layer.m_drawsContent),
m_haveImage(layer.m_haveImage),
- m_haveClip(layer.m_haveClip)
+ m_haveClip(layer.m_haveClip),
+ m_findOnPage(0),
+ m_uniqueId(layer.m_uniqueId)
{
m_recordingPicture = layer.m_recordingPicture;
SkSafeRef(m_recordingPicture);
for (int i = 0; i < layer.countChildren(); i++)
- addChild(new LayerAndroid(*static_cast<LayerAndroid*>(layer.getChild(i))))->unref();
+ addChild(new LayerAndroid(*layer.getChild(i)))->unref();
KeyframesMap::const_iterator end = layer.m_animations.end();
for (KeyframesMap::const_iterator it = layer.m_animations.begin(); it != end; ++it)
bool LayerAndroid::hasAnimations() const
{
for (int i = 0; i < countChildren(); i++) {
- if (static_cast<LayerAndroid*>(getChild(i))->hasAnimations())
+ if (getChild(i)->hasAnimations())
return true;
}
return !!m_animations.size();
{
bool hasRunningAnimations = false;
for (int i = 0; i < countChildren(); i++) {
- if (static_cast<LayerAndroid*>(getChild(i))->evaluateAnimations(time))
+ if (getChild(i)->evaluateAnimations(time))
hasRunningAnimations = true;
}
KeyframesMap::const_iterator end = m_animations.end();
void LayerAndroid::setDrawsContent(bool drawsContent)
{
m_drawsContent = drawsContent;
- for (int i = 0; i < countChildren(); i++) {
- LayerAndroid* layer = static_cast<LayerAndroid*>(getChild(i));
- layer->setDrawsContent(drawsContent);
- }
+ for (int i = 0; i < countChildren(); i++)
+ getChild(i)->setDrawsContent(drawsContent);
}
// We only use the bounding rect of the layer as mask...
paintChildren(viewPort, canvas, 1);
}
+void LayerAndroid::bounds(SkRect* rect) const
+{
+ rect->fLeft = m_position.fX + m_translation.fX;
+ rect->fTop = m_position.fY + m_translation.fY;
+ rect->fRight = rect->fLeft + m_size.width();
+ rect->fBottom = rect->fTop + m_size.height();
+}
+
+bool LayerAndroid::boundsIsUnique(SkTDArray<SkRect>* region,
+ const SkRect& local) const
+{
+ for (int i = 0; i < region->count(); i++) {
+ if ((*region)[i].contains(local))
+ return false;
+ }
+ return true;
+}
+
+void LayerAndroid::clipArea(SkTDArray<SkRect>* region) const
+{
+ SkRect local;
+ local.set(0, 0, std::numeric_limits<float>::max(),
+ std::numeric_limits<float>::max());
+ clipInner(region, local);
+}
+
+void LayerAndroid::clipInner(SkTDArray<SkRect>* region,
+ const SkRect& local) const
+{
+ SkRect localBounds;
+ bounds(&localBounds);
+ localBounds.intersect(local);
+ if (localBounds.isEmpty())
+ return;
+ if (m_recordingPicture && boundsIsUnique(region, localBounds))
+ *region->append() = localBounds;
+ for (int i = 0; i < countChildren(); i++)
+ getChild(i)->clipInner(region, m_haveClip ? localBounds : local);
+}
+
+const LayerAndroid* LayerAndroid::find(FloatPoint pos) const
+{
+ for (int i = 0; i < countChildren(); i++) {
+ const LayerAndroid* found = getChild(i)->find(pos);
+ if (found)
+ return found;
+ }
+ SkRect localBounds;
+ bounds(&localBounds);
+ if (localBounds.contains(pos))
+ return this;
+ return 0;
+}
+
void LayerAndroid::setClip(SkCanvas* canvas)
{
SkRect clip;
- clip.fLeft = m_position.fX + m_translation.fX;
- clip.fTop = m_position.fY + m_translation.fY;
- clip.fRight = clip.fLeft + m_size.width();
- clip.fBottom = clip.fTop + m_size.height();
+ bounds(&clip);
canvas->clipRect(clip);
}
m_position.fY + m_translation.fY);
for (int i = 0; i < countChildren(); i++) {
- LayerAndroid* layer = static_cast<LayerAndroid*>(getChild(i));
- if (layer) {
- gDebugChildLevel++;
- layer->paintChildren(viewPort,
- canvas, opacity * m_opacity);
- gDebugChildLevel--;
- }
+ gDebugChildLevel++;
+ getChild(i)->paintChildren(viewPort, canvas, opacity * m_opacity);
+ gDebugChildLevel--;
}
canvas->restoreToCount(count);
else if (m_fixedBottom.defined())
y = dy + h - m_fixedBottom.calcFloatValue(h) - m_size.height();
- matrix->setTranslate(x, y);
+ if (matrix)
+ matrix->setTranslate(x, y);
+ setPosition(x, y);
return true;
}
return false;
m_recordingPicture->draw(canvas);
+ if (m_findOnPage)
+ m_findOnPage->drawLayer(canvas, 0, m_uniqueId);
#ifdef LAYER_DEBUG
float w = m_size.width();
float h = m_size.height();
fprintf(file, "%s = { type = %d; value = %.2f; };\n", str, length.type, length.value);
}
-void LayerAndroid::dumpLayers(FILE* file, int indentLevel)
+void LayerAndroid::dumpLayers(FILE* file, int indentLevel) const
{
writeln(file, indentLevel, "{");
for (int i = 0; i < countChildren(); i++) {
if (i > 0)
writeln(file, indentLevel + 1, ", ");
- LayerAndroid* layer = static_cast<LayerAndroid*>(getChild(i));
- if (layer)
- layer->dumpLayers(file, indentLevel + 1);
+ getChild(i)->dumpLayers(file, indentLevel + 1);
}
writeln(file, indentLevel + 1, "];");
}
writeln(file, indentLevel, "}");
}
+const LayerAndroid* LayerAndroid::findById(int match) const
+{
+ if (m_uniqueId == match)
+ return this;
+ for (int i = 0; i < countChildren(); i++) {
+ const LayerAndroid* result = getChild(i)->findById(match);
+ if (result)
+ return result;
+ }
+ return 0;
+}
+
+void LayerAndroid::setFindOnPage(FindOnPage* findOnPage)
+{
+ m_findOnPage = findOnPage;
+ for (int i = 0; i < countChildren(); i++)
+ getChild(i)->setFindOnPage(findOnPage);
+}
+
} // namespace WebCore
#endif // USE(ACCELERATED_COMPOSITING)
#if USE(ACCELERATED_COMPOSITING)
-#include "Color.h"
#include "FloatPoint.h"
-#include "FloatPoint3D.h"
-#include "FloatSize.h"
-#include "Length.h"
#include "RefPtr.h"
+#include "SkColor.h"
#include "SkLayer.h"
#include "StringHash.h"
-#include "Vector.h"
#include <wtf/HashMap.h>
+class FindOnPage;
class SkCanvas;
class SkMatrix;
class SkPicture;
-class SkRect;
namespace WebCore {
class AndroidAnimation;
-class AndroidAnimationValue;
class LayerAndroid : public SkLayer {
void setHaveContents(bool haveContents) { m_haveContents = haveContents; }
void setHaveImage(bool haveImage) { m_haveImage = haveImage; }
void setDrawsContent(bool drawsContent);
+ void setFindOnPage(FindOnPage* findOnPage);
void setMaskLayer(LayerAndroid*);
void setMasksToBounds(bool);
virtual void setBackgroundColor(SkColor color);
void setIsRootLayer(bool isRootLayer) { m_isRootLayer = isRootLayer; }
virtual void draw(SkCanvas*, const SkRect* viewPort);
+// GraphicsContext* paintContext();
bool prepareContext(bool force = false);
void startRecording();
void stopRecording();
SkPicture* picture() const { return m_recordingPicture; }
- void dumpLayers(FILE*, int indentLevel);
-
-private:
+ void dumpLayers(FILE*, int indentLevel) const;
+ void bounds(SkRect* ) const;
bool calcPosition(const SkRect* viewPort, SkMatrix*);
-
- void paintChildren(const SkRect* viewPort, SkCanvas* canvas,
- float opacity);
-
+ void clipArea(SkTDArray<SkRect>* region) const;
+ const LayerAndroid* find(FloatPoint position) const;
+ const LayerAndroid* findById(int uniqueID) const;
+ LayerAndroid* getChild(int index) const { return
+ static_cast<LayerAndroid*>(m_children[index]); }
+ bool haveClip() const { return m_haveClip; }
+ int uniqueId() const { return m_uniqueId; }
+private:
+ bool boundsIsUnique(SkTDArray<SkRect>* region, const SkRect& local) const;
+ void clipInner(SkTDArray<SkRect>* region, const SkRect& local) const;
+ void paintChildren(const SkRect* viewPort, SkCanvas* canvas, float opacity);
void paintMe(const SkRect* viewPort, SkCanvas* canvas,
float opacity);
typedef HashMap<String, RefPtr<AndroidAnimation> > KeyframesMap;
KeyframesMap m_animations;
+ FindOnPage* m_findOnPage;
+ int m_uniqueId;
};
}
android/nav/CachedFrame.cpp \
android/nav/CachedHistory.cpp \
android/nav/CachedInput.cpp \
+ android/nav/CachedLayer.cpp \
android/nav/CachedNode.cpp \
android/nav/CachedRoot.cpp \
android/nav/FindCanvas.cpp \
env->CallVoidMethod(m_javaGlue->object(env).get(),
m_javaGlue->m_setRootLayer,
layer);
- mRootLayer = layer;
checkException(env);
}
#if USE(ACCELERATED_COMPOSITING)
void immediateRepaint();
void setRootLayer(int layer);
- int rootLayer() { return mRootLayer; }
#endif
/** Invalidate the view/screen, NOT the content/DOM, but expressed in
uint32_t m_now;
#endif
-#if USE(ACCELERATED_COMPOSITING)
- int mRootLayer;
-#endif
-
private:
// called from constructor, to add this to a global list
static void addInstance(WebViewCore*);
#include "FrameTree.h"
#include "FrameView.h"
//#include "GraphicsContext.h"
+#include "GraphicsLayerAndroid.h"
#include "HTMLAreaElement.h"
#include "HTMLImageElement.h"
#include "HTMLInputElement.h"
#include "RegisteredEventListener.h"
#include "RenderImage.h"
#include "RenderInline.h"
+#include "RenderLayerBacking.h"
#include "RenderListBox.h"
#include "RenderSkinCombo.h"
#include "RenderTextControl.h"
print("\"\"");
RenderObject* renderer = node->renderer();
int tabindex = node->isElementNode() ? node->tabIndex() : 0;
+ RenderLayer* layer = 0;
if (renderer) {
const IntRect& absB = renderer->absoluteBoundingBoxRect();
+ bool hasLayer = renderer->hasLayer();
+ layer = hasLayer ? toRenderBoxModelObject(renderer)->layer() : 0;
snprintf(scratch, sizeof(scratch), ", {%d, %d, %d, %d}, %s"
- ", %d},",absB.x(), absB.y(), absB.width(), absB.height(),
- renderer->hasOverflowClip() ? "true" : "false", tabindex);
+ ", %d, %s, %s},",
+ absB.x(), absB.y(), absB.width(), absB.height(),
+ renderer->hasOverflowClip() ? "true" : "false", tabindex,
+ hasLayer ? "true" : "false",
+ hasLayer && layer->isComposited() ? "true" : "false");
// TODO: add renderer->style()->visibility()
print(scratch);
} else
}
count++;
newLine();
+#if USE(ACCELERATED_COMPOSITING)
+ if (renderer && layer) {
+ RenderLayerBacking* back = layer->backing();
+ GraphicsLayerAndroid* grLayer = static_cast
+ <GraphicsLayerAndroid*>(back ? back->graphicsLayer() : 0);
+ LayerAndroid* aLayer = grLayer ? grLayer->contentLayer() : 0;
+ const SkPicture* pict = aLayer ? aLayer->picture() : 0;
+ snprintf(scratch, sizeof(scratch), "// layer:%p back:%p"
+ " gLayer:%p aLayer:%p pict:%p", layer, back, grLayer,
+ aLayer, pict);
+ print(scratch);
+ newLine();
+ }
+#endif
} while ((node = node->traverseNextNode()) != NULL);
DUMP_NAV_LOGD("}; // focusables = %d\n", count - 1);
DUMP_NAV_LOGD("\n");
void CacheBuilder::BuildFrame(Frame* root, Frame* frame,
CachedRoot* cachedRoot, CachedFrame* cachedFrame)
{
- WTF::Vector<Tracker> tracker(1);
+ WTF::Vector<FocusTracker> tracker(1); // sentinel
{
- Tracker* baseTracker = tracker.data(); // sentinel
- bzero(baseTracker, sizeof(Tracker));
+ FocusTracker* baseTracker = tracker.data();
+ bzero(baseTracker, sizeof(FocusTracker));
baseTracker->mCachedNodeIndex = -1;
}
- WTF::Vector<ClipColumnTracker> clipTracker(1);
- {
- ClipColumnTracker* baseTracker = clipTracker.data(); // sentinel
- bzero(baseTracker, sizeof(ClipColumnTracker));
- }
- WTF::Vector<TabIndexTracker> tabIndexTracker(1);
- {
- TabIndexTracker* baseTracker = tabIndexTracker.data(); // sentinel
- bzero(baseTracker, sizeof(TabIndexTracker));
- }
+ WTF::Vector<LayerTracker> layerTracker(1); // sentinel
+ bzero(layerTracker.data(), sizeof(LayerTracker));
+ WTF::Vector<ClipColumnTracker> clipTracker(1); // sentinel
+ bzero(clipTracker.data(), sizeof(ClipColumnTracker));
+ WTF::Vector<TabIndexTracker> tabIndexTracker(1); // sentinel
+ bzero(tabIndexTracker.data(), sizeof(TabIndexTracker));
#if DUMP_NAV_CACHE
char* frameNamePtr = cachedFrame->mDebug.mFrameName;
Builder(frame)->mDebug.frameName(frameNamePtr, frameNamePtr +
#if DUMP_NAV_CACHE
nodeIndex++;
#endif
- Tracker* last = &tracker.last();
+ FocusTracker* last = &tracker.last();
int lastChildIndex = cachedFrame->size() - 1;
while (node == last->mLastChild) {
if (CleanUpContainedNodes(cachedFrame, last, lastChildIndex))
clipTracker.removeLast();
} while (true);
do {
+ const LayerTracker* lastLayer = &layerTracker.last();
+ if (node != lastLayer->mLastChild)
+ break;
+ layerTracker.removeLast();
+ } while (true);
+ do {
const TabIndexTracker* lastTabIndex = &tabIndexTracker.last();
if (node != lastTabIndex->mLastChild)
break;
#ifdef ANDROID_CSS_TAP_HIGHLIGHT_COLOR
hasCursorRing = style->tapHighlightColor().alpha() > 0;
#endif
+#if USE(ACCELERATED_COMPOSITING)
+ if (nodeRenderer->hasLayer())
+ TrackLayer(layerTracker, nodeRenderer, lastChild);
+#endif
}
bool more = walk.mMore;
walk.reset();
IntRect(0, 0, INT_MAX, INT_MAX);
if (ConstructTextRects((WebCore::Text*) node, walk.mStart,
(WebCore::Text*) walk.mFinalNode, walk.mEnd, globalOffsetX,
- globalOffsetY, &bounds, clip, &cachedNode.cursorRings()) == false)
+ globalOffsetY, &bounds, clip, cachedNode.cursorRingsPtr()) == false)
continue;
absBounds = bounds;
cachedNode.setBounds(bounds);
cachedNode.init(node);
if (computeCursorRings == false) {
cachedNode.setBounds(bounds);
- cachedNode.cursorRings().append(bounds);
+ cachedNode.cursorRingsPtr()->append(bounds);
} else if (ConstructPartRects(node, bounds, cachedNode.boundsPtr(),
- globalOffsetX, globalOffsetY, &cachedNode.cursorRings()) == false)
+ globalOffsetX, globalOffsetY, cachedNode.cursorRingsPtr()) == false)
continue;
keepTextNode:
IntRect clip = hasClip ? bounds : absBounds;
else if (cachedNode.clip(clip) == false)
continue; // skip this node if outside of the clip
}
+ bool isInLayer = false;
+#if USE(ACCELERATED_COMPOSITING)
+ // FIXME: does not work for area rects
+ LayerAndroid* layer = layerTracker.last().mLayer;
+ if (layer) {
+ isInLayer = true;
+ isUnclipped = true; // FIXME: add clipping analysis before blindly setting this
+ CachedLayer cachedLayer;
+ cachedLayer.reset();
+ cachedLayer.setCachedNodeIndex(cachedFrame->size());
+ cachedLayer.setOffset(layerTracker.last().mPosition);
+ cachedLayer.setUniqueId(layer->uniqueId());
+ cachedFrame->add(cachedLayer);
+ }
+#endif
cachedNode.setNavableRects();
cachedNode.setExport(exported);
cachedNode.setHasCursorRing(hasCursorRing);
cachedNode.setHitBounds(absBounds);
cachedNode.setIndex(cacheIndex);
cachedNode.setIsFocus(isFocus);
+ cachedNode.setIsInLayer(isInLayer);
cachedNode.setIsTransparent(isTransparent);
cachedNode.setIsUnclipped(isUnclipped);
cachedNode.setOriginalAbsoluteBounds(originalAbsBounds);
}
if (lastChild != NULL) {
tracker.grow(tracker.size() + 1);
- Tracker& working = tracker.last();
+ FocusTracker& working = tracker.last();
working.mCachedNodeIndex = lastIndex;
working.mLastChild = OneAfter(lastChild);
last = &tracker.at(tracker.size() - 2);
cacheIndex++;
}
while (tracker.size() > 1) {
- Tracker* last = &tracker.last();
+ FocusTracker* last = &tracker.last();
int lastChildIndex = cachedFrame->size() - 1;
if (CleanUpContainedNodes(cachedFrame, last, lastChildIndex))
cacheIndex--;
}
bool CacheBuilder::CleanUpContainedNodes(CachedFrame* cachedFrame,
- const Tracker* last, int lastChildIndex)
+ const FocusTracker* last, int lastChildIndex)
{
// if outer is body, disable outer
// or if there's more than one inner, disable outer
lastNode->hasTagName(HTMLNames::bodyTag) ||
lastNode->hasTagName(HTMLNames::formTag)) {
lastCached->setBounds(IntRect(0, 0, 0, 0));
- lastCached->cursorRings().clear();
+ lastCached->cursorRingsPtr()->clear();
lastCached->setNavableRects();
return false;
}
return true;
}
+#if USE(ACCELERATED_COMPOSITING)
+void CacheBuilder::TrackLayer(WTF::Vector<LayerTracker>& layerTracker,
+ RenderObject* nodeRenderer, Node* lastChild)
+{
+ RenderLayer* layer = toRenderBoxModelObject(nodeRenderer)->layer();
+ RenderLayerBacking* back = layer->backing();
+ if (!back)
+ return;
+ GraphicsLayerAndroid* grLayer = static_cast
+ <GraphicsLayerAndroid*>(back->graphicsLayer());
+ if (!grLayer)
+ return;
+ LayerAndroid* aLayer = grLayer->contentLayer();
+ if (!aLayer)
+ return;
+ layerTracker.grow(layerTracker.size() + 1);
+ LayerTracker& indexTracker = layerTracker.last();
+ indexTracker.mLayer = aLayer;
+ indexTracker.mPosition = nodeRenderer->absoluteBoundingBoxRect().location();
+ indexTracker.mLastChild = OneAfter(lastChild);
+ DBG_NAV_LOGD("layer=%p [%d] pos=(%d,%d)", aLayer, aLayer->uniqueId(),
+ indexTracker.mPosition.x(), indexTracker.mPosition.y());
+}
+#endif
+
bool CacheBuilder::validNode(Frame* startFrame, void* matchFrame,
void* matchNode)
{
class Frame;
class HTMLAreaElement;
class InlineTextBox;
+class LayerAndroid;
class Node;
class PlatformGraphicsContext;
class RenderFlow;
mStarts[mWordCount] = mCurrentStart;
}
};
- struct ClipColumnTracker {
- IntRect mBounds;
+ struct Tracker {
Node* mLastChild;
+ };
+ struct ClipColumnTracker : Tracker {
Node* mNode;
+ IntRect mBounds;
WTF::Vector<IntRect>* mColumns;
int mColumnGap;
TextDirection mDirection;
bool mHasClip;
};
- struct TabIndexTracker {
+ struct LayerTracker : Tracker {
+ LayerAndroid* mLayer;
+ IntPoint mPosition;
+ };
+ struct TabIndexTracker : Tracker {
int mTabIndex;
- Node* mLastChild;
};
- struct Tracker {
+ struct FocusTracker : TabIndexTracker {
int mCachedNodeIndex;
- int mTabIndex;
- Node* mLastChild;
bool mSomeParentTakesFocus;
};
void adjustForColumns(const ClipColumnTracker& track,
void BuildFrame(Frame* root, Frame* frame,
CachedRoot* cachedRoot, CachedFrame* cachedFrame);
bool CleanUpContainedNodes(CachedFrame* cachedFrame,
- const Tracker* last, int lastChildIndex);
+ const FocusTracker* last, int lastChildIndex);
static bool ConstructTextRect(Text* textNode,
InlineTextBox* textBox, int start, int relEnd, int x, int y,
IntRect* focusBounds, const IntRect& clip, WTF::Vector<IntRect>* result);
static bool IsRealNode(Frame* , Node* );
int overlap(int left, int right); // returns distance scale factor as 16.16 scalar
bool setData(CachedFrame* );
+#if USE(ACCELERATED_COMPOSITING)
+ void TrackLayer(WTF::Vector<LayerTracker>& layerTracker,
+ RenderObject* nodeRenderer, Node* lastChild);
+#endif
Node* tryFocus(Direction direction);
Node* trySegment(Direction direction, int mainStart, int mainEnd);
CachedNodeBits mAllowableTypes;
#define NAV_CACHE_LOG_FILE "/data/data/com.android.browser/navlog"
#define DUMP_NAV_LOGD(...) do { if (gNavCacheLogFile) \
fprintf(gNavCacheLogFile, __VA_ARGS__); else LOGD(__VA_ARGS__); } while (false)
+#define DUMP_NAV_LOGX(format, ...) do { if (gNavCacheLogFile) \
+ fprintf(gNavCacheLogFile, format, __VA_ARGS__); \
+ else LOGD("%s " format, __FUNCTION__, __VA_ARGS__); } while (false)
#else
#define DUMP_NAV_LOGD(...) LOGD(__VA_ARGS__)
+#define DUMP_NAV_LOGX(format, ...) LOGD("%s " format, __FUNCTION__, __VA_ARGS__)
#endif
#else
#define DUMP_NAV_LOGD(...) ((void)0)
+#define DUMP_NAV_LOGX(...) ((void)0)
#endif
#endif
namespace android {
+WebCore::IntRect CachedFrame::adjustBounds(const CachedNode* node,
+ const WebCore::IntRect& rect) const
+{
+ DBG_NAV_LOGD("node=%p [%d] rect=(%d,%d,w=%d,h=%d)",
+ node, node->index(), rect.x(), rect.y(), rect.width(), rect.height());
+#if USE(ACCELERATED_COMPOSITING)
+ return layer(node)->adjustBounds(mRoot->rootLayer(), rect);
+#else
+ return rect;
+#endif
+}
+
bool CachedFrame::CheckBetween(Direction direction, const WebCore::IntRect& bestRect,
const WebCore::IntRect& prior, WebCore::IntRect* result)
{
return true;
}
+bool CachedFrame::checkRings(const CachedNode* node,
+ const WTF::Vector<WebCore::IntRect>& rings,
+ const WebCore::IntRect& bounds) const
+{
+ return mRoot->checkRings(picture(node), rings, bounds);
+}
+
bool CachedFrame::checkVisited(const CachedNode* node, Direction direction) const
{
return history()->checkVisited(node, direction);
}
// returns 0 if test is preferable to best, 1 if not preferable, or -1 if unknown
-int CachedFrame::compare(BestData& testData, const BestData& bestData,
- const CachedNode* cursor) const
+int CachedFrame::compare(BestData& testData, const BestData& bestData) const
{
if (testData.mNode->tabIndex() != bestData.mNode->tabIndex()) {
if (testData.mNode->tabIndex() < bestData.mNode->tabIndex()
- || (cursor && cursor->tabIndex() < bestData.mNode->tabIndex())) {
+ || (mRoot->cursor() && mRoot->cursor()->tabIndex() < bestData.mNode->tabIndex())) {
testData.mNode->setCondition(CachedNode::HIGHER_TAB_INDEX);
return REJECT_TEST;
}
const CachedFrame* frame = hasFrame(result);
if (frame != NULL)
return frame->currentCursor(framePtr);
- (const_cast<CachedNode*>(result))->fixUpCursorRects(mRoot);
+ (const_cast<CachedNode*>(result))->fixUpCursorRects(this);
return result;
}
size_t parts = test->navableRects();
BestData testData;
testData.mNode = test;
- testData.mMouseBounds = testData.mNodeBounds = test->getBounds();
+ testData.mFrame = this;
+ WebCore::IntRect bounds = test->bounds(this);
+ testData.setMouseBounds(bounds);
+ testData.setNodeBounds(bounds);
bool checkForHidden = checkForHiddenStart;
for (size_t part = 0; part < parts; part++) {
- if (test->cursorRings().at(part).intersects(rect)) {
+ WebCore::IntRect testRect = test->ring(this, part);
+ if (test->isInLayer()) {
+ DBG_NAV_LOGD("[%d] intersects=%ss testRect=(%d,%d,w=%d,h=%d)"
+ " rect=(%d,%d,w=%d,h=%d)", test->index(),
+ testRect.intersects(rect) ? "true" : "false",
+ testRect.x(), testRect.y(), testRect.width(), testRect.height(),
+ rect.x(), rect.y(), rect.width(), rect.height());
+ }
+ if (testRect.intersects(rect)) {
if (checkForHidden && mRoot->maskIfHidden(&testData) == true)
break;
checkForHidden = false;
- WebCore::IntRect testRect = test->cursorRings().at(part);
- testRect.intersect(testData.mMouseBounds);
+ testRect.intersect(testData.mouseBounds());
if (testRect.contains(center)) {
// We have a direct hit.
if (*directHit == NULL) {
} else {
// We have hit another one before
const CachedNode* d = *directHit;
- if (d->getBounds().contains(testRect)) {
+ if (d->bounds(this).contains(testRect)) {
// This rectangle is inside the other one, so it is
// the best one.
*directHit = test;
test != mCachedNodes.begin() - 1; test--) {
if (test->disabled())
continue;
- const WebCore::IntRect& testRect = test->hitBounds();
+ WebCore::IntRect testRect = test->hitBounds(this);
if (testRect.intersects(rect) == false)
continue;
BestData testData;
testData.mNode = test;
- testData.mMouseBounds = testData.mNodeBounds = testRect;
+ testData.mFrame = this;
+ testData.setMouseBounds(testRect);
+ testData.setNodeBounds(testRect);
if (mRoot->maskIfHidden(&testData) == true)
continue;
- for (unsigned i = 0; i < test->cursorRings().size(); i++) {
- const WebCore::IntRect& cursorRect = test->cursorRings().at(i);
+ for (int i = 0; i < test->navableRects(); i++) {
+ WebCore::IntRect cursorRect = test->ring(this, i);
if (cursorRect.intersects(rect)) {
WebCore::IntRect intersection(cursorRect);
intersection.intersect(rect);
}
if (test->noSecondChance())
continue;
- if (test->isNavable(*clip) == false)
+ if (test->isNavable(this, *clip) == false)
continue;
if (checkVisited(test, originalDirection) == false)
continue;
size_t partMax = test->navableRects();
for (size_t part = 0; part < partMax; part++) {
- WebCore::IntRect testBounds = test->cursorRings().at(part);
+ WebCore::IntRect testBounds = test->ring(this, part);
if (clip->intersects(testBounds) == false)
continue;
if (clip->contains(testBounds) == false) {
bestData->mNode = test;
bestData->mFrame = this;
bestData->mDistance = distance;
- bestData->mMouseBounds = bestData->mNodeBounds =
- test->cursorRings().at(part);
+ WebCore::IntRect rect = test->ring(this, part);
+ bestData->setMouseBounds(rect);
+ bestData->setNodeBounds(rect);
CachedHistory* cachedHistory = history();
switch (direction) {
case LEFT:
frameParent->setFocusIndex(indexInParent());
}
-const CachedNode* CachedFrame::frameDown(const CachedNode* test, const CachedNode* limit, BestData* bestData,
- const CachedNode* cursor) const
+const CachedNode* CachedFrame::frameDown(const CachedNode* test,
+ const CachedNode* limit, BestData* bestData) const
{
BestData originalData = *bestData;
do {
- if (moveInFrame(&CachedFrame::frameDown, test, bestData, cursor))
+ if (moveInFrame(&CachedFrame::frameDown, test, bestData))
continue;
BestData testData;
- if (frameNodeCommon(testData, test, bestData, &originalData, cursor) == REJECT_TEST)
+ if (frameNodeCommon(testData, test, bestData, &originalData) == REJECT_TEST)
continue;
if (checkVisited(test, DOWN) == false)
continue;
size_t parts = test->navableRects();
for (size_t part = 0; part < parts; part++) {
- testData.mNodeBounds = test->cursorRings().at(part);
+ testData.setNodeBounds(test->ring(this, part));
if (testData.setDownDirection(history()))
continue;
- int result = framePartCommon(testData, test, bestData, cursor);
+ int result = framePartCommon(testData, test, bestData);
if (result == REJECT_TEST)
continue;
if (result == 0 && limit == NULL) { // retry all data up to this point, since smaller may have replaced node preferable to larger
BestData innerData = testData;
- frameDown(document(), test, &innerData, cursor);
+ frameDown(document(), test, &innerData);
if (checkVisited(innerData.mNode, DOWN)) {
*bestData = innerData;
continue;
*bestData = testData;
}
} while ((test = test->traverseNextNode()) != limit);
- ASSERT(cursor == NULL || bestData->mNode != cursor);
+ ASSERT(mRoot->cursor() == NULL || bestData->mNode != mRoot->cursor());
// does the best contain something (or, is it contained by an area which is not the cursor?)
// if so, is the conainer/containee should have been chosen, but wasn't -- so there's a better choice
// in the doc list prior to this choice
return bestData->mNode;
}
-const CachedNode* CachedFrame::frameLeft(const CachedNode* test, const CachedNode* limit, BestData* bestData,
- const CachedNode* cursor) const
+const CachedNode* CachedFrame::frameLeft(const CachedNode* test,
+ const CachedNode* limit, BestData* bestData) const
{
BestData originalData = *bestData;
do {
- if (moveInFrame(&CachedFrame::frameLeft, test, bestData, cursor))
+ if (moveInFrame(&CachedFrame::frameLeft, test, bestData))
continue;
BestData testData;
- if (frameNodeCommon(testData, test, bestData, &originalData, cursor) == REJECT_TEST)
+ if (frameNodeCommon(testData, test, bestData, &originalData) == REJECT_TEST)
continue;
if (checkVisited(test, LEFT) == false)
continue;
size_t parts = test->navableRects();
for (size_t part = 0; part < parts; part++) {
- testData.mNodeBounds = test->cursorRings().at(part);
+ testData.setNodeBounds(test->ring(this, part));
if (testData.setLeftDirection(history()))
continue;
- int result = framePartCommon(testData, test, bestData, cursor);
+ int result = framePartCommon(testData, test, bestData);
if (result == REJECT_TEST)
continue;
if (result == 0 && limit == NULL) { // retry all data up to this point, since smaller may have replaced node preferable to larger
BestData innerData = testData;
- frameLeft(document(), test, &innerData, cursor);
+ frameLeft(document(), test, &innerData);
if (checkVisited(innerData.mNode, LEFT)) {
*bestData = innerData;
continue;
*bestData = testData;
}
} while ((test = test->traverseNextNode()) != limit); // FIXME ??? left and up should use traversePreviousNode to choose reverse document order
- ASSERT(cursor == NULL || bestData->mNode != cursor);
+ ASSERT(mRoot->cursor() == NULL || bestData->mNode != mRoot->cursor());
return bestData->mNode;
}
-int CachedFrame::frameNodeCommon(BestData& testData, const CachedNode* test, BestData* bestData, BestData* originalData,
- const CachedNode* cursor) const
+int CachedFrame::frameNodeCommon(BestData& testData, const CachedNode* test,
+ BestData* bestData, BestData* originalData) const
{
testData.mFrame = this;
testData.mNode = test;
testData.mNode->setCondition(CachedNode::DISABLED);
return REJECT_TEST;
}
- if (mRoot->scrolledBounds().intersects(test->bounds()) == false) {
+ if (mRoot->scrolledBounds().intersects(test->bounds(this)) == false) {
testData.mNode->setCondition(CachedNode::NAVABLE);
return REJECT_TEST;
}
+ if (mRoot->rootLayer() && !test->isInLayer()
+ && !mRoot->baseUncovered().intersects(test->bounds(this))) {
+ testData.mNode->setCondition(CachedNode::UNDER_LAYER);
+ return REJECT_TEST;
+ }
// if (isNavable(test, &testData.mNodeBounds, walk) == false) {
// testData.mNode->setCondition(CachedNode::NAVABLE);
// return REJECT_TEST;
// }
//
- if (test == cursor) {
+ if (test == mRoot->cursor()) {
testData.mNode->setCondition(CachedNode::NOT_CURSOR_NODE);
return REJECT_TEST;
}
// testData.mNode->setCondition(CachedNode::NOT_ENCLOSING_CURSOR);
// return REJECT_TEST;
// }
- void* par = cursor ? cursor->parentGroup() : NULL;
+ void* par = mRoot->cursor() ? mRoot->cursor()->parentGroup() : NULL;
testData.mCursorChild = par ? test->parentGroup() == par : false;
-#if 0 // not debugged
- if (cursor && cursor->hasMouseOver() && test->hasMouseOver() == false &&
- cursor->bounds().contains(test->bounds()))
- return REJECT_TEST;
-#endif
if (bestData->mNode == NULL)
return TEST_IS_BEST;
-#if 0 // not debugged
- if (cursor && cursor->hasMouseOver() && test->hasMouseOver() == false &&
- cursor->bounds().contains(test->bounds()))
- return REJECT_TEST;
- if (test->hasMouseOver() != bestData->mNode->hasMouseOver()) {
- if (test->hasMouseOver()) {
- if (test->bounds().contains(bestData->mNode->bounds())) {
- const_cast<CachedNode*>(bestData->mNode)->setDisabled(true);
- bestData->mNode = NULL; // force part tests to be ignored, yet still set up remaining test data for later comparison
- return TEST_IS_BEST;
- }
- } else {
- if (bestData->mNode->bounds().contains(test->bounds())) {
- test->setCondition(CachedNode::ANCHOR_IN_ANCHOR);
- return REJECT_TEST;
- }
- }
- }
-#endif
- if (cursor && testData.mNode->parentIndex() != bestData->mNode->parentIndex()) {
- int cursorParentIndex = cursor->parentIndex();
+ if (mRoot->cursor() && testData.mNode->parentIndex() != bestData->mNode->parentIndex()) {
+ int cursorParentIndex = mRoot->cursor()->parentIndex();
if (cursorParentIndex >= 0) {
if (bestData->mNode->parentIndex() == cursorParentIndex)
return REJECT_TEST;
}
int CachedFrame::framePartCommon(BestData& testData,
- const CachedNode* test, BestData* bestData, const CachedNode* cursor) const
+ const CachedNode* test, BestData* bestData) const
{
- if (cursor && testData.mNodeBounds.contains(cursor->bounds()) && !test->wantsKeyEvents()) {
+ if (mRoot->cursor()
+ && testData.bounds().contains(mRoot->cursorBounds())
+ && !test->wantsKeyEvents()) {
testData.mNode->setCondition(CachedNode::NOT_ENCLOSING_CURSOR);
return REJECT_TEST;
}
testData.setDistances();
if (bestData->mNode != NULL) {
- int compared = compare(testData, *bestData, cursor);
+ int compared = compare(testData, *bestData);
if (compared == 0 && test->isArea() == false && bestData->mNode->isArea() == false)
goto pickTest;
if (compared >= 0)
return -1; // pick test
}
-const CachedNode* CachedFrame::frameRight(const CachedNode* test, const CachedNode* limit, BestData* bestData,
- const CachedNode* cursor) const
+const CachedNode* CachedFrame::frameRight(const CachedNode* test,
+ const CachedNode* limit, BestData* bestData) const
{
BestData originalData = *bestData;
do {
- if (moveInFrame(&CachedFrame::frameRight, test, bestData, cursor))
+ if (moveInFrame(&CachedFrame::frameRight, test, bestData))
continue;
BestData testData;
- if (frameNodeCommon(testData, test, bestData, &originalData, cursor) == REJECT_TEST)
+ if (frameNodeCommon(testData, test, bestData, &originalData) == REJECT_TEST)
continue;
if (checkVisited(test, RIGHT) == false)
continue;
size_t parts = test->navableRects();
for (size_t part = 0; part < parts; part++) {
- testData.mNodeBounds = test->cursorRings().at(part);
+ testData.setNodeBounds(test->ring(this, part));
if (testData.setRightDirection(history()))
continue;
- int result = framePartCommon(testData, test, bestData, cursor);
+ int result = framePartCommon(testData, test, bestData);
if (result == REJECT_TEST)
continue;
if (result == 0 && limit == NULL) { // retry all data up to this point, since smaller may have replaced node preferable to larger
BestData innerData = testData;
- frameRight(document(), test, &innerData, cursor);
+ frameRight(document(), test, &innerData);
if (checkVisited(innerData.mNode, RIGHT)) {
*bestData = innerData;
continue;
*bestData = testData;
}
} while ((test = test->traverseNextNode()) != limit);
- ASSERT(cursor == NULL || bestData->mNode != cursor);
+ ASSERT(mRoot->cursor() == NULL || bestData->mNode != mRoot->cursor());
return bestData->mNode;
}
-const CachedNode* CachedFrame::frameUp(const CachedNode* test, const CachedNode* limit, BestData* bestData,
- const CachedNode* cursor) const
+const CachedNode* CachedFrame::frameUp(const CachedNode* test,
+ const CachedNode* limit, BestData* bestData) const
{
BestData originalData = *bestData;
do {
- if (moveInFrame(&CachedFrame::frameUp, test, bestData, cursor))
+ if (moveInFrame(&CachedFrame::frameUp, test, bestData))
continue;
BestData testData;
- if (frameNodeCommon(testData, test, bestData, &originalData, cursor) == REJECT_TEST)
+ if (frameNodeCommon(testData, test, bestData, &originalData) == REJECT_TEST)
continue;
if (checkVisited(test, UP) == false)
continue;
size_t parts = test->navableRects();
for (size_t part = 0; part < parts; part++) {
- testData.mNodeBounds = test->cursorRings().at(part);
+ testData.setNodeBounds(test->ring(this, part));
if (testData.setUpDirection(history()))
continue;
- int result = framePartCommon(testData, test, bestData, cursor);
+ int result = framePartCommon(testData, test, bestData);
if (result == REJECT_TEST)
continue;
if (result == 0 && limit == NULL) { // retry all data up to this point, since smaller may have replaced node preferable to larger
BestData innerData = testData;
- frameUp(document(), test, &innerData, cursor);
+ frameUp(document(), test, &innerData);
if (checkVisited(innerData.mNode, UP)) {
*bestData = innerData;
continue;
*bestData = testData;
}
} while ((test = test->traverseNextNode()) != limit); // FIXME ??? left and up should use traversePreviousNode to choose reverse document order
- ASSERT(cursor == NULL || bestData->mNode != cursor);
+ ASSERT(mRoot->cursor() == NULL || bestData->mNode != mRoot->cursor());
return bestData->mNode;
}
mIndexInParent = childFrameIndex;
}
+#if USE(ACCELERATED_COMPOSITING)
+const CachedLayer* CachedFrame::layer(const CachedNode* node) const
+{
+ if (!node->isInLayer())
+ return 0;
+ CachedLayer test;
+ test.setCachedNodeIndex(node->index());
+ return std::lower_bound(mCachedLayers.begin(), mCachedLayers.end(), test);
+}
+#endif
+
int CachedFrame::minWorkingHorizontal() const
{
return history()->minWorkingHorizontal();
}
bool CachedFrame::moveInFrame(MoveInDirection moveInDirection,
- const CachedNode* test, BestData* bestData,
- const CachedNode* cursor) const
+ const CachedNode* test, BestData* bestData) const
{
const CachedFrame* frame = hasFrame(test);
if (frame == NULL)
const CachedNode* childDoc = frame->validDocument();
if (childDoc == NULL)
return true;
- (frame->*moveInDirection)(childDoc, NULL, bestData, cursor);
+ (frame->*moveInDirection)(childDoc, NULL, bestData);
return true;
}
return history()->navBounds();
}
+SkPicture* CachedFrame::picture(const CachedNode* node) const
+{
+#if USE(ACCELERATED_COMPOSITING)
+ if (node->isInLayer())
+ return layer(node)->picture(mRoot->rootLayer());
+#endif
+ return mRoot->getPicture();
+}
+
void CachedFrame::resetClippedOut()
{
for (CachedNode* test = mCachedNodes.begin(); test != mCachedNodes.end(); test++)
}
}
+void CachedFrame::resetLayers()
+{
+#if USE(ACCELERATED_COMPOSITING)
+ for (CachedLayer* test = mCachedLayers.begin(); test != mCachedLayers.end();
+ test++) {
+ test->reset();
+ }
+ for (CachedFrame* frame = mCachedFrames.begin(); frame != mCachedFrames.end();
+ frame++) {
+ frame->resetLayers();
+ }
+#endif
+}
+
bool CachedFrame::sameFrame(const CachedFrame* test) const
{
ASSERT(test);
if (test->nodePointer() != node && first)
continue;
size_t partMax = test->navableRects();
- WTF::Vector<WebCore::IntRect>& cursorRings = test->cursorRings();
for (size_t part = 0; part < partMax; part++) {
- const WebCore::IntRect& testBounds = cursorRings.at(part);
+ WebCore::IntRect testBounds = test->ring(this, part);
if (testBounds.contains(x, y) == false)
continue;
if (test->isCursor()) {
DEBUG_PRINT_RECT("//", CONTENTS, mContents);
DEBUG_PRINT_RECT("", BOUNDS, mLocalViewBounds);
DEBUG_PRINT_RECT("//", VIEW, mViewBounds);
+
DUMP_NAV_LOGD("// CachedNode mCachedNodes={ // count=%d\n", b->mCachedNodes.size());
for (CachedNode* node = b->mCachedNodes.begin();
node != b->mCachedNodes.end(); node++) {
input->mDebug.print();
}
DUMP_NAV_LOGD("// }; // end of nodes\n");
+#if USE(ACCELERATED_COMPOSITING)
+ DUMP_NAV_LOGD("// CachedLayer mCachedLayers={ // count=%d\n", b->mCachedLayers.size());
+ for (CachedLayer* layer = b->mCachedLayers.begin();
+ layer != b->mCachedLayers.end(); layer++) {
+ layer->mDebug.print();
+ }
+ DUMP_NAV_LOGD("// }; // end of layers\n");
+#endif // USE(ACCELERATED_COMPOSITING)
DUMP_NAV_LOGD("// CachedFrame mCachedFrames={ // count=%d\n", b->mCachedFrames.size());
for (CachedFrame* child = b->mCachedFrames.begin();
child != b->mCachedFrames.end(); child++)
#define CachedFrame_H
#include "CachedInput.h"
+#include "CachedLayer.h"
#include "CachedNode.h"
#include "IntRect.h"
#include "SkFixed.h"
#include "wtf/Vector.h"
+class SkPicture;
+
namespace WebCore {
class Frame;
class Node;
};
CachedFrame() {}
void add(CachedInput& input) { mCachedTextInputs.append(input); }
+#if USE(ACCELERATED_COMPOSITING)
+ void add(CachedLayer& layer) { mCachedLayers.append(layer); }
+#endif
void add(CachedNode& node) { mCachedNodes.append(node); }
void addFrame(CachedFrame& child) { mCachedFrames.append(child); }
+ WebCore::IntRect adjustBounds(const CachedNode* ,
+ const WebCore::IntRect& ) const;
+ bool checkRings(const CachedNode* node,
+ const WTF::Vector<WebCore::IntRect>& rings,
+ const WebCore::IntRect& bounds) const;
bool checkVisited(const CachedNode* , CachedFrame::Direction ) const;
size_t childCount() { return mCachedFrames.size(); }
void clearCursor();
const CachedFrame* lastChild() const { return &mCachedFrames.last(); }
CachedNode* lastNode() { return &mCachedNodes.last(); }
CachedFrame* lastChild() { return &mCachedFrames.last(); }
+#if USE(ACCELERATED_COMPOSITING)
+ const CachedLayer* layer(const CachedNode* ) const;
+#endif
/**
* Find the next textfield/textarea
* @param start Must be a CachedNode in this CachedFrame's tree, or
const CachedFrame** framePtr, bool includeTextAreas) const;
const CachedFrame* parent() const { return mParent; }
CachedFrame* parent() { return mParent; }
+ SkPicture* picture(const CachedNode* ) const;
+ void resetLayers();
bool sameFrame(const CachedFrame* ) const;
void removeLast() { mCachedNodes.removeLast(); }
void resetClippedOut();
const CachedNode* validDocument() const;
protected:
struct BestData {
- WebCore::IntRect mNodeBounds;
- WebCore::IntRect mMouseBounds;
int mDistance;
int mSideDistance;
int mMajorDelta; // difference of center of object
bool inOrSubsumesNav() const { return (mNavDelta ^ mNavDelta2) >= 0; }
bool inOrSubsumesWorking() const { return (mWorkingDelta ^ mWorkingDelta2) >= 0; }
int isContainer(BestData* );
+ const WebCore::IntRect& mouseBounds() const { return mMouseBounds; }
static SkFixed Overlap(int span, int left, int right);
void reset() { mNode = NULL; }
int right() const { return bounds().right(); }
+ void setMouseBounds(const WebCore::IntRect& b) { mMouseBounds = b; }
+ void setNodeBounds(const WebCore::IntRect& b) { mNodeBounds = b; }
void setDistances();
bool setDownDirection(const CachedHistory* );
bool setLeftDirection(const CachedHistory* );
int width() const { return bounds().width(); }
int x() const { return bounds().x(); }
int y() const { return bounds().y(); }
+private: // since computing these is complicated, protect them so that the
+ // are only written by appropriate helpers
+ WebCore::IntRect mMouseBounds;
+ WebCore::IntRect mNodeBounds;
};
typedef const CachedNode* (CachedFrame::*MoveInDirection)(
- const CachedNode* test, const CachedNode* limit, BestData* bestData,
- const CachedNode* focus) const;
+ const CachedNode* test, const CachedNode* limit, BestData* ) const;
void adjustToTextColumn(int* delta) const;
static bool CheckBetween(Direction , const WebCore::IntRect& bestRect,
const WebCore::IntRect& prior, WebCore::IntRect* result);
bool checkBetween(BestData* , Direction );
- int compare(BestData& testData, const BestData& bestData, const
- CachedNode* focus) const;
+ int compare(BestData& testData, const BestData& bestData) const;
void findClosest(BestData* , Direction original, Direction test,
WebCore::IntRect* clip) const;
int frameNodeCommon(BestData& testData, const CachedNode* test,
- BestData* bestData, BestData* originalData,
- const CachedNode* focus) const;
+ BestData* bestData, BestData* originalData) const;
int framePartCommon(BestData& testData, const CachedNode* test,
- BestData* bestData, const CachedNode* focus) const;
+ BestData* ) const;
const CachedNode* frameDown(const CachedNode* test, const CachedNode* limit,
- BestData* , const CachedNode* focus) const;
+ BestData* ) const;
const CachedNode* frameLeft(const CachedNode* test, const CachedNode* limit,
- BestData* , const CachedNode* focus) const;
+ BestData* ) const;
const CachedNode* frameRight(const CachedNode* test, const CachedNode* limit,
- BestData* , const CachedNode* focus) const;
+ BestData* ) const;
const CachedNode* frameUp(const CachedNode* test, const CachedNode* limit,
- BestData* , const CachedNode* focus) const;
+ BestData* ) const;
int minWorkingHorizontal() const;
int minWorkingVertical() const;
int maxWorkingHorizontal() const;
int maxWorkingVertical() const;
- bool moveInFrame(MoveInDirection , const CachedNode* test, BestData* best,
- const CachedNode* focus) const;
+ bool moveInFrame(MoveInDirection , const CachedNode* test, BestData* ) const;
const WebCore::IntRect& _navBounds() const;
WebCore::IntRect mContents;
WebCore::IntRect mLocalViewBounds;
WTF::Vector<CachedNode> mCachedNodes;
WTF::Vector<CachedFrame> mCachedFrames;
WTF::Vector<CachedInput> mCachedTextInputs;
+#if USE(ACCELERATED_COMPOSITING)
+ WTF::Vector<CachedLayer> mCachedLayers;
+#endif
void* mFrame; // WebCore::Frame*, used only to compare pointers
CachedFrame* mParent;
int mCursorIndex;
}
void CachedHistory::setWorking(CachedFrame::Direction newMove,
- const CachedNode* cursor, const WebCore::IntRect& viewBounds)
+ const CachedFrame* cursorFrame, const CachedNode* cursor,
+ const WebCore::IntRect& viewBounds)
{
CachedFrame::Direction lastAxis = (CachedFrame::Direction) (mLastMove & ~CachedFrame::RIGHT_DOWN); // up, left or uninitialized
CachedFrame::Direction newAxis = (CachedFrame::Direction) (newMove & ~CachedFrame::RIGHT_DOWN);
}
const WebCore::IntRect* navBounds = &mNavBounds;
if (cursor != NULL) {
- WebCore::IntRect cursorBounds;
- cursor->getBounds(&cursorBounds);
+ WebCore::IntRect cursorBounds = cursor->bounds(cursorFrame);
if (cursorBounds.isEmpty() == false)
mNavBounds = cursorBounds;
}
void setDidFirstLayout(bool did) { mDidFirstLayout = did; }
void setMouseBounds(const WebCore::IntRect& loc) { mMouseBounds = loc; }
void setNavBounds(const WebCore::IntRect& loc) { mNavBounds = loc; }
- void setWorking(CachedFrame::Direction , const CachedNode* focus,
- const WebCore::IntRect& viewBounds);
+ void setWorking(CachedFrame::Direction , const CachedFrame* ,
+ const CachedNode* , const WebCore::IntRect& viewBounds);
void reset();
private:
void pinMaxMin(const WebCore::IntRect& viewBounds);
--- /dev/null
+/*
+ * Copyright 2010, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "CachedPrefix.h"
+
+#include "CachedLayer.h"
+#include "FloatRect.h"
+#include "LayerAndroid.h"
+
+namespace android {
+
+#if USE(ACCELERATED_COMPOSITING)
+
+IntRect CachedLayer::adjustBounds(const LayerAndroid* root,
+ const IntRect& bounds) const
+{
+ const LayerAndroid* aLayer = layer(root);
+ if (!aLayer) {
+ DBG_NAV_LOGD("no layer in root=%p uniqueId=%d", root, mUniqueId);
+#if DUMP_NAV_CACHE
+ if (root)
+ mDebug.printRootLayerAndroid(root);
+#endif
+ return bounds;
+ }
+ FloatRect temp = bounds;
+ const FloatPoint& position = aLayer->position();
+ temp.move(position.x(), position.y());
+ const FloatPoint& translation = aLayer->translation();
+ temp.move(translation.x(), translation.y());
+ IntRect result = enclosingIntRect(temp);
+ DBG_NAV_LOGD("root=%p aLayer=%p [%d]"
+ " bounds=(%d,%d,w=%d,h=%d) pos=(%g,%g) trans=(%g,%g)"
+ " result=(%d,%d,w=%d,h=%d) offset=(%d,%d)",
+ root, aLayer, aLayer->uniqueId(),
+ bounds.x(), bounds.y(), bounds.width(), bounds.height(),
+ position.x(), position.y(), translation.x(), translation.y(),
+ result.x(), result.y(), result.width(), result.height(),
+ mOffset.x(), mOffset.y());
+ result.move(-mOffset.x(), -mOffset.y());
+ return result;
+}
+
+const LayerAndroid* CachedLayer::layer(const LayerAndroid* root) const
+{
+ if (!root || mLayer)
+ return mLayer;
+ return mLayer = root->findById(mUniqueId);
+}
+
+SkPicture* CachedLayer::picture(const LayerAndroid* root) const
+{
+ const LayerAndroid* aLayer = layer(root);
+ if (!aLayer)
+ return 0;
+ DBG_NAV_LOGD("root=%p aLayer=%p [%d] picture=%p",
+ root, aLayer, aLayer->uniqueId(), aLayer->picture());
+ return aLayer->picture();
+}
+
+#if DUMP_NAV_CACHE
+
+CachedLayer* CachedLayer::Debug::base() const {
+ return (CachedLayer*) ((char*) this - OFFSETOF(CachedLayer, mDebug));
+}
+
+void CachedLayer::Debug::print() const
+{
+ CachedLayer* b = base();
+ DUMP_NAV_LOGD(" // int mCachedNodeIndex=%d;", b->mCachedNodeIndex);
+ DUMP_NAV_LOGD(" LayerAndroid* mLayer=%p;", b->mLayer);
+ DUMP_NAV_LOGD(" int mOffset=(%d, %d);", b->mOffset.x(), b->mOffset.y());
+ DUMP_NAV_LOGD(" int mUniqueId=%p;\n", b->mUniqueId);
+}
+
+#endif
+
+#if DUMP_NAV_CACHE
+
+int CachedLayer::Debug::spaces;
+
+void CachedLayer::Debug::printLayerAndroid(const LayerAndroid* layer)
+{
+ ++spaces;
+ SkRect bounds;
+ layer->bounds(&bounds);
+ DUMP_NAV_LOGX("%.*s layer=%p [%d] (%g,%g,%g,%g) picture=%p clipped=%s",
+ spaces, " ", layer, layer->uniqueId(),
+ bounds.fLeft, bounds.fTop, bounds.width(), bounds.height(),
+ layer->picture(), layer->haveClip() ? "true" : "false");
+ for (int i = 0; i < layer->countChildren(); i++)
+ printLayerAndroid(layer->getChild(i));
+ --spaces;
+}
+
+void CachedLayer::Debug::printRootLayerAndroid(const LayerAndroid* layer)
+{
+ spaces = 0;
+ printLayerAndroid(layer);
+}
+#endif
+
+#endif // USE(ACCELERATED_COMPOSITING)
+
+}
+
--- /dev/null
+/*
+ * Copyright 2010, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef CachedLayer_H
+#define CachedLayer_H
+
+#include "CachedDebug.h"
+#include "IntRect.h"
+
+class SkPicture;
+
+namespace WebCore {
+ class LayerAndroid;
+}
+
+using namespace WebCore;
+
+namespace android {
+
+class CachedLayer {
+public:
+#if USE(ACCELERATED_COMPOSITING)
+ bool operator<(const CachedLayer& l) const {
+ return mCachedNodeIndex < l.mCachedNodeIndex;
+ }
+ IntRect adjustBounds(const LayerAndroid* root, const IntRect& bounds) const;
+ int cachedNodeIndex() const { return mCachedNodeIndex; }
+ const LayerAndroid* layer(const LayerAndroid* root) const;
+ SkPicture* picture(const LayerAndroid* root) const;
+ void reset() { mLayer = 0; }
+ void setCachedNodeIndex(int index) { mCachedNodeIndex = index; }
+ void setOffset(const IntPoint& offset) { mOffset = offset; }
+ void setUniqueId(int uniqueId) { mUniqueId = uniqueId; }
+ int uniqueId() const { return mUniqueId; }
+private:
+ int mCachedNodeIndex;
+ mutable const LayerAndroid* mLayer;
+ IntPoint mOffset;
+ int mUniqueId;
+
+#if DUMP_NAV_CACHE
+public:
+ class Debug {
+public:
+ CachedLayer* base() const;
+ void print() const;
+ static void printLayerAndroid(const LayerAndroid* );
+ static void printRootLayerAndroid(const LayerAndroid* );
+ static int spaces;
+ } mDebug;
+#endif
+#endif // USE(ACCELERATED_COMPOSITING)
+};
+
+}
+
+#endif
*/
#include "CachedPrefix.h"
+#include "android_graphics.h"
+#include "CachedFrame.h"
#include "CachedHistory.h"
-#include "CachedRoot.h"
#include "Node.h"
#include "PlatformString.h"
-#include "android_graphics.h"
#include "CachedNode.h"
namespace android {
+WebCore::IntRect CachedNode::bounds(const CachedFrame* frame) const
+{
+ return mIsInLayer ? frame->adjustBounds(this, mBounds) : mBounds;
+}
+
void CachedNode::clearCursor(CachedFrame* parent)
{
if (isFrame()) {
return Clip(bounds, &mBounds, &mCursorRing);
}
-void CachedNode::cursorRingBounds(WebCore::IntRect* bounds) const
+
+void CachedNode::cursorRings(const CachedFrame* frame,
+ WTF::Vector<WebCore::IntRect>* rings) const
+{
+ rings->clear();
+ for (unsigned index = 0; index < mCursorRing.size(); index++)
+ rings->append(ring(frame, index));
+}
+
+WebCore::IntRect CachedNode::cursorRingBounds(const CachedFrame* frame) const
{
int partMax = mNavableRects;
ASSERT(partMax > 0);
- *bounds = mCursorRing[0];
+ WebCore::IntRect bounds = mCursorRing[0];
for (int partIndex = 1; partIndex < partMax; partIndex++)
- bounds->unite(mCursorRing[partIndex]);
- bounds->inflate(CURSOR_RING_HIT_TEST_RADIUS);
+ bounds.unite(mCursorRing[partIndex]);
+ bounds.inflate(CURSOR_RING_HIT_TEST_RADIUS);
+ return mIsInLayer ? frame->adjustBounds(this, bounds) : bounds;
}
#define OVERLAP 3
-void CachedNode::fixUpCursorRects(const CachedRoot* root)
+void CachedNode::fixUpCursorRects(const CachedFrame* frame)
{
if (mFixedUpCursorRects)
return;
mFixedUpCursorRects = true;
// if the hit-test rect doesn't intersect any other rect, use it
if (mHitBounds != mBounds && mHitBounds.contains(mBounds) &&
- root->checkRings(mCursorRing, mHitBounds)) {
+ frame->checkRings(this, mCursorRing, mHitBounds)) {
DBG_NAV_LOGD("use mHitBounds (%d,%d,%d,%d)", mHitBounds.x(),
mHitBounds.y(), mHitBounds.width(), mHitBounds.height());
mUseHitBounds = true;
return;
// if there is more than 1 rect, and the bounds doesn't intersect
// any other cursor ring bounds, use it
- if (root->checkRings(mCursorRing, mBounds)) {
+ if (frame->checkRings(this, mCursorRing, mBounds)) {
DBG_NAV_LOGD("use mBounds (%d,%d,%d,%d)", mBounds.x(),
mBounds.y(), mBounds.width(), mBounds.height());
mUseBounds = true;
} while (again);
}
+
void CachedNode::hideCursor(CachedFrame* parent)
{
if (isFrame()) {
mIsHidden = true;
}
+WebCore::IntRect CachedNode::hitBounds(const CachedFrame* frame) const
+{
+ return mIsInLayer ? frame->adjustBounds(this, mHitBounds) : mHitBounds;
+}
+
void CachedNode::init(WebCore::Node* node)
{
bzero(this, sizeof(CachedNode));
return false;
}
+WebCore::IntRect CachedNode::ring(const CachedFrame* frame, size_t part) const
+{
+ const WebCore::IntRect& rect = mCursorRing.at(part);
+ return mIsInLayer ? frame->adjustBounds(this, rect) : rect;
+}
+
#if DUMP_NAV_CACHE
#define DEBUG_PRINT_BOOL(field) \
DUMP_NAV_LOGD("%.*s\"\n", index, scratch);
DEBUG_PRINT_RECT(mBounds);
DEBUG_PRINT_RECT(mHitBounds);
- const WTF::Vector<WebCore::IntRect>& rects = b->cursorRings();
- size_t size = rects.size();
+ DEBUG_PRINT_RECT(mOriginalAbsoluteBounds);
+ const WTF::Vector<WebCore::IntRect>* rects = b->cursorRingsPtr();
+ size_t size = rects->size();
DUMP_NAV_LOGD("// IntRect cursorRings={ // size=%d\n", size);
- for (size_t i = 0; i < size; i++)
- DUMP_NAV_LOGD(" // {%d, %d, %d, %d}, // %d\n", rects[i].x(), rects[i].y(),
- rects[i].width(), rects[i].height(), i);
+ for (size_t i = 0; i < size; i++) {
+ const WebCore::IntRect& rect = (*rects)[i];
+ DUMP_NAV_LOGD(" // {%d, %d, %d, %d}, // %d\n", rect.x(), rect.y(),
+ rect.width(), rect.height(), i);
+ }
DUMP_NAV_LOGD("// };\n");
DUMP_NAV_LOGD("// void* mNode=%p; // (%d) \n", b->mNode, mNodeIndex);
DUMP_NAV_LOGD("// void* mParentGroup=%p; // (%d) \n", b->mParentGroup, mParentGroupIndex);
DEBUG_PRINT_BOOL(mIsCursor);
DEBUG_PRINT_BOOL(mIsFocus);
DEBUG_PRINT_BOOL(mIsHidden);
+ DEBUG_PRINT_BOOL(mIsInLayer);
DEBUG_PRINT_BOOL(mIsParentAnchor);
DEBUG_PRINT_BOOL(mIsTransparent);
DEBUG_PRINT_BOOL(mIsUnclipped);
#include "PlatformString.h"
#include "wtf/Vector.h"
+class SkPicture;
+
namespace WebCore {
class Node;
}
NOT_CURSOR_NODE,
OUTSIDE_OF_BEST, // containership
OUTSIDE_OF_ORIGINAL, // containership
+ UNDER_LAYER,
CONDITION_SIZE // FIXME: test that CONDITION_SIZE fits in mCondition
};
CachedNode() {
// constructor
}
- const WebCore::IntRect& bounds() const { return mBounds; }
- WebCore::IntRect* boundsPtr() { return &mBounds; }
+ WebCore::IntRect bounds(const CachedFrame* ) const;
+ WebCore::IntRect* boundsPtr() { return &mBounds; } // CacheBuilder only
int childFrameIndex() const { return isFrame() ? mDataIndex : -1; }
void clearCondition() const { mCondition = NOT_REJECTED; }
void clearCursor(CachedFrame* );
WTF::Vector<WebCore::IntRect>* rings);
bool clip(const WebCore::IntRect& );
bool clippedOut() { return mClippedOut; }
- void cursorRingBounds(WebCore::IntRect* ) const;
- WTF::Vector<WebCore::IntRect>& cursorRings() { return mCursorRing; }
- const WTF::Vector<WebCore::IntRect>& cursorRings() const { return mCursorRing; }
+ WebCore::IntRect cursorRingBounds(const CachedFrame* ) const;
+ // cursorRingsPtr() only for CacheBuilder since it points to raw data
+ WTF::Vector<WebCore::IntRect>* cursorRingsPtr() { return &mCursorRing; }
+ void cursorRings(const CachedFrame* , WTF::Vector<WebCore::IntRect>* ) const;
bool disabled() const { return mDisabled; }
const CachedNode* document() const { return &this[-mIndex]; }
- void fixUpCursorRects(const CachedRoot* root);
- const WebCore::IntRect& getBounds() const { return mBounds; }
- void getBounds(WebCore::IntRect* bounds) const { *bounds = mBounds; }
+ void fixUpCursorRects(const CachedFrame* frame);
const WebCore::String& getExport() const { return mExport; }
bool hasCursorRing() const { return mHasCursorRing; }
bool hasMouseOver() const { return mHasMouseOver; }
void hideCursor(CachedFrame* );
- const WebCore::IntRect& hitBounds() const { return mHitBounds; }
+ WebCore::IntRect hitBounds(const CachedFrame* ) const;
int index() const { return mIndex; }
void init(WebCore::Node* node);
bool isAnchor() const { return mType == ANCHOR_CACHEDNODETYPE; }
bool isFocus() const { return mIsFocus; }
bool isFrame() const { return mType == FRAME_CACHEDNODETYPE; }
bool isHidden() const { return mIsHidden; }
- bool isNavable(const WebCore::IntRect& clip) const {
- return clip.intersects(mBounds);
+ bool isInLayer() const { return mIsInLayer; }
+ bool isNavable(const CachedFrame* frame, const WebCore::IntRect& clip) const {
+ return clip.intersects(bounds(frame));
}
bool isPlugin() const { return mType == PLUGIN_CACHEDNODETYPE; }
bool isSyntheticLink() const {
int parentIndex() const { return mParentIndex; }
bool partRectsContains(const CachedNode* other) const;
void reset();
+ WebCore::IntRect ring(const CachedFrame* , size_t part) const;
void setBounds(const WebCore::IntRect& bounds) { mBounds = bounds; }
void setClippedOut(bool clipped) { mClippedOut = clipped; }
void setCondition(Condition condition) const { mCondition = condition; }
void setIndex(int index) { mIndex = index; }
void setIsCursor(bool isCursor) { mIsCursor = isCursor; }
void setIsFocus(bool isFocus) { mIsFocus = isFocus; }
+ void setIsInLayer(bool isInLayer) { mIsInLayer = isInLayer; }
void setIsParentAnchor(bool isAnchor) { mIsParentAnchor = isAnchor; }
void setIsTransparent(bool isTransparent) { mIsTransparent = isTransparent; }
void setIsUnclipped(bool unclipped) { mIsUnclipped = unclipped; }
bool mIsCursor : 1;
bool mIsFocus : 1;
bool mIsHidden : 1;
+ bool mIsInLayer : 1;
bool mIsParentAnchor : 1;
bool mIsTransparent : 1;
bool mIsUnclipped : 1;
#include "CachedHistory.h"
#include "CachedInput.h"
#include "CachedNode.h"
+#include "FindCanvas.h"
+#include "FloatRect.h"
+#include "LayerAndroid.h"
#include "SkBitmap.h"
#include "SkBounder.h"
-#include "SkCanvas.h"
#include "SkPixelRef.h"
#include "SkRegion.h"
#include "CachedRoot.h"
+using std::min;
+using std::max;
+
#ifdef DUMP_NAV_CACHE_USING_PRINTF
extern android::Mutex gWriteLogMutex;
#endif
innerMove(document(), best, direction, scrollPtr, false);
return true;
}
- newNode->cursorRingBounds(&newOutset);
+ newOutset = newNode->cursorRingBounds(best->mFrame);
}
int delta;
bool newNodeInView = scrollDelta(newOutset, direction, &delta);
checker.setBitmapDevice(bitmap);
checker.translate(SkIntToScalar(width - mViewBounds.x()),
SkIntToScalar(-mViewBounds.y()));
- checker.drawPicture(*mPicture);
+ checker.drawPicture(*pictureAt(x, y));
return centerCheck.center();
}
bitmap.setConfig(SkBitmap::kARGB_8888_Config, mViewBounds.width() +
absDelta, mViewBounds.height());
checker.setBitmapDevice(bitmap);
- checker.translate(SkIntToScalar(-mViewBounds.x() -
- (xDelta < 0 ? xDelta : 0)), SkIntToScalar(-mViewBounds.y()));
- checker.drawPicture(*mPicture);
+ int x = -mViewBounds.x() - (xDelta < 0 ? xDelta : 0);
+ int y = -mViewBounds.y();
+ checker.translate(SkIntToScalar(x), SkIntToScalar(y));
+ checker.drawPicture(*pictureAt(x, y));
*xDeltaPtr = jiggleCheck.jiggle();
}
-bool CachedRoot::checkRings(const WTF::Vector<WebCore::IntRect>& rings,
+bool CachedRoot::checkRings(SkPicture* picture,
+ const WTF::Vector<WebCore::IntRect>& rings,
const WebCore::IntRect& bounds) const
{
- if (!mPicture)
+ if (!picture)
return false;
RingCheck ringCheck(rings, bounds.location());
BoundsCanvas checker(&ringCheck);
bounds.height());
checker.setBitmapDevice(bitmap);
checker.translate(SkIntToScalar(-bounds.x()), SkIntToScalar(-bounds.y()));
- checker.drawPicture(*mPicture);
+ checker.drawPicture(*picture);
DBG_NAV_LOGD("bounds=(%d,%d,r=%d,b=%d) success=%s",
bounds.x(), bounds.y(), bounds.right(), bounds.bottom(),
ringCheck.success() ? "true" : "false");
return ringCheck.success();
}
+void CachedRoot::draw(FindCanvas& canvas) const
+{
+ canvas.setLayerId(-1); // overlays change the ID as their pictures draw
+ canvas.drawPicture(*mPicture);
+#if USE(ACCELERATED_COMPOSITING)
+ if (!mRootLayer)
+ return;
+ canvas.drawLayers(mRootLayer);
+#endif
+}
+
const CachedNode* CachedRoot::findAt(const WebCore::IntRect& rect,
const CachedFrame** framePtr, int* x, int* y, bool checkForHidden) const
{
int fx, fy;
const CachedNode* node = findAt(rect, &frame, &fx, &fy, true);
if (node && node->wantsKeyEvents()) {
- DBG_NAV_LOGD("x=%d (%s)", node->bounds().x(),
+ DBG_NAV_LOGD("x=%d (%s)", node->bounds(frame).x(),
node->isTextInput() ? "text" : "plugin");
- return node->bounds().x();
+ return node->bounds(frame).x();
}
+ SkPicture* picture = node ? frame->picture(node) : pictureAt(x, y);
+ if (!picture)
+ return x;
int halfW = (int) (mViewBounds.width() * scale * 0.5f);
int fullW = halfW << 1;
int halfH = (int) (mViewBounds.height() * scale * 0.5f);
bitmap.setConfig(SkBitmap::kARGB_8888_Config, fullW, fullH);
checker.setBitmapDevice(bitmap);
checker.translate(SkIntToScalar(fullW - x), SkIntToScalar(halfH - y));
- checker.drawPicture(*mPicture);
+ checker.drawPicture(*picture);
int result = x + leftCheck.left() - fullW;
DBG_NAV_LOGD("halfW=%d halfH=%d mMostLeft=%d x=%d",
halfW, halfH, leftCheck.mMostLeft, result);
mScrolledBounds.setY(navTop);
}
}
- frameDown(test, NULL, bestData, currentCursor());
+ setCursorCache(0, mMaxYScroll);
+ frameDown(test, NULL, bestData);
return true;
}
if (testRight > navRight && navRight > (scrollLeft = mScrolledBounds.x()))
mScrolledBounds.setWidth(navRight - scrollLeft);
}
- frameLeft(test, NULL, bestData, currentCursor());
+ setCursorCache(-mMaxXScroll, 0);
+ frameLeft(test, NULL, bestData);
return true;
}
mHistory->reset();
outOfCursor = true;
}
- const CachedNode* cursor = currentCursor();
- mHistory->setWorking(direction, cursor, mViewBounds);
+ const CachedFrame* cursorFrame;
+ const CachedNode* cursor = currentCursor(&cursorFrame);
+ mHistory->setWorking(direction, cursorFrame, cursor, mViewBounds);
bool findClosest = false;
if (mScrollOnly == false) {
switch (direction) {
}
if (firstCall)
mHistory->mPriorBounds = mHistory->mNavBounds; // bounds always advances, even if new node is ultimately NULL
- bestData->mMouseBounds = bestData->mNodeBounds;
+ bestData->setMouseBounds(bestData->bounds());
if (adjustForScroll(bestData, direction, scroll, findClosest))
return;
if (bestData->mNode != NULL) {
mHistory->addToVisited(bestData->mNode, direction);
- mHistory->mNavBounds = bestData->mNodeBounds;
- mHistory->mMouseBounds = bestData->mMouseBounds;
+ mHistory->mNavBounds = bestData->bounds();
+ mHistory->mMouseBounds = bestData->mouseBounds();
} else if (scroll->x() != 0 || scroll->y() != 0) {
WebCore::IntRect newBounds = mHistory->mNavBounds;
int offsetX = scroll->x();
mScrolledBounds.setX(navLeft);
}
}
- frameRight(test, NULL, bestData, currentCursor());
+ setCursorCache(mMaxXScroll, 0);
+ frameRight(test, NULL, bestData);
return true;
}
if (testBottom > navBottom && navBottom > (scrollTop = mScrolledBounds.y()))
mScrolledBounds.setHeight(navBottom - scrollTop);
}
- frameUp(test, NULL, bestData, currentCursor());
+ setCursorCache(0, -mMaxYScroll);
+ frameUp(test, NULL, bestData);
return true;
}
bitmap.setConfig(SkBitmap::kARGB_8888_Config, 1, 1);
checker.setBitmapDevice(bitmap);
checker.translate(SkIntToScalar(-x), SkIntToScalar(-y));
- checker.drawPicture(*mPicture);
+ checker.drawPicture(*pictureAt(x, y));
return WebCore::String(checker.mURI);
}
bool CachedRoot::maskIfHidden(BestData* best) const
{
- if (mPicture == NULL) {
- DBG_NAV_LOG("missing picture");
- return false;
- }
const CachedNode* bestNode = best->mNode;
if (bestNode->isUnclipped())
return false;
+ SkPicture* picture = best->mFrame->picture(bestNode);
+ if (picture == NULL) {
+ DBG_NAV_LOG("missing picture");
+ return false;
+ }
// given the picture matching this nav cache
// create an SkBitmap with dimensions of the cursor intersected w/ extended view
- const WebCore::IntRect& nodeBounds = bestNode->getBounds();
+ const WebCore::IntRect& nodeBounds = bestNode->bounds(best->mFrame);
WebCore::IntRect bounds = nodeBounds;
bounds.intersect(mScrolledBounds);
int leftMargin = bounds.x() == nodeBounds.x() ? kMargin : 0;
// ? need to know (like imdb menu bar) to give up sometimes (when?)
checker.translate(SkIntToScalar(leftMargin - bounds.x()),
SkIntToScalar(topMargin - bounds.y()));
- checker.drawPicture(*mPicture);
+ checker.drawPicture(*picture);
boundsCheck.checkLast();
// was it not drawn or clipped out?
CachedNode* node = const_cast<CachedNode*>(best->mNode);
orig.fLeft, orig.fTop, orig.fRight, orig.fBottom,
base.fLeft, base.fTop, base.fRight, base.fBottom);
#endif
- best->mMouseBounds = WebCore::IntRect(bounds.x() + base.fLeft - kMargin,
- bounds.y() + base.fTop - kMargin, base.width(), base.height());
- node->clip(best->mMouseBounds);
+ best->setMouseBounds(WebCore::IntRect(bounds.x() + base.fLeft - kMargin,
+ bounds.y() + base.fTop - kMargin, base.width(), base.height()));
+ node->clip(best->mouseBounds());
return true;
}
return false;
setData();
BestData bestData;
innerMove(node, &bestData, direction, scroll, true);
+ // if node is partially or fully concealed by layer, scroll it into view
+ if (mRootLayer && bestData.mNode && !bestData.mNode->isInLayer()) {
+#if USE(ACCELERATED_COMPOSITING)
+#if DUMP_NAV_CACHE
+ CachedLayer::Debug::printRootLayerAndroid(mRootLayer);
+#endif
+ SkIRect original = bestData.mNode->cursorRingBounds(bestData.mFrame);
+ DBG_NAV_LOGD("original=(%d,%d,w=%d,h=%d) scroll=(%d,%d)",
+ original.fLeft, original.fTop, original.width(), original.height(),
+ scroll->x(), scroll->y());
+ original.offset(-scroll->x(), -scroll->y());
+ SkRegion rings(original);
+ SkTDArray<SkRect> region;
+ mRootLayer->clipArea(®ion);
+ SkRegion layers;
+ for (int index = 0; index < region.count(); index++) {
+ SkIRect enclosing;
+ region[index].round(&enclosing);
+ rings.op(enclosing, SkRegion::kDifference_Op);
+ layers.op(enclosing, SkRegion::kUnion_Op);
+ }
+ SkIRect layerBounds(layers.getBounds());
+ SkIRect ringBounds(rings.getBounds());
+ int scrollX = scroll->x();
+ int scrollY = scroll->y();
+ if (rings.getBounds() != original) {
+ int topOverlap = layerBounds.fBottom - original.fTop;
+ int bottomOverlap = original.fBottom - layerBounds.fTop;
+ int leftOverlap = layerBounds.fRight - original.fLeft;
+ int rightOverlap = original.fRight - layerBounds.fLeft;
+ if (direction & UP_DOWN) {
+ if (layerBounds.fLeft < original.fLeft && leftOverlap < 0)
+ scroll->setX(leftOverlap);
+ if (original.fRight < layerBounds.fRight && rightOverlap > 0
+ && -leftOverlap > rightOverlap)
+ scroll->setX(rightOverlap);
+ bool topSet = scrollY > topOverlap && (direction == UP
+ || !scrollY);
+ if (topSet)
+ scroll->setY(topOverlap);
+ if (scrollY < bottomOverlap && (direction == DOWN || (!scrollY
+ && (!topSet || -topOverlap > bottomOverlap))))
+ scroll->setY(bottomOverlap);
+ } else {
+ if (layerBounds.fTop < original.fTop && topOverlap < 0)
+ scroll->setY(topOverlap);
+ if (original.fBottom < layerBounds.fBottom && bottomOverlap > 0
+ && -topOverlap > bottomOverlap)
+ scroll->setY(bottomOverlap);
+ bool leftSet = scrollX > leftOverlap && (direction == LEFT
+ || !scrollX);
+ if (leftSet)
+ scroll->setX(leftOverlap);
+ if (scrollX < rightOverlap && (direction == RIGHT || (!scrollX
+ && (!leftSet || -leftOverlap > rightOverlap))))
+ scroll->setX(rightOverlap);
+ }
+ DBG_NAV_LOGD("rings=(%d,%d,w=%d,h=%d) layers=(%d,%d,w=%d,h=%d)"
+ " scroll=(%d,%d)",
+ ringBounds.fLeft, ringBounds.fTop, ringBounds.width(), ringBounds.height(),
+ layerBounds.fLeft, layerBounds.fTop, layerBounds.width(), layerBounds.height(),
+ scroll->x(), scroll->y());
+ }
+#endif
+ }
*framePtr = bestData.mFrame;
return const_cast<CachedNode*>(bestData.mNode);
}
+SkPicture* CachedRoot::pictureAt(int x, int y) const
+{
+#if USE(ACCELERATED_COMPOSITING)
+ if (mRootLayer) {
+ const LayerAndroid* layer = mRootLayer->find(FloatPoint(x, y));
+ if (layer)
+ return layer->picture();
+ }
+#endif
+ return mPicture;
+}
+
void CachedRoot::reset()
{
#ifndef NDEBUG
#endif
mContents = mViewBounds = WebCore::IntRect(0, 0, 0, 0);
mMaxXScroll = mMaxYScroll = 0;
+ mRootLayer = 0;
mSelectionStart = mSelectionEnd = -1;
mScrollOnly = false;
}
if (node == NULL)
return;
node->setIsFocus(true);
- mFocusBounds = node->bounds();
+ mFocusBounds = node->bounds(frame);
frame->setFocusIndex(node - frame->document());
CachedFrame* parent;
while ((parent = frame->parent()) != NULL) {
frame = parent;
}
#if DEBUG_NAV_UI
- const CachedNode* focus = frame->currentFocus();
+ const CachedFrame* focusFrame;
+ const CachedNode* focus = currentFocus(&focusFrame);
WebCore::IntRect bounds = WebCore::IntRect(0, 0, 0, 0);
if (focus)
- bounds = focus->bounds();
+ bounds = focus->bounds(focusFrame);
DBG_NAV_LOGD("new focus %d (nodePointer=%p) bounds={%d,%d,%d,%d}",
focus ? focus->index() : 0,
focus ? focus->nodePointer() : NULL, bounds.x(), bounds.y(),
void CachedRoot::setCursor(CachedFrame* frame, CachedNode* node)
{
#if DEBUG_NAV_UI
- const CachedNode* cursor = currentCursor();
+ const CachedFrame* cursorFrame;
+ const CachedNode* cursor = currentCursor(&cursorFrame);
WebCore::IntRect bounds;
if (cursor)
- bounds = cursor->bounds();
+ bounds = cursor->bounds(cursorFrame);
DBG_NAV_LOGD("old cursor %d (nodePointer=%p) bounds={%d,%d,%d,%d}",
cursor ? cursor->index() : 0,
cursor ? cursor->nodePointer() : NULL, bounds.x(), bounds.y(),
frame = parent;
}
#if DEBUG_NAV_UI
- cursor = currentCursor();
+ cursor = currentCursor(&cursorFrame);
bounds = WebCore::IntRect(0, 0, 0, 0);
if (cursor)
- bounds = cursor->bounds();
+ bounds = cursor->bounds(cursorFrame);
DBG_NAV_LOGD("new cursor %d (nodePointer=%p) bounds={%d,%d,%d,%d}",
cursor ? cursor->index() : 0,
cursor ? cursor->nodePointer() : NULL, bounds.x(), bounds.y(),
#endif
}
+void CachedRoot::setCursorCache(int scrollX, int scrollY) const
+{
+ mCursor = currentCursor();
+ if (mCursor)
+ mCursorBounds = mCursor->bounds(this);
+ if (!mRootLayer)
+ return;
+ SkRegion baseScrolled(mScrolledBounds);
+ mBaseUncovered = SkRegion(mScrolledBounds);
+#if USE(ACCELERATED_COMPOSITING)
+#if DUMP_NAV_CACHE
+ CachedLayer::Debug::printRootLayerAndroid(mRootLayer);
+#endif
+ SkTDArray<SkRect> region;
+ mRootLayer->clipArea(®ion);
+ WebCore::IntSize offset(
+ copysign(min(max(0, mContents.width() - mScrolledBounds.width()),
+ abs(scrollX)), scrollX),
+ copysign(min(max(0, mContents.height() - mScrolledBounds.height()),
+ abs(scrollY)), scrollY));
+ bool hasOffset = offset.width() || offset.height();
+ // restrict scrollBounds to that which is not under layer
+ for (int index = 0; index < region.count(); index++) {
+ SkIRect less;
+ region[index].round(&less);
+ DBG_NAV_LOGD("less=(%d,%d,w=%d,h=%d)", less.fLeft, less.fTop,
+ less.width(), less.height());
+ mBaseUncovered.op(less, SkRegion::kDifference_Op);
+ if (!hasOffset)
+ continue;
+ less.offset(offset.width(), offset.height());
+ baseScrolled.op(less, SkRegion::kDifference_Op);
+ }
+ if (hasOffset)
+ mBaseUncovered.op(baseScrolled, SkRegion::kUnion_Op);
+#endif
+}
+
#if DUMP_NAV_CACHE
#define DEBUG_PRINT_BOOL(field) \
#include "CachedFrame.h"
#include "IntRect.h"
#include "SkPicture.h"
+#include "SkRegion.h"
#include "wtf/Vector.h"
+class FindCanvas;
class SkRect;
+namespace WebCore {
+ class LayerAndroid;
+}
+
namespace android {
class CachedHistory;
public:
bool adjustForScroll(BestData* , Direction , WebCore::IntPoint* scrollPtr,
bool findClosest);
+ const SkRegion& baseUncovered() const { return mBaseUncovered; }
int checkForCenter(int x, int y) const;
void checkForJiggle(int* ) const;
- bool checkRings(const WTF::Vector<WebCore::IntRect>& rings,
+ bool checkRings(SkPicture* , const WTF::Vector<WebCore::IntRect>& rings,
const WebCore::IntRect& bounds) const;
WebCore::IntPoint cursorLocation() const;
+ const WebCore::IntRect& cursorBounds() const { return mCursorBounds; } // should only be called by CachedFrame
+ const CachedNode* cursor() const { return mCursor; } // should only be called by CachedFrame
int documentHeight() { return mContents.height(); }
int documentWidth() { return mContents.width(); }
+ void draw(FindCanvas& ) const;
const CachedNode* findAt(const WebCore::IntRect& , const CachedFrame** ,
int* x, int* y, bool checkForHidden) const;
const WebCore::IntRect& focusBounds() const { return mFocusBounds; }
WebCore::IntPoint focusLocation() const;
- SkPicture* getPicture() { return mPicture; }
+ SkPicture* getPicture() const { return mPicture; } // should only be called by CachedFrame
int getAndResetSelectionEnd();
int getAndResetSelectionStart();
int getBlockLeftEdge(int x, int y, float scale) const;
WebCore::String imageURI(int x, int y) const;
bool maskIfHidden(BestData* ) const;
const CachedNode* moveCursor(Direction , const CachedFrame** , WebCore::IntPoint* scroll);
+ SkPicture* pictureAt(int x, int y) const;
void reset();
CachedHistory* rootHistory() const { return mHistory; }
+ const WebCore::LayerAndroid* rootLayer() const { return mRootLayer; }
bool scrollDelta(WebCore::IntRect& cursorRingBounds, Direction , int* delta);
const WebCore::IntRect& scrolledBounds() const { return mScrolledBounds; }
void setCursor(CachedFrame* , CachedNode* );
+ void setCursorCache(int scrollX, int scrollY) const; // compute cached state used to find next cursor
void setCachedFocus(CachedFrame* , CachedNode* );
void setFocusBounds(const WebCore::IntRect& r) { mFocusBounds = r; }
void setTextGeneration(int textGeneration) { mTextGeneration = textGeneration; }
void setMaxScroll(int x, int y) { mMaxXScroll = x; mMaxYScroll = y; }
void setPicture(SkPicture* picture) { mPicture = picture; }
+ void setRootLayer(WebCore::LayerAndroid* layer) { mRootLayer = layer; }
void setScrollOnly(bool state) { mScrollOnly = state; }
void setSelection(int start, int end) { mSelectionStart = start; mSelectionEnd = end; }
void setupScrolledBounds() const { mScrolledBounds = mViewBounds; }
private:
CachedHistory* mHistory;
SkPicture* mPicture;
+ WebCore::LayerAndroid* mRootLayer;
WebCore::IntRect mFocusBounds; // dom text input focus node bounds
mutable WebCore::IntRect mScrolledBounds; // view bounds + amount visible as result of scroll
int mTextGeneration;
// These two are ONLY used when the tree is rebuilt and the focus is a textfield/area
int mSelectionStart;
int mSelectionEnd;
+ // these four set up as cache for use by frameDown/Up/Left/Right etc
+ mutable WebCore::IntRect mCursorBounds;
+ mutable const CachedNode* mCursor;
+ mutable SkRegion mBaseUncovered;
bool mScrollOnly;
#if DUMP_NAV_CACHE
public:
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#define LOG_TAG "webviewglue"
+
#include "config.h"
#include "FindCanvas.h"
-
+#include "LayerAndroid.h"
+#include "IntRect.h"
+#include "SkBlurMaskFilter.h"
+#include "SkCornerPathEffect.h"
#include "SkRect.h"
+#include <utils/Log.h>
+
// MatchInfo methods
////////////////////////////////////////////////////////////////////////////////
}
MatchInfo::MatchInfo(const MatchInfo& src) {
+ m_layerId = src.m_layerId;
m_location = src.m_location;
m_picture = src.m_picture;
m_picture->safeRef();
}
-void MatchInfo::set(const SkRegion& region, SkPicture* pic) {
+void MatchInfo::set(const SkRegion& region, SkPicture* pic, int layerId) {
m_picture->safeUnref();
+ m_layerId = layerId;
m_location = region;
m_picture = pic;
SkASSERT(pic);
return r;
}
+void FindCanvas::drawLayers(WebCore::LayerAndroid* layer) {
+ SkPicture* picture = layer->picture();
+ if (picture) {
+ setLayerId(layer->uniqueId());
+ drawPicture(*picture);
+ }
+ for (int i = 0; i < layer->countChildren(); i++)
+ drawLayers(layer->getChild(i));
+}
+
void FindCanvas::drawText(const void* text, size_t byteLength, SkScalar x,
SkScalar y, const SkPaint& paint) {
findHelper(text, byteLength, paint, &x, y, &FindCanvas::addMatchNormal);
mWorkingPicture->endRecording();
MatchInfo matchInfo;
mMatches->append(matchInfo);
- mMatches->last().set(region, mWorkingPicture);
+ LOGD("%s region=%p pict=%p layer=%d", __FUNCTION__,
+ region, mWorkingPicture, mLayerId);
+ mMatches->last().set(region, mWorkingPicture, mLayerId);
}
void FindCanvas::resetWorkingCanvas() {
// Do not need to reset mWorkingCanvas itself because we only access it via
// getWorkingCanvas.
}
+
+// This function sets up the paints that are used to draw the matches.
+void FindOnPage::setUpFindPaint() {
+ // Set up the foreground paint
+ m_findPaint.setAntiAlias(true);
+ const SkScalar roundiness = SkIntToScalar(2);
+ SkCornerPathEffect* cornerEffect = new SkCornerPathEffect(roundiness);
+ m_findPaint.setPathEffect(cornerEffect);
+ m_findPaint.setARGB(255, 132, 190, 0);
+
+ // Set up the background blur paint.
+ m_findBlurPaint.setAntiAlias(true);
+ m_findBlurPaint.setARGB(204, 0, 0, 0);
+ m_findBlurPaint.setPathEffect(cornerEffect);
+ cornerEffect->unref();
+ SkMaskFilter* blurFilter = SkBlurMaskFilter::Create(SK_Scalar1,
+ SkBlurMaskFilter::kNormal_BlurStyle);
+ m_findBlurPaint.setMaskFilter(blurFilter)->unref();
+ m_isFindPaintSetUp = true;
+}
+
+WebCore::IntRect FindOnPage::currentMatchBounds() const {
+ if (!m_matches || !m_matches->size())
+ return WebCore::IntRect(0, 0, 0, 0);
+ return (*m_matches)[m_findIndex].getLocation().getBounds();
+}
+
+// This function is only used by findNext and setMatches. In it, we store
+// upper left corner of the match specified by m_findIndex in
+// m_currentMatchLocation.
+void FindOnPage::storeCurrentMatchLocation() {
+ SkASSERT(m_findIndex < m_matches->size());
+ const SkIRect& bounds = (*m_matches)[m_findIndex].getLocation().getBounds();
+ m_currentMatchLocation.set(bounds.fLeft, bounds.fTop);
+ m_hasCurrentLocation = true;
+}
+
+// Put a cap on the number of matches to draw. If the current page has more
+// matches than this, only draw the focused match.
+#define MAX_NUMBER_OF_MATCHES_TO_DRAW 101
+
+void FindOnPage::drawLayer(SkCanvas* canvas, const WebCore::IntRect* visRect,
+ int layerId) {
+ if (!m_matches || !m_matches->size())
+ return;
+ if (m_findIndex >= m_matches->size())
+ m_findIndex = 0;
+ const MatchInfo& matchInfo = (*m_matches)[m_findIndex];
+ const SkRegion& currentMatchRegion = matchInfo.getLocation();
+
+ // Set up the paints used for drawing the matches
+ if (!m_isFindPaintSetUp)
+ setUpFindPaint();
+
+ // Draw the current match
+ if (matchInfo.layerId() == layerId) {
+ drawMatch(currentMatchRegion, canvas, true);
+ // Now draw the picture, so that it shows up on top of the rectangle
+ canvas->drawPicture(*matchInfo.getPicture());
+ }
+ // Draw the rest
+ unsigned numberOfMatches = m_matches->size();
+ if (numberOfMatches > 1
+ && numberOfMatches < MAX_NUMBER_OF_MATCHES_TO_DRAW) {
+ for(unsigned i = 0; i < numberOfMatches; i++) {
+ // The current match has already been drawn
+ if (i == m_findIndex)
+ continue;
+ if ((*m_matches)[i].layerId() != layerId)
+ continue;
+ const SkRegion& region = (*m_matches)[i].getLocation();
+ // Do not draw matches which intersect the current one, or if it is
+ // offscreen
+ if (currentMatchRegion.intersects(region)
+ || (visRect && !region.intersects(*visRect)))
+ continue;
+ drawMatch(region, canvas, false);
+ }
+ }
+}
+
+// Draw the match specified by region to the canvas.
+void FindOnPage::drawMatch(const SkRegion& region, SkCanvas* canvas,
+ bool focused)
+{
+ // For the match which has focus, use a filled paint. For the others, use
+ // a stroked paint.
+ if (focused) {
+ m_findPaint.setStyle(SkPaint::kFill_Style);
+ m_findBlurPaint.setStyle(SkPaint::kFill_Style);
+ } else {
+ m_findPaint.setStyle(SkPaint::kStroke_Style);
+ m_findPaint.setStrokeWidth(SK_Scalar1);
+ m_findBlurPaint.setStyle(SkPaint::kStroke_Style);
+ m_findBlurPaint.setStrokeWidth(SkIntToScalar(2));
+ }
+ // Find the path for the current match
+ SkPath matchPath;
+ region.getBoundaryPath(&matchPath);
+ // Offset the path for a blurred shadow
+ SkPath blurPath;
+ matchPath.offset(SK_Scalar1, SkIntToScalar(2), &blurPath);
+ int saveCount = 0;
+ if (!focused) {
+ saveCount = canvas->save();
+ canvas->clipPath(matchPath, SkRegion::kDifference_Op);
+ }
+ // Draw the blurred background
+ canvas->drawPath(blurPath, m_findBlurPaint);
+ if (!focused)
+ canvas->restoreToCount(saveCount);
+ // Draw the foreground
+ canvas->drawPath(matchPath, m_findPaint);
+}
+
+void FindOnPage::findNext(bool forward)
+{
+ if (!m_matches || !m_matches->size())
+ return;
+ if (forward) {
+ m_findIndex++;
+ if (m_findIndex == m_matches->size())
+ m_findIndex = 0;
+ } else {
+ if (m_findIndex == 0) {
+ m_findIndex = m_matches->size() - 1;
+ } else {
+ m_findIndex--;
+ }
+ }
+ storeCurrentMatchLocation();
+}
+
+// With this call, WebView takes ownership of matches, and is responsible for
+// deleting it.
+void FindOnPage::setMatches(WTF::Vector<MatchInfo>* matches)
+{
+ if (m_matches)
+ delete m_matches;
+ m_matches = matches;
+ if (m_matches->size()) {
+ if (m_hasCurrentLocation) {
+ for (unsigned i = 0; i < m_matches->size(); i++) {
+ const SkIRect& rect = (*m_matches)[i].getLocation().getBounds();
+ if (rect.fLeft == m_currentMatchLocation.fX
+ && rect.fTop == m_currentMatchLocation.fY) {
+ m_findIndex = i;
+ return;
+ }
+ }
+ }
+ // If we did not have a stored location, or if we were unable to restore
+ // it, store the new one.
+ m_findIndex = 0;
+ storeCurrentMatchLocation();
+ } else {
+ m_hasCurrentLocation = false;
+ }
+}
+
#ifndef Find_Canvas_h
#define Find_Canvas_h
+#include "IntRect.h"
#include "SkBounder.h"
#include "SkCanvas.h"
#include "SkPicture.h"
#include "icu/unicode/umachine.h"
#include "wtf/Vector.h"
-class SkRect;
-class SkTypeface;
+// class SkIRect;
+// class SkRect;
+// class SkTypeface;
+
+namespace WebCore {
+ class LayerAndroid;
+}
// Stores both region information and an SkPicture of the match, so that the
// region can be drawn, followed by drawing the matching text on top of it.
SkPicture* getPicture() const { return m_picture; }
// This will make a copy of the region, and increase the ref count on the
// SkPicture. If this MatchInfo already had one, unref it.
- void set(const SkRegion& region, SkPicture* pic);
+ bool isInLayer() const { return m_layerId >= 0; }
+ int layerId() const { return m_layerId; }
+ void set(const SkRegion& region, SkPicture* pic, int layerId);
private:
MatchInfo& operator=(MatchInfo& src);
SkRegion m_location;
SkPicture* m_picture;
+ int m_layerId;
};
// A class containing a typeface for reference, the length in glyphs, and
const SkPaint& paint) {
}
+ void drawLayers(WebCore::LayerAndroid* );
int found() const { return mNumFound; }
+ void setLayerId(int layerId) { mLayerId = layerId; }
// This method detaches our array of matches and passes ownership to
// the caller, who is then responsible for deleting them.
SkCanvas* mWorkingCanvas;
SkRegion mWorkingRegion;
int mWorkingIndex;
+ int mLayerId;
+};
+
+class FindOnPage {
+public:
+ FindOnPage() {
+ m_matches = 0;
+ m_hasCurrentLocation = false;
+ m_isFindPaintSetUp = false;
+ }
+ ~FindOnPage() { delete m_matches; }
+ void clearCurrentLocation() { m_hasCurrentLocation = false; }
+ WebCore::IntRect currentMatchBounds() const;
+ void drawLayer(SkCanvas* canvas, const WebCore::IntRect* vis, int layerId);
+ void findNext(bool forward);
+ void setMatches(WTF::Vector<MatchInfo>* matches);
+private:
+ void drawMatch(const SkRegion& region, SkCanvas* canvas, bool focused);
+ void setUpFindPaint();
+ void storeCurrentMatchLocation();
+ WTF::Vector<MatchInfo>* m_matches;
+ // Stores the location of the current match.
+ SkIPoint m_currentMatchLocation;
+ // Tells whether the value in m_currentMatchLocation is valid.
+ bool m_hasCurrentLocation;
+ // Tells whether we have done the setup to draw the Find matches.
+ bool m_isFindPaintSetUp;
+ // Paint used to draw our Find matches.
+ SkPaint m_findPaint;
+ // Paint used for the background of our Find matches.
+ SkPaint m_findBlurPaint;
+ unsigned m_findIndex;
};
#endif // Find_Canvas_h
#include "PlatformGraphicsContext.h"
#include "PlatformString.h"
#include "SelectText.h"
-#include "SkBlurMaskFilter.h"
#include "SkCanvas.h"
-#include "SkCornerPathEffect.h"
#include "SkDumpCanvas.h"
#include "SkPath.h"
#include "SkPicture.h"
jmethodID m_getScaledMaxXScroll;
jmethodID m_getScaledMaxYScroll;
jmethodID m_getVisibleRect;
+ jmethodID m_getViewMetrics;
jmethodID m_rebuildWebTextView;
jmethodID m_viewInvalidate;
jmethodID m_viewInvalidateRect;
jfieldID m_rectTop;
jmethodID m_rectWidth;
jmethodID m_rectHeight;
+ jfieldID m_metricsScrollX;
+ jfieldID m_metricsScrollY;
+ jfieldID m_metricsWidth;
+ jfieldID m_metricsHeight;
+ jfieldID m_metricsScale;
AutoJObject object(JNIEnv* env) {
return getRealObject(env, m_obj);
}
m_javaGlue.m_getScaledMaxXScroll = GetJMethod(env, clazz, "getScaledMaxXScroll", "()I");
m_javaGlue.m_getScaledMaxYScroll = GetJMethod(env, clazz, "getScaledMaxYScroll", "()I");
m_javaGlue.m_getVisibleRect = GetJMethod(env, clazz, "sendOurVisibleRect", "()Landroid/graphics/Rect;");
+ m_javaGlue.m_getViewMetrics = GetJMethod(env, clazz, "getViewMetrics", "()Landroid/webkit/WebView$Metrics;");
m_javaGlue.m_rebuildWebTextView = GetJMethod(env, clazz, "rebuildWebTextView", "()V");
m_javaGlue.m_viewInvalidate = GetJMethod(env, clazz, "viewInvalidate", "()V");
m_javaGlue.m_viewInvalidateRect = GetJMethod(env, clazz, "viewInvalidate", "(IIII)V");
m_javaGlue.m_rectTop = env->GetFieldID(rectClass, "top", "I");
m_javaGlue.m_rectWidth = GetJMethod(env, rectClass, "width", "()I");
m_javaGlue.m_rectHeight = GetJMethod(env, rectClass, "height", "()I");
+ jclass metricsClass = env->FindClass("android/webkit/WebView$Metrics");
+ m_javaGlue.m_metricsScrollX = env->GetFieldID(metricsClass, "mScrollX", "I");
+ m_javaGlue.m_metricsScrollY = env->GetFieldID(metricsClass, "mScrollY", "I");
+ m_javaGlue.m_metricsWidth = env->GetFieldID(metricsClass, "mWidth", "I");
+ m_javaGlue.m_metricsHeight = env->GetFieldID(metricsClass, "mHeight", "I");
+ m_javaGlue.m_metricsScale = env->GetFieldID(metricsClass, "mScale", "F");
env->SetIntField(javaWebView, gWebViewField, (jint)this);
m_viewImpl = (WebViewCore*) viewImpl;
m_ringAnimationEnd = 0;
m_selStart.setEmpty();
m_selEnd.setEmpty();
- m_matches = 0;
- m_hasCurrentLocation = false;
- m_isFindPaintSetUp = false;
+ m_rootLayer = 0;
}
~WebView()
}
delete m_frameCacheUI;
delete m_navPictureUI;
- if (m_matches)
- delete m_matches;
}
WebViewCore* getWebViewCore() const {
void nativeRecordButtons(bool hasFocus, bool pressed, bool invalidate)
{
bool cursorIsOnButton = false;
+ const CachedFrame* cachedFrame;
const CachedNode* cachedCursor = 0;
// Lock the mutex, since we now share with the WebCore thread.
m_viewImpl->gButtonMutex.lock();
WebCore::Node* cursor = 0;
CachedRoot* root = getFrameCache(DontAllowNewer);
if (root) {
- cachedCursor = root->currentCursor();
+ cachedCursor = root->currentCursor(&cachedFrame);
if (cachedCursor)
cursor = (WebCore::Node*) cachedCursor->nodePointer();
}
}
m_viewImpl->gButtonMutex.unlock();
if (invalidate && cachedCursor && cursorIsOnButton) {
- const WebCore::IntRect& b = cachedCursor->getBounds();
+ const WebCore::IntRect& b = cachedCursor->bounds(cachedFrame);
viewInvalidateRect(b.x(), b.y(), b.right(), b.bottom());
}
}
-// These two functions separate out the particular look of the drawn find
-// matches from the code that draws them. This function sets up the paints that
-// are used to draw the matches.
-void setUpFindPaint()
-{
- // Set up the foreground paint
- m_findPaint.setAntiAlias(true);
- const SkScalar roundiness = SkIntToScalar(2);
- SkCornerPathEffect* cornerEffect = new SkCornerPathEffect(roundiness);
- m_findPaint.setPathEffect(cornerEffect);
- m_findPaint.setARGB(255, 132, 190, 0);
-
- // Set up the background blur paint.
- m_findBlurPaint.setAntiAlias(true);
- m_findBlurPaint.setARGB(204, 0, 0, 0);
- m_findBlurPaint.setPathEffect(cornerEffect);
- cornerEffect->unref();
- SkMaskFilter* blurFilter = SkBlurMaskFilter::Create(SK_Scalar1,
- SkBlurMaskFilter::kNormal_BlurStyle);
- m_findBlurPaint.setMaskFilter(blurFilter)->unref();
- m_isFindPaintSetUp = true;
-}
-
-// Draw the match specified by region to the canvas.
-void drawMatch(const SkRegion& region, SkCanvas* canvas, bool focused)
-{
- // For the match which has focus, use a filled paint. For the others, use
- // a stroked paint.
- if (focused) {
- m_findPaint.setStyle(SkPaint::kFill_Style);
- m_findBlurPaint.setStyle(SkPaint::kFill_Style);
- } else {
- m_findPaint.setStyle(SkPaint::kStroke_Style);
- m_findPaint.setStrokeWidth(SK_Scalar1);
- m_findBlurPaint.setStyle(SkPaint::kStroke_Style);
- m_findBlurPaint.setStrokeWidth(SkIntToScalar(2));
- }
- // Find the path for the current match
- SkPath matchPath;
- region.getBoundaryPath(&matchPath);
- // Offset the path for a blurred shadow
- SkPath blurPath;
- matchPath.offset(SK_Scalar1, SkIntToScalar(2), &blurPath);
- int saveCount = 0;
- if (!focused) {
- saveCount = canvas->save();
- canvas->clipPath(matchPath, SkRegion::kDifference_Op);
- }
- // Draw the blurred background
- canvas->drawPath(blurPath, m_findBlurPaint);
- if (!focused) {
- canvas->restoreToCount(saveCount);
- }
- // Draw the foreground
- canvas->drawPath(matchPath, m_findPaint);
-}
-
bool scrollRectOnScreen(int left, int top, int right, int bottom)
{
WebCore::IntRect visible;
return true;
}
-// Put a cap on the number of matches to draw. If the current page has more
-// matches than this, only draw the focused match.
-#define MAX_NUMBER_OF_MATCHES_TO_DRAW 101
-
+// draws the root matches only. Matches over layers are drawn by LayerAndroid
void drawMatches(SkCanvas* canvas)
{
- if (!m_matches || !m_matches->size())
- return;
- if (m_findIndex >= m_matches->size())
- m_findIndex = 0;
- const MatchInfo& matchInfo = (*m_matches)[m_findIndex];
- const SkRegion& currentMatchRegion = matchInfo.getLocation();
- const SkIRect& currentMatchBounds = currentMatchRegion.getBounds();
- if (scrollRectOnScreen(currentMatchBounds.fLeft, currentMatchBounds.fTop,
- currentMatchBounds.fRight, currentMatchBounds.fBottom))
+ WebCore::IntRect visible;
+ getVisibleRect(&visible);
+ m_findOnPage.drawLayer(canvas, &visible, -1);
+ WebCore::IntRect currentMatchBounds = m_findOnPage.currentMatchBounds();
+ if (currentMatchBounds.isEmpty())
return;
+ scrollRectOnScreen(currentMatchBounds.x(), currentMatchBounds.y(),
+ currentMatchBounds.right(), currentMatchBounds.bottom());
+}
- // Set up the paints used for drawing the matches
- if (!m_isFindPaintSetUp)
- setUpFindPaint();
-
- // Draw the current match
- drawMatch(currentMatchRegion, canvas, true);
- // Now draw the picture, so that it shows up on top of the rectangle
- canvas->drawPicture(*matchInfo.getPicture());
-
- // Draw the rest
- unsigned numberOfMatches = m_matches->size();
- if (numberOfMatches > 1
- && numberOfMatches < MAX_NUMBER_OF_MATCHES_TO_DRAW) {
- WebCore::IntRect visible;
- getVisibleRect(&visible);
- SkIRect visibleIRect(visible);
- for(unsigned i = 0; i < numberOfMatches; i++) {
- // The current match has already been drawn
- if (i == m_findIndex)
- continue;
- const SkRegion& region = (*m_matches)[i].getLocation();
- // Do not draw matches which intersect the current one, or if it is
- // offscreen
- if (currentMatchRegion.intersects(region)
- || !region.intersects(visibleIRect))
- continue;
- drawMatch(region, canvas, false);
- }
- }
+FindOnPage* findOnPage()
+{
+ return m_viewImpl->m_findIsUp ? &m_findOnPage : 0;
}
void resetCursorRing()
void drawCursorRing(SkCanvas* canvas)
{
- const CachedRoot* root = getFrameCache(AllowNewer);
+ CachedRoot* root = getFrameCache(AllowNewer);
if (!root) {
DBG_NAV_LOG("!root");
resetCursorRing();
m_viewImpl->m_hasCursorBounds = false;
return;
}
- const WTF::Vector<WebCore::IntRect>* rings = &node->cursorRings();
- if (!rings->size()) {
- DBG_NAV_LOG("!rings->size()");
+ setVisibleRect(root);
+ WTF::Vector<WebCore::IntRect> rings;
+ node->cursorRings(frame, &rings);
+ if (!rings.size()) {
+ DBG_NAV_LOG("!rings.size()");
m_viewImpl->m_hasCursorBounds = false;
return;
}
}
}
m_viewImpl->gButtonMutex.unlock();
- WebCore::IntRect bounds = node->bounds();
+ WebCore::IntRect bounds = node->bounds(frame);
updateCursorBounds(root, frame, node);
- WTF::Vector<WebCore::IntRect> oneRing;
bool useHitBounds = node->useHitBounds();
if (useHitBounds) {
- bounds = node->hitBounds();
+ bounds = node->hitBounds(frame);
}
if (useHitBounds || node->useBounds()) {
- oneRing.append(bounds);
- rings = &oneRing;
+ rings.clear();
+ rings.append(bounds);
}
bounds.inflate(SkScalarCeil(CURSOR_RING_OUTER_DIAMETER));
if (canvas->quickReject(bounds, SkCanvas::kAA_EdgeType)) {
(flavor + CursorRing::NORMAL_ANIMATING);
}
#if DEBUG_NAV_UI
- const WebCore::IntRect& ring = (*rings)[0];
+ const WebCore::IntRect& ring = rings[0];
DBG_NAV_LOGD("cursorNode=%d (nodePointer=%p) flavor=%s rings=%d"
" (%d, %d, %d, %d) isPlugin=%s",
node->index(), node->nodePointer(),
flavor == CursorRing::FAKE_FLAVOR ? "FAKE_FLAVOR" :
flavor == CursorRing::NORMAL_ANIMATING ? "NORMAL_ANIMATING" :
flavor == CursorRing::FAKE_ANIMATING ? "FAKE_ANIMATING" : "NORMAL_FLAVOR",
- rings->size(), ring.x(), ring.y(), ring.width(), ring.height(),
+ rings.size(), ring.x(), ring.y(), ring.width(), ring.height(),
node->isPlugin() ? "true" : "false");
#endif
}
}
}
if (!isButton)
- CursorRing::DrawRing(canvas, *rings, flavor);
+ CursorRing::DrawRing(canvas, rings, flavor);
}
bool cursorIsTextInput(FrameCachePermission allowNewer)
DBG_NAV_LOGD("%s", "");
CachedRoot* root = getFrameCache(DontAllowNewer);
if (root) {
- const CachedNode* cachedNode = root->currentCursor();
+ const CachedFrame* cachedFrame;
+ const CachedNode* cachedNode = root->currentCursor(&cachedFrame);
if (cachedNode) {
- cachedNode->cursorRingBounds(bounds);
+ *bounds = cachedNode->cursorRingBounds(cachedFrame);
DBG_NAV_LOGD("bounds={%d,%d,%d,%d}", bounds->x(), bounds->y(),
bounds->width(), bounds->height());
return;
// center (+/- 2)
IntPoint oldCenter = IntPoint(bounds.x() + (bounds.width() >> 1),
bounds.y() + (bounds.height() >> 1));
- IntRect newBounds = node->bounds();
+ IntRect newBounds = node->bounds(frame);
IntPoint newCenter = IntPoint(newBounds.x() + (newBounds.width() >> 1),
newBounds.y() + (newBounds.height() >> 1));
DBG_NAV_LOGD("oldCenter=(%d,%d) newCenter=(%d,%d)"
return m_frameCacheUI;
}
DBG_NAV_LOGD("%s", "m_viewImpl->m_updatedFrameCache == true");
- bool hadCursor = m_frameCacheUI && m_frameCacheUI->currentCursor();
+ const CachedFrame* oldCursorFrame;
+ const CachedNode* oldCursorNode = m_frameCacheUI ?
+ m_frameCacheUI->currentCursor(&oldCursorFrame) : 0;
+#if USE(ACCELERATED_COMPOSITING)
+ int layerId = oldCursorNode && oldCursorNode->isInLayer() ?
+ oldCursorFrame->layer(oldCursorNode)->layer(
+ m_frameCacheUI->rootLayer())->uniqueId() : -1;
+#endif
+ // get id from old layer and use to find new layer
const CachedNode* oldFocus = m_frameCacheUI ? m_frameCacheUI->currentFocus() : 0;
m_viewImpl->gFrameCacheMutex.lock();
delete m_frameCacheUI;
m_viewImpl->m_frameCacheKit = 0;
m_viewImpl->m_navPictureKit = 0;
m_viewImpl->gFrameCacheMutex.unlock();
+ if (m_frameCacheUI)
+ m_frameCacheUI->setRootLayer(m_rootLayer);
+#if USE(ACCELERATED_COMPOSITING)
+ if (layerId >= 0) {
+ SkRect viewMetrics;
+ getViewMetrics(&viewMetrics);
+ LayerAndroid* layer = const_cast<LayerAndroid*>(
+ m_frameCacheUI->rootLayer()->findById(layerId));
+ layer->calcPosition(&viewMetrics, 0);
+ }
+#endif
fixCursor();
if (oldFocus && m_frameCacheUI) {
const CachedNode* newFocus = m_frameCacheUI->currentFocus();
checkException(env);
}
}
- if (hadCursor && (!m_frameCacheUI || !m_frameCacheUI->currentCursor()))
+ if (oldCursorNode && (!m_frameCacheUI || !m_frameCacheUI->currentCursor()))
viewInvalidate(); // redraw in case cursor ring is still visible
return m_frameCacheUI;
}
checkException(env);
}
+void getViewMetrics(SkRect* viewMetrics)
+{
+ JNIEnv* env = JSC::Bindings::getJNIEnv();
+ jobject jMetrics = env->CallObjectMethod(m_javaGlue.object(env).get(),
+ m_javaGlue.m_getViewMetrics);
+ checkException(env);
+ int scrollX = env->GetIntField(jMetrics, m_javaGlue.m_metricsScrollX);
+ int scrollY = env->GetIntField(jMetrics, m_javaGlue.m_metricsScrollY);
+ int width = env->GetIntField(jMetrics, m_javaGlue.m_metricsWidth);
+ int height = env->GetIntField(jMetrics, m_javaGlue.m_metricsHeight);
+ int scale = env->GetFloatField(jMetrics, m_javaGlue.m_metricsScale);
+ *viewMetrics = IntRect(scrollX / scale, scrollY / scale,
+ width / scale, height / scale);
+ env->DeleteLocalRef(jMetrics);
+ checkException(env);
+}
+
static CachedFrame::Direction KeyToDirection(KeyCode keyCode)
{
switch (keyCode) {
// If m_viewImpl->m_hasCursorBounds is false, we never look at the other
// values, so do not bother setting them.
if (m_viewImpl->m_hasCursorBounds) {
- WebCore::IntRect bounds = cachedNode->bounds();
+ WebCore::IntRect bounds = cachedNode->bounds(cachedFrame);
if (m_viewImpl->m_cursorBounds != bounds)
DBG_NAV_LOGD("new cursor bounds=(%d,%d,w=%d,h=%d)",
bounds.x(), bounds.y(), bounds.width(), bounds.height());
- m_viewImpl->m_cursorBounds = cachedNode->bounds();
- m_viewImpl->m_cursorHitBounds = cachedNode->hitBounds();
+ m_viewImpl->m_cursorBounds = bounds;
+ m_viewImpl->m_cursorHitBounds = cachedNode->hitBounds(cachedFrame);
m_viewImpl->m_cursorFrame = cachedFrame->framePointer();
root->getSimulatedMousePosition(&m_viewImpl->m_cursorLocation);
m_viewImpl->m_cursorNode = cachedNode->nodePointer();
DBG_NAV_LOGD("old cursor %d (nativeNode=%p) cursorLocation={%d, %d}",
cursor ? cursor->index() : 0,
cursor ? cursor->nodePointer() : 0, cursorLocation.x(), cursorLocation.y());
- WebCore::IntRect visibleRect;
- getVisibleRect(&visibleRect);
- DBG_NAV_LOGD("getVisibleRect %d,%d,%d,%d",
- visibleRect.x(), visibleRect.y(), visibleRect.width(), visibleRect.height());
- root->setVisibleRect(visibleRect);
+ WebCore::IntRect visibleRect = setVisibleRect(root);
int xMax = getScaledMaxXScroll();
int yMax = getScaledMaxYScroll();
root->setMaxScroll(xMax, yMax);
"bounds={%d,%d,w=%d,h=%d}", cachedNode ? cachedNode->index() : 0,
cachedNode ? cachedNode->nodePointer() : 0,
root->cursorLocation().x(), root->cursorLocation().y(),
- cachedNode ? cachedNode->bounds().x() : 0,
- cachedNode ? cachedNode->bounds().y() : 0,
- cachedNode ? cachedNode->bounds().width() : 0,
- cachedNode ? cachedNode->bounds().height() : 0);
+ cachedNode ? cachedNode->bounds(cachedFrame).x() : 0,
+ cachedNode ? cachedNode->bounds(cachedFrame).y() : 0,
+ cachedNode ? cachedNode->bounds(cachedFrame).width() : 0,
+ cachedNode ? cachedNode->bounds(cachedFrame).height() : 0);
// If !m_heightCanMeasure (such as in the browser), we want to scroll no
// matter what
if (!ignoreScroll && (!m_heightCanMeasure ||
*framePtr = 0;
if (!root)
return 0;
- WebCore::IntRect visibleRect;
+ setVisibleRect(root);
+ return root->findAt(rect, framePtr, rxPtr, ryPtr, true);
+}
+
+IntRect setVisibleRect(CachedRoot* root)
+{
+ IntRect visibleRect;
getVisibleRect(&visibleRect);
+ DBG_NAV_LOGD("getVisibleRect %d,%d,%d,%d",
+ visibleRect.x(), visibleRect.y(), visibleRect.width(), visibleRect.height());
root->setVisibleRect(visibleRect);
- return root->findAt(rect, framePtr, rxPtr, ryPtr, true);
+ return visibleRect;
}
void selectBestAt(const WebCore::IntRect& rect)
root->setCursor(0, 0);
} else {
DBG_NAV_LOGD("CachedNode:%p (%d)", node, node->index());
- root->rootHistory()->setMouseBounds(node->bounds());
+ root->rootHistory()->setMouseBounds(node->bounds(frame));
updateCursorBounds(root, frame, node);
root->setCursor(const_cast<CachedFrame*>(frame),
const_cast<CachedNode*>(node));
{
m_viewImpl->m_findIsUp = up;
if (!up)
- m_hasCurrentLocation = false;
+ m_findOnPage.clearCurrentLocation();
}
void setFollowedLink(bool followed)
checkException(env);
}
-// This function is only used by findNext and setMatches. In it, we store
-// upper left corner of the match specified by m_findIndex in
-// m_currentMatchLocation.
-void inline storeCurrentMatchLocation()
-{
- SkASSERT(m_findIndex < m_matches->size());
- const SkIRect& bounds = (*m_matches)[m_findIndex].getLocation().getBounds();
- m_currentMatchLocation.set(bounds.fLeft, bounds.fTop);
- m_hasCurrentLocation = true;
-}
-
void findNext(bool forward)
{
- if (!m_matches || !m_matches->size())
- return;
- if (forward) {
- m_findIndex++;
- if (m_findIndex == m_matches->size())
- m_findIndex = 0;
- } else {
- if (m_findIndex == 0) {
- m_findIndex = m_matches->size() - 1;
- } else {
- m_findIndex--;
- }
- }
- storeCurrentMatchLocation();
+ m_findOnPage.findNext(forward);
viewInvalidate();
}
// deleting it.
void setMatches(WTF::Vector<MatchInfo>* matches)
{
- if (m_matches)
- delete m_matches;
- m_matches = matches;
- if (m_matches->size()) {
- if (m_hasCurrentLocation) {
- for (unsigned i = 0; i < m_matches->size(); i++) {
- const SkIRect& rect = (*m_matches)[i].getLocation().getBounds();
- if (rect.fLeft == m_currentMatchLocation.fX
- && rect.fTop == m_currentMatchLocation.fY) {
- m_findIndex = i;
- viewInvalidate();
- return;
- }
- }
- }
- // If we did not have a stored location, or if we were unable to restore
- // it, store the new one.
- m_findIndex = 0;
- storeCurrentMatchLocation();
- } else {
- m_hasCurrentLocation = false;
- }
+ m_findOnPage.setMatches(matches);
viewInvalidate();
}
return m_viewImpl->m_moveGeneration;
}
+const LayerAndroid* rootLayer() const
+{
+ return m_rootLayer;
+}
+
+void setRootLayer(LayerAndroid* layer)
+{
+ m_rootLayer = layer;
+ CachedRoot* root = getFrameCache(DontAllowNewer);
+ if (!root)
+ return;
+ root->resetLayers();
+ root->setRootLayer(m_rootLayer);
+}
+
private: // local state for WebView
// private to getFrameCache(); other functions operate in a different thread
CachedRoot* m_frameCacheUI; // navigation data ready for use
bool m_heightCanMeasure;
int m_lastDx;
SkMSec m_lastDxTime;
- WTF::Vector<MatchInfo>* m_matches;
- // Stores the location of the current match.
- SkIPoint m_currentMatchLocation;
- // Tells whether the value in m_currentMatchLocation is valid.
- bool m_hasCurrentLocation;
- // Tells whether we have done the setup to draw the Find matches.
- bool m_isFindPaintSetUp;
- // Paint used to draw our Find matches.
- SkPaint m_findPaint;
- // Paint used for the background of our Find matches.
- SkPaint m_findBlurPaint;
- unsigned m_findIndex;
+ FindOnPage m_findOnPage;
+ LayerAndroid* m_rootLayer;
}; // end of WebView class
/*
return root ? root->currentCursor(frame) : 0;
}
-static const CachedNode* getFocusCandidate(JNIEnv *env, jobject obj)
+static const CachedNode* getFocusCandidate(JNIEnv *env, jobject obj,
+ const CachedFrame** frame)
{
WebView* view = GET_NATIVE_VIEW(env, obj);
CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer);
if (!root)
return 0;
- const CachedNode* cursor = root->currentCursor();
+ const CachedNode* cursor = root->currentCursor(frame);
if (cursor && cursor->wantsKeyEvents())
return cursor;
return root->currentFocus();
static jobject nativeCursorNodeBounds(JNIEnv *env, jobject obj)
{
- const CachedNode* node = getCursorNode(env, obj);
- WebCore::IntRect bounds = node ? node->getBounds()
+ const CachedFrame* frame;
+ const CachedNode* node = getCursorNode(env, obj, &frame);
+ WebCore::IntRect bounds = node ? node->bounds(frame)
: WebCore::IntRect(0, 0, 0, 0);
jclass rectClass = env->FindClass("android/graphics/Rect");
jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
static bool nativeCursorIntersects(JNIEnv *env, jobject obj, jobject visRect)
{
- const CachedNode* node = getCursorNode(env, obj);
- return node ? node->getBounds().intersects(jrect_to_webrect(env, visRect))
- : false;
+ const CachedFrame* frame;
+ const CachedNode* node = getCursorNode(env, obj, &frame);
+ return node ? node->bounds(frame).intersects(
+ jrect_to_webrect(env, visRect)) : false;
}
static bool nativeCursorIsAnchor(JNIEnv *env, jobject obj)
return node ? node->isAnchor() : false;
}
+static bool nativeCursorIsInLayer(JNIEnv *env, jobject obj)
+{
+ const CachedNode* node = getCursorNode(env, obj);
+ return node ? node->isInLayer() : false;
+}
+
static bool nativeCursorIsTextInput(JNIEnv *env, jobject obj)
{
const CachedNode* node = getCursorNode(env, obj);
view->drawMatches(canvas);
}
-static void setXYWH(SkRect* r, SkScalar x, SkScalar y, SkScalar w, SkScalar h) {
- r->set(x, y, x + w, y + h);
-}
-
-static void nativeDrawLayers(JNIEnv *env, jobject obj,
- jint layer, jint scrollX, jint scrollY,
- jint width, jint height,
- jfloat scale, jobject canv)
+static void nativeDrawLayers(JNIEnv *env, jobject obj, jint layer, jobject canv)
{
if (!env)
return;
#if USE(ACCELERATED_COMPOSITING)
LayerAndroid* layerImpl = reinterpret_cast<LayerAndroid*>(layer);
SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv);
- if (canvas) {
- SkRect viewPort;
- setXYWH(&viewPort,
- scrollX / scale, scrollY / scale,
- width / scale, height / scale);
- layerImpl->draw(canvas, &viewPort);
- }
+ WebView* view = GET_NATIVE_VIEW(env, obj);
+ SkRect viewMetrics;
+ view->getViewMetrics(&viewMetrics);
+ layerImpl->setFindOnPage(view->findOnPage());
+ layerImpl->draw(canvas, &viewMetrics);
#endif
}
#endif
}
+static void nativeSetRootLayer(JNIEnv *env, jobject obj, jint layer)
+{
+#if USE(ACCELERATED_COMPOSITING)
+ LayerAndroid* layerImpl = reinterpret_cast<LayerAndroid*>(layer);
+ GET_NATIVE_VIEW(env, obj)->setRootLayer(layerImpl);
+#endif
+}
+
static void nativeDrawCursorRing(JNIEnv *env, jobject obj, jobject canv)
{
SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv);
static bool nativeFocusCandidateIsTextInput(JNIEnv *env, jobject obj)
{
- const CachedNode* node = getFocusCandidate(env, obj);
+ const CachedNode* node = getFocusCandidate(env, obj, 0);
return node ? node->isTextInput() : false;
}
static jobject nativeFocusCandidateNodeBounds(JNIEnv *env, jobject obj)
{
- const CachedNode* node = getFocusCandidate(env, obj);
- WebCore::IntRect bounds = node ? node->getBounds()
+ const CachedFrame* frame;
+ const CachedNode* node = getFocusCandidate(env, obj, &frame);
+ WebCore::IntRect bounds = node ? node->bounds(frame)
: WebCore::IntRect(0, 0, 0, 0);
jclass rectClass = env->FindClass("android/graphics/Rect");
jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
static jint nativeFocusCandidatePointer(JNIEnv *env, jobject obj)
{
- const CachedNode* node = getFocusCandidate(env, obj);
+ const CachedNode* node = getFocusCandidate(env, obj, 0);
return reinterpret_cast<int>(node ? node->nodePointer() : 0);
}
static jobject nativeFocusCandidateText(JNIEnv *env, jobject obj)
{
- const CachedNode* node = getFocusCandidate(env, obj);
+ const CachedNode* node = getFocusCandidate(env, obj, 0);
if (!node)
return 0;
WebCore::String value = node->getExport();
SkBitmap bitmap;
bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
canvas.setBitmapDevice(bitmap);
- canvas.drawPicture(*(root->getPicture()));
+ root->draw(canvas);
WTF::Vector<MatchInfo>* matches = canvas.detachMatches();
// With setMatches, the WebView takes ownership of matches
view->setMatches(matches);
true);
if (!next)
return;
- const WebCore::IntRect& bounds = next->bounds();
+ const WebCore::IntRect& bounds = next->bounds(frame);
root->rootHistory()->setMouseBounds(bounds);
view->updateCursorBounds(root, frame, next);
root->setCursor(const_cast<CachedFrame*>(frame),
fclose(file);
}
#if USE(ACCELERATED_COMPOSITING)
- int pRootLayer = view->getWebViewCore()->rootLayer();
- if (pRootLayer) {
- LayerAndroid* rootLayer = reinterpret_cast<LayerAndroid*>(pRootLayer);
+ const LayerAndroid* rootLayer = view->rootLayer();
+ if (rootLayer) {
FILE* file = fopen(LAYERS_TREE_LOG_FILE,"w");
if (file) {
rootLayer->dumpLayers(file, 0);
(void*) nativeCursorIntersects },
{ "nativeCursorIsAnchor", "()Z",
(void*) nativeCursorIsAnchor },
+ { "nativeCursorIsInLayer", "()Z",
+ (void*) nativeCursorIsInLayer },
{ "nativeCursorIsTextInput", "()Z",
(void*) nativeCursorIsTextInput },
{ "nativeCursorPosition", "()Landroid/graphics/Point;",
(void*) nativeDrawCursorRing },
{ "nativeDestroyLayer", "(I)V",
(void*) nativeDestroyLayer },
- { "nativeDrawLayers", "(IIIIIFLandroid/graphics/Canvas;)V",
+ { "nativeDrawLayers", "(ILandroid/graphics/Canvas;)V",
(void*) nativeDrawLayers },
{ "nativeEvaluateLayersAnimations", "(I)Z",
(void*) nativeEvaluateLayersAnimations },
(void*) nativeSetFollowedLink },
{ "nativeSetHeightCanMeasure", "(Z)V",
(void*) nativeSetHeightCanMeasure },
+ { "nativeSetRootLayer", "(I)V",
+ (void*) nativeSetRootLayer },
{ "nativeTextGeneration", "()I",
(void*) nativeTextGeneration },
{ "nativeUpdateCachedTextfield", "(Ljava/lang/String;I)V",