diff options
author | Victoria Lease <violets@google.com> | 2012-02-13 15:46:16 -0800 |
---|---|---|
committer | Victoria Lease <violets@google.com> | 2012-02-21 11:08:13 -0800 |
commit | 66c40fc863939bd103a5256eb48e944508725c53 (patch) | |
tree | c6e64c85ff11af2c1a45533fb8fc562c78d08314 /Source | |
parent | a54eb7fa1e850d7096f97065f35ed00bcb5384d3 (diff) | |
download | external_webkit-66c40fc863939bd103a5256eb48e944508725c53.zip external_webkit-66c40fc863939bd103a5256eb48e944508725c53.tar.gz external_webkit-66c40fc863939bd103a5256eb48e944508725c53.tar.bz2 |
async find-on-page implementation via WebKit
Change-Id: I5804c865f4bce6452213dc89337ff6a5e6100c9e
Diffstat (limited to 'Source')
-rw-r--r-- | Source/WebCore/platform/android/RenderThemeAndroid.cpp | 10 | ||||
-rw-r--r-- | Source/WebCore/platform/android/RenderThemeAndroid.h | 3 | ||||
-rw-r--r-- | Source/WebCore/platform/graphics/android/GLExtras.cpp | 51 | ||||
-rw-r--r-- | Source/WebCore/platform/graphics/android/GLExtras.h | 6 | ||||
-rw-r--r-- | Source/WebKit/Android.mk | 1 | ||||
-rw-r--r-- | Source/WebKit/android/jni/WebViewCore.cpp | 139 | ||||
-rw-r--r-- | Source/WebKit/android/jni/WebViewCore.h | 12 | ||||
-rw-r--r-- | Source/WebKit/android/nav/FindCanvas.cpp | 715 | ||||
-rw-r--r-- | Source/WebKit/android/nav/FindCanvas.h | 268 | ||||
-rw-r--r-- | Source/WebKit/android/nav/WebView.cpp | 216 |
10 files changed, 157 insertions, 1264 deletions
diff --git a/Source/WebCore/platform/android/RenderThemeAndroid.cpp b/Source/WebCore/platform/android/RenderThemeAndroid.cpp index b570d0e..97110ee 100644 --- a/Source/WebCore/platform/android/RenderThemeAndroid.cpp +++ b/Source/WebCore/platform/android/RenderThemeAndroid.cpp @@ -181,6 +181,16 @@ Color RenderThemeAndroid::platformInactiveListBoxSelectionForegroundColor() cons return Color(Color::transparent); } +Color RenderThemeAndroid::platformActiveTextSearchHighlightColor() const +{ + return Color(0x00, 0x99, 0xcc, 0x99); // HOLO_DARK +} + +Color RenderThemeAndroid::platformInactiveTextSearchHighlightColor() const +{ + return Color(0x33, 0xb5, 0xe5, 0x66); // HOLO_LIGHT +} + int RenderThemeAndroid::baselinePosition(const RenderObject* obj) const { // From the description of this function in RenderTheme.h: diff --git a/Source/WebCore/platform/android/RenderThemeAndroid.h b/Source/WebCore/platform/android/RenderThemeAndroid.h index 802d3c3..165abf8 100644 --- a/Source/WebCore/platform/android/RenderThemeAndroid.h +++ b/Source/WebCore/platform/android/RenderThemeAndroid.h @@ -67,6 +67,9 @@ public: virtual Color platformActiveListBoxSelectionForegroundColor() const; virtual Color platformInactiveListBoxSelectionForegroundColor() const; + virtual Color platformActiveTextSearchHighlightColor() const; + virtual Color platformInactiveTextSearchHighlightColor() const; + virtual void systemFont(int, WebCore::FontDescription&) const {} virtual int minimumMenuListSize(RenderStyle*) const { return 0; } diff --git a/Source/WebCore/platform/graphics/android/GLExtras.cpp b/Source/WebCore/platform/graphics/android/GLExtras.cpp index b872951..8a1d2fa 100644 --- a/Source/WebCore/platform/graphics/android/GLExtras.cpp +++ b/Source/WebCore/platform/graphics/android/GLExtras.cpp @@ -26,7 +26,6 @@ #include "config.h" #include "DrawExtra.h" -#include "FindCanvas.h" #include "GLExtras.h" #include "IntRect.h" #include "TilesManager.h" @@ -58,8 +57,7 @@ #define MAX_NUMBER_OF_MATCHES_TO_DRAW 101 GLExtras::GLExtras() - : m_findOnPage(0) - , m_ring(0) + : m_ring(0) , m_drawExtra(0) , m_viewport() { @@ -170,58 +168,11 @@ void GLExtras::drawCursorRings(const LayerAndroid* layer) layer ? layer->drawTransform() : 0); } -void GLExtras::drawFindOnPage(const LayerAndroid* layer) -{ - WTF::Vector<MatchInfo>* matches = m_findOnPage->matches(); - XLOG("drawFindOnPage, matches: %p", matches); - if (!matches || !m_findOnPage->isCurrentLocationValid()) - return; - std::pair<unsigned, unsigned> matchRange = - m_findOnPage->getLayerMatchRange(layer ? layer->uniqueId() : -1); - if (matchRange.first >= matchRange.second) - return; - - int count = matches->size(); - unsigned current = m_findOnPage->currentMatchIndex(); - XLOG("match count: %d", count); - const TransformationMatrix* drawTransform = - layer ? layer->drawTransform() : 0; - if (count < MAX_NUMBER_OF_MATCHES_TO_DRAW) - for (unsigned i = matchRange.first; i < matchRange.second; i++) { - MatchInfo& info = matches->at(i); - const SkRegion& region = info.getLocation(); - SkIRect rect = region.getBounds(); - if (drawTransform) { - IntRect intRect(rect.fLeft, rect.fTop, rect.width(), - rect.height()); - IntRect transformedRect = drawTransform->mapRect(intRect); - rect.setXYWH(transformedRect.x(), transformedRect.y(), - transformedRect.width(), transformedRect.height()); - } - if (rect.intersect(m_viewport.fLeft, m_viewport.fTop, - m_viewport.fRight, m_viewport.fBottom)) - drawRegion(region, i == current, false, drawTransform, COLOR_HOLO_DARK); -#ifdef DEBUG - else - XLOG("Quick rejecting [%dx%d, %d, %d", rect.fLeft, rect.fTop, - rect.width(), rect.height()); -#endif // DEBUG - } - else { - if (matchRange.first <= current && current < matchRange.second) { - MatchInfo& info = matches->at(current); - drawRegion(info.getLocation(), true, false, drawTransform, COLOR_HOLO_DARK); - } - } -} - void GLExtras::drawGL(const LayerAndroid* layer) { if (m_drawExtra) { if (m_drawExtra == m_ring) drawCursorRings(layer); - else if (m_drawExtra == m_findOnPage) - drawFindOnPage(layer); else m_drawExtra->drawGL(this, layer); } diff --git a/Source/WebCore/platform/graphics/android/GLExtras.h b/Source/WebCore/platform/graphics/android/GLExtras.h index 51ad8d8..72ee41c 100644 --- a/Source/WebCore/platform/graphics/android/GLExtras.h +++ b/Source/WebCore/platform/graphics/android/GLExtras.h @@ -32,7 +32,6 @@ #include "SkRegion.h" namespace android { - class FindOnPage; class CursorRing; } @@ -47,9 +46,6 @@ public: virtual ~GLExtras(); void drawGL(const LayerAndroid* layer); - void setFindOnPageExtra(android::FindOnPage* findOnPage) { - m_findOnPage = findOnPage; - } void setCursorRingExtra(android::CursorRing* ring) { m_ring = ring; } void setDrawExtra(android::DrawExtra* extra) { m_drawExtra = extra; } void setViewport(const SkRect & viewport) { m_viewport = viewport; } @@ -60,9 +56,7 @@ public: private: void drawRing(SkRect& srcRect, Color color, const TransformationMatrix* drawMat); void drawCursorRings(const LayerAndroid* layer); - void drawFindOnPage(const LayerAndroid* layer); - android::FindOnPage* m_findOnPage; android::CursorRing* m_ring; android::DrawExtra* m_drawExtra; SkRect m_viewport; diff --git a/Source/WebKit/Android.mk b/Source/WebKit/Android.mk index ee7f3ce..68ba036 100644 --- a/Source/WebKit/Android.mk +++ b/Source/WebKit/Android.mk @@ -89,7 +89,6 @@ LOCAL_SRC_FILES += \ android/nav/CachedNode.cpp \ android/nav/CachedRoot.cpp \ android/nav/DrawExtra.cpp \ - android/nav/FindCanvas.cpp \ android/nav/SelectText.cpp \ android/nav/WebView.cpp \ \ diff --git a/Source/WebKit/android/jni/WebViewCore.cpp b/Source/WebKit/android/jni/WebViewCore.cpp index 8d819b2..a8b8499 100644 --- a/Source/WebKit/android/jni/WebViewCore.cpp +++ b/Source/WebKit/android/jni/WebViewCore.cpp @@ -44,6 +44,7 @@ #include "CSSValueKeywords.h" #include "DatabaseTracker.h" #include "Document.h" +#include "DocumentMarkerController.h" #include "DOMWindow.h" #include "DOMSelection.h" #include "Element.h" @@ -296,7 +297,6 @@ struct WebViewCore::JavaGlue { jmethodID m_destroySurface; jmethodID m_getContext; jmethodID m_keepScreenOn; - jmethodID m_sendFindAgain; jmethodID m_showRect; jmethodID m_centerFitRect; jmethodID m_setScrollbarModes; @@ -306,6 +306,7 @@ struct WebViewCore::JavaGlue { jmethodID m_setWebTextViewAutoFillable; jmethodID m_selectAt; jmethodID m_initEditField; + jmethodID m_updateMatchCount; AutoJObject object(JNIEnv* env) { // We hold a weak reference to the Java WebViewCore to avoid memeory // leaks due to circular references when WebView.destroy() is not @@ -374,6 +375,9 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m , m_isPaused(false) , m_cacheMode(0) , m_fullscreenVideoMode(false) + , m_matchCount(0) + , m_activeMatchIndex(0) + , m_activeMatch(0) , m_pluginInvalTimer(this, &WebViewCore::pluginInvalTimerFired) , m_screenOnCounter(0) , m_currentNodeDomNavigationAxis(0) @@ -429,7 +433,6 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m m_javaGlue->m_destroySurface = GetJMethod(env, clazz, "destroySurface", "(Landroid/webkit/ViewManager$ChildView;)V"); m_javaGlue->m_getContext = GetJMethod(env, clazz, "getContext", "()Landroid/content/Context;"); m_javaGlue->m_keepScreenOn = GetJMethod(env, clazz, "keepScreenOn", "(Z)V"); - m_javaGlue->m_sendFindAgain = GetJMethod(env, clazz, "sendFindAgain", "()V"); m_javaGlue->m_showRect = GetJMethod(env, clazz, "showRect", "(IIIIIIFFFF)V"); m_javaGlue->m_centerFitRect = GetJMethod(env, clazz, "centerFitRect", "(IIII)V"); m_javaGlue->m_setScrollbarModes = GetJMethod(env, clazz, "setScrollbarModes", "(II)V"); @@ -441,6 +444,7 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m m_javaGlue->m_setWebTextViewAutoFillable = GetJMethod(env, clazz, "setWebTextViewAutoFillable", "(ILjava/lang/String;)V"); m_javaGlue->m_selectAt = GetJMethod(env, clazz, "selectAt", "(II)V"); m_javaGlue->m_initEditField = GetJMethod(env, clazz, "initEditField", "(ILjava/lang/String;II)V"); + m_javaGlue->m_updateMatchCount = GetJMethod(env, clazz, "updateMatchCount", "(IILjava/lang/String;)V"); env->DeleteLocalRef(clazz); env->SetIntField(javaWebViewCore, gWebViewCoreFields.m_nativeClass, (jint)this); @@ -748,15 +752,6 @@ void WebViewCore::recordPictureSet(PictureSet* content) DBG_NAV_LOG("call updateFrameCache"); updateFrameCache(); #endif - if (m_findIsUp) { - ALOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); - JNIEnv* env = JSC::Bindings::getJNIEnv(); - AutoJObject javaObject = m_javaGlue->object(env); - if (javaObject.get()) { - env->CallVoidMethod(javaObject.get(), m_javaGlue->m_sendFindAgain); - checkException(env); - } - } } // note: updateCursorBounds is called directly by the WebView thread @@ -4357,6 +4352,109 @@ void WebViewCore::insertText(const WTF::String &text) client->setUiGeneratedSelectionChange(false); } +void WebViewCore::resetFindOnPage() +{ + m_searchText.truncate(0); + m_matchCount = 0; + m_activeMatchIndex = 0; + m_activeMatch = 0; +} + +int WebViewCore::findTextOnPage(const WTF::String &text) +{ + resetFindOnPage(); // reset even if parameters are bad + + WebCore::Frame* frame = m_mainFrame; + if (!frame) + return 0; + + m_searchText = text; + FindOptions findOptions = WebCore::CaseInsensitive; + + do { + frame->document()->markers()->removeMarkers(DocumentMarker::TextMatch); + m_matchCount += frame->editor()->countMatchesForText(text, findOptions, + 0, true); + updateMatchCount(); + frame->editor()->setMarkedTextMatchesAreHighlighted(true); + frame = frame->tree()->traverseNextWithWrap(false); + } while (frame); + + m_activeMatchIndex = m_matchCount - 1; // prime first findNext + findNextOnPage(true); + return m_matchCount; +} + +void WebViewCore::findNextOnPage(bool forward) +{ + if (!m_mainFrame) + return; + if (!m_matchCount) + return; + + EditorClientAndroid* client = static_cast<EditorClientAndroid*>( + m_mainFrame->editor()->client()); + client->setUiGeneratedSelectionChange(true); + + // Clear previous active match. + if (m_activeMatch) { + m_mainFrame->document()->markers()->setMarkersActive( + m_activeMatch.get(), false); + } + + FindOptions findOptions = WebCore::CaseInsensitive + | WebCore::StartInSelection | WebCore::WrapAround; + if (!forward) + findOptions |= WebCore::Backwards; + + // Start from the previous active match. + if (m_activeMatch) { + m_mainFrame->selection()->setSelection(m_activeMatch.get()); + } + + bool found = m_mainFrame->editor()->findString(m_searchText, findOptions); + if (found) { + VisibleSelection selection(m_mainFrame->selection()->selection()); + if (selection.isNone() || selection.start() == selection.end()) { + // Temporary workaround for findString() refusing to select text + // marked "-webkit-user-select: none". + m_activeMatchIndex = 0; + m_activeMatch = 0; + } else { + // Mark current match "active". + if (forward) { + ++m_activeMatchIndex; + if (m_activeMatchIndex == m_matchCount) + m_activeMatchIndex = 0; + } else { + if (m_activeMatchIndex == 0) + m_activeMatchIndex = m_matchCount; + --m_activeMatchIndex; + } + m_activeMatch = selection.firstRange(); + m_mainFrame->document()->markers()->setMarkersActive( + m_activeMatch.get(), true); + } + updateMatchCount(); + } + + // Clear selection so it doesn't display. + m_mainFrame->selection()->clear(); + client->setUiGeneratedSelectionChange(false); +} + +void WebViewCore::updateMatchCount() const +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + AutoJObject javaObject = m_javaGlue->object(env); + if (!javaObject.get()) + return; + jstring javaText = wtfStringToJstring(env, m_searchText, true); + env->CallVoidMethod(javaObject.get(), m_javaGlue->m_updateMatchCount, + m_activeMatchIndex, m_matchCount, javaText); + checkException(env); +} + String WebViewCore::getText(int startX, int startY, int endX, int endY) { String text; @@ -5056,6 +5154,21 @@ static void SelectAll(JNIEnv* env, jobject obj, jint nativeClass) viewImpl->focusedFrame()->selection()->selectAll(); } +static int FindAll(JNIEnv* env, jobject obj, jint nativeClass, + jstring text) +{ + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + WTF::String wtfText = jstringToWtfString(env, text); + return viewImpl->findTextOnPage(wtfText); +} + +static void FindNext(JNIEnv* env, jobject obj, jint nativeClass, + jboolean forward) +{ + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); + viewImpl->findNextOnPage(forward); +} + // ---------------------------------------------------------------------------- /* @@ -5186,6 +5299,10 @@ static JNINativeMethod gJavaWebViewCoreMethods[] = { (void*) SelectAll }, { "nativeCertTrustChanged","()V", (void*) nativeCertTrustChanged }, + { "nativeFindAll", "(ILjava/lang/String;)I", + (void*) FindAll }, + { "nativeFindNext", "(IZ)V", + (void*) FindNext }, }; int registerWebViewCore(JNIEnv* env) diff --git a/Source/WebKit/android/jni/WebViewCore.h b/Source/WebKit/android/jni/WebViewCore.h index 952e39d..41e681e 100644 --- a/Source/WebKit/android/jni/WebViewCore.h +++ b/Source/WebKit/android/jni/WebViewCore.h @@ -560,6 +560,12 @@ namespace android { WTF::String getText(int startX, int startY, int endX, int endY); void insertText(const WTF::String &text); + // find on page + void resetFindOnPage(); + int findTextOnPage(const WTF::String &text); + void findNextOnPage(bool forward); + void updateMatchCount() const; + #if ENABLE(VIDEO) void enterFullscreenForVideoLayer(int layerId, const WTF::String& url); void exitFullscreenVideo(); @@ -757,6 +763,12 @@ namespace android { int m_cacheMode; bool m_fullscreenVideoMode; + // find on page data + WTF::String m_searchText; + int m_matchCount; + int m_activeMatchIndex; + RefPtr<WebCore::Range> m_activeMatch; + SkTDArray<PluginWidgetAndroid*> m_plugins; WebCore::Timer<WebViewCore> m_pluginInvalTimer; void pluginInvalTimerFired(WebCore::Timer<WebViewCore>*) { diff --git a/Source/WebKit/android/nav/FindCanvas.cpp b/Source/WebKit/android/nav/FindCanvas.cpp deleted file mode 100644 index dca9a75..0000000 --- a/Source/WebKit/android/nav/FindCanvas.cpp +++ /dev/null @@ -1,715 +0,0 @@ -/* - * Copyright 2008, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 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. - */ - -#define LOG_TAG "webviewglue" - -#include "config.h" -#include "FindCanvas.h" -#include "LayerAndroid.h" -#include "IntRect.h" -#include "SelectText.h" -#include "SkBlurMaskFilter.h" -#include "SkCornerPathEffect.h" -#include "SkRect.h" -#include "SkUtils.h" - -#include <utils/Log.h> - -#define INTEGER_OUTSET 2 - -namespace android { - -// MatchInfo methods -//////////////////////////////////////////////////////////////////////////////// - -MatchInfo::MatchInfo() { - m_picture = 0; -} - -MatchInfo::~MatchInfo() { - SkSafeUnref(m_picture); -} - -MatchInfo::MatchInfo(const MatchInfo& src) { - m_layerId = src.m_layerId; - m_location = src.m_location; - m_picture = src.m_picture; - SkSafeRef(m_picture); -} - -void MatchInfo::set(const SkRegion& region, SkPicture* pic, int layerId) { - SkSafeUnref(m_picture); - m_layerId = layerId; - m_location = region; - m_picture = pic; - SkASSERT(pic); - pic->ref(); -} - -// GlyphSet methods -//////////////////////////////////////////////////////////////////////////////// - -GlyphSet::GlyphSet(const SkPaint& paint, const UChar* lower, const UChar* upper, - size_t byteLength) { - SkPaint clonePaint(paint); - clonePaint.setTextEncoding(SkPaint::kUTF16_TextEncoding); - mTypeface = paint.getTypeface(); - mCount = clonePaint.textToGlyphs(lower, byteLength, NULL); - if (mCount > MAX_STORAGE_COUNT) { - mLowerGlyphs = new uint16_t[2*mCount]; - } else { - mLowerGlyphs = &mStorage[0]; - } - // Use one array, and have mUpperGlyphs point to a portion of it, - // so that we can reduce the number of new/deletes - mUpperGlyphs = mLowerGlyphs + mCount; - int count2 = clonePaint.textToGlyphs(lower, byteLength, mLowerGlyphs); - SkASSERT(mCount == count2); - count2 = clonePaint.textToGlyphs(upper, byteLength, mUpperGlyphs); - SkASSERT(mCount == count2); -} - -GlyphSet::~GlyphSet() { - // Do not need to delete mTypeface, which is not owned by us. - if (mCount > MAX_STORAGE_COUNT) { - delete[] mLowerGlyphs; - } // Otherwise, we just used local storage space, so no need to delete - // Also do not need to delete mUpperGlyphs, which simply points to a - // part of mLowerGlyphs -} - -GlyphSet& GlyphSet::operator=(GlyphSet& src) { - mTypeface = src.mTypeface; - mCount = src.mCount; - if (mCount > MAX_STORAGE_COUNT) { - mLowerGlyphs = new uint16_t[2*mCount]; - } else { - mLowerGlyphs = &mStorage[0]; - } - memcpy(mLowerGlyphs, src.mLowerGlyphs, 2*mCount*sizeof(uint16_t)); - mUpperGlyphs = mLowerGlyphs + mCount; - return *this; -} - -bool GlyphSet::characterMatches(uint16_t c, int index) { - SkASSERT(index < mCount && index >= 0); - return c == mLowerGlyphs[index] || c == mUpperGlyphs[index]; -} - -// FindCanvas methods -//////////////////////////////////////////////////////////////////////////////// - -FindCanvas::FindCanvas(int width, int height, const UChar* lower, - const UChar* upper, size_t byteLength) - : mLowerText(lower) - , mUpperText(upper) - , mLength(byteLength) - , mNumFound(0) { - // the text has been provided in read order. Reverse as needed so the - // result contains left-to-right characters. - const uint16_t* start = mLowerText; - size_t count = byteLength >> 1; - const uint16_t* end = mLowerText + count; - while (start < end) { - SkUnichar ch = SkUTF16_NextUnichar(&start); - WTF::Unicode::Direction charDirection = WTF::Unicode::direction(ch); - if (WTF::Unicode::RightToLeftArabic == charDirection - || WTF::Unicode::RightToLeft == charDirection) { - mLowerReversed.clear(); - mLowerReversed.append(mLowerText, count); - WebCore::ReverseBidi(mLowerReversed.begin(), count); - mLowerText = mLowerReversed.begin(); - mUpperReversed.clear(); - mUpperReversed.append(mUpperText, count); - WebCore::ReverseBidi(mUpperReversed.begin(), count); - mUpperText = mUpperReversed.begin(); - break; - } - } - - setBounder(&mBounder); - mOutset = -SkIntToScalar(INTEGER_OUTSET); - mMatches = new WTF::Vector<MatchInfo>(); - mWorkingIndex = 0; - mWorkingCanvas = 0; - mWorkingPicture = 0; -} - -FindCanvas::~FindCanvas() { - setBounder(NULL); - /* Just in case getAndClear was not called. */ - delete mMatches; - SkSafeUnref(mWorkingPicture); -} - -// Each version of addMatch returns a rectangle for a match. -// Not all of the parameters are used by each version. -SkRect FindCanvas::addMatchNormal(int index, - const SkPaint& paint, int count, const uint16_t* glyphs, - const SkScalar pos[], SkScalar y) { - const uint16_t* lineStart = glyphs - index; - /* Use the original paint, since "text" is in glyphs */ - SkScalar before = paint.measureText(lineStart, index * sizeof(uint16_t), 0); - SkRect rect; - rect.fLeft = pos[0] + before; - int countInBytes = count * sizeof(uint16_t); - rect.fRight = paint.measureText(glyphs, countInBytes, 0) + rect.fLeft; - SkPaint::FontMetrics fontMetrics; - paint.getFontMetrics(&fontMetrics); - SkScalar baseline = y; - rect.fTop = baseline + fontMetrics.fAscent; - rect.fBottom = baseline + fontMetrics.fDescent; - const SkMatrix& matrix = getTotalMatrix(); - matrix.mapRect(&rect); - // Add the text to our picture. - SkCanvas* canvas = getWorkingCanvas(); - int saveCount = canvas->save(); - canvas->concat(matrix); - canvas->drawText(glyphs, countInBytes, pos[0] + before, y, paint); - canvas->restoreToCount(saveCount); - return rect; -} - -SkRect FindCanvas::addMatchPos(int index, - const SkPaint& paint, int count, const uint16_t* glyphs, - const SkScalar xPos[], SkScalar /* y */) { - SkRect r; - r.setEmpty(); - const SkPoint* temp = reinterpret_cast<const SkPoint*> (xPos); - const SkPoint* points = &temp[index]; - int countInBytes = count * sizeof(uint16_t); - SkPaint::FontMetrics fontMetrics; - paint.getFontMetrics(&fontMetrics); - // Need to check each character individually, since the heights may be - // different. - for (int j = 0; j < count; j++) { - SkRect bounds; - bounds.fLeft = points[j].fX; - bounds.fRight = bounds.fLeft + - paint.measureText(&glyphs[j], sizeof(uint16_t), 0); - SkScalar baseline = points[j].fY; - bounds.fTop = baseline + fontMetrics.fAscent; - bounds.fBottom = baseline + fontMetrics.fDescent; - /* Accumulate and then add the resulting rect to mMatches */ - r.join(bounds); - } - SkMatrix matrix = getTotalMatrix(); - matrix.mapRect(&r); - SkCanvas* canvas = getWorkingCanvas(); - int saveCount = canvas->save(); - canvas->concat(matrix); - canvas->drawPosText(glyphs, countInBytes, points, paint); - canvas->restoreToCount(saveCount); - return r; -} - -SkRect FindCanvas::addMatchPosH(int index, - const SkPaint& paint, int count, const uint16_t* glyphs, - const SkScalar position[], SkScalar constY) { - SkRect r; - // We only care about the positions starting at the index of our match - const SkScalar* xPos = &position[index]; - // This assumes that the position array is monotonic increasing - // The left bounds will be the position of the left most character - r.fLeft = xPos[0]; - // The right bounds will be the position of the last character plus its - // width - int lastIndex = count - 1; - r.fRight = paint.measureText(&glyphs[lastIndex], sizeof(uint16_t), 0) - + xPos[lastIndex]; - // Grab font metrics to determine the top and bottom of the bounds - SkPaint::FontMetrics fontMetrics; - paint.getFontMetrics(&fontMetrics); - r.fTop = constY + fontMetrics.fAscent; - r.fBottom = constY + fontMetrics.fDescent; - const SkMatrix& matrix = getTotalMatrix(); - matrix.mapRect(&r); - SkCanvas* canvas = getWorkingCanvas(); - int saveCount = canvas->save(); - canvas->concat(matrix); - canvas->drawPosTextH(glyphs, count * sizeof(uint16_t), xPos, constY, paint); - canvas->restoreToCount(saveCount); - return r; -} - -void FindCanvas::drawLayers(LayerAndroid* layer, FindOnPage& findOnPage) { -#if USE(ACCELERATED_COMPOSITING) - int layerId = layer->uniqueId(); - unsigned matchesBegin = found(); - SkPicture* picture = layer->picture(); - if (picture) { - setLayerId(layerId); - drawPicture(*picture); - } - findOnPage.setLayerMatchRange(layerId, - std::pair<unsigned, unsigned>(matchesBegin, found())); - for (int i = 0; i < layer->countChildren(); i++) - drawLayers(layer->getChild(i), findOnPage); -#endif -} - -void FindCanvas::drawText(const void* text, size_t byteLength, SkScalar x, - SkScalar y, const SkPaint& paint) { - findHelper(text, byteLength, paint, &x, y, &FindCanvas::addMatchNormal); -} - -void FindCanvas::drawPosText(const void* text, size_t byteLength, - const SkPoint pos[], const SkPaint& paint) { - // Pass in the first y coordinate for y so that we can check to see whether - // it is lower than the last draw call (to check if we are continuing to - // another line). - findHelper(text, byteLength, paint, (const SkScalar*) pos, pos[0].fY, - &FindCanvas::addMatchPos); -} - -void FindCanvas::drawPosTextH(const void* text, size_t byteLength, - const SkScalar xpos[], SkScalar constY, - const SkPaint& paint) { - findHelper(text, byteLength, paint, xpos, constY, - &FindCanvas::addMatchPosH); -} - -/* The current behavior is to skip substring matches. This means that in the - * string - * batbatbat - * a search for - * batbat - * will return 1 match. If the desired behavior is to return 2 matches, define - * INCLUDE_SUBSTRING_MATCHES to be 1. - */ -#define INCLUDE_SUBSTRING_MATCHES 0 - -// Need a quick way to know a maximum distance between drawText calls to know if -// they are part of the same logical phrase when searching. By crude -// inspection, half the point size seems a good guess at the width of a space -// character. -static inline SkScalar approximateSpaceWidth(const SkPaint& paint) { - return SkScalarHalf(paint.getTextSize()); -} - -void FindCanvas::findHelper(const void* text, size_t byteLength, - const SkPaint& paint, const SkScalar positions[], - SkScalar y, - SkRect (FindCanvas::*addMatch)(int index, - const SkPaint& paint, int count, - const uint16_t* glyphs, - const SkScalar positions[], SkScalar y)) { - SkASSERT(paint.getTextEncoding() == SkPaint::kGlyphID_TextEncoding); - SkASSERT(mMatches); - GlyphSet* glyphSet = getGlyphs(paint); - const int count = glyphSet->getCount(); - int numCharacters = byteLength >> 1; - const uint16_t* chars = (const uint16_t*) text; - // This block will check to see if we are continuing from another line. If - // so, the user needs to have added a space, which we do not draw. - if (mWorkingIndex) { - SkPoint newY; - getTotalMatrix().mapXY(0, y, &newY); - SkIRect workingBounds = mWorkingRegion.getBounds(); - int newYInt = SkScalarRound(newY.fY); - if (workingBounds.fTop > newYInt) { - // The new text is above the working region, so we know it's not - // a continuation. - resetWorkingCanvas(); - mWorkingIndex = 0; - mWorkingRegion.setEmpty(); - } else if (workingBounds.fBottom < newYInt) { - // Now we know that this line is lower than our partial match. - SkPaint clonePaint(paint); - clonePaint.setTextEncoding(SkPaint::kUTF8_TextEncoding); - uint16_t space; - clonePaint.textToGlyphs(" ", 1, &space); - if (glyphSet->characterMatches(space, mWorkingIndex)) { - mWorkingIndex++; - if (mWorkingIndex == count) { - // We already know that it is not clipped out because we - // checked for that before saving the working region. - insertMatchInfo(mWorkingRegion); - - resetWorkingCanvas(); - mWorkingIndex = 0; - mWorkingRegion.setEmpty(); - // We have found a match, so continue on this line from - // scratch. - } - } else { - resetWorkingCanvas(); - mWorkingIndex = 0; - mWorkingRegion.setEmpty(); - } - } - // If neither one is true, then we are likely continuing on the same - // line, but are in a new draw call because the paint has changed. In - // this case, we can continue without adding a space. - } - // j is the position in the search text - // Start off with mWorkingIndex in case we are continuing from a prior call - int j = mWorkingIndex; - // index is the position in the drawn text - int index = 0; - for ( ; index != numCharacters; index++) { - if (glyphSet->characterMatches(chars[index], j)) { - // The jth character in the search text matches the indexth position - // in the drawn text, so increase j. - j++; - if (j != count) { - continue; - } - // The last count characters match, so we found the entire - // search string. - int remaining = count - mWorkingIndex; - int matchIndex = index - remaining + 1; - // Set up a pointer to the matching text in 'chars'. - const uint16_t* glyphs = chars + matchIndex; - SkRect rect = (this->*addMatch)(matchIndex, paint, - remaining, glyphs, positions, y); - // We need an SkIRect for SkRegion operations. - SkIRect iRect; - rect.roundOut(&iRect); - // Want to outset the drawn rectangle by the same amount as - // mOutset - iRect.inset(-INTEGER_OUTSET, -INTEGER_OUTSET); - SkRegion regionToAdd(iRect); - if (!mWorkingRegion.isEmpty()) { - // If this is on the same line as our working region, make - // sure that they are close enough together that they are - // supposed to be part of the same text string. - // The width of two spaces has arbitrarily been chosen. - const SkIRect& workingBounds = mWorkingRegion.getBounds(); - if (workingBounds.fTop <= iRect.fBottom && - workingBounds.fBottom >= iRect.fTop && - SkIntToScalar(iRect.fLeft - workingBounds.fRight) > - approximateSpaceWidth(paint)) { - index = -1; // Will increase to 0 on next run - // In this case, we need to start from the beginning of - // the text being searched and our search term. - j = 0; - mWorkingIndex = 0; - mWorkingRegion.setEmpty(); - continue; - } - // Add the mWorkingRegion, which contains rectangles from - // the previous line(s). - regionToAdd.op(mWorkingRegion, SkRegion::kUnion_Op); - } - insertMatchInfo(regionToAdd); -#if INCLUDE_SUBSTRING_MATCHES - // Reset index to the location of the match and reset j to the - // beginning, so that on the next iteration of the loop, index - // will advance by 1 and we will compare the next character in - // chars to the first character in the GlyphSet. - index = matchIndex; -#endif - // Whether the clip contained it or not, we need to start over - // with our recording canvas - resetWorkingCanvas(); - } else { - // Index needs to be set to index - j + 1. - // This is a ridiculous case, but imagine the situation where the - // user is looking for the string "jjog" in the drawText call for - // "jjjog". The first two letters match. However, when the index - // is 2, and we discover that 'o' and 'j' do not match, we should go - // back to 1, where we do, in fact, have a match - // FIXME: This does not work if (as in our example) "jj" is in one - // draw call and "jog" is in the next. Doing so would require a - // stack, keeping track of multiple possible working indeces and - // regions. This is likely an uncommon case. - index = index - j; // index will be increased by one on the next - // iteration - } - // We reach here in one of two cases: - // 1) We just completed a match, so any working rectangle/index is no - // longer needed, and we will start over from the beginning - // 2) The glyphs do not match, so we start over at the beginning of - // the search string. - j = 0; - mWorkingIndex = 0; - mWorkingRegion.setEmpty(); - } - // At this point, we have searched all of the text in the current drawText - // call. - // Keep track of a partial match that may start on this line. - if (j > 0) { // if j is greater than 0, we have a partial match - int relativeCount = j - mWorkingIndex; // Number of characters in this - // part of the match. - int partialIndex = index - relativeCount; // Index that starts our - // partial match. - const uint16_t* partialGlyphs = chars + partialIndex; - SkRect partial = (this->*addMatch)(partialIndex, paint, relativeCount, - partialGlyphs, positions, y); - partial.inset(mOutset, mOutset); - SkIRect dest; - partial.roundOut(&dest); - mWorkingRegion.op(dest, SkRegion::kUnion_Op); - mWorkingIndex = j; - return; - } - // This string doesn't go into the next drawText, so reset our working - // variables - mWorkingRegion.setEmpty(); - mWorkingIndex = 0; -} - -SkCanvas* FindCanvas::getWorkingCanvas() { - if (!mWorkingPicture) { - mWorkingPicture = new SkPicture; - mWorkingCanvas = mWorkingPicture->beginRecording(0,0); - } - return mWorkingCanvas; -} - -GlyphSet* FindCanvas::getGlyphs(const SkPaint& paint) { - SkTypeface* typeface = paint.getTypeface(); - GlyphSet* end = mGlyphSets.end(); - for (GlyphSet* ptr = mGlyphSets.begin();ptr != end; ptr++) { - if (ptr->getTypeface() == typeface) { - return ptr; - } - } - - GlyphSet set(paint, mLowerText, mUpperText, mLength); - *mGlyphSets.append() = set; - return &(mGlyphSets.top()); -} - -void FindCanvas::insertMatchInfo(const SkRegion& region) { - mNumFound++; - mWorkingPicture->endRecording(); - MatchInfo matchInfo; - mMatches->append(matchInfo); - ALOGD("%s region=%p pict=%p layer=%d", __FUNCTION__, - ®ion, mWorkingPicture, mLayerId); - mMatches->last().set(region, mWorkingPicture, mLayerId); -} - -void FindCanvas::resetWorkingCanvas() { - mWorkingPicture->unref(); - mWorkingPicture = 0; - // 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; -} - -IntRect FindOnPage::currentMatchBounds() const { - IntRect noBounds = IntRect(0, 0, 0, 0); - if (!m_matches || !m_matches->size()) - return noBounds; - MatchInfo& info = (*m_matches)[m_findIndex]; - return info.getLocation().getBounds(); -} - -bool FindOnPage::currentMatchIsInLayer() const { - if (!m_matches || !m_matches->size()) - return false; - MatchInfo& info = (*m_matches)[m_findIndex]; - return info.isInLayer(); -} - -int FindOnPage::currentMatchLayerId() const { - return (*m_matches)[m_findIndex].layerId(); -} - -// 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::drawLegacy(SkCanvas* canvas, LayerAndroid* layer, IntRect* inval) { - if (!m_lastBounds.isEmpty()) { - inval->unite(m_lastBounds); - m_lastBounds.setEmpty(); - } - if (!m_hasCurrentLocation || !m_matches || !m_matches->size()) - return; - int layerId = layer ? layer->uniqueId() : -1; - 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 - int saveCount = canvas->save(); - SkPath matchPath; - currentMatchRegion.getBoundaryPath(&matchPath); - canvas->clipPath(matchPath); - canvas->drawPicture(*matchInfo.getPicture()); - canvas->restoreToCount(saveCount); - const SkMatrix& matrix = canvas->getTotalMatrix(); - const SkRect& localBounds = matchPath.getBounds(); - SkRect globalBounds; - matrix.mapRect(&globalBounds, localBounds); - globalBounds.round(&m_lastBounds); - inval->unite(m_lastBounds); - } - // 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)) - continue; - SkRect bounds; - bounds.set(region.getBounds()); - if (canvas->quickReject(bounds, SkCanvas::kAA_EdgeType)) - 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() || !m_hasCurrentLocation) - 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; - } -} - -std::pair<unsigned, unsigned> FindOnPage::getLayerMatchRange(int layerId) const -{ - return m_layerMatchRangeMap.get(layerId); -} - -void FindOnPage::setLayerMatchRange(int layerId, - const std::pair<unsigned, unsigned> range) -{ - m_layerMatchRangeMap.set(layerId, range); -} - -} diff --git a/Source/WebKit/android/nav/FindCanvas.h b/Source/WebKit/android/nav/FindCanvas.h deleted file mode 100644 index 1d81f9a..0000000 --- a/Source/WebKit/android/nav/FindCanvas.h +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Copyright 2008, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 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 Find_Canvas_h -#define Find_Canvas_h - -#include "DrawExtra.h" -#include "IntRect.h" -#include "SkBounder.h" -#include "SkCanvas.h" -#include "SkPicture.h" -#include "SkRect.h" -#include "SkRegion.h" -#include "SkTDArray.h" - -#include <unicode/umachine.h> -#include <wtf/Vector.h> -#include <wtf/HashMap.h> - -namespace android { -class FindOnPage; - -// Stores both region information and an SkPicture of the match, so that the -// region can be drawn, followed by drawing the matching text on top of it. -// This class owns its SkPicture -class MatchInfo { -public: - MatchInfo(); - ~MatchInfo(); - MatchInfo(const MatchInfo& src); - const SkRegion& getLocation() const { return m_location; } - // Return a pointer to our picture, representing the matching text. Does - // not transfer ownership of the picture. - SkPicture* getPicture() const { return m_picture; } - // This will make a copy of the region, and increase the ref count on the - // SkPicture. If this MatchInfo already had one, unref it. - void set(const SkRegion& region, SkPicture* pic, int layerId); - bool isInLayer() const { return m_layerId >= 0; } - int layerId() const { return m_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 -// the upper and lower case representations of the search string. -class GlyphSet { -public: - GlyphSet(const SkPaint& paint, const UChar* lower, const UChar* upper, - size_t byteLength); - ~GlyphSet(); - GlyphSet& operator=(GlyphSet& src); - - // Return true iff c matches one of our glyph arrays at index - bool characterMatches(uint16_t c, int index); - - int getCount() const { return mCount; } - - const SkTypeface* getTypeface() const { return mTypeface; } - -private: - // Disallow copy constructor - GlyphSet(GlyphSet& src) { } - - // mTypeface is used for comparison only - const SkTypeface* mTypeface; - // mLowerGlyphs points to all of our storage space: the lower set followed - // by the upper set. mUpperGlyphs is purely a convenience pointer to the - // start of the upper case glyphs. - uint16_t* mLowerGlyphs; - uint16_t* mUpperGlyphs; - // mCount is the number of glyphs of the search string. Must be the same - // for both the lower case set and the upper case set. - int mCount; - - // Arbitrarily chose the maximum storage to use in the GlyphSet. This is - // based on the length of the word being searched. If users are always - // searching for 3 letter words (for example), an ideal number would be 3. - // Each time the user searches for a word longer than (in this case, 3) that - // will result in calling new/delete. - enum Storage { - MAX_STORAGE_COUNT = 16 - }; - // In order to eliminate new/deletes, create storage that will be enough - // most of the time - uint16_t mStorage[2*MAX_STORAGE_COUNT]; -}; - -class FindBounder : public SkBounder { -public: - FindBounder() {} - ~FindBounder() {} -protected: - virtual bool onIRect(const SkIRect&) { return false; } -}; - -class FindCanvas : public SkCanvas { -public: - FindCanvas(int width, int height, const UChar* , const UChar*, - size_t byteLength); - - virtual ~FindCanvas(); - - virtual void drawText(const void* text, size_t byteLength, SkScalar x, - SkScalar y, const SkPaint& paint); - - /* FIXME: This path has not been tested. */ - virtual void drawPosText(const void* text, size_t byteLength, - const SkPoint pos[], const SkPaint& paint); - - /* Also untested */ - virtual void drawPosTextH(const void* text, size_t byteLength, - const SkScalar xpos[], SkScalar constY, - const SkPaint& paint); - - /* Not sure what to do here or for drawTextOnPathHV */ - virtual void drawTextOnPath(const void* text, size_t byteLength, - const SkPath& path, const SkMatrix* matrix, - const SkPaint& paint) { - } - - void drawLayers(LayerAndroid* rootLayer, FindOnPage& findOnPage); - 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. - WTF::Vector<MatchInfo>* detachMatches() { - WTF::Vector<MatchInfo>* array = mMatches; - mMatches = NULL; - return array; - } - -private: - // These calls are made by findHelper to store information about each match - // that is found. They return a rectangle which is used to highlight the - // match. They also add to our SkPicture (which can be accessed with - // getDrawnMatches) a draw of each match. This way it can be drawn after - // the rectangle. The rect that is returned is in device coordinates. - SkRect addMatchNormal(int index, - const SkPaint& paint, int count, const uint16_t* glyphs, - const SkScalar pos[], SkScalar y); - - SkRect addMatchPos(int index, - const SkPaint& paint, int count, const uint16_t* glyphs, - const SkScalar xPos[], SkScalar /* y */); - - SkRect addMatchPosH(int index, - const SkPaint& paint, int count, const uint16_t* glyphs, - const SkScalar position[], SkScalar constY); - - // Helper for each of our draw calls - void findHelper(const void* text, size_t byteLength, const SkPaint& paint, - const SkScalar xPos[], SkScalar y, - SkRect (FindCanvas::*addMatch)(int index, - const SkPaint& paint, int count, const uint16_t* glyphs, - const SkScalar pos[], SkScalar y)); - - // If we already have a working canvas, grab it. Otherwise, create a new - // one. - SkCanvas* getWorkingCanvas(); - - // Return the set of glyphs and its count for the text being searched for - // and the parameter paint. If one has already been created and cached - // for this paint, use it. If not, create a new one and cache it. - GlyphSet* getGlyphs(const SkPaint& paint); - - // Store all the accumulated info about a match in our vector. - void insertMatchInfo(const SkRegion& region); - - // Throw away our cumulative information about our working SkCanvas. After - // this call, next call to getWorkingCanvas will create a new one. - void resetWorkingCanvas(); - - // Since we may transfer ownership of this array (see detachRects()), we - // hold a pointer to the array instead of just the array itself. - WTF::Vector<MatchInfo>* mMatches; - const UChar* mLowerText; - const UChar* mUpperText; - Vector<UChar> mLowerReversed; - Vector<UChar> mUpperReversed; - size_t mLength; - FindBounder mBounder; - int mNumFound; - SkScalar mOutset; - SkTDArray<GlyphSet> mGlyphSets; - - SkPicture* mWorkingPicture; - SkCanvas* mWorkingCanvas; - SkRegion mWorkingRegion; - int mWorkingIndex; - int mLayerId; -}; - -class FindOnPage : public DrawExtra { -public: - FindOnPage() { - m_matches = 0; - m_hasCurrentLocation = false; - m_isFindPaintSetUp = false; - m_lastBounds.setEmpty(); - } - virtual ~FindOnPage() { if (m_matches) delete m_matches; } - void clearCurrentLocation() { m_hasCurrentLocation = false; } - IntRect currentMatchBounds() const; - int currentMatchIndex() const { return m_findIndex; } - bool currentMatchIsInLayer() const; - // This requires the current match to be in a layer. See - // currentMatchIsInLayer(). - int currentMatchLayerId() const; - virtual void drawLegacy(SkCanvas* , LayerAndroid* , IntRect* ); - void findNext(bool forward); - bool isCurrentLocationValid() { return m_hasCurrentLocation; } - void setMatches(WTF::Vector<MatchInfo>* matches); - WTF::Vector<MatchInfo>* matches() { return m_matches; } - - // Some functions to determine which matches belong to which layers. - std::pair<unsigned, unsigned> getLayerMatchRange(int layerId) const; - void setLayerMatchRange(int layerId, - const std::pair<unsigned, unsigned> range); - -private: - void drawMatch(const SkRegion& region, SkCanvas* canvas, bool focused); - void setUpFindPaint(); - void storeCurrentMatchLocation(); - WTF::Vector<MatchInfo>* m_matches; - WTF::HashMap< int, std::pair<unsigned, unsigned> > m_layerMatchRangeMap; - // 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; - SkIRect m_lastBounds; -}; - -} - -#endif // Find_Canvas_h diff --git a/Source/WebKit/android/nav/WebView.cpp b/Source/WebKit/android/nav/WebView.cpp index d2d1321..a63675c 100644 --- a/Source/WebKit/android/nav/WebView.cpp +++ b/Source/WebKit/android/nav/WebView.cpp @@ -34,7 +34,6 @@ #include "CachedNode.h" #include "CachedRoot.h" #include "DrawExtra.h" -#include "FindCanvas.h" #include "Frame.h" #include "GraphicsJNI.h" #include "HTMLInputElement.h" @@ -107,12 +106,11 @@ enum FrameCachePermission { AllowNewer }; -#define DRAW_EXTRAS_SIZE 3 +#define DRAW_EXTRAS_SIZE 2 enum DrawExtras { // keep this in sync with WebView.java DrawExtrasNone = 0, - DrawExtrasFind = 1, - DrawExtrasSelection = 2, - DrawExtrasCursorRing = 3 + DrawExtrasSelection = 1, + DrawExtrasCursorRing = 2 }; struct JavaGlue { @@ -243,9 +241,6 @@ DrawExtra* getDrawExtraLegacy(DrawExtras extras) DrawExtra* extra = getDrawExtra(extras); if (!extra) { switch (extras) { - case DrawExtrasFind: - extra = &m_findOnPage; - break; case DrawExtrasCursorRing: if (drawCursorPreamble(root) && m_ring.setup()) { if (m_ring.m_isPressed || m_ringAnimationEnd == UINT_MAX) @@ -313,71 +308,6 @@ void debugDump() } #endif -void scrollToCurrentMatch() -{ - if (!m_findOnPage.currentMatchIsInLayer()) { - scrollRectOnScreen(m_findOnPage.currentMatchBounds()); - return; - } - - SkRect matchBounds = m_findOnPage.currentMatchBounds(); - LayerAndroid* rootLayer = compositeRoot(); - if (!rootLayer) - return; - - Layer* layerContainingMatch = rootLayer->findById(m_findOnPage.currentMatchLayerId()); - if (!layerContainingMatch) - return; - - // If the match is in a fixed position layer, there's nothing to do. - if (layerContainingMatch->shouldInheritFromRootTransform()) - return; - - // If the match is in a scrollable layer or a descendant of such a layer, - // there may be a range of of scroll configurations that will make the - // current match visible. Our approach is the simplest possible. Starting at - // the layer in which the match is found, we move up the layer tree, - // scrolling any scrollable layers as little as possible to make sure that - // the current match is in view. This approach has the disadvantage that we - // may end up scrolling a larger number of elements than is necessary, which - // may be visually jarring. However, minimising the number of layers - // scrolled would complicate the code significantly. - - bool didScrollLayer = false; - for (Layer* layer = layerContainingMatch; layer; layer = layer->getParent()) { - ASSERT(layer->getParent() || layer == rootLayer); - - if (layer->contentIsScrollable()) { - // Convert the match location to layer's local space and scroll it. - // Repeatedly calling Layer::localToAncestor() is inefficient as - // each call repeats part of the calculation. It would be more - // efficient to maintain the transform here and update it on each - // iteration, but that would mean duplicating logic from - // Layer::localToAncestor() and would complicate things. - SkMatrix transform; - layerContainingMatch->localToAncestor(layer, &transform); - SkRect transformedMatchBounds; - transform.mapRect(&transformedMatchBounds, matchBounds); - SkIRect roundedTransformedMatchBounds; - transformedMatchBounds.roundOut(&roundedTransformedMatchBounds); - // Only ScrollableLayerAndroid returns true for contentIsScrollable(). - didScrollLayer |= static_cast<ScrollableLayerAndroid*>(layer)->scrollRectIntoView(roundedTransformedMatchBounds); - } - } - // Invalidate, as the call below to scroll the main page may be a no-op. - if (didScrollLayer) - viewInvalidate(); - - // Convert matchBounds to the global space so we can scroll the main page. - SkMatrix transform; - layerContainingMatch->localToGlobal(&transform); - SkRect transformedMatchBounds; - transform.mapRect(&transformedMatchBounds, matchBounds); - SkIRect roundedTransformedMatchBounds; - transformedMatchBounds.roundOut(&roundedTransformedMatchBounds); - scrollRectOnScreen(roundedTransformedMatchBounds); -} - void scrollRectOnScreen(const IntRect& rect) { if (rect.isEmpty()) @@ -471,7 +401,6 @@ bool drawGL(WebCore::IntRect& viewRect, WebCore::IntRect* invalRect, TilesManager::instance()->setHighEndGfx(m_isHighEndGfx); m_glWebViewState = new GLWebViewState(); m_glWebViewState->glExtras()->setCursorRingExtra(&m_ring); - m_glWebViewState->glExtras()->setFindOnPageExtra(&m_findOnPage); if (m_baseLayer->content()) { SkRegion region; SkIRect rect; @@ -1083,12 +1012,6 @@ void setFindIsUp(bool up) m_viewImpl->m_findIsUp = up; } -void setFindIsEmpty() -{ - DBG_NAV_LOG(""); - m_findOnPage.clearCurrentLocation(); -} - void showCursorTimed() { DBG_NAV_LOG(""); @@ -1165,39 +1088,6 @@ void sendMotionUp(WebCore::Frame* framePtr, WebCore::Node* nodePtr, int x, int y checkException(env); } -void findNext(bool forward) -{ - m_findOnPage.findNext(forward); - scrollToCurrentMatch(); - viewInvalidate(); -} - -// With this call, WebView takes ownership of matches, and is responsible for -// deleting it. -void setMatches(WTF::Vector<MatchInfo>* matches, jboolean sameAsLastSearch) -{ - // If this search is the same as the last one, check against the old - // location to determine whether to scroll. If the same word is found - // in the same place, then do not scroll. - IntRect oldLocation; - bool checkAgainstOldLocation = false; - if (sameAsLastSearch && m_findOnPage.isCurrentLocationValid()) { - oldLocation = m_findOnPage.currentMatchBounds(); - checkAgainstOldLocation = true; - } - - m_findOnPage.setMatches(matches); - - if (!checkAgainstOldLocation || oldLocation != m_findOnPage.currentMatchBounds()) - scrollToCurrentMatch(); - viewInvalidate(); -} - -int currentMatchIndex() -{ - return m_findOnPage.currentMatchIndex(); -} - bool scrollBy(int dx, int dy) { ALOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!"); @@ -1394,10 +1284,6 @@ void setVisibleRect(SkRect& visibleRect) { m_visibleRect = visibleRect; } -FindOnPage& findOnPage() { - return m_findOnPage; -} - void setDrawExtra(DrawExtra *extra, DrawExtras type) { if (type == DrawExtrasNone) @@ -1442,7 +1328,6 @@ private: // local state for WebView bool m_heightCanMeasure; int m_lastDx; SkMSec m_lastDxTime; - FindOnPage m_findOnPage; CursorRing m_ring; DrawExtra* m_extras[DRAW_EXTRAS_SIZE]; BaseLayerAndroid* m_baseLayer; @@ -2163,11 +2048,6 @@ static void nativeSetFindIsUp(JNIEnv *env, jobject obj, jboolean isUp) view->setFindIsUp(isUp); } -static void nativeSetFindIsEmpty(JNIEnv *env, jobject obj) -{ - GET_NATIVE_VIEW(env, obj)->setFindIsEmpty(); -} - static void nativeShowCursorTimed(JNIEnv *env, jobject obj) { GET_NATIVE_VIEW(env, obj)->showCursorTimed(); @@ -2196,88 +2076,6 @@ static jobject nativeGetCursorRingBounds(JNIEnv *env, jobject obj) return rect; } -static int nativeFindAll(JNIEnv *env, jobject obj, jstring findLower, - jstring findUpper, jboolean sameAsLastSearch) -{ - // If one or the other is null, do not search. - if (!(findLower && findUpper)) - return 0; - // Obtain the characters for both the lower case string and the upper case - // string representing the same word. - const jchar* findLowerChars = env->GetStringChars(findLower, 0); - const jchar* findUpperChars = env->GetStringChars(findUpper, 0); - // If one or the other is null, do not search. - if (!(findLowerChars && findUpperChars)) { - if (findLowerChars) - env->ReleaseStringChars(findLower, findLowerChars); - if (findUpperChars) - env->ReleaseStringChars(findUpper, findUpperChars); - checkException(env); - return 0; - } - WebView* view = GET_NATIVE_VIEW(env, obj); - ALOG_ASSERT(view, "view not set in nativeFindAll"); - BaseLayerAndroid* baseLayer = view->getBaseLayer(); - android::PictureSet* pictureSet = baseLayer ? baseLayer->content() : 0; - if (!pictureSet) { - env->ReleaseStringChars(findLower, findLowerChars); - env->ReleaseStringChars(findUpper, findUpperChars); - checkException(env); - return 0; - } - int length = env->GetStringLength(findLower); - // If the lengths of the strings do not match, then they are not the same - // word, so do not search. - if (!length || env->GetStringLength(findUpper) != length) { - env->ReleaseStringChars(findLower, findLowerChars); - env->ReleaseStringChars(findUpper, findUpperChars); - checkException(env); - return 0; - } - int width = pictureSet->width(); - int height = pictureSet->height(); - // Create a FindCanvas, which allows us to fake draw into it so we can - // figure out where our search string is rendered (and how many times). - FindCanvas canvas(width, height, (const UChar*) findLowerChars, - (const UChar*) findUpperChars, length << 1); - SkBitmap bitmap; - bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height); - canvas.setBitmapDevice(bitmap); - FindOnPage& findOnPage = view->findOnPage(); - canvas.setLayerId(-1); - unsigned matchesBegin = canvas.found(); - baseLayer->drawCanvas(&canvas); - findOnPage.setLayerMatchRange(-1, - std::pair<unsigned, unsigned>(matchesBegin, canvas.found())); -#if USE(ACCELERATED_COMPOSITING) - LayerAndroid* compositeLayer = view->compositeRoot(); - if (compositeLayer) - canvas.drawLayers(compositeLayer, findOnPage); -#endif - WTF::Vector<MatchInfo>* matches = canvas.detachMatches(); - // With setMatches, the WebView takes ownership of matches - view->setMatches(matches, sameAsLastSearch); - - env->ReleaseStringChars(findLower, findLowerChars); - env->ReleaseStringChars(findUpper, findUpperChars); - checkException(env); - return canvas.found(); -} - -static void nativeFindNext(JNIEnv *env, jobject obj, bool forward) -{ - WebView* view = GET_NATIVE_VIEW(env, obj); - ALOG_ASSERT(view, "view not set in nativeFindNext"); - view->findNext(forward); -} - -static int nativeFindIndex(JNIEnv *env, jobject obj) -{ - WebView* view = GET_NATIVE_VIEW(env, obj); - ALOG_ASSERT(view, "view not set in nativeFindIndex"); - return view->currentMatchIndex(); -} - static void nativeUpdateCachedTextfield(JNIEnv *env, jobject obj, jstring updatedText, jint generation) { WebView* view = GET_NATIVE_VIEW(env, obj); @@ -2677,12 +2475,6 @@ static JNINativeMethod gJavaWebViewMethods[] = { (void*) nativeDumpDisplayTree }, { "nativeEvaluateLayersAnimations", "(I)Z", (void*) nativeEvaluateLayersAnimations }, - { "nativeFindAll", "(Ljava/lang/String;Ljava/lang/String;Z)I", - (void*) nativeFindAll }, - { "nativeFindNext", "(Z)V", - (void*) nativeFindNext }, - { "nativeFindIndex", "()I", - (void*) nativeFindIndex}, { "nativeFocusCandidateFramePointer", "()I", (void*) nativeFocusCandidateFramePointer }, { "nativeFocusCandidateHasNextTextfield", "()Z", @@ -2751,8 +2543,6 @@ static JNINativeMethod gJavaWebViewMethods[] = { (void*) nativeSelectBestAt }, { "nativeSelectAt", "(II)V", (void*) nativeSelectAt }, - { "nativeSetFindIsEmpty", "()V", - (void*) nativeSetFindIsEmpty }, { "nativeSetFindIsUp", "(Z)V", (void*) nativeSetFindIsUp }, { "nativeSetHeightCanMeasure", "(Z)V", |