#include "AndroidAnimation.h"
#include "DrawExtra.h"
+#include "ParseCanvas.h"
#include "SkBitmapRef.h"
-#include "SkCanvas.h"
+#include "SkBounder.h"
#include "SkDrawFilter.h"
#include "SkPaint.h"
#include "SkPicture.h"
getChild(i)->clipInner(region, m_haveClip ? localBounds : local);
}
-const LayerAndroid* LayerAndroid::find(int x, int y) const
-{
- for (int i = 0; i < countChildren(); i++) {
- const LayerAndroid* found = getChild(i)->find(x, y);
- if (found)
- return found;
+class FindCheck : public SkBounder {
+public:
+ FindCheck()
+ : m_drew(false)
+ , m_drewText(false)
+ {
+ }
+
+ bool drew() const { return m_drew; }
+ bool drewText() const { return m_drewText; }
+ void reset() { m_drew = m_drewText = false; }
+
+protected:
+ virtual bool onIRect(const SkIRect& )
+ {
+ m_drew = true;
+ return false;
+ }
+
+ virtual bool onIRectGlyph(const SkIRect& , const SkBounder::GlyphRec& )
+ {
+ m_drewText = true;
+ return false;
+ }
+
+ bool m_drew;
+ bool m_drewText;
+};
+
+class FindCanvas : public ParseCanvas {
+public:
+ void draw(SkPicture* picture, SkScalar offsetX, SkScalar offsetY)
+ {
+ save();
+ translate(-offsetX, -offsetY);
+ picture->draw(this);
+ restore();
+ }
+};
+
+class LayerAndroidFindState {
+public:
+ static const int TOUCH_SLOP = 10;
+
+ LayerAndroidFindState(int x, int y)
+ : m_x(x)
+ , m_y(y)
+ , m_best(0)
+ {
+ m_bitmap.setConfig(SkBitmap::kARGB_8888_Config, TOUCH_SLOP * 2,
+ TOUCH_SLOP * 2);
+ m_checker.setBounder(&m_findCheck);
+ m_checker.setBitmapDevice(m_bitmap);
+ }
+
+ const LayerAndroid* best() const { return m_best; }
+
+ bool drew(SkPicture* picture, const SkRect& localBounds) {
+ m_findCheck.reset();
+ SkScalar localX = SkIntToScalar(m_x - TOUCH_SLOP) - localBounds.fLeft;
+ SkScalar localY = SkIntToScalar(m_y - TOUCH_SLOP) - localBounds.fTop;
+ m_checker.draw(picture, localX, localY);
+ return m_findCheck.drew();
}
+
+ bool drewText() { return m_findCheck.drewText(); }
+
+ void setBest(const LayerAndroid* best) { m_best = best; }
+ int x() const { return m_x; }
+ int y() const { return m_y; }
+
+protected:
+ int m_x;
+ int m_y;
+ const LayerAndroid* m_best;
+ FindCheck m_findCheck;
+ SkBitmap m_bitmap;
+ FindCanvas m_checker;
+};
+
+void LayerAndroid::findInner(LayerAndroidFindState& state) const
+{
+ int x = state.x();
+ int y = state.y();
+ for (int i = 0; i < countChildren(); i++)
+ getChild(i)->findInner(state);
SkRect localBounds;
bounds(&localBounds);
- if (localBounds.contains(x, y))
- return this;
- return 0;
+ if (!localBounds.contains(x, y))
+ return;
+ if (!m_recordingPicture)
+ return;
+ if (!state.drew(m_recordingPicture, localBounds))
+ return;
+ state.setBest(this); // set last match (presumably on top)
+}
+
+const LayerAndroid* LayerAndroid::find(int x, int y, SkPicture* root) const
+{
+ LayerAndroidFindState state(x, y);
+ SkRect rootBounds;
+ rootBounds.setEmpty();
+ if (state.drew(root, rootBounds) && state.drewText())
+ return 0; // use the root picture only if it contains the text
+ findInner(state);
+ return state.best();
}
///////////////////////////////////////////////////////////////////////////////
namespace WebCore {
class AndroidAnimation;
+class LayerAndroidFindState;
class LayerAndroid : public SkLayer {
void updatePositions();
void clipArea(SkTDArray<SkRect>* region) const;
- const LayerAndroid* find(int x, int y) const;
+ const LayerAndroid* find(int x, int y, SkPicture* root) const;
const LayerAndroid* findById(int uniqueID) const;
LayerAndroid* getChild(int index) const {
return static_cast<LayerAndroid*>(this->INHERITED::getChild(index));
*/
void setContentsImage(SkBitmapRef* img);
+ void bounds(SkRect* ) const;
protected:
virtual void onDraw(SkCanvas*, SkScalar opacity);
#if DUMP_NAV_CACHE
friend class CachedLayer::Debug; // debugging access only
#endif
- void bounds(SkRect* ) const;
+
+ void findInner(LayerAndroidFindState& ) const;
bool prepareContext(bool force = false);
void clipInner(SkTDArray<SkRect>* region, const SkRect& local) const;
return mRoot->mPicture;
}
+SkPicture* CachedFrame::picture(const CachedNode* node, int* xPtr, int* yPtr) const
+{
+#if USE(ACCELERATED_COMPOSITING)
+ if (node->isInLayer()) {
+ const CachedLayer* cachedLayer = layer(node);
+ const LayerAndroid* rootLayer = mRoot->rootLayer();
+ cachedLayer->toLocal(rootLayer, xPtr, yPtr);
+ return cachedLayer->picture(rootLayer);
+ }
+#endif
+ return mRoot->mPicture;
+}
+
void CachedFrame::resetClippedOut()
{
for (CachedNode* test = mCachedNodes.begin(); test != mCachedNodes.end(); test++)
const CachedFrame* parent() const { return mParent; }
CachedFrame* parent() { return mParent; }
SkPicture* picture(const CachedNode* ) const;
+ SkPicture* picture(const CachedNode* , int* xPtr, int* yPtr) const;
void resetLayers();
bool sameFrame(const CachedFrame* ) const;
void removeLast() { mCachedNodes.removeLast(); }
return aLayer->picture();
}
+void CachedLayer::toLocal(const LayerAndroid* root, int* xPtr, int* yPtr) const
+{
+ const LayerAndroid* aLayer = layer(root);
+ if (!aLayer)
+ return;
+ DBG_NAV_LOGD("root=%p aLayer=%p [%d]", root, aLayer, aLayer->uniqueId());
+ SkRect localBounds;
+ aLayer->bounds(&localBounds);
+ *xPtr -= localBounds.fLeft;
+ *yPtr -= localBounds.fTop;
+}
+
#if DUMP_NAV_CACHE
CachedLayer* CachedLayer::Debug::base() const {
const LayerAndroid* layer(const LayerAndroid* root) const;
IntRect localBounds(const LayerAndroid* root, const IntRect& bounds) const;
SkPicture* picture(const LayerAndroid* root) const;
+ void toLocal(const LayerAndroid* root, int* xPtr, int* yPtr) const;
void reset() { mLayer = 0; }
void setCachedNodeIndex(int index) { mCachedNodeIndex = index; }
void setOffset(const IntPoint& offset) { mOffset = offset; }
#include "FindCanvas.h"
#include "FloatRect.h"
#include "LayerAndroid.h"
+#include "ParseCanvas.h"
#include "SkBitmap.h"
#include "SkBounder.h"
#include "SkPixelRef.h"
SkIRect mLastAll;
};
-class BoundsCanvas : public SkCanvas {
+class BoundsCanvas : public ParseCanvas {
public:
BoundsCanvas(CommonCheck* bounder) : mBounder(*bounder) {
setBounder(bounder);
}
- virtual ~BoundsCanvas() {
- setBounder(NULL);
- }
-
virtual void drawPaint(const SkPaint& paint) {
mBounder.setType(CommonCheck::kDrawPaint_Type);
- SkCanvas::drawPaint(paint);
+ INHERITED::drawPaint(paint);
}
virtual void drawPoints(PointMode mode, size_t count, const SkPoint pts[],
const SkPaint& paint) {
mBounder.setType(CommonCheck::kDrawPoints_Type);
- SkCanvas::drawPoints(mode, count, pts, paint);
+ INHERITED::drawPoints(mode, count, pts, paint);
}
virtual void drawRect(const SkRect& rect, const SkPaint& paint) {
mBounder.setType(CommonCheck::kDrawRect_Type);
- SkCanvas::drawRect(rect, paint);
+ INHERITED::drawRect(rect, paint);
}
virtual void drawPath(const SkPath& path, const SkPaint& paint) {
mBounder.setType(CommonCheck::kDrawPath_Type);
- SkCanvas::drawPath(path, paint);
+ INHERITED::drawPath(path, paint);
}
virtual void commonDrawBitmap(const SkBitmap& bitmap,
const SkMatrix& matrix, const SkPaint& paint) {
mBounder.setType(CommonCheck::kDrawBitmap_Type);
mBounder.setIsOpaque(bitmap.isOpaque());
- SkCanvas::commonDrawBitmap(bitmap, matrix, paint);
+ INHERITED::commonDrawBitmap(bitmap, matrix, paint);
}
virtual void drawSprite(const SkBitmap& bitmap, int left, int top,
mBounder.setType(CommonCheck::kDrawSprite_Type);
mBounder.setIsOpaque(bitmap.isOpaque() &&
(!paint || paint->getAlpha() == 255));
- SkCanvas::drawSprite(bitmap, left, top, paint);
+ INHERITED::drawSprite(bitmap, left, top, paint);
}
virtual void drawText(const void* text, size_t byteLength, SkScalar x,
SkScalar y, const SkPaint& paint) {
mBounder.setEmpty();
mBounder.setType(CommonCheck::kDrawGlyph_Type);
- SkCanvas::drawText(text, byteLength, x, y, paint);
+ INHERITED::drawText(text, byteLength, x, y, paint);
mBounder.doRect(CommonCheck::kDrawText_Type);
}
const SkPoint pos[], const SkPaint& paint) {
mBounder.setEmpty();
mBounder.setType(CommonCheck::kDrawGlyph_Type);
- SkCanvas::drawPosText(text, byteLength, pos, paint);
+ INHERITED::drawPosText(text, byteLength, pos, paint);
mBounder.doRect(CommonCheck::kDrawPosText_Type);
}
const SkPaint& paint) {
mBounder.setEmpty();
mBounder.setType(CommonCheck::kDrawGlyph_Type);
- SkCanvas::drawPosTextH(text, byteLength, xpos, constY, paint);
+ INHERITED::drawPosTextH(text, byteLength, xpos, constY, paint);
if (mBounder.mUnion.isEmpty()) {
DBG_NAV_LOGD("empty constY=%g", SkScalarToFloat(constY));
return;
const SkPaint& paint) {
mBounder.setEmpty();
mBounder.setType(CommonCheck::kDrawGlyph_Type);
- SkCanvas::drawTextOnPath(text, byteLength, path, matrix, paint);
+ INHERITED::drawTextOnPath(text, byteLength, path, matrix, paint);
mBounder.doRect(CommonCheck::kDrawTextOnPath_Type);
}
virtual void drawPicture(SkPicture& picture) {
mBounder.setType(CommonCheck::kDrawPicture_Type);
- SkCanvas::drawPicture(picture);
+ INHERITED::drawPicture(picture);
}
virtual int saveLayer(const SkRect* bounds, const SkPaint* paint,
SaveFlags flags) {
- int depth = SkCanvas::save(flags);
+ int depth = INHERITED::saveLayer(bounds, paint, flags);
if (mTransparentLayer == 0 && paint && paint->getAlpha() < 255) {
mTransparentLayer = depth;
mBounder.setAllOpaque(false);
mTransparentLayer = 0;
mBounder.setAllOpaque(true);
}
- SkCanvas::restore();
+ INHERITED::restore();
}
int mTransparentLayer;
CommonCheck& mBounder;
+private:
+ typedef ParseCanvas INHERITED;
};
/*
const int mViewRight;
};
-class ImageCanvas : public SkCanvas {
+class ImageCanvas : public ParseCanvas {
public:
ImageCanvas(SkBounder* bounder) : mURI(NULL) {
setBounder(bounder);
}
+ const char* getURI() { return mURI; }
+
+protected:
// Currently webkit's bitmap draws always seem to be cull'd before this entry
// point is called, so we assume that any bitmap that gets here is inside our
// tiny clip (may not be true in the future)
}
}
+private:
const char* mURI;
};
int CachedRoot::checkForCenter(int x, int y) const
{
int width = mViewBounds.width();
+ SkPicture* picture = pictureAt(&x, &y);
CenterCheck centerCheck(x + width - mViewBounds.x(), y - mViewBounds.y(),
width);
BoundsCanvas checker(¢erCheck);
checker.setBitmapDevice(bitmap);
checker.translate(SkIntToScalar(width - mViewBounds.x()),
SkIntToScalar(-mViewBounds.y()));
- checker.drawPicture(*pictureAt(x, y));
+ checker.drawPicture(*picture);
return centerCheck.center();
}
checker.setBitmapDevice(bitmap);
int x = -mViewBounds.x() - (xDelta < 0 ? xDelta : 0);
int y = -mViewBounds.y();
+ SkPicture* picture = pictureAt(&x, &y);
checker.translate(SkIntToScalar(x), SkIntToScalar(y));
- checker.drawPicture(*pictureAt(x, y));
+ checker.drawPicture(*picture);
*xDeltaPtr = jiggleCheck.jiggle();
}
node->isTextInput() ? "text" : "plugin");
return node->bounds(frame).x();
}
- SkPicture* picture = node ? frame->picture(node) : pictureAt(x, y);
+ SkPicture* picture = node ? frame->picture(node, &x, &y) : pictureAt(&x, &y);
if (!picture)
return x;
int halfW = (int) (mViewBounds.width() * scale * 0.5f);
WTF::String CachedRoot::imageURI(int x, int y) const
{
+ DBG_NAV_LOGD("x/y=(%d,%d)", x, y);
ImageCheck imageCheck;
ImageCanvas checker(&imageCheck);
SkBitmap bitmap;
bitmap.setConfig(SkBitmap::kARGB_8888_Config, 1, 1);
checker.setBitmapDevice(bitmap);
+ SkPicture* picture = pictureAt(&x, &y);
checker.translate(SkIntToScalar(-x), SkIntToScalar(-y));
- checker.drawPicture(*pictureAt(x, y));
- return WTF::String(checker.mURI);
+ checker.drawPicture(*picture);
+ DBG_NAV_LOGD("uri=%s", checker.getURI());
+ return WTF::String(checker.getURI());
}
bool CachedRoot::maskIfHidden(BestData* best) const
return CachedFrame::nextTextField(start, framePtr, &startFound);
}
-SkPicture* CachedRoot::pictureAt(int x, int y) const
+SkPicture* CachedRoot::pictureAt(int* xPtr, int* yPtr) const
{
#if USE(ACCELERATED_COMPOSITING)
if (mRootLayer) {
- const LayerAndroid* layer = mRootLayer->find(x, y);
+ const LayerAndroid* layer = mRootLayer->find(*xPtr, *yPtr, mPicture);
if (layer) {
SkPicture* picture = layer->picture();
+ DBG_NAV_LOGD("layer %d picture=%p (%d,%d)", layer->uniqueId(),
+ picture, picture ? picture->width() : 0,
+ picture ? picture->height() : 0);
+ SkRect localBounds;
+ layer->bounds(&localBounds);
+ *xPtr -= localBounds.fLeft;
+ *yPtr -= localBounds.fTop;
if (picture)
return picture;
}
}
#endif
+ DBG_NAV_LOGD("root mPicture=%p (%d,%d)", mPicture, mPicture ?
+ mPicture->width() : 0, mPicture ? mPicture->height() : 0);
return mPicture;
}
*/
const CachedNode* nextTextField(const CachedNode* start,
const CachedFrame** framePtr) const;
- SkPicture* pictureAt(int x, int y) const;
+ SkPicture* pictureAt(int* xPtr, int* yPtr) const;
void reset();
CachedHistory* rootHistory() const { return mHistory; }
const WebCore::LayerAndroid* rootLayer() const { return mRootLayer; }
--- /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 PARSE_CANVAS_H
+#define PARSE_CANVAS_H
+
+#include "SkCanvas.h"
+
+namespace android {
+
+class ParseCanvas : public SkCanvas {
+protected:
+ virtual ~ParseCanvas() {
+ setBounder(0);
+ }
+
+ // Pictures parsed for content never want to create offscreen bitmaps.
+ // Instead, just save and restore the canvas state -- this also keeps
+ // the picture contents at their original coordinates.
+ virtual int saveLayer(const SkRect* , const SkPaint* , SaveFlags flags) {
+ return INHERITED::save(flags);
+ }
+private:
+ typedef SkCanvas INHERITED;
+};
+
+}
+
+#endif
+
#include "BidiResolver.h"
#include "CachedRoot.h"
#include "LayerAndroid.h"
+#include "ParseCanvas.h"
#include "SelectText.h"
#include "SkBitmap.h"
#include "SkBounder.h"
-#include "SkCanvas.h"
#include "SkGradientShader.h"
#include "SkMatrix.h"
#include "SkPicture.h"
SkBounder::GlyphRec mLastGlyph;
};
-class SpaceCanvas : public SkCanvas {
+class SpaceCanvas : public ParseCanvas {
public:
SpaceCanvas(const SkIRect& area)
{
if (mDistance > distance) {
mBestBase = base();
mBestBounds.set(rect.fLeft, top(), rect.fRight, bottom());
- if (distance < 100) {
+#ifndef EXTRA_NOISY_LOGGING
+ if (distance < 100)
+#endif
+ {
DBG_NAV_LOGD("FirstCheck mBestBounds={%d,%d,r=%d,b=%d} distance=%d",
mBestBounds.fLeft, mBestBounds.fTop,
mBestBounds.fRight, mBestBounds.fBottom, distance >> 2);
typedef BuilderCheck INHERITED;
};
-class TextCanvas : public SkCanvas {
+class TextCanvas : public ParseCanvas {
public:
TextCanvas(CommonCheck* bounder, const SkIRect& area)
area.height());
setBitmapDevice(bitmap);
translate(SkIntToScalar(-area.fLeft), SkIntToScalar(-area.fTop));
- }
-
- virtual ~TextCanvas() {
- setBounder(NULL);
+#ifdef DEBUG_NAV_UI
+ const SkIRect& clip = getTotalClip().getBounds();
+ const SkMatrix& matrix = getTotalMatrix();
+ DBG_NAV_LOGD("bitmap=(%d,%d) clip=(%d,%d,%d,%d) matrix=(%g,%g)",
+ bitmap.width(), bitmap.height(), clip.fLeft, clip.fTop,
+ clip.fRight, clip.fBottom, matrix.getTranslateX(), matrix.getTranslateY());
+#endif
}
virtual void drawPaint(const SkPaint& paint) {
virtual void drawText(const void* text, size_t byteLength, SkScalar x,
SkScalar y, const SkPaint& paint) {
mBounder.setUp(paint, getTotalMatrix(), y, text);
- SkCanvas::drawText(text, byteLength, x, y, paint);
+ INHERITED::drawText(text, byteLength, x, y, paint);
}
virtual void drawPosTextH(const void* text, size_t byteLength,
const SkScalar xpos[], SkScalar constY,
const SkPaint& paint) {
mBounder.setUp(paint, getTotalMatrix(), constY, text);
- SkCanvas::drawPosTextH(text, byteLength, xpos, constY, paint);
+ INHERITED::drawPosTextH(text, byteLength, xpos, constY, paint);
}
virtual void drawVertices(VertexMode vmode, int vertexCount,
}
CommonCheck& mBounder;
+private:
+ typedef ParseCanvas INHERITED;
};
static bool buildSelection(const SkPicture& picture, const SkIRect& area,
SelectText::SelectText()
{
+ m_picture = 0;
reset();
SkPaint paint;
m_endControl.endRecording();
fillGradient->safeUnref();
dropGradient->safeUnref();
- m_picture = 0;
+}
+
+SelectText::~SelectText()
+{
+ m_picture->safeUnref();
}
void SelectText::draw(SkCanvas* canvas, LayerAndroid* layer)
{
- // FIXME: layer may not own the original selected picture
- m_picture = layer->picture();
- if (!m_picture)
+ if (!m_picture || m_picture != layer->picture())
return;
- DBG_NAV_LOGD("m_extendSelection=%d m_drawPointer=%d", m_extendSelection, m_drawPointer);
+ DBG_NAV_LOGD("m_extendSelection=%d m_drawPointer=%d layer [%d]",
+ m_extendSelection, m_drawPointer, layer->uniqueId());
if (m_extendSelection)
drawSelectionRegion(canvas);
if (m_drawPointer)
void SelectText::drawSelectionRegion(SkCanvas* canvas)
{
m_selRegion.setEmpty();
- SkRect visBounds;
- if (!canvas->getClipBounds(&visBounds, SkCanvas::kAA_EdgeType))
- return;
- SkIRect ivisBounds;
- visBounds.round(&ivisBounds);
+ SkIRect ivisBounds = m_visibleRect;
ivisBounds.join(m_selStart);
ivisBounds.join(m_selEnd);
- DBG_NAV_LOGD("m_selStart=(%d, %d, %d, %d) m_selEnd=(%d, %d, %d, %d)",
+ DBG_NAV_LOGD("m_selStart=(%d, %d, %d, %d) m_selEnd=(%d, %d, %d, %d)"
+ " ivisBounds=(%d,%d,r=%d,b=%d)",
m_selStart.fLeft, m_selStart.fTop, m_selStart.fRight, m_selStart.fBottom,
- m_selEnd.fLeft, m_selEnd.fTop, m_selEnd.fRight, m_selEnd.fBottom);
+ m_selEnd.fLeft, m_selEnd.fTop, m_selEnd.fRight, m_selEnd.fBottom,
+ ivisBounds.fLeft, ivisBounds.fTop, ivisBounds.fRight, ivisBounds.fBottom);
m_flipped = buildSelection(*m_picture, ivisBounds, m_selStart, m_startBase,
m_selEnd, m_endBase, &m_selRegion);
SkPath path;
canvas->restore();
}
-void SelectText::extendSelection(const SkPicture* picture, int x, int y)
+void SelectText::extendSelection(const IntRect& vis, int x, int y)
{
- if (!picture)
+ if (!m_picture)
return;
+ setVisibleRect(vis);
SkIRect clipRect = m_visibleRect;
int base;
+ x -= m_startOffset.fX;
+ y -= m_startOffset.fY;
if (m_startSelection) {
if (!clipRect.contains(x, y)
|| !clipRect.contains(m_original.fX, m_original.fY)) {
}
DBG_NAV_LOGD("selStart clip=(%d,%d,%d,%d)", clipRect.fLeft,
clipRect.fTop, clipRect.fRight, clipRect.fBottom);
- m_picture = picture;
FirstCheck center(m_original.fX, m_original.fY, clipRect);
- m_selStart = m_selEnd = findClosest(center, *picture, clipRect, &base);
+ m_selStart = m_selEnd = findClosest(center, *m_picture, clipRect, &base);
m_startBase = m_endBase = base;
m_startSelection = false;
m_extendSelection = true;
m_original.fX = m_original.fY = 0;
- } else if (picture != m_picture)
- return;
+ }
x -= m_original.fX;
y -= m_original.fY;
if (!clipRect.contains(x, y) || !clipRect.contains(m_selStart)) {
DBG_NAV_LOGD("extend clip=(%d,%d,%d,%d)", clipRect.fLeft,
clipRect.fTop, clipRect.fRight, clipRect.fBottom);
FirstCheck extension(x, y, clipRect);
- SkIRect found = findClosest(extension, *picture, clipRect, &base);
- DBG_NAV_LOGD("pic=%p x=%d y=%d m_startSelection=%s %s=(%d, %d, %d, %d)"
+ SkIRect found = findClosest(extension, *m_picture, clipRect, &base);
+ DBG_NAV_LOGD("x=%d y=%d m_startSelection=%s %s=(%d, %d, %d, %d)"
" m_extendSelection=%s",
- picture, x, y, m_startSelection ? "true" : "false",
+ x, y, m_startSelection ? "true" : "false",
m_hitTopLeft ? "m_selStart" : "m_selEnd",
found.fLeft, found.fTop, found.fRight, found.fBottom,
m_extendSelection ? "true" : "false");
bool SelectText::hitSelection(int x, int y) const
{
+ x -= m_startOffset.fX;
+ y -= m_startOffset.fY;
int left = m_selStart.fLeft - CONTROL_WIDTH / 2;
int top = m_selStart.fBottom + CONTROL_HEIGHT / 2;
if (hitCorner(left, top, x, y))
return m_selRegion.contains(x, y);
}
-void SelectText::moveSelection(const SkPicture* picture, int x, int y)
+void SelectText::moveSelection(const IntRect& vis, int x, int y)
{
- if (!picture)
+ if (!m_picture)
return;
+ x -= m_startOffset.fX;
+ y -= m_startOffset.fY;
+ setVisibleRect(vis);
SkIRect clipRect = m_visibleRect;
clipRect.join(m_selStart);
clipRect.join(m_selEnd);
- if (!m_extendSelection)
- m_picture = picture;
FirstCheck center(x, y, clipRect);
int base;
- SkIRect found = findClosest(center, *picture, clipRect, &base);
+ SkIRect found = findClosest(center, *m_picture, clipRect, &base);
if (m_hitTopLeft || !m_extendSelection) {
m_startBase = base;
m_selStart = found;
m_selEnd.setEmpty();
m_extendSelection = false;
m_startSelection = false;
+ m_picture->safeUnref();
+ m_picture = 0;
}
-void SelectText::selectAll(const SkPicture* picture)
+void SelectText::selectAll()
{
- m_selStart = findFirst(*picture, &m_startBase);
- m_selEnd = findLast(*picture, &m_endBase);
+ if (!m_picture)
+ return;
+ m_selStart = findFirst(*m_picture, &m_startBase);
+ m_selEnd = findLast(*m_picture, &m_endBase);
m_extendSelection = true;
}
int SelectText::selectionX() const
{
- return m_hitTopLeft ? m_selStart.fLeft : m_selEnd.fRight;
+ return (m_hitTopLeft ? m_selStart.fLeft : m_selEnd.fRight) + m_startOffset.fX;
}
int SelectText::selectionY() const
{
const SkIRect& rect = m_hitTopLeft ? m_selStart : m_selEnd;
- return (rect.fTop + rect.fBottom) >> 1;
+ return ((rect.fTop + rect.fBottom) >> 1) + m_startOffset.fY;
+}
+
+void SelectText::setVisibleRect(const IntRect& vis)
+{
+ DBG_NAV_LOGD("vis=(%d,%d,w=%d,h=%d) offset=(%g,%g)",
+ vis.x(), vis.y(), vis.width(), vis.height(), m_startOffset.fX,
+ m_startOffset.fY);
+ m_visibleRect = vis;
+ m_visibleRect.offset(-m_startOffset.fX, -m_startOffset.fY);
}
-bool SelectText::startSelection(int x, int y)
+bool SelectText::startSelection(const CachedRoot* root, const IntRect& vis,
+ int x, int y)
{
+ m_startOffset.set(x, y);
+ m_picture->safeUnref();
+ m_picture = root->pictureAt(&x, &y);
+ if (!m_picture) {
+ DBG_NAV_LOG("picture==0");
+ return false;
+ }
+ m_picture->ref();
+ m_startOffset.fX -= x;
+ m_startOffset.fY -= y;
m_original.fX = x;
m_original.fY = y;
+ setVisibleRect(vis);
if (m_selStart.isEmpty()) {
- DBG_NAV_LOGD("empty start x=%d y=%d", x, y);
+ DBG_NAV_LOGD("empty start picture=(%d,%d) x=%d y=%d",
+ m_picture->width(), m_picture->height(), x, y);
m_startSelection = true;
return true;
}
int right = m_selEnd.fRight + CONTROL_WIDTH / 2;
int bottom = m_selEnd.fBottom + CONTROL_HEIGHT / 2;
bool hitBottomRight = hitCorner(right, bottom, x, y);
- DBG_NAV_LOGD("left=%d top=%d right=%d bottom=%d x=%d y=%d", left, top,
- right, bottom, x, y);
+ DBG_NAV_LOGD("picture=(%d,%d) left=%d top=%d right=%d bottom=%d x=%d y=%d",
+ m_picture->width(), m_picture->height(),left, top, right, bottom, x, y);
if (m_hitTopLeft && (!hitBottomRight || y - top < bottom - y)) {
DBG_NAV_LOG("hit top left");
m_original.fX -= left;
* FIXME: digit find isn't implemented yet
* returns true if a word was selected
*/
-bool SelectText::wordSelection(const SkPicture* picture)
+bool SelectText::wordSelection()
{
int x = m_selStart.fLeft;
int y = (m_selStart.fTop + m_selStart.fBottom) >> 1;
SkIRect clipRect = m_visibleRect;
clipRect.fLeft -= m_visibleRect.width() >> 1;
int base;
- SkIRect left = findLeft(*picture, clipRect, x, y, &base);
+ SkIRect left = findLeft(*m_picture, clipRect, x, y, &base);
if (!left.isEmpty()) {
m_startBase = base;
m_selStart = left;
y = (m_selEnd.fTop + m_selEnd.fBottom) >> 1;
clipRect = m_visibleRect;
clipRect.fRight += m_visibleRect.width() >> 1;
- SkIRect right = findRight(*picture, clipRect, x, y, &base);
+ SkIRect right = findRight(*m_picture, clipRect, x, y, &base);
if (!right.isEmpty()) {
m_endBase = base;
m_selEnd = right;
#include "IntRect.h"
#include "PlatformString.h"
#include "SkPath.h"
-
-class SkPicture;
-struct SkIRect;
-class SkRegion;
+#include "SkPicture.h"
+#include "SkRect.h"
+#include "SkRegion.h"
namespace android {
class SelectText : public DrawExtra {
public:
SelectText();
+ virtual ~SelectText();
virtual void draw(SkCanvas* , LayerAndroid* );
- void extendSelection(const SkPicture* , int x, int y);
+ void extendSelection(const IntRect& vis, int x, int y);
const String getSelection();
bool hitSelection(int x, int y) const;
- void moveSelection(const SkPicture* , int x, int y);
+ void moveSelection(const IntRect& vis, int x, int y);
void reset();
- void selectAll(const SkPicture* );
+ void selectAll();
int selectionX() const;
int selectionY() const;
void setDrawPointer(bool drawPointer) { m_drawPointer = drawPointer; }
void setExtendSelection(bool extend) { m_extendSelection = extend; }
- void setVisibleRect(const IntRect& rect) { m_visibleRect = rect; }
- bool startSelection(int x, int y);
- bool wordSelection(const SkPicture* picture);
+ bool startSelection(const CachedRoot* , const IntRect& vis, int x, int y);
+ bool wordSelection();
public:
float m_inverseScale; // inverse scale, x, y used for drawing select path
int m_selectX;
static void getSelectionArrow(SkPath* );
void getSelectionCaret(SkPath* );
bool hitCorner(int cx, int cy, int x, int y) const;
+ void setVisibleRect(const IntRect& );
void swapAsNeeded();
SkIPoint m_original; // computed start of extend selection
+ SkIPoint m_startOffset; // difference from global to layer
SkIRect m_selStart;
SkIRect m_selEnd;
int m_startBase;
return result;
}
-void getVisibleRect(WebCore::IntRect* rect)
+IntRect getVisibleRect()
{
+ IntRect rect;
LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
JNIEnv* env = JSC::Bindings::getJNIEnv();
jobject jRect = env->CallObjectMethod(m_javaGlue.object(env).get(), m_javaGlue.m_getVisibleRect);
checkException(env);
- int left = (int) env->GetIntField(jRect, m_javaGlue.m_rectLeft);
+ rect.setX(env->GetIntField(jRect, m_javaGlue.m_rectLeft));
checkException(env);
- rect->setX(left);
- int top = (int) env->GetIntField(jRect, m_javaGlue.m_rectTop);
+ rect.setY(env->GetIntField(jRect, m_javaGlue.m_rectTop));
checkException(env);
- rect->setY(top);
- int width = (int) env->CallIntMethod(jRect, m_javaGlue.m_rectWidth);
+ rect.setWidth(env->CallIntMethod(jRect, m_javaGlue.m_rectWidth));
checkException(env);
- rect->setWidth(width);
- int height = (int) env->CallIntMethod(jRect, m_javaGlue.m_rectHeight);
+ rect.setHeight(env->CallIntMethod(jRect, m_javaGlue.m_rectHeight));
checkException(env);
- rect->setHeight(height);
env->DeleteLocalRef(jRect);
checkException(env);
+ return rect;
}
static CachedFrame::Direction KeyToDirection(int32_t keyCode)
IntRect setVisibleRect(CachedRoot* root)
{
- IntRect visibleRect;
- getVisibleRect(&visibleRect);
+ IntRect visibleRect = getVisibleRect();
DBG_NAV_LOGD("getVisibleRect %d,%d,%d,%d",
visibleRect.x(), visibleRect.y(), visibleRect.width(), visibleRect.height());
root->setVisibleRect(visibleRect);
const LayerAndroid* scrollableLayer(int x, int y)
{
#if ENABLE(ANDROID_OVERFLOW_SCROLL) && USE(ACCELERATED_COMPOSITING)
- const LayerAndroid* root = compositeRoot();
- if (!root)
+ const LayerAndroid* layerRoot = compositeRoot();
+ if (!layerRoot)
+ return 0;
+ CachedRoot* cachedRoot = getFrameCache(DontAllowNewer);
+ if (!cachedRoot)
return 0;
- const LayerAndroid* result = root->find(x, y);
+ SkPicture* picture = cachedRoot->pictureAt(&x, &y);
+ const LayerAndroid* result = layerRoot->find(x, y, picture);
if (result != 0 && result->contentIsScrollable())
return result;
#endif
void moveSelection(int x, int y)
{
- const CachedRoot* root = getFrameCache(DontAllowNewer);
- if (!root)
- return;
- SkPicture* picture = root->pictureAt(x, y);
- // FIXME: use the visibleRect only for the main picture
- // for layer pictures, use the equivalent of the canvas clipping rect
- IntRect visibleRect;
- getVisibleRect(&visibleRect);
- m_selectText.setVisibleRect(visibleRect);
- m_selectText.moveSelection(picture, x, y);
+ m_selectText.moveSelection(getVisibleRect(), x, y);
}
void selectAll()
{
- const CachedRoot* root = getFrameCache(DontAllowNewer);
- if (!root)
- return;
- SkPicture* picture = root->pictureAt(0, 0);
- m_selectText.selectAll(picture);
+ m_selectText.selectAll();
}
int selectionX()
bool startSelection(int x, int y)
{
- return m_selectText.startSelection(x, y);
+ const CachedRoot* root = getFrameCache(DontAllowNewer);
+ if (!root)
+ return false;
+ return m_selectText.startSelection(root, getVisibleRect(), x, y);
}
bool wordSelection(int x, int y)
{
- startSelection(x, y);
- if (!extendSelection(x, y))
+ if (!startSelection(x, y))
return false;
+ extendSelection(x, y);
m_selectText.setDrawPointer(false);
- SkPicture* picture = getFrameCache(DontAllowNewer)->pictureAt(x, y);
- return m_selectText.wordSelection(picture);
+ return m_selectText.wordSelection();
}
bool extendSelection(int x, int y)
{
- const CachedRoot* root = getFrameCache(DontAllowNewer);
- if (!root)
- return false;
- SkPicture* picture = root->pictureAt(x, y);
- IntRect visibleRect;
- getVisibleRect(&visibleRect);
- m_selectText.setVisibleRect(visibleRect);
- m_selectText.extendSelection(picture, x, y);
+ m_selectText.extendSelection(getVisibleRect(), x, y);
return true;
}