diff options
Diffstat (limited to 'WebKit/android')
| -rw-r--r-- | WebKit/android/WebCoreSupport/CachedFramePlatformDataAndroid.h | 2 | ||||
| -rw-r--r-- | WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp | 34 | ||||
| -rw-r--r-- | WebKit/android/WebCoreSupport/ChromeClientAndroid.h | 2 | ||||
| -rw-r--r-- | WebKit/android/WebCoreSupport/PlatformBridge.cpp | 20 | ||||
| -rw-r--r-- | WebKit/android/jni/WebCoreFrameBridge.cpp | 91 | ||||
| -rw-r--r-- | WebKit/android/jni/WebViewCore.cpp | 177 | ||||
| -rw-r--r-- | WebKit/android/jni/WebViewCore.h | 20 | ||||
| -rw-r--r-- | WebKit/android/nav/SelectText.cpp | 403 | ||||
| -rw-r--r-- | WebKit/android/nav/SelectText.h | 3 | ||||
| -rw-r--r-- | WebKit/android/nav/WebView.cpp | 163 |
10 files changed, 545 insertions, 370 deletions
diff --git a/WebKit/android/WebCoreSupport/CachedFramePlatformDataAndroid.h b/WebKit/android/WebCoreSupport/CachedFramePlatformDataAndroid.h index ac22d05..20c7be4 100644 --- a/WebKit/android/WebCoreSupport/CachedFramePlatformDataAndroid.h +++ b/WebKit/android/WebCoreSupport/CachedFramePlatformDataAndroid.h @@ -60,4 +60,4 @@ private: } -#endif
\ No newline at end of file +#endif diff --git a/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp b/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp index 7a18221..30ac36c 100644 --- a/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp +++ b/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp @@ -56,27 +56,14 @@ static unsigned long long tryToReclaimDatabaseQuota(SecurityOrigin* originNeedin #if USE(ACCELERATED_COMPOSITING) -void ChromeClientAndroid::layersSync() +WebCore::GraphicsLayer* ChromeClientAndroid::layersSync() { - if (!m_rootGraphicsLayer) - return; - - if (!m_needsLayerSync) - return; - - m_needsLayerSync = false; - - if (m_webFrame) { - FrameView* frameView = m_webFrame->page()->mainFrame()->view(); - if (frameView && frameView->syncCompositingStateRecursive()) { - GraphicsLayerAndroid* androidGraphicsLayer = - static_cast<GraphicsLayerAndroid*>(m_rootGraphicsLayer); - if (androidGraphicsLayer) { - androidGraphicsLayer->sendImmediateRepaint(); - androidGraphicsLayer->notifyClientAnimationStarted(); - } - } + if (m_rootGraphicsLayer && m_needsLayerSync && m_webFrame) { + if (FrameView* frameView = m_webFrame->page()->mainFrame()->view()) + frameView->syncCompositingStateRecursive(); } + m_needsLayerSync = false; + return m_rootGraphicsLayer; } void ChromeClientAndroid::scheduleCompositingLayerSync() @@ -89,15 +76,12 @@ void ChromeClientAndroid::setNeedsOneShotDrawingSynchronization() // This should not be needed } -void ChromeClientAndroid::attachRootGraphicsLayer(WebCore::Frame* frame, WebCore::GraphicsLayer* layer) +void ChromeClientAndroid::attachRootGraphicsLayer(WebCore::Frame*, WebCore::GraphicsLayer* layer) { + // frame is not used in Android as we should only get root graphics layer for the main frame m_rootGraphicsLayer = layer; - if (!layer) { - WebViewCore::getWebViewCore(frame->view())->setUIRootLayer(0); + if (!layer) return; - } - WebCore::GraphicsLayerAndroid* androidGraphicsLayer = static_cast<GraphicsLayerAndroid*>(layer); - androidGraphicsLayer->setFrame(frame); scheduleCompositingLayerSync(); } diff --git a/WebKit/android/WebCoreSupport/ChromeClientAndroid.h b/WebKit/android/WebCoreSupport/ChromeClientAndroid.h index 517a439..a1f097c 100644 --- a/WebKit/android/WebCoreSupport/ChromeClientAndroid.h +++ b/WebKit/android/WebCoreSupport/ChromeClientAndroid.h @@ -169,7 +169,7 @@ namespace android { virtual void attachRootGraphicsLayer(WebCore::Frame*, WebCore::GraphicsLayer* g); virtual void setNeedsOneShotDrawingSynchronization(); virtual void scheduleCompositingLayerSync(); - void layersSync(); + WebCore::GraphicsLayer* layersSync(); #endif #if ENABLE(ANDROID_INSTALLABLE_WEB_APPS) diff --git a/WebKit/android/WebCoreSupport/PlatformBridge.cpp b/WebKit/android/WebCoreSupport/PlatformBridge.cpp index b75cdfc..833deb5 100644 --- a/WebKit/android/WebCoreSupport/PlatformBridge.cpp +++ b/WebKit/android/WebCoreSupport/PlatformBridge.cpp @@ -38,30 +38,10 @@ #include <wtf/android/AndroidThreading.h> #include <wtf/MainThread.h> -#if USE(ACCELERATED_COMPOSITING) -#include "LayerAndroid.h" -#endif - using namespace android; namespace WebCore { -#if USE(ACCELERATED_COMPOSITING) - -void PlatformBridge::setUIRootLayer(const WebCore::FrameView* view, const LayerAndroid* layer) -{ - android::WebViewCore* core = android::WebViewCore::getWebViewCore(view); - core->setUIRootLayer(layer); -} - -void PlatformBridge::immediateRepaint(const WebCore::FrameView* view) -{ - android::WebViewCore* core = android::WebViewCore::getWebViewCore(view); - core->immediateRepaint(); -} - -#endif // USE(ACCELERATED_COMPOSITING) - WTF::Vector<String> PlatformBridge::getSupportedKeyStrengthList() { KeyGeneratorClient* client = JavaSharedClient::GetKeyGeneratorClient(); diff --git a/WebKit/android/jni/WebCoreFrameBridge.cpp b/WebKit/android/jni/WebCoreFrameBridge.cpp index 87ee07b..bfd4b62 100644 --- a/WebKit/android/jni/WebCoreFrameBridge.cpp +++ b/WebKit/android/jni/WebCoreFrameBridge.cpp @@ -112,6 +112,10 @@ #include "TimeCounter.h" #endif +#if ENABLE(ARCHIVE) +#include "WebArchiveAndroid.h" +#endif + using namespace JSC::Bindings; static String* gUploadFileLabel; @@ -1095,6 +1099,91 @@ static void StopLoading(JNIEnv *env, jobject obj) pFrame->loader()->stopForUserCancel(); } +#if ENABLE(ARCHIVE) +static String saveArchiveAutoname(String basename, String name, String extension) { + if (name.isNull() || name.isEmpty()) { + name = String("index"); + } + + String testname = basename; + testname.append(name); + testname.append(extension); + + errno = 0; + struct stat permissions; + if (stat(testname.utf8().data(), &permissions) < 0) { + if (errno == ENOENT) + return testname; + return String(); + } + + const int maxAttempts = 100; + for (int i = 1; i < maxAttempts; i++) { + String testname = basename; + testname.append(name); + testname.append("-"); + testname.append(String::number(i)); + testname.append(extension); + + errno = 0; + if (stat(testname.utf8().data(), &permissions) < 0) { + if (errno == ENOENT) + return testname; + return String(); + } + } + + return String(); +} +#endif + +static jobject SaveWebArchive(JNIEnv *env, jobject obj, jstring basename, jboolean autoname) +{ +#if ENABLE(ARCHIVE) + WebCore::Frame* pFrame = GET_NATIVE_FRAME(env, obj); + LOG_ASSERT(pFrame, "nativeSaveWebArchive must take a valid frame pointer!"); + + const char* basenameNative = getCharactersFromJStringInEnv(env, basename); + String basenameString = String::fromUTF8(basenameNative); + String filename; + + if (autoname) { + String name = pFrame->loader()->documentLoader()->originalURL().lastPathComponent(); + String extension = String(".webarchivexml"); + filename = saveArchiveAutoname(basenameString, name, extension); + } else { + filename = basenameString; + } + + if (filename.isNull() || filename.isEmpty()) { + LOGD("saveWebArchive: Failed to select a filename to save."); + releaseCharactersForJStringInEnv(env, basename, basenameNative); + return JNI_FALSE; + } + + const int noCompression = 0; + xmlTextWriterPtr writer = xmlNewTextWriterFilename(filename.utf8().data(), noCompression); + if (writer == NULL) { + LOGD("saveWebArchive: Failed to initialize xml writer."); + releaseCharactersForJStringInEnv(env, basename, basenameNative); + return JNI_FALSE; + } + + RefPtr<WebArchiveAndroid> archive = WebCore::WebArchiveAndroid::create(pFrame); + + bool result = archive->saveWebArchive(writer); + + releaseCharactersForJStringInEnv(env, basename, basenameNative); + xmlFreeTextWriter(writer); + + if (result) { + return env->NewStringUTF(filename.utf8().data()); + } + + return NULL; +#endif +} + static jstring ExternalRepresentation(JNIEnv *env, jobject obj) { #ifdef ANDROID_INSTRUMENT @@ -1640,6 +1729,8 @@ static JNINativeMethod gBrowserFrameNativeMethods[] = { (void*) PostUrl }, { "nativeLoadData", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V", (void*) LoadData }, + { "nativeSaveWebArchive", "(Ljava/lang/String;Z)Ljava/lang/String;", + (void*) SaveWebArchive }, { "externalRepresentation", "()Ljava/lang/String;", (void*) ExternalRepresentation }, { "documentAsText", "()Ljava/lang/String;", diff --git a/WebKit/android/jni/WebViewCore.cpp b/WebKit/android/jni/WebViewCore.cpp index 955b654..daca51e 100644 --- a/WebKit/android/jni/WebViewCore.cpp +++ b/WebKit/android/jni/WebViewCore.cpp @@ -29,6 +29,7 @@ #include "WebViewCore.h" #include "AtomicString.h" +#include "BaseLayerAndroid.h" #include "CachedNode.h" #include "CachedRoot.h" #include "Chrome.h" @@ -230,8 +231,6 @@ struct WebViewCore::JavaGlue { jmethodID m_updateViewport; jmethodID m_sendNotifyProgressFinished; jmethodID m_sendViewInvalidate; - jmethodID m_sendImmediateRepaint; - jmethodID m_setRootLayer; jmethodID m_updateTextfield; jmethodID m_updateTextSelection; jmethodID m_clearTextEntry; @@ -276,7 +275,6 @@ static jmethodID GetJMethod(JNIEnv* env, jclass clazz, const char name[], const Mutex WebViewCore::gFrameCacheMutex; Mutex WebViewCore::gButtonMutex; Mutex WebViewCore::gCursorBoundsMutex; -Mutex WebViewCore::m_contentMutex; WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* mainframe) : m_pluginInvalTimer(this, &WebViewCore::pluginInvalTimerFired) @@ -321,8 +319,6 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m m_javaGlue->m_updateViewport = GetJMethod(env, clazz, "updateViewport", "()V"); m_javaGlue->m_sendNotifyProgressFinished = GetJMethod(env, clazz, "sendNotifyProgressFinished", "()V"); m_javaGlue->m_sendViewInvalidate = GetJMethod(env, clazz, "sendViewInvalidate", "(IIII)V"); - m_javaGlue->m_sendImmediateRepaint = GetJMethod(env, clazz, "sendImmediateRepaint", "()V"); - m_javaGlue->m_setRootLayer = GetJMethod(env, clazz, "setRootLayer", "(I)V"); m_javaGlue->m_updateTextfield = GetJMethod(env, clazz, "updateTextfield", "(IZLjava/lang/String;I)V"); m_javaGlue->m_updateTextSelection = GetJMethod(env, clazz, "updateTextSelection", "(IIII)V"); m_javaGlue->m_clearTextEntry = GetJMethod(env, clazz, "clearTextEntry", "()V"); @@ -749,50 +745,11 @@ void WebViewCore::updateCursorBounds(const CachedRoot* root, void WebViewCore::clearContent() { DBG_SET_LOG(""); - m_contentMutex.lock(); m_content.clear(); - m_contentMutex.unlock(); m_addInval.setEmpty(); m_rebuildInval.setEmpty(); } -void WebViewCore::copyContentToPicture(SkPicture* picture) -{ - DBG_SET_LOG("start"); - m_contentMutex.lock(); - PictureSet copyContent = PictureSet(m_content); - m_contentMutex.unlock(); - - int w = copyContent.width(); - int h = copyContent.height(); - copyContent.draw(picture->beginRecording(w, h, PICT_RECORD_FLAGS)); - picture->endRecording(); - DBG_SET_LOG("end"); -} - -bool WebViewCore::drawContent(SkCanvas* canvas, SkColor color) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewUIDrawTimeCounter); -#endif - DBG_SET_LOG("start"); - m_contentMutex.lock(); - PictureSet copyContent = PictureSet(m_content); - m_contentMutex.unlock(); - int sc = canvas->save(SkCanvas::kClip_SaveFlag); - SkRect clip; - clip.set(0, 0, copyContent.width(), copyContent.height()); - canvas->clipRect(clip, SkRegion::kDifference_Op); - canvas->drawColor(color); - canvas->restoreToCount(sc); - bool tookTooLong = copyContent.draw(canvas); - m_contentMutex.lock(); - m_content.setDrawTimes(copyContent); - m_contentMutex.unlock(); - DBG_SET_LOG("end"); - return tookTooLong; -} - bool WebViewCore::focusBoundsChanged() { bool result = m_focusBoundsChanged; @@ -800,18 +757,6 @@ bool WebViewCore::focusBoundsChanged() return result; } -bool WebViewCore::pictureReady() -{ - bool done; - m_contentMutex.lock(); - PictureSet copyContent = PictureSet(m_content); - done = m_progressDone; - m_contentMutex.unlock(); - DBG_NAV_LOGD("done=%s empty=%s", done ? "true" : "false", - copyContent.isEmpty() ? "true" : "false"); - return done || !copyContent.isEmpty(); -} - SkPicture* WebViewCore::rebuildPicture(const SkIRect& inval) { WebCore::FrameView* view = m_mainFrame->view(); @@ -859,54 +804,52 @@ void WebViewCore::rebuildPictureSet(PictureSet* pictureSet) pictureSet->validate(__FUNCTION__); } -bool WebViewCore::recordContent(SkRegion* region, SkIPoint* point) +BaseLayerAndroid* WebViewCore::recordContent(SkRegion* region, SkIPoint* point) { DBG_SET_LOG("start"); float progress = (float) m_mainFrame->page()->progress()->estimatedProgress(); - m_contentMutex.lock(); - PictureSet contentCopy(m_content); m_progressDone = progress <= 0.0f || progress >= 1.0f; - m_contentMutex.unlock(); - recordPictureSet(&contentCopy); - if (!m_progressDone && contentCopy.isEmpty()) { + recordPictureSet(&m_content); + if (!m_progressDone && m_content.isEmpty()) { DBG_SET_LOGD("empty (progress=%g)", progress); - return false; + return 0; } region->set(m_addInval); m_addInval.setEmpty(); region->op(m_rebuildInval, SkRegion::kUnion_Op); m_rebuildInval.setEmpty(); - m_contentMutex.lock(); - contentCopy.setDrawTimes(m_content); - m_content.set(contentCopy); point->fX = m_content.width(); point->fY = m_content.height(); - m_contentMutex.unlock(); DBG_SET_LOGD("region={%d,%d,r=%d,b=%d}", region->getBounds().fLeft, region->getBounds().fTop, region->getBounds().fRight, region->getBounds().fBottom); DBG_SET_LOG("end"); + BaseLayerAndroid* base = new BaseLayerAndroid(); + base->setContent(m_content); + #if USE(ACCELERATED_COMPOSITING) // We update the layers ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(m_mainFrame->page()->chrome()->client()); - chromeC->layersSync(); + GraphicsLayerAndroid* root = static_cast<GraphicsLayerAndroid*>(chromeC->layersSync()); + if (root) { + root->notifyClientAnimationStarted(); + LayerAndroid* copyLayer = new LayerAndroid(*root->contentLayer()); + base->addChild(copyLayer); + copyLayer->unref(); + } #endif - return true; + + return base; } -void WebViewCore::splitContent() +void WebViewCore::splitContent(PictureSet* content) { bool layoutSuceeded = layoutIfNeededRecursive(m_mainFrame); LOG_ASSERT(layoutSuceeded, "Can never be called recursively"); - PictureSet tempPictureSet; - m_contentMutex.lock(); - m_content.split(&tempPictureSet); - m_contentMutex.unlock(); - rebuildPictureSet(&tempPictureSet); - m_contentMutex.lock(); - m_content.set(tempPictureSet); - m_contentMutex.unlock(); + content->split(&m_content); + rebuildPictureSet(&m_content); + content->set(m_content); } void WebViewCore::scrollTo(int x, int y, bool animate) @@ -950,28 +893,6 @@ void WebViewCore::scrollBy(int dx, int dy, bool animate) checkException(env); } -#if USE(ACCELERATED_COMPOSITING) - -void WebViewCore::immediateRepaint() -{ - LOG_ASSERT(m_javaGlue->m_obj, "A Java widget was not associated with this view bridge!"); - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), - m_javaGlue->m_sendImmediateRepaint); - checkException(env); -} - -void WebViewCore::setUIRootLayer(const LayerAndroid* layer) -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - env->CallVoidMethod(m_javaGlue->object(env).get(), - m_javaGlue->m_setRootLayer, - reinterpret_cast<jint>(layer)); - checkException(env); -} - -#endif // USE(ACCELERATED_COMPOSITING) - void WebViewCore::contentDraw() { JNIEnv* env = JSC::Bindings::getJNIEnv(); @@ -3058,7 +2979,7 @@ void WebViewCore::addVisitedLink(const UChar* string, int length) m_groupForVisitedLinks->addVisitedLink(string, length); } -static bool RecordContent(JNIEnv *env, jobject obj, jobject region, jobject pt) +static jint RecordContent(JNIEnv *env, jobject obj, jobject region, jobject pt) { #ifdef ANDROID_INSTRUMENT TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); @@ -3066,18 +2987,18 @@ static bool RecordContent(JNIEnv *env, jobject obj, jobject region, jobject pt) WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); SkRegion* nativeRegion = GraphicsJNI::getNativeRegion(env, region); SkIPoint nativePt; - bool result = viewImpl->recordContent(nativeRegion, &nativePt); + BaseLayerAndroid* result = viewImpl->recordContent(nativeRegion, &nativePt); GraphicsJNI::ipoint_to_jpoint(nativePt, env, pt); - return result; + return reinterpret_cast<jint>(result); } -static void SplitContent(JNIEnv *env, jobject obj) +static void SplitContent(JNIEnv *env, jobject obj, jint content) { #ifdef ANDROID_INSTRUMENT TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); #endif WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - viewImpl->splitContent(); + viewImpl->splitContent(reinterpret_cast<PictureSet*>(content)); } static void SendListBoxChoice(JNIEnv* env, jobject obj, jint choice) @@ -3366,45 +3287,11 @@ static void RegisterURLSchemeAsLocal(JNIEnv* env, jobject obj, jstring scheme) { WebCore::SecurityOrigin::registerURLSchemeAsLocal(to_string(env, scheme)); } -static void ClearContent(JNIEnv *env, jobject obj) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - viewImpl->clearContent(); -} - -static void CopyContentToPicture(JNIEnv *env, jobject obj, jobject pict) -{ -#ifdef ANDROID_INSTRUMENT - TimeCounterAuto counter(TimeCounter::WebViewCoreTimeCounter); -#endif - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - if (!viewImpl) - return; - SkPicture* picture = GraphicsJNI::getNativePicture(env, pict); - viewImpl->copyContentToPicture(picture); -} - -static bool DrawContent(JNIEnv *env, jobject obj, jobject canv, jint color) -{ - // Note: this is called from UI thread, don't count it for WebViewCoreTimeCounter - WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); - SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv); - return viewImpl->drawContent(canvas, color); -} - static bool FocusBoundsChanged(JNIEnv* env, jobject obj) { return GET_NATIVE_VIEW(env, obj)->focusBoundsChanged(); } -static bool PictureReady(JNIEnv* env, jobject obj) -{ - return GET_NATIVE_VIEW(env, obj)->pictureReady(); -} - static void Pause(JNIEnv* env, jobject obj) { // This is called for the foreground tab when the browser is put to the @@ -3541,20 +3428,12 @@ static jobject GetTouchHighlightRects(JNIEnv* env, jobject obj, jint x, jint y, * JNI registration. */ static JNINativeMethod gJavaWebViewCoreMethods[] = { - { "nativeClearContent", "()V", - (void*) ClearContent }, - { "nativeCopyContentToPicture", "(Landroid/graphics/Picture;)V", - (void*) CopyContentToPicture }, - { "nativeDrawContent", "(Landroid/graphics/Canvas;I)Z", - (void*) DrawContent } , { "nativeFocusBoundsChanged", "()Z", (void*) FocusBoundsChanged } , { "nativeKey", "(IIIZZZZ)Z", (void*) Key }, { "nativeClick", "(II)V", (void*) Click }, - { "nativePictureReady", "()Z", - (void*) PictureReady } , { "nativeSendListBoxChoices", "([ZI)V", (void*) SendListBoxChoices }, { "nativeSendListBoxChoice", "(I)V", @@ -3601,11 +3480,11 @@ static JNINativeMethod gJavaWebViewCoreMethods[] = { (void*) UpdateFrameCache }, { "nativeGetContentMinPrefWidth", "()I", (void*) GetContentMinPrefWidth }, - { "nativeRecordContent", "(Landroid/graphics/Region;Landroid/graphics/Point;)Z", + { "nativeRecordContent", "(Landroid/graphics/Region;Landroid/graphics/Point;)I", (void*) RecordContent }, { "setViewportSettingsFromNative", "()V", (void*) SetViewportSettingsFromNative }, - { "nativeSplitContent", "()V", + { "nativeSplitContent", "(I)V", (void*) SplitContent }, { "nativeSetBackgroundColor", "(I)V", (void*) SetBackgroundColor }, diff --git a/WebKit/android/jni/WebViewCore.h b/WebKit/android/jni/WebViewCore.h index 42656d4..99f02e9 100644 --- a/WebKit/android/jni/WebViewCore.h +++ b/WebKit/android/jni/WebViewCore.h @@ -61,10 +61,13 @@ namespace WebCore { #if USE(ACCELERATED_COMPOSITING) namespace WebCore { class GraphicsLayerAndroid; - class LayerAndroid; } #endif +namespace WebCore { + class BaseLayerAndroid; +} + struct PluginWidgetAndroid; class SkPicture; class SkIRect; @@ -137,8 +140,6 @@ namespace android { #if USE(ACCELERATED_COMPOSITING) GraphicsLayerAndroid* graphicsRootLayer() const; - void immediateRepaint(); - void setUIRootLayer(const LayerAndroid* layer); #endif /** Invalidate the view/screen, NOT the content/DOM, but expressed in @@ -449,16 +450,10 @@ namespace android { // reset the picture set to empty void clearContent(); - // flatten the picture set to a picture - void copyContentToPicture(SkPicture* ); - - // draw the picture set with the specified background color - bool drawContent(SkCanvas* , SkColor ); bool focusBoundsChanged(); - bool pictureReady(); // record the inval area, and the picture size - bool recordContent(SkRegion* , SkIPoint* ); + BaseLayerAndroid* recordContent(SkRegion* , SkIPoint* ); int textWrapWidth() const { return m_textWrapWidth; } float scale() const { return m_scale; } float textWrapScale() const { return m_screenWidth * m_scale / m_textWrapWidth; } @@ -468,7 +463,7 @@ namespace android { void updateFrameCacheIfLoading(); // utility to split slow parts of the picture set - void splitContent(); + void splitContent(PictureSet*); void notifyWebAppCanBeInstalled(); @@ -520,8 +515,7 @@ namespace android { WebCore::IntRect m_lastFocusedBounds; int m_lastFocusedSelStart; int m_lastFocusedSelEnd; - static Mutex m_contentMutex; // protects ui/core thread pictureset access - PictureSet m_content; // the set of pictures to draw (accessed by UI too) + PictureSet m_content; // the set of pictures to draw SkRegion m_addInval; // the accumulated inval region (not yet drawn) SkRegion m_rebuildInval; // the accumulated region for rebuilt pictures // Used in passToJS to avoid updating the UI text field until after the diff --git a/WebKit/android/nav/SelectText.cpp b/WebKit/android/nav/SelectText.cpp index 7d2aaa7..9df6ef5 100644 --- a/WebKit/android/nav/SelectText.cpp +++ b/WebKit/android/nav/SelectText.cpp @@ -236,7 +236,7 @@ public: return isSpace(rec); } - void finish() + void finishGlyph() { mLastGlyph = mLastCandidate; mLastUni = mLastUniCandidate; @@ -400,8 +400,9 @@ public: reset(); } - const SkIRect& adjustedBounds(const SkIRect& area) + const SkIRect& adjustedBounds(const SkIRect& area, int* base) { + *base = mBestBase + area.fTop; mBestBounds.offset(area.fLeft, area.fTop); DBG_NAV_LOGD("FirstCheck mBestBounds:(%d, %d, %d, %d) mTop=%d mBottom=%d", mBestBounds.fLeft, mBestBounds.fTop, mBestBounds.fRight, @@ -424,6 +425,7 @@ public: DBG_NAV_LOGD("FirstCheck distance=%d mDistance=%d", distance, mDistance); #endif if (mDistance > distance) { + mBestBase = base(); mBestBounds.set(rect.fLeft, top(), rect.fRight, bottom()); if (distance < 100) { DBG_NAV_LOGD("FirstCheck mBestBounds={%d,%d,r=%d,b=%d} distance=%d", @@ -449,6 +451,7 @@ public: } protected: + int mBestBase; SkIRect mBestBounds; int mDistance; int mFocusX; @@ -475,8 +478,9 @@ public: return !mLast.isSpace(mLastGlyph); } - const SkIRect& bestBounds() + const SkIRect& bestBounds(int* base) { + *base = mBestBase; return mBestBounds; } @@ -501,6 +505,7 @@ public: } recordGlyph(rec); mDistance = distance; + mBestBase = base(); mBestBounds.set(rect.fLeft, top(), rect.fRight, bottom()); if (distance <= 100) { DBG_NAV_LOGD("EdgeCheck mBestBounds={%d,%d,r=%d,b=%d} distance=%d", @@ -535,19 +540,23 @@ public: mBestBounds.set(width, height, width, height); } - const SkIRect& bestBounds() + const SkIRect& bestBounds(int* base) { + *base = mBestBase; return mBestBounds; } virtual bool onIRect(const SkIRect& rect) { - if (mBestBounds.isEmpty()) + if (mBestBounds.isEmpty()) { + mBestBase = base(); mBestBounds.set(rect.fLeft, top(), rect.fRight, bottom()); + } return false; } protected: + int mBestBase; SkIRect mBestBounds; private: typedef CommonCheck INHERITED; @@ -563,6 +572,7 @@ public: virtual bool onIRect(const SkIRect& rect) { + mBestBase = base(); mBestBounds.set(rect.fLeft, top(), rect.fRight, bottom()); return false; } @@ -571,71 +581,197 @@ private: typedef FindFirst INHERITED; }; +static bool baseLinesAgree(const SkIRect& rectA, int baseA, + const SkIRect& rectB, int baseB) +{ + return (rectA.fTop < baseB && rectA.fBottom >= baseB) + || (rectB.fTop < baseA && rectB.fBottom >= baseA); +} + class MultilineBuilder : public CommonCheck { public: - MultilineBuilder(const SkIRect& start, const SkIRect& end, - const SkIRect& area, SkRegion* region) + MultilineBuilder(const SkIRect& start, int startBase, const SkIRect& end, + int endBase, const SkIRect& area, SkRegion* region) : INHERITED(area.width(),area.height()) - , mStart(start) + , mCapture(false) , mEnd(end) + , mEndBase(endBase) + , mFlipped(false) , mSelectRegion(region) - , mCapture(false) + , mStart(start) + , mStartBase(startBase) { + mEnd.offset(-area.fLeft, -area.fTop); + mEndBase -= area.fTop; mLast.setEmpty(); mLastBase = INT_MAX; mStart.offset(-area.fLeft, -area.fTop); - mEnd.offset(-area.fLeft, -area.fTop); + mStartBase -= area.fTop; } - virtual bool onIRect(const SkIRect& rect) { - bool captureLast = false; - if ((rect.fLeft == mStart.fLeft && rect.fRight == mStart.fRight && - top() == mStart.fTop && bottom() == mStart.fBottom) || - (rect.fLeft == mEnd.fLeft && rect.fRight == mEnd.fRight && - top() == mEnd.fTop && bottom() == mEnd.fBottom)) { - captureLast = mCapture; - mCapture ^= true; + void finish() { + if (!mFlipped || SkIRect::Intersects(mLast, mSelectRect)) { + if (VERBOSE_LOGGING) DBG_NAV_LOGD(" mLast=(%d,%d,r=%d,b=%d)", + mLast.fLeft, mLast.fTop, mLast.fRight, mLast.fBottom); + mSelectRegion->op(mLast, SkRegion::kUnion_Op); } - if (mCapture || captureLast) { - SkIRect full; - full.set(rect.fLeft, top(), rect.fRight, bottom()); - if ((mLast.fTop < base() && mLast.fBottom >= base()) - || (mLastBase <= full.fBottom && mLastBase > full.fTop)) { - if (full.fLeft > mLast.fRight) - full.fLeft = mLast.fRight; - else if (full.fRight < mLast.fLeft) - full.fRight = mLast.fLeft; + } + + // return true if capture end was not found after capture begin + bool flipped() { + DBG_NAV_LOGD("flipped=%s", mCapture ? "true" : "false"); + if (!mCapture) + return false; + mFlipped = true; + mSelectRect = mStart; + mSelectRect.join(mEnd); + mLast.setEmpty(); + mLastBase = INT_MAX; + mSelectRegion->setEmpty(); + return true; + } + + virtual bool onIRect(const SkIRect& rect) { + SkIRect full; + full.set(rect.fLeft, top(), rect.fRight, bottom()); + int fullBase = base(); + if (mFlipped) { + if (fullBase < mStart.fTop || fullBase > mEnd.fBottom + || (baseLinesAgree(mStart, mStartBase, full, fullBase) + && full.fLeft < mStart.fLeft) + || (baseLinesAgree(mEnd, mEndBase, full, fullBase) + && full.fRight > mEnd.fRight)) { + return false; + } + if (baseLinesAgree(mLast, mLastBase, full, fullBase) + && (full.fLeft - mLast.fRight < minSpaceWidth() * 3 + || (SkIRect::Intersects(full, mSelectRect) + && SkIRect::Intersects(mLast, mSelectRect)))) { + mLast.join(full); + return false; } - mSelectRegion->op(full, SkRegion::kUnion_Op); - if (VERBOSE_LOGGING) DBG_NAV_LOGD("MultilineBuilder full=(%d,%d,r=%d,b=%d)", - full.fLeft, full.fTop, full.fRight, full.fBottom); + finish(); mLast = full; - mLastBase = base(); - if (mStart == mEnd) - mCapture = false; + mLastBase = fullBase; + return false; } + if (full == mStart) + mCapture = true; + if (mCapture) { + if (baseLinesAgree(mLast, mLastBase, full, fullBase)) + mLast.join(full); + else { + finish(); + mLast = full; + mLastBase = fullBase; + } + } + if (full == mEnd) + mCapture = false; return false; } -protected: - SkIRect mStart; + +protected: + bool mCapture; SkIRect mEnd; + int mEndBase; + bool mFlipped; SkIRect mLast; int mLastBase; + SkIRect mSelectRect; SkRegion* mSelectRegion; - bool mCapture; + SkIRect mStart; + int mStartBase; private: typedef CommonCheck INHERITED; }; +static inline bool compareBounds(const SkIRect* first, const SkIRect* second) +{ + return first->fTop < second->fTop; +} + class TextExtractor : public CommonCheck { public: - TextExtractor(const SkIRect& start, const SkIRect& end, const SkIRect& area) + TextExtractor(const SkIRect& start, int startBase, const SkIRect& end, + int endBase, const SkIRect& area, bool flipped) : INHERITED(area.width(), area.height()) + , mEnd(end) + , mEndBase(endBase) + , mFlipped(flipped) , mRecord(false) - , mSelectEnd(end) - , mSelectStart(start) + , mSelectRect(start) , mSkipFirstSpace(true) // don't start with a space + , mStart(start) + , mStartBase(startBase) { + mEmpty.setEmpty(); + mEnd.offset(-area.fLeft, -area.fTop); + mEndBase -= area.fTop; + mLast.setEmpty(); + mLastBase = INT_MAX; + mSelectRect.join(end); + mSelectRect.offset(-area.fLeft, -area.fTop); + mStart.offset(-area.fLeft, -area.fTop); + mStartBase -= area.fTop; + } + + void addCharacter(const SkBounder::GlyphRec& rec) + { + if (!mSkipFirstSpace) { + if (addNewLine(rec)) { + DBG_NAV_LOG("write new line"); + *mSelectText.append() = '\n'; + *mSelectText.append() = '\n'; + } else if (addSpace(rec)) { + DBG_NAV_LOG("write space"); + *mSelectText.append() = ' '; + } + } else + mSkipFirstSpace = false; + recordGlyph(rec); + finishGlyph(); + if (VERBOSE_LOGGING) DBG_NAV_LOGD("glyphID=%d uni=%d '%c'", rec.fGlyphID, + mLastUni, mLastUni && mLastUni < 0x7f ? mLastUni : '?'); + if (mLastUni) { + uint16_t chars[2]; + size_t count = SkUTF16_FromUnichar(mLastUni, chars); + *mSelectText.append() = chars[0]; + if (count == 2) + *mSelectText.append() = chars[1]; + } + } + + void finish() + { + Vector<SkIRect*> sortedBounds; + SkTDArray<uint16_t> temp; + int index; + DBG_NAV_LOGD("mSelectBounds.count=%d text=%d", mSelectBounds.count(), + mSelectText.count()); + for (index = 0; index < mSelectBounds.count(); index++) + sortedBounds.append(&mSelectBounds[index]); + std::sort(sortedBounds.begin(), sortedBounds.end(), compareBounds); + int lastEnd = -1; + for (index = 0; index < mSelectBounds.count(); index++) { + if (sortedBounds[index]->isEmpty()) + continue; + int order = sortedBounds[index] - &mSelectBounds[0]; + int start = order > 0 ? mSelectCount[order - 1] : 0; + int end = mSelectCount[order]; + DBG_NAV_LOGD("order=%d start=%d end=%d top=%d", order, start, end, + mSelectBounds[order].fTop); + int count = temp.count(); + if (count > 0 && temp[count - 1] != '\n' && start != lastEnd) { + // always separate paragraphs when original text is out of order + DBG_NAV_LOG("write new line"); + *temp.append() = '\n'; + *temp.append() = '\n'; + } + temp.append(end - start, &mSelectText[start]); + lastEnd = end; + } + mSelectText.swap(temp); } virtual bool onIRectGlyph(const SkIRect& rect, @@ -643,44 +779,54 @@ public: { SkIRect full; full.set(rect.fLeft, top(), rect.fRight, bottom()); - if (full == mSelectStart) - mRecord = true; - if (mRecord) { - if (!mSkipFirstSpace) { - if (addNewLine(rec)) { - DBG_NAV_LOG("write new line"); - *mSelectText.append() = '\n'; - *mSelectText.append() = '\n'; - } else if (addSpace(rec)) { - DBG_NAV_LOG("write space"); - *mSelectText.append() = ' '; - } - } else - mSkipFirstSpace = false; - recordGlyph(rec); - finish(); - DBG_NAV_LOGD("TextExtractor glyphID=%d uni=%d '%c'" - " append full=(%d,%d,r=%d,b=%d)", rec.fGlyphID, - mLastUni, mLastUni && mLastUni < 0x7f ? mLastUni : '?', - full.fLeft, full.fTop, full.fRight, full.fBottom); - if (mLastUni) { - uint16_t chars[2]; - size_t count = SkUTF16_FromUnichar(mLastUni, chars); - *mSelectText.append() = chars[0]; - if (count == 2) - *mSelectText.append() = chars[1]; + int fullBase = base(); + if (mFlipped) { + if (fullBase < mStart.fTop || fullBase > mEnd.fBottom + || (baseLinesAgree(mStart, mStartBase, full, fullBase) + && full.fLeft < mStart.fLeft) + || (baseLinesAgree(mEnd, mEndBase, full, fullBase) + && full.fRight > mEnd.fRight)) { + mSkipFirstSpace = true; + return false; } - } else { - mSkipFirstSpace = true; - DBG_NAV_LOGD("TextExtractor [%02x] skip full=(%d,%d,r=%d,b=%d)", - rec.fGlyphID, full.fLeft, full.fTop, full.fRight, full.fBottom); + if (baseLinesAgree(mLast, mLastBase, full, fullBase) + && (full.fLeft - mLast.fRight < minSpaceWidth() * 3 + || (SkIRect::Intersects(full, mSelectRect) + && SkIRect::Intersects(mLast, mSelectRect)))) { + mLast.join(full); + addCharacter(rec); + return false; + } + if (VERBOSE_LOGGING) DBG_NAV_LOGD("baseLinesAgree=%s" + " mLast=(%d,%d,r=%d,b=%d) mLastBase=%d" + " full=(%d,%d,r=%d,b=%d) fullBase=%d" + " mSelectRect=(%d,%d,r=%d,b=%d)", + baseLinesAgree(mLast, mLastBase, full, fullBase) ? "true" : "false", + mLast.fLeft, mLast.fTop, mLast.fRight, mLast.fBottom, mLastBase, + full.fLeft, full.fTop, full.fRight, full.fBottom, fullBase, + mSelectRect.fLeft, mSelectRect.fTop, mSelectRect.fRight, mSelectRect.fBottom); + *mSelectBounds.append() = SkIRect::Intersects(mLast, mSelectRect) + ? mLast : mEmpty; + *mSelectCount.append() = mSelectText.count(); + addCharacter(rec); + mLast = full; + mLastBase = fullBase; + return false; } - if (full == mSelectEnd) + if (full == mStart) + mRecord = true; + if (mRecord) + addCharacter(rec); + else + mSkipFirstSpace = true; + if (full == mEnd) mRecord = false; return false; } WebCore::String text() { + if (mFlipped) + finish(); // the text has been copied in visual order. Reverse as needed if // result contains right-to-left characters. const uint16_t* start = mSelectText.begin(); @@ -698,11 +844,20 @@ public: } protected: + SkIRect mEmpty; + SkIRect mEnd; + int mEndBase; + bool mFlipped; + SkIRect mLast; + int mLastBase; bool mRecord; - const SkIRect& mSelectEnd; - const SkIRect& mSelectStart; + SkTDArray<SkIRect> mSelectBounds; + SkTDArray<int> mSelectCount; + SkIRect mSelectRect; SkTDArray<uint16_t> mSelectText; bool mSkipFirstSpace; + SkIRect mStart; + int mStartBase; private: typedef CommonCheck INHERITED; }; @@ -768,39 +923,48 @@ public: CommonCheck& mBounder; }; -static void buildSelection(const SkPicture& picture, const SkIRect& area, - const SkIRect& selStart, const SkIRect& selEnd, SkRegion* region) +static bool buildSelection(const SkPicture& picture, const SkIRect& area, + const SkIRect& selStart, int startBase, + const SkIRect& selEnd, int endBase, SkRegion* region) { DBG_NAV_LOGD("area=(%d, %d, %d, %d) selStart=(%d, %d, %d, %d)" " selEnd=(%d, %d, %d, %d)", area.fLeft, area.fTop, area.fRight, area.fBottom, selStart.fLeft, selStart.fTop, selStart.fRight, selStart.fBottom, selEnd.fLeft, selEnd.fTop, selEnd.fRight, selEnd.fBottom); - MultilineBuilder builder(selStart, selEnd, area, region); + MultilineBuilder builder(selStart, startBase, selEnd, endBase, area, region); TextCanvas checker(&builder, area); checker.drawPicture(const_cast<SkPicture&>(picture)); + bool flipped = builder.flipped(); + if (flipped) { + TextCanvas checker(&builder, area); + checker.drawPicture(const_cast<SkPicture&>(picture)); + } + builder.finish(); region->translate(area.fLeft, area.fTop); + return flipped; } static SkIRect findClosest(FirstCheck& _check, const SkPicture& picture, - const SkIRect& area) + const SkIRect& area, int* base) { DBG_NAV_LOGD("area=(%d, %d, %d, %d)", area.fLeft, area.fTop, area.fRight, area.fBottom); TextCanvas checker(&_check, area); checker.drawPicture(const_cast<SkPicture&>(picture)); - _check.finish(); - return _check.adjustedBounds(area); + _check.finishGlyph(); + return _check.adjustedBounds(area, base); } static SkIRect findEdge(const SkPicture& picture, const SkIRect& area, - int x, int y, bool left) + int x, int y, bool left, int* base) { SkIRect result; result.setEmpty(); FirstCheck center(x, y, area); center.setRecordGlyph(); - SkIRect closest = findClosest(center, picture, area); + int closestBase; + SkIRect closest = findClosest(center, picture, area, &closestBase); closest.inset(-TOUCH_SLOP, -TOUCH_SLOP); if (!closest.contains(x, y)) { DBG_NAV_LOGD("closest=(%d, %d, %d, %d) area=(%d, %d, %d, %d) x/y=%d,%d", @@ -814,12 +978,13 @@ static SkIRect findEdge(const SkPicture& picture, const SkIRect& area, &edge, &picture, area.fLeft, area.fTop, area.fRight, area.fBottom); TextCanvas checker(&edge, area); checker.drawPicture(const_cast<SkPicture&>(picture)); - edge.finish(); + edge.finishGlyph(); if (!edge.adjacent()) { DBG_NAV_LOG("adjacent break"); break; } - const SkIRect& next = edge.bestBounds(); + int nextBase; + const SkIRect& next = edge.bestBounds(&nextBase); if (next.isEmpty()) { DBG_NAV_LOG("empty"); break; @@ -828,50 +993,54 @@ static SkIRect findEdge(const SkPicture& picture, const SkIRect& area, DBG_NAV_LOG("result == next"); break; } + *base = nextBase; result = next; edge.shiftStart(result); } while (true); - if (!result.isEmpty()) + if (!result.isEmpty()) { + *base += area.fTop; result.offset(area.fLeft, area.fTop); + } return result; } -static SkIRect findFirst(const SkPicture& picture) +static SkIRect findFirst(const SkPicture& picture, int* base) { FindFirst finder(picture.width(), picture.height()); SkIRect area; area.set(0, 0, picture.width(), picture.height()); TextCanvas checker(&finder, area); checker.drawPicture(const_cast<SkPicture&>(picture)); - return finder.bestBounds(); + return finder.bestBounds(base); } -static SkIRect findLast(const SkPicture& picture) +static SkIRect findLast(const SkPicture& picture, int* base) { FindLast finder(picture.width(), picture.height()); SkIRect area; area.set(0, 0, picture.width(), picture.height()); TextCanvas checker(&finder, area); checker.drawPicture(const_cast<SkPicture&>(picture)); - return finder.bestBounds(); + return finder.bestBounds(base); } static SkIRect findLeft(const SkPicture& picture, const SkIRect& area, - int x, int y) + int x, int y, int* base) { - return findEdge(picture, area, x, y, true); + return findEdge(picture, area, x, y, true, base); } static SkIRect findRight(const SkPicture& picture, const SkIRect& area, - int x, int y) + int x, int y, int* base) { - return findEdge(picture, area, x, y, false); + return findEdge(picture, area, x, y, false, base); } static WebCore::String text(const SkPicture& picture, const SkIRect& area, - const SkIRect& start, const SkIRect& end) + const SkIRect& start, int startBase, const SkIRect& end, + int endBase, bool flipped) { - TextExtractor extractor(start, end, area); + TextExtractor extractor(start, startBase, end, endBase, area, flipped); TextCanvas checker(&extractor, area); checker.drawPicture(const_cast<SkPicture&>(picture)); return extractor.text(); @@ -995,7 +1164,8 @@ void SelectText::drawSelectionRegion(SkCanvas* canvas) DBG_NAV_LOGD("m_selStart=(%d, %d, %d, %d) m_selEnd=(%d, %d, %d, %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); - buildSelection(*m_picture, ivisBounds, m_selStart, m_selEnd, &m_selRegion); + m_flipped = buildSelection(*m_picture, ivisBounds, m_selStart, m_startBase, + m_selEnd, m_endBase, &m_selRegion); SkPath path; m_selRegion.getBoundaryPath(&path); path.setFillType(SkPath::kEvenOdd_FillType); @@ -1018,6 +1188,7 @@ void SelectText::drawSelectionRegion(SkCanvas* canvas) void SelectText::extendSelection(const SkPicture* picture, int x, int y) { SkIRect clipRect = m_visibleRect; + int base; if (m_startSelection) { if (!clipRect.contains(x, y) || !clipRect.contains(m_original.fX, m_original.fY)) { @@ -1029,7 +1200,8 @@ void SelectText::extendSelection(const SkPicture* picture, int x, int y) 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); + m_selStart = m_selEnd = findClosest(center, *picture, clipRect, &base); + m_startBase = m_endBase = base; m_startSelection = false; m_extendSelection = true; m_original.fX = m_original.fY = 0; @@ -1045,17 +1217,20 @@ void SelectText::extendSelection(const SkPicture* picture, int x, int y) 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); + SkIRect found = findClosest(extension, *picture, clipRect, &base); DBG_NAV_LOGD("pic=%p x=%d y=%d m_startSelection=%s %s=(%d, %d, %d, %d)" " m_extendSelection=%s", picture, x, y, m_startSelection ? "true" : "false", m_hitTopLeft ? "m_selStart" : "m_selEnd", found.fLeft, found.fTop, found.fRight, found.fBottom, m_extendSelection ? "true" : "false"); - if (m_hitTopLeft) + if (m_hitTopLeft) { + m_startBase = base; m_selStart = found; - else + } else { + m_endBase = base; m_selEnd = found; + } swapAsNeeded(); } @@ -1063,7 +1238,8 @@ const String SelectText::getSelection() { SkIRect clipRect; clipRect.set(0, 0, m_picture->width(), m_picture->height()); - String result = text(*m_picture, clipRect, m_selStart, m_selEnd); + String result = text(*m_picture, clipRect, m_selStart, m_startBase, + m_selEnd, m_endBase, m_flipped); DBG_NAV_LOGD("clip=(%d,%d,%d,%d)" " m_selStart=(%d, %d, %d, %d) m_selEnd=(%d, %d, %d, %d)", clipRect.fLeft, clipRect.fTop, clipRect.fRight, clipRect.fBottom, @@ -1125,11 +1301,16 @@ void SelectText::moveSelection(const SkPicture* picture, int x, int y) if (!m_extendSelection) m_picture = picture; FirstCheck center(x, y, clipRect); - SkIRect found = findClosest(center, *picture, clipRect); - if (m_hitTopLeft || !m_extendSelection) + int base; + SkIRect found = findClosest(center, *picture, clipRect, &base); + if (m_hitTopLeft || !m_extendSelection) { + m_startBase = base; m_selStart = found; - if (!m_hitTopLeft || !m_extendSelection) + } + if (!m_hitTopLeft || !m_extendSelection) { + m_endBase = base; m_selEnd = found; + } swapAsNeeded(); DBG_NAV_LOGD("x=%d y=%d extendSelection=%s m_selStart=(%d, %d, %d, %d)" " m_selEnd=(%d, %d, %d, %d)", x, y, m_extendSelection ? "true" : "false", @@ -1148,8 +1329,8 @@ void SelectText::reset() void SelectText::selectAll(const SkPicture* picture) { - m_selStart = findFirst(*picture); - m_selEnd = findLast(*picture); + m_selStart = findFirst(*picture, &m_startBase); + m_selEnd = findLast(*picture, &m_endBase); m_extendSelection = true; } @@ -1205,16 +1386,21 @@ bool SelectText::wordSelection(const SkPicture* picture) int y = (m_selStart.fTop + m_selStart.fBottom) >> 1; SkIRect clipRect = m_visibleRect; clipRect.fLeft -= m_visibleRect.width() >> 1; - SkIRect left = findLeft(*picture, clipRect, x, y); - if (!left.isEmpty()) + int base; + SkIRect left = findLeft(*picture, clipRect, x, y, &base); + if (!left.isEmpty()) { + m_startBase = base; m_selStart = left; + } x = m_selEnd.fRight; y = (m_selEnd.fTop + m_selEnd.fBottom) >> 1; clipRect = m_visibleRect; clipRect.fRight += m_visibleRect.width() >> 1; - SkIRect right = findRight(*picture, clipRect, x, y); - if (!right.isEmpty()) + SkIRect right = findRight(*picture, clipRect, x, y, &base); + if (!right.isEmpty()) { + m_endBase = base; m_selEnd = right; + } DBG_NAV_LOGD("m_selStart=(%d, %d, %d, %d) m_selEnd=(%d, %d, %d, %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); @@ -1231,6 +1417,7 @@ void SelectText::swapAsNeeded() || (m_selStart.fBottom > m_selEnd.fTop && m_selStart.fRight > m_selEnd.fLeft)) { + SkTSwap(m_startBase, m_endBase); SkTSwap(m_selStart, m_selEnd); m_hitTopLeft ^= true; DBG_NAV_LOGD("m_hitTopLeft=%s", m_hitTopLeft ? "true" : "false"); diff --git a/WebKit/android/nav/SelectText.h b/WebKit/android/nav/SelectText.h index 00b9ca9..404e9e7 100644 --- a/WebKit/android/nav/SelectText.h +++ b/WebKit/android/nav/SelectText.h @@ -70,6 +70,8 @@ private: SkIPoint m_original; // computed start of extend selection SkIRect m_selStart; SkIRect m_selEnd; + int m_startBase; + int m_endBase; SkIRect m_visibleRect; // constrains picture computations to visible area SkRegion m_selRegion; // computed from sel start, end SkPicture m_startControl; @@ -77,6 +79,7 @@ private: const SkPicture* m_picture; bool m_drawPointer; bool m_extendSelection; // false when trackball is moving pointer + bool m_flipped; bool m_hitTopLeft; bool m_startSelection; }; diff --git a/WebKit/android/nav/WebView.cpp b/WebKit/android/nav/WebView.cpp index 9dbefd9..ac36b73 100644 --- a/WebKit/android/nav/WebView.cpp +++ b/WebKit/android/nav/WebView.cpp @@ -30,6 +30,7 @@ #include "AndroidAnimation.h" #include "AndroidLog.h" #include "AtomicString.h" +#include "BaseLayerAndroid.h" #include "CachedFrame.h" #include "CachedNode.h" #include "CachedRoot.h" @@ -177,7 +178,7 @@ WebView(JNIEnv* env, jobject javaWebView, int viewImpl) : m_lastDx = 0; m_lastDxTime = 0; m_ringAnimationEnd = 0; - m_rootLayer = 0; + m_baseLayer = 0; } ~WebView() @@ -190,7 +191,7 @@ WebView(JNIEnv* env, jobject javaWebView, int viewImpl) : } delete m_frameCacheUI; delete m_navPictureUI; - delete m_rootLayer; + delete m_baseLayer; } WebViewCore* getWebViewCore() const { @@ -303,10 +304,11 @@ void scrollRectOnScreen(const IntRect& rect) SkRect visible; calcOurContentVisibleRect(&visible); #if USE(ACCELERATED_COMPOSITING) - if (m_rootLayer) { - m_rootLayer->updateFixedLayersPositions(visible); - m_rootLayer->updatePositions(); - visible = m_rootLayer->subtractLayers(visible); + LayerAndroid* root = compositeRoot(); + if (root) { + root->updateFixedLayersPositions(visible); + root->updatePositions(); + visible = root->subtractLayers(visible); } #endif int dx = 0; @@ -394,14 +396,30 @@ void drawCursorPostamble() } } -void drawExtras(SkCanvas* canvas, int extras) +PictureSet* draw(SkCanvas* canvas, SkColor bgColor, int extras, bool split) { + PictureSet* ret = 0; + if (!m_baseLayer) { + canvas->drawColor(bgColor); + return ret; + } + + // draw the content of the base layer first + PictureSet* content = m_baseLayer->content(); + int sc = canvas->save(SkCanvas::kClip_SaveFlag); + canvas->clipRect(SkRect::MakeLTRB(0, 0, content->width(), + content->height()), SkRegion::kDifference_Op); + canvas->drawColor(bgColor); + canvas->restoreToCount(sc); + if (content->draw(canvas)) + ret = split ? new PictureSet(*content) : 0; + CachedRoot* root = getFrameCache(AllowNewer); if (!root) { DBG_NAV_LOG("!root"); if (extras == DrawExtrasCursorRing) resetCursorRing(); - return; + return ret; } LayerAndroid mainPicture(m_navPictureUI); DrawExtra* extra = 0; @@ -425,22 +443,24 @@ void drawExtras(SkCanvas* canvas, int extras) if (extra) extra->draw(canvas, &mainPicture); #if USE(ACCELERATED_COMPOSITING) - if (!m_rootLayer) - return; - m_rootLayer->setExtra(extra); + LayerAndroid* compositeLayer = compositeRoot(); + if (!compositeLayer) + return ret; + compositeLayer->setExtra(extra); SkRect visible; calcOurContentVisibleRect(&visible); // call this to be sure we've adjusted for any scrolling or animations // before we actually draw - m_rootLayer->updateFixedLayersPositions(visible); - m_rootLayer->updatePositions(); - // We have to set the canvas' matrix on the root layer + compositeLayer->updateFixedLayersPositions(visible); + compositeLayer->updatePositions(); + // We have to set the canvas' matrix on the base layer // (to have fixed layers work as intended) SkAutoCanvasRestore restore(canvas, true); - m_rootLayer->setMatrix(canvas->getTotalMatrix()); + m_baseLayer->setMatrix(canvas->getTotalMatrix()); canvas->resetMatrix(); - m_rootLayer->draw(canvas); + m_baseLayer->draw(canvas); #endif + return ret; } @@ -565,7 +585,7 @@ CachedRoot* getFrameCache(FrameCachePermission allowNewer) m_viewImpl->m_navPictureKit = 0; m_viewImpl->gFrameCacheMutex.unlock(); if (m_frameCacheUI) - m_frameCacheUI->setRootLayer(m_rootLayer); + m_frameCacheUI->setRootLayer(compositeRoot()); #if USE(ACCELERATED_COMPOSITING) if (layerId >= 0) { SkRect visible; @@ -1170,20 +1190,49 @@ int moveGeneration() return m_viewImpl->m_moveGeneration; } -LayerAndroid* rootLayer() const +LayerAndroid* compositeRoot() const { - return m_rootLayer; + LOG_ASSERT(!m_baseLayer || m_baseLayer->countChildren() == 1, + "base layer can't have more than one child %s", __FUNCTION__); + if (m_baseLayer && m_baseLayer->countChildren() == 1) + return static_cast<LayerAndroid*>(m_baseLayer->getChild(0)); + else + return 0; } -void setRootLayer(LayerAndroid* layer) +void setBaseLayer(BaseLayerAndroid* layer) { - delete m_rootLayer; - m_rootLayer = layer; + delete m_baseLayer; + m_baseLayer = layer; CachedRoot* root = getFrameCache(DontAllowNewer); if (!root) return; root->resetLayers(); - root->setRootLayer(m_rootLayer); + root->setRootLayer(compositeRoot()); +} + +void replaceBaseContent(PictureSet* set) +{ + if (!m_baseLayer) + return; + m_baseLayer->setContent(*set); + delete set; +} + +void copyBaseContentToPicture(SkPicture* picture) +{ + if (!m_baseLayer) + return; + PictureSet* content = m_baseLayer->content(); + content->draw(picture->beginRecording(content->width(), content->height(), + SkPicture::kUsePathBoundsForClip_RecordingFlag)); + picture->endRecording(); +} + +bool hasContent() { + if (!m_baseLayer) + return false; + return !m_baseLayer->content()->isEmpty(); } private: // local state for WebView @@ -1200,7 +1249,7 @@ private: // local state for WebView SelectText m_selectText; FindOnPage m_findOnPage; CursorRing m_ring; - LayerAndroid* m_rootLayer; + BaseLayerAndroid* m_baseLayer; }; // end of WebView class /* @@ -1431,28 +1480,43 @@ static void nativeDebugDump(JNIEnv *env, jobject obj) #endif } -static void nativeDrawExtras(JNIEnv *env, jobject obj, jobject canv, jint extras) -{ +static jint nativeDraw(JNIEnv *env, jobject obj, jobject canv, jint color, + jint extras, jboolean split) { SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv); - GET_NATIVE_VIEW(env, obj)->drawExtras(canvas, extras); + return reinterpret_cast<jint>(GET_NATIVE_VIEW(env, obj)->draw(canvas, color, extras, split)); } static bool nativeEvaluateLayersAnimations(JNIEnv *env, jobject obj) { #if USE(ACCELERATED_COMPOSITING) - const LayerAndroid* root = GET_NATIVE_VIEW(env, obj)->rootLayer(); + const LayerAndroid* root = GET_NATIVE_VIEW(env, obj)->compositeRoot(); if (root) return root->evaluateAnimations(); #endif return false; } -static void nativeSetRootLayer(JNIEnv *env, jobject obj, jint layer) +static void nativeSetBaseLayer(JNIEnv *env, jobject obj, jint layer) { -#if USE(ACCELERATED_COMPOSITING) - LayerAndroid* layerImpl = reinterpret_cast<LayerAndroid*>(layer); - GET_NATIVE_VIEW(env, obj)->setRootLayer(layerImpl); -#endif + BaseLayerAndroid* layerImpl = reinterpret_cast<BaseLayerAndroid*>(layer); + GET_NATIVE_VIEW(env, obj)->setBaseLayer(layerImpl); +} + +static void nativeReplaceBaseContent(JNIEnv *env, jobject obj, jint content) +{ + PictureSet* set = reinterpret_cast<PictureSet*>(content); + GET_NATIVE_VIEW(env, obj)->replaceBaseContent(set); +} + +static void nativeCopyBaseContentToPicture(JNIEnv *env, jobject obj, jobject pict) +{ + SkPicture* picture = GraphicsJNI::getNativePicture(env, pict); + GET_NATIVE_VIEW(env, obj)->copyBaseContentToPicture(picture); +} + +static bool nativeHasContent(JNIEnv *env, jobject obj) +{ + return GET_NATIVE_VIEW(env, obj)->hasContent(); } static jobject nativeImageURI(JNIEnv *env, jobject obj, jint x, jint y) @@ -1642,7 +1706,7 @@ static jobject nativeSubtractLayers(JNIEnv* env, jobject obj, jobject jrect) { SkIRect irect = jrect_to_webrect(env, jrect); #if USE(ACCELERATED_COMPOSITING) - LayerAndroid* root = GET_NATIVE_VIEW(env, obj)->rootLayer(); + LayerAndroid* root = GET_NATIVE_VIEW(env, obj)->compositeRoot(); if (root) { SkRect rect; rect.set(irect); @@ -1981,26 +2045,13 @@ static void nativeDumpDisplayTree(JNIEnv* env, jobject jwebview, jstring jurl) SkDumpCanvas canvas(&dumper); // this will playback the picture into the canvas, which will // spew its contents to the dumper - view->getWebViewCore()->drawContent(&canvas, 0); -#if USE(ACCELERATED_COMPOSITING) - if (true) { - LayerAndroid* rootLayer = view->rootLayer(); - if (rootLayer) { - // We have to set the canvas' matrix on the root layer - // (to have fixed layers work as intended) - SkAutoCanvasRestore restore(&canvas, true); - rootLayer->setMatrix(canvas.getTotalMatrix()); - canvas.resetMatrix(); - rootLayer->draw(&canvas); - } - } -#endif + view->draw(&canvas, 0, 0, false); // we're done with the file now fwrite("\n", 1, 1, file); fclose(file); } #if USE(ACCELERATED_COMPOSITING) - const LayerAndroid* rootLayer = view->rootLayer(); + const LayerAndroid* rootLayer = view->compositeRoot(); if (rootLayer) { FILE* file = fopen(LAYERS_TREE_LOG_FILE,"w"); if (file) { @@ -2053,8 +2104,8 @@ static JNINativeMethod gJavaWebViewMethods[] = { (void*) nativeDebugDump }, { "nativeDestroy", "()V", (void*) nativeDestroy }, - { "nativeDrawExtras", "(Landroid/graphics/Canvas;I)V", - (void*) nativeDrawExtras }, + { "nativeDraw", "(Landroid/graphics/Canvas;IIZ)I", + (void*) nativeDraw }, { "nativeDumpDisplayTree", "(Ljava/lang/String;)V", (void*) nativeDumpDisplayTree }, { "nativeEvaluateLayersAnimations", "()Z", @@ -2147,8 +2198,14 @@ static JNINativeMethod gJavaWebViewMethods[] = { (void*) nativeSetFollowedLink }, { "nativeSetHeightCanMeasure", "(Z)V", (void*) nativeSetHeightCanMeasure }, - { "nativeSetRootLayer", "(I)V", - (void*) nativeSetRootLayer }, + { "nativeSetBaseLayer", "(I)V", + (void*) nativeSetBaseLayer }, + { "nativeReplaceBaseContent", "(I)V", + (void*) nativeReplaceBaseContent }, + { "nativeCopyBaseContentToPicture", "(Landroid/graphics/Picture;)V", + (void*) nativeCopyBaseContentToPicture }, + { "nativeHasContent", "()Z", + (void*) nativeHasContent }, { "nativeSetSelectionPointer", "(ZFII)V", (void*) nativeSetSelectionPointer }, { "nativeStartSelection", "(II)Z", |
