diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-02-10 15:44:00 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-02-10 15:44:00 -0800 |
commit | 498e5e4ad10920a9cfae6fdb7ffb19a6ed936ba7 (patch) | |
tree | 13d9b7c37da5daa52b9a744a11e4660c7f6aa917 /WebKit | |
parent | f7e76168422a049a356179665d34ddfb74184920 (diff) | |
download | external_webkit-498e5e4ad10920a9cfae6fdb7ffb19a6ed936ba7.zip external_webkit-498e5e4ad10920a9cfae6fdb7ffb19a6ed936ba7.tar.gz external_webkit-498e5e4ad10920a9cfae6fdb7ffb19a6ed936ba7.tar.bz2 |
auto import from //branches/cupcake/...@130745
Diffstat (limited to 'WebKit')
39 files changed, 733 insertions, 267 deletions
diff --git a/WebKit/Android.mk b/WebKit/Android.mk index e5fa4df..d8e355c 100644 --- a/WebKit/Android.mk +++ b/WebKit/Android.mk @@ -16,15 +16,17 @@ ## LOCAL_SRC_FILES := \ - android/ChromeClientAndroid.cpp \ - android/DragClientAndroid.cpp \ - android/EditorClientAndroid.cpp \ - android/FrameLoaderClientAndroid.cpp \ + android/WebCoreSupport/ChromeClientAndroid.cpp \ + android/WebCoreSupport/ContextMenuClientAndroid.cpp \ + android/WebCoreSupport/DragClientAndroid.cpp \ + android/WebCoreSupport/EditorClientAndroid.cpp \ + android/WebCoreSupport/FrameLoaderClientAndroid.cpp \ + \ android/RenderSkinAndroid.cpp \ android/RenderSkinButton.cpp \ android/RenderSkinCombo.cpp \ android/RenderSkinRadio.cpp \ - android/TimeCounter.cpp \ + android/TimeCounter.cpp \ android/sort.cpp \ \ android/jni/JavaBridge.cpp \ @@ -50,6 +52,7 @@ LOCAL_SRC_FILES := \ \ android/plugins/ANPCanvasInterface.cpp \ android/plugins/ANPLogInterface.cpp \ + android/plugins/ANPMatrixInterface.cpp \ android/plugins/ANPPaintInterface.cpp \ android/plugins/ANPSoundInterface.cpp \ android/plugins/ANPTypefaceInterface.cpp \ diff --git a/WebKit/android/RenderSkinCombo.h b/WebKit/android/RenderSkinCombo.h index 0970b6b..b5321ff 100644 --- a/WebKit/android/RenderSkinCombo.h +++ b/WebKit/android/RenderSkinCombo.h @@ -52,12 +52,12 @@ public: */ static bool Draw(SkCanvas* , Node* , int x, int y, int w, int h); - // The image is an extra 30 pixels wider than the RenderObject, so this accounts for that. + // The image is wider than the RenderObject, so this accounts for that. static int extraWidth() { return arrowMargin; } private: - static const int arrowMargin = 30; + static const int arrowMargin = 22; }; } // WebCore diff --git a/WebKit/android/RenderSkinRadio.cpp b/WebKit/android/RenderSkinRadio.cpp index 847de03..2fca175 100644 --- a/WebKit/android/RenderSkinRadio.cpp +++ b/WebKit/android/RenderSkinRadio.cpp @@ -24,11 +24,16 @@ */ #include "config.h" +#include "RenderSkinRadio.h" + +#include "android_graphics.h" #include "Document.h" +#include "IntRect.h" #include "Node.h" -#include "PlatformGraphicsContext.h" -#include "RenderSkinRadio.h" +#include "RenderSkinAndroid.h" +#include "SkBitmap.h" #include "SkCanvas.h" +#include "SkRect.h" static const char* checks[] = { "res/drawable/checkbox_off_background.png", "res/drawable/checkbox_on_background.png", "res/drawable/radiobutton_off_background.png", "res/drawable/radiobutton_on_background.png"}; @@ -36,55 +41,45 @@ static const SkScalar SIZE = SkIntToScalar(19); // Default height and width - co namespace WebCore { -SkBitmap RenderSkinRadio::m_bitmap[4]; -bool RenderSkinRadio::m_decoded; - -RenderSkinRadio::RenderSkinRadio(bool isCheckBox) -{ - m_checked = false; - m_enabled = true; - m_isCheckBox = isCheckBox; -} +static SkBitmap s_bitmap[4]; +static bool s_decoded; void RenderSkinRadio::Init(android::AssetManager* am) { - if (m_decoded) + if (s_decoded) return; - m_decoded = RenderSkinAndroid::DecodeBitmap(am, checks[0], &m_bitmap[0]); - m_decoded = RenderSkinAndroid::DecodeBitmap(am, checks[1], &m_bitmap[1]) && m_decoded; - m_decoded = RenderSkinAndroid::DecodeBitmap(am, checks[2], &m_bitmap[2]) && m_decoded; - m_decoded = RenderSkinAndroid::DecodeBitmap(am, checks[3], &m_bitmap[3]) && m_decoded; + s_decoded = RenderSkinAndroid::DecodeBitmap(am, checks[0], &s_bitmap[0]); + s_decoded = RenderSkinAndroid::DecodeBitmap(am, checks[1], &s_bitmap[1]) && s_decoded; + s_decoded = RenderSkinAndroid::DecodeBitmap(am, checks[2], &s_bitmap[2]) && s_decoded; + s_decoded = RenderSkinAndroid::DecodeBitmap(am, checks[3], &s_bitmap[3]) && s_decoded; } - -bool RenderSkinRadio::draw(PlatformGraphicsContext* pgc) +void RenderSkinRadio::Draw(SkCanvas* canvas, Node* element, const IntRect& ir, + bool isCheckBox) { - if (!m_decoded) // Seems like an unnecessary slowdown, since it should always decode - return false; - SkCanvas* canvas = pgc->mCanvas; - if (!m_enabled) { - SkRect r; - r.set(0, 0, m_size, m_size); - canvas->saveLayerAlpha(&r, 0x80); - } else { - canvas->save(); + if (!s_decoded || !element) { + return; } - if (SIZE != m_size) { - SkScalar scale = SkScalarDiv(m_size, SIZE); - canvas->scale(scale, scale); + SkRect r; + android_setrect(&r, ir); + int saveLayerCount = 0; + int saveScaleCount = 0; + if (!element->isEnabled()) { + saveLayerCount = canvas->saveLayerAlpha(&r, 0x80); } - canvas->drawBitmap(m_bitmap[m_checked + 2*(!m_isCheckBox)], 0, 0, &m_paint); - canvas->restore(); - return false; // True if we need to redraw -} - -void RenderSkinRadio::notifyState(Node* element) -{ - if (!element) { - return; + SkScalar width = r.width(); + if (SIZE != width) { + SkScalar scale = SkScalarDiv(width, SIZE); + saveScaleCount = canvas->scale(scale, scale); + } + canvas->drawBitmap(s_bitmap[element->isChecked() + 2*(!isCheckBox)], + r.fLeft, r.fTop, NULL); + if (saveLayerCount != 0) { + canvas->restoreToCount(saveLayerCount); + } else if (saveScaleCount != 0) { + canvas->restoreToCount(saveScaleCount); } - m_checked = element->isChecked(); - m_enabled = element->isEnabled(); + return; } } //WebCore diff --git a/WebKit/android/RenderSkinRadio.h b/WebKit/android/RenderSkinRadio.h index a1ca999..f70098f 100644 --- a/WebKit/android/RenderSkinRadio.h +++ b/WebKit/android/RenderSkinRadio.h @@ -26,41 +26,33 @@ #ifndef RenderSkinRadio_h #define RenderSkinRadio_h -#include "RenderSkinAndroid.h" -#include "SkBitmap.h" -#include "SkPaint.h" -#include "SkRect.h" +class SkCanvas; + +namespace android { + class AssetManager; +} namespace WebCore { class Node; +class IntRect; /* RenderSkin for a radio button or a checkbox */ -class RenderSkinRadio : public RenderSkinAndroid +class RenderSkinRadio { public: - /* This skin represents a checkbox if isCheckBox is true, otherwise it is a radio button */ - RenderSkinRadio(bool isCheckBox); - virtual ~RenderSkinRadio() {} - /** * Initialize the class before use. Uses the AssetManager to initialize any bitmaps the class may use. */ static void Init(android::AssetManager*); - virtual bool draw(PlatformGraphicsContext*); - virtual void notifyState(Node* element); - virtual void setDim(int width, int height) { RenderSkinAndroid::setDim(width, height); m_size = SkIntToScalar(height); } - -protected: - static SkBitmap m_bitmap[4]; // Bitmaps representing all states - static bool m_decoded; // True if all assets were decoded. - bool m_isCheckBox; - bool m_checked; - bool m_enabled; - SkPaint m_paint; - SkScalar m_size; + /** + * Draw the element to the canvas at the specified size and location. + * param isCheckBox If true, draws a checkbox. Else, draw a radio button. + */ + static void Draw(SkCanvas* canvas, Node* element, const IntRect&, + bool isCheckBox); }; } // WebCore diff --git a/WebKit/android/ChromeClientAndroid.cpp b/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp index abc6a32..abc6a32 100644 --- a/WebKit/android/ChromeClientAndroid.cpp +++ b/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp diff --git a/WebKit/android/ChromeClientAndroid.h b/WebKit/android/WebCoreSupport/ChromeClientAndroid.h index 60b3a8f..60b3a8f 100644 --- a/WebKit/android/ChromeClientAndroid.h +++ b/WebKit/android/WebCoreSupport/ChromeClientAndroid.h diff --git a/WebKit/android/WebCoreSupport/ContextMenuClientAndroid.cpp b/WebKit/android/WebCoreSupport/ContextMenuClientAndroid.cpp new file mode 100644 index 0000000..7aabfc9 --- /dev/null +++ b/WebKit/android/WebCoreSupport/ContextMenuClientAndroid.cpp @@ -0,0 +1,46 @@ +/* + * Copyright 2007, 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 APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ContextMenuClientAndroid.h" + +#include "NotImplemented.h" +#include <wtf/Assertions.h> + +namespace WebCore { + +void ContextMenuClientAndroid::contextMenuDestroyed() { delete this; } + +PlatformMenuDescription ContextMenuClientAndroid::getCustomMenuFromDefaultItems(ContextMenu*) { notImplemented(); return 0; } +void ContextMenuClientAndroid::contextMenuItemSelected(ContextMenuItem*, const ContextMenu*) { notImplemented(); } + +void ContextMenuClientAndroid::downloadURL(const KURL& url) { notImplemented(); } +void ContextMenuClientAndroid::copyImageToClipboard(const HitTestResult&) { notImplemented(); } +void ContextMenuClientAndroid::searchWithGoogle(const Frame*) { notImplemented(); } +void ContextMenuClientAndroid::lookUpInDictionary(Frame*) { notImplemented(); } +void ContextMenuClientAndroid::speak(const String&) { notImplemented(); } +void ContextMenuClientAndroid::stopSpeaking() { notImplemented(); } + +} diff --git a/WebKit/android/WebCoreSupport/ContextMenuClientAndroid.h b/WebKit/android/WebCoreSupport/ContextMenuClientAndroid.h new file mode 100644 index 0000000..1860e4e --- /dev/null +++ b/WebKit/android/WebCoreSupport/ContextMenuClientAndroid.h @@ -0,0 +1,50 @@ +/* + * Copyright 2007, 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 APPLE COMPUTER, INC. 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 ContextMenuClientAndroid_h +#define ContextMenuClientAndroid_h + +#include "ContextMenuClient.h" + +namespace WebCore { + +class ContextMenuClientAndroid : public ContextMenuClient { +public: + virtual void contextMenuDestroyed(); + + virtual PlatformMenuDescription getCustomMenuFromDefaultItems(ContextMenu*); + virtual void contextMenuItemSelected(ContextMenuItem*, const ContextMenu*); + + virtual void downloadURL(const KURL& url); + virtual void copyImageToClipboard(const HitTestResult&); + virtual void searchWithGoogle(const Frame*); + virtual void lookUpInDictionary(Frame*); + virtual void speak(const String&); + virtual void stopSpeaking(); +}; + +} // namespace WebCore + +#endif // ContextMenuClientAndroid_h diff --git a/WebKit/android/DragClientAndroid.cpp b/WebKit/android/WebCoreSupport/DragClientAndroid.cpp index 64406e7..64406e7 100644 --- a/WebKit/android/DragClientAndroid.cpp +++ b/WebKit/android/WebCoreSupport/DragClientAndroid.cpp diff --git a/WebKit/android/DragClientAndroid.h b/WebKit/android/WebCoreSupport/DragClientAndroid.h index 5f0548f..5f0548f 100644 --- a/WebKit/android/DragClientAndroid.h +++ b/WebKit/android/WebCoreSupport/DragClientAndroid.h diff --git a/WebKit/android/EditorClientAndroid.cpp b/WebKit/android/WebCoreSupport/EditorClientAndroid.cpp index fb71fa2..fb71fa2 100644 --- a/WebKit/android/EditorClientAndroid.cpp +++ b/WebKit/android/WebCoreSupport/EditorClientAndroid.cpp diff --git a/WebKit/android/EditorClientAndroid.h b/WebKit/android/WebCoreSupport/EditorClientAndroid.h index fc35761..fc35761 100644 --- a/WebKit/android/EditorClientAndroid.h +++ b/WebKit/android/WebCoreSupport/EditorClientAndroid.h diff --git a/WebKit/android/FrameLoaderClientAndroid.cpp b/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp index 93dcdf4..93dcdf4 100644 --- a/WebKit/android/FrameLoaderClientAndroid.cpp +++ b/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp diff --git a/WebKit/android/FrameLoaderClientAndroid.h b/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.h index 58b296e..58b296e 100644 --- a/WebKit/android/FrameLoaderClientAndroid.h +++ b/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.h diff --git a/WebKit/android/InspectorClientAndroid.h b/WebKit/android/WebCoreSupport/InspectorClientAndroid.h index 9eb85e5..9eb85e5 100644 --- a/WebKit/android/InspectorClientAndroid.h +++ b/WebKit/android/WebCoreSupport/InspectorClientAndroid.h diff --git a/WebKit/android/jni/PictureSet.cpp b/WebKit/android/jni/PictureSet.cpp index 6f57c67..410769e 100644 --- a/WebKit/android/jni/PictureSet.cpp +++ b/WebKit/android/jni/PictureSet.cpp @@ -76,9 +76,9 @@ void PictureSet::add(const Pictures* temp) void PictureSet::add(const SkRegion& area, SkPicture* picture, uint32_t elapsed, bool split) { - DBG_SET_LOGD("%p {%d,%d,r=%d,b=%d} elapsed=%d split=%d", this, + DBG_SET_LOGD("%p area={%d,%d,r=%d,b=%d} pict=%p elapsed=%d split=%d", this, area.getBounds().fLeft, area.getBounds().fTop, - area.getBounds().fRight, area.getBounds().fBottom, + area.getBounds().fRight, area.getBounds().fBottom, picture, elapsed, split); picture->safeRef(); /* if nothing is drawn beneath part of the new picture, mark it as a base */ @@ -207,7 +207,7 @@ void PictureSet::checkDimensions(int width, int height, SkRegion* inval) void PictureSet::clear() { - // dump(__FUNCTION__); + DBG_SET_LOG(""); Pictures* last = mPictures.end(); for (Pictures* working = mPictures.begin(); working != last; working++) { working->mArea.setEmpty(); @@ -219,7 +219,6 @@ void PictureSet::clear() bool PictureSet::draw(SkCanvas* canvas) { - DBG_SET_LOG(""); validate(__FUNCTION__); Pictures* first = mPictures.begin(); Pictures* last = mPictures.end(); @@ -242,7 +241,7 @@ bool PictureSet::draw(SkCanvas* canvas) break; } } - DBG_SET_LOGD("first=%d last=%d", first - mPictures.begin(), + DBG_SET_LOGD("%p first=%d last=%d", this, first - mPictures.begin(), last - mPictures.begin()); uint32_t maxElapsed = 0; for (working = first; working != last; working++) { @@ -309,20 +308,32 @@ bool PictureSet::draw(SkCanvas* canvas) void PictureSet::dump(const char* label) const { #if PICTURE_SET_DUMP - DBG_SET_LOGD("%p %s (%d)", this, label, mPictures.size()); + DBG_SET_LOGD("%p %s (%d) (w=%d,h=%d)", this, label, mPictures.size(), + mWidth, mHeight); const Pictures* last = mPictures.end(); for (const Pictures* working = mPictures.begin(); working != last; working++) { const SkIRect& bounds = working->mArea.getBounds(); + const SkIRect& unsplit = working->mUnsplit; MeasureStream measure; if (working->mPicture != NULL) working->mPicture->serialize(&measure); - LOGD(" [%d] {%d,%d,r=%d,b=%d} elapsed=%d split=%s" - " wroteElapsed=%s base=%s pictSize=%d", + LOGD(" [%d]" + " mArea.bounds={%d,%d,r=%d,b=%d}" + " mPicture=%p" + " mUnsplit={%d,%d,r=%d,b=%d}" + " mElapsed=%d" + " mSplit=%s" + " mWroteElapsed=%s" + " mBase=%s" + " pict-size=%d", working - mPictures.begin(), bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, + working->mPicture, + unsplit.fLeft, unsplit.fTop, unsplit.fRight, unsplit.fBottom, working->mElapsed, working->mSplit ? "true" : "false", - working->mWroteElapsed ? "true" : "false", - working->mBase ? "true" : "false", measure.mTotal); + working->mWroteElapsed ? "true" : "false", + working->mBase ? "true" : "false", + measure.mTotal); } #endif } @@ -465,7 +476,7 @@ bool PictureSet::reuseSubdivided(const SkRegion& inval) void PictureSet::set(const PictureSet& src) { - DBG_SET_LOG("start"); + DBG_SET_LOGD("start %p src=%p", this, &src); clear(); mWidth = src.mWidth; mHeight = src.mHeight; @@ -514,55 +525,35 @@ void PictureSet::setPicture(size_t i, SkPicture* p) void PictureSet::split(PictureSet* out) const { dump(__FUNCTION__); + DBG_SET_LOGD("%p", this); SkIRect totalBounds; out->mWidth = mWidth; out->mHeight = mHeight; totalBounds.set(0, 0, mWidth, mHeight); SkRegion* total = new SkRegion(totalBounds); const Pictures* last = mPictures.end(); + const Pictures* working; uint32_t balance = 0; - bool firstTime = true; - const Pictures* singleton = NULL; - int singleOut = -1; - for (const Pictures* working = mPictures.begin(); working != last; working++) { + int multiUnsplitFastPictures = 0; // > 1 has more than 1 + for (working = mPictures.begin(); working != last; working++) { + if (working->mElapsed >= MAX_DRAW_TIME || working->mSplit) + continue; + if (++multiUnsplitFastPictures > 1) + break; + } + for (working = mPictures.begin(); working != last; working++) { uint32_t elapsed = working->mElapsed; if (elapsed < MAX_DRAW_TIME) { - if (working->mSplit) { + bool split = working->mSplit; + DBG_SET_LOGD("elapsed=%d working=%p total->getBounds()=" + "{%d,%d,r=%d,b=%d} split=%s", elapsed, working, + total->getBounds().fLeft, total->getBounds().fTop, + total->getBounds().fRight, total->getBounds().fBottom, + split ? "true" : "false"); + if (multiUnsplitFastPictures <= 1 || split) { total->op(working->mArea, SkRegion::kDifference_Op); - DBG_SET_LOGD("%p total->getBounds()={%d,%d,r=%d,b=%d", this, - total->getBounds().fLeft, total->getBounds().fTop, - total->getBounds().fRight, total->getBounds().fBottom); - singleOut = out->mPictures.end() - out->mPictures.begin(); - out->add(working->mArea, working->mPicture, elapsed, true); - continue; - } - if (firstTime) { - singleton = working; - DBG_SET_LOGD("%p firstTime working=%p working->mArea=" - "{%d,%d,r=%d,b=%d}", this, working, - working->mArea.getBounds().fLeft, - working->mArea.getBounds().fTop, - working->mArea.getBounds().fRight, - working->mArea.getBounds().fBottom); - out->add(working->mArea, working->mPicture, elapsed, false); - firstTime = false; - } else { - if (singleOut >= 0) { - Pictures& outWork = out->mPictures[singleOut]; - DBG_SET_LOGD("%p clear singleton outWork=%p outWork->mArea=" - "{%d,%d,r=%d,b=%d}", this, &outWork, - outWork.mArea.getBounds().fLeft, - outWork.mArea.getBounds().fTop, - outWork.mArea.getBounds().fRight, - outWork.mArea.getBounds().fBottom); - outWork.mArea.setEmpty(); - outWork.mPicture->safeUnref(); - outWork.mPicture = NULL; - singleOut = -1; - } - singleton = NULL; - } - if (balance < elapsed) + out->add(working->mArea, working->mPicture, elapsed, split); + } else if (balance < elapsed) balance = elapsed; continue; } @@ -600,9 +591,10 @@ void PictureSet::split(PictureSet* out) const top = bottom; } } - DBG_SET_LOGD("%p w=%d h=%d total->isEmpty()=%s singleton=%p", - this, mWidth, mHeight, total->isEmpty() ? "true" : "false", singleton); - if (total->isEmpty() == false && singleton == NULL) + DBG_SET_LOGD("%p w=%d h=%d total->isEmpty()=%s multiUnsplitFastPictures=%d", + this, mWidth, mHeight, total->isEmpty() ? "true" : "false", + multiUnsplitFastPictures); + if (!total->isEmpty() && multiUnsplitFastPictures > 1) out->add(*total, NULL, balance, false); delete total; validate(__FUNCTION__); diff --git a/WebKit/android/jni/PictureSet.h b/WebKit/android/jni/PictureSet.h index 17a7b25..ce94fc0 100644 --- a/WebKit/android/jni/PictureSet.h +++ b/WebKit/android/jni/PictureSet.h @@ -57,7 +57,7 @@ namespace android { virtual ~PictureSet(); void add(const SkRegion& area, SkPicture* picture, uint32_t elapsed, bool split); - const SkIRect& bounds(size_t i) { + const SkIRect& bounds(size_t i) const { return mPictures[i].mArea.getBounds(); } bool build(); // Update mWidth/mHeight, and adds any additional inval region @@ -71,10 +71,10 @@ namespace android { void set(const PictureSet& ); void setDrawTimes(const PictureSet& ); void setPicture(size_t i, SkPicture* p); - size_t size() { return mPictures.size(); } + size_t size() const { return mPictures.size(); } void split(PictureSet* result) const; void toPicture(SkPicture* ) const; - bool upToDate(size_t i) { return mPictures[i].mPicture != NULL; } + bool upToDate(size_t i) const { return mPictures[i].mPicture != NULL; } int width() const { return mWidth; } void dump(const char* label) const; bool validate(const char* label) const; diff --git a/WebKit/android/jni/WebCoreFrameBridge.cpp b/WebKit/android/jni/WebCoreFrameBridge.cpp index 860109b..e14a534 100644 --- a/WebKit/android/jni/WebCoreFrameBridge.cpp +++ b/WebKit/android/jni/WebCoreFrameBridge.cpp @@ -687,6 +687,9 @@ static void CreateFrame(JNIEnv* env, jobject obj, jobject javaview, jobject jAss InspectorClientAndroid* inspectorC = new InspectorClientAndroid; // Create a new page WebCore::Page* page = new WebCore::Page(chromeC, contextMenuC, editorC, dragC, inspectorC); + // css files without explicit MIMETYPE is treated as generic text files in + // the Java side. So we can't enforce CSS MIMETYPE. + page->settings()->setEnforceCSSMIMETypeInStrictMode(false); /* TODO: Don't turn on PageCache until we can restore the ScrollView State. * This caused bug http://b/issue?id=1202983 page->settings()->setUsesPageCache(true); diff --git a/WebKit/android/jni/WebHistory.cpp b/WebKit/android/jni/WebHistory.cpp index 028d62e..8a75230 100644 --- a/WebKit/android/jni/WebHistory.cpp +++ b/WebKit/android/jni/WebHistory.cpp @@ -231,10 +231,7 @@ jbyteArray WebHistory::Flatten(JNIEnv* env, WTF::Vector<char>& v, WebCore::Histo return NULL; // Write our flattened data to the java array. - jbyte* bytes = env->GetByteArrayElements(b, NULL); - if (bytes) - memcpy(bytes, v.data(), v.size()); - env->ReleaseByteArrayElements(b, bytes, 0); + env->SetByteArrayRegion(b, 0, v.size(), (const jbyte*)v.data()); return b; } diff --git a/WebKit/android/jni/WebViewCore.cpp b/WebKit/android/jni/WebViewCore.cpp index 64bfd8f..12dc9ef 100644 --- a/WebKit/android/jni/WebViewCore.cpp +++ b/WebKit/android/jni/WebViewCore.cpp @@ -280,6 +280,7 @@ void WebViewCore::reset(bool fromConstructor) m_useReplay = false; m_skipContentDraw = false; m_findIsUp = false; + m_domtree_version = 0; } static bool layoutIfNeededRecursive(WebCore::Frame* f) @@ -382,16 +383,19 @@ void WebViewCore::recordPictureSet(PictureSet* content) m_frameCacheOutOfDate = true; WebCore::IntRect oldBounds = oldFocusNode ? oldFocusNode->getRect() : WebCore::IntRect(0,0,0,0); - DBG_NAV_LOGD_THROTTLE("m_lastFocused=%p oldFocusNode=%p" + DBG_NAV_LOGD("m_lastFocused=%p oldFocusNode=%p" " m_lastFocusedBounds={%d,%d,%d,%d} oldBounds={%d,%d,%d,%d}", m_lastFocused, oldFocusNode, m_lastFocusedBounds.x(), m_lastFocusedBounds.y(), m_lastFocusedBounds.width(), m_lastFocusedBounds.height(), oldBounds.x(), oldBounds.y(), oldBounds.width(), oldBounds.height()); + unsigned latestVersion = m_mainFrame->document()->domTreeVersion(); if (m_lastFocused != oldFocusNode || m_lastFocusedBounds != oldBounds - || m_findIsUp) { + || m_findIsUp || latestVersion != m_domtree_version) { m_lastFocused = oldFocusNode; m_lastFocusedBounds = oldBounds; - DBG_NAV_LOG("call updateFrameCache"); + DBG_NAV_LOGD("call updateFrameCache m_domtree_version=%d latest=%d", + m_domtree_version, latestVersion); + m_domtree_version = latestVersion; updateFrameCache(); } } @@ -508,8 +512,8 @@ void WebViewCore::rebuildPictureSet(PictureSet* pictureSet) if (pictureSet->upToDate(index)) continue; const SkIRect& inval = pictureSet->bounds(index); - DBG_SET_LOGD("draw [%d] {%d,%d,w=%d,h=%d}", index, inval.fLeft, - inval.fTop, inval.width(), inval.height()); + DBG_SET_LOGD("pictSet=%p [%d] {%d,%d,w=%d,h=%d}", pictureSet, index, + inval.fLeft, inval.fTop, inval.width(), inval.height()); pictureSet->setPicture(index, rebuildPicture(inval)); } pictureSet->validate(__FUNCTION__); @@ -599,21 +603,13 @@ void WebViewCore::sendRecomputeFocus() checkException(env); } -void WebViewCore::viewInvalidate(const SkIRect& rect) -{ - 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_sendViewInvalidate, - rect.fLeft, rect.fTop, rect.fRight, rect.fBottom); - checkException(env); -} - void WebViewCore::viewInvalidate(const WebCore::IntRect& rect) -{ +{ 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_sendViewInvalidate, - rect.x(), rect.y(), rect.right(), rect.bottom()); + env->CallVoidMethod(m_javaGlue->object(env).get(), + m_javaGlue->m_sendViewInvalidate, + rect.x(), rect.y(), rect.right(), rect.bottom()); checkException(env); } @@ -749,12 +745,12 @@ void WebViewCore::setScrollOffset(int dx, int dy) if (m_scrollOffsetX != dx || m_scrollOffsetY != dy) { m_scrollOffsetX = dx; m_scrollOffsetY = dy; - m_mainFrame->sendScrollEvent(); // The visible rect is located within our coordinate space so it // contains the actual scroll position. Setting the location makes hit // testing work correctly. m_mainFrame->view()->platformWidget()->setLocation(m_scrollOffsetX, m_scrollOffsetY); + m_mainFrame->sendScrollEvent(); } } @@ -1011,7 +1007,10 @@ void WebViewCore::drawPlugins() if (!inval.isEmpty()) { // inval.getBounds() is our rectangle - this->viewInvalidate(inval.getBounds()); + const SkIRect& bounds = inval.getBounds(); + WebCore::IntRect r(bounds.fLeft, bounds.fTop, + bounds.width(), bounds.height()); + this->viewInvalidate(r); } } @@ -1021,7 +1020,7 @@ void WebViewCore::setFinalFocus(WebCore::Frame* frame, WebCore::Node* node, int x, int y, bool block) { DBG_NAV_LOGD("frame=%p node=%p x=%d y=%d", frame, node, x, y); - bool result = finalKitFocus(frame, node, x, y); + bool result = finalKitFocus(frame, node, x, y, false); if (block) { m_blockFocusChange = true; if (!result && node) @@ -1082,12 +1081,16 @@ bool WebViewCore::commonKitFocus(int generation, int buildGeneration, releaseFrameCache(newCache); if (!node && ignoreNullFocus) return true; - finalKitFocus(frame, node, x, y); + finalKitFocus(frame, node, x, y, false); return true; } +// Update mouse position and may change focused node. +// If donotChangeDOMFocus is true, the function does not changed focused node +// in the DOM tree. Changing the focus in DOM may trigger onblur event +// handler on the current focused node before firing mouse up and down events. bool WebViewCore::finalKitFocus(WebCore::Frame* frame, WebCore::Node* node, - int x, int y) + int x, int y, bool donotChangeDOMFocus) { if (!frame) frame = m_mainFrame; @@ -1103,41 +1106,48 @@ bool WebViewCore::finalKitFocus(WebCore::Frame* frame, WebCore::Node* node, WebCore::MouseEventMoved, 1, false, false, false, false, WebCore::currentTime()); frame->eventHandler()->handleMouseMoveEvent(mouseEvent); } - WebCore::Document* oldDoc = oldFocusNode ? oldFocusNode->document() : 0; - if (!node) { - if (oldFocusNode) - oldDoc->setFocusedNode(0); - return false; - } else if (!valid) { - DBG_NAV_LOGD("sendMarkNodeInvalid node=%p", node); - sendMarkNodeInvalid(node); - if (oldFocusNode) + + if (!donotChangeDOMFocus) { + WebCore::Document* oldDoc = oldFocusNode ? oldFocusNode->document() : 0; + if (!node) { + if (oldFocusNode) + oldDoc->setFocusedNode(0); + return false; + } else if (!valid) { + DBG_NAV_LOGD("sendMarkNodeInvalid node=%p", node); + sendMarkNodeInvalid(node); + if (oldFocusNode) + oldDoc->setFocusedNode(0); + return false; + } + // If we jump frames (docs), kill the focus on the old doc + if (oldFocusNode && node->document() != oldDoc) { oldDoc->setFocusedNode(0); - return false; - } - // If we jump frames (docs), kill the focus on the old doc - builder.setLastFocus(node); - if (oldFocusNode && node->document() != oldDoc) { - oldDoc->setFocusedNode(0); - } - if (!node->isTextNode()) - static_cast<WebCore::Element*>(node)->focus(false); - if (node->document()->focusedNode() != node) { - // This happens when Element::focus() fails as we may try to set the - // focus to a node which WebCore doesn't recognize as a focusable node. - // So we need to do some extra work, as it does in Element::focus(), - // besides calling Document::setFocusedNode. - if (oldFocusNode) { - // copied from clearSelectionIfNeeded in FocusController.cpp - WebCore::SelectionController* s = oldDoc->frame()->selection(); - if (!s->isNone()) - s->clear(); } - //setFocus on things that WebCore doesn't recognize as supporting focus - //for instance, if there is an onclick element that does not support focus - node->document()->setFocusedNode(node); + if (!node->isTextNode()) + static_cast<WebCore::Element*>(node)->focus(false); + if (node->document()->focusedNode() != node) { + // This happens when Element::focus() fails as we may try to set the + // focus to a node which WebCore doesn't recognize as a focusable node. + // So we need to do some extra work, as it does in Element::focus(), + // besides calling Document::setFocusedNode. + if (oldFocusNode) { + // copied from clearSelectionIfNeeded in FocusController.cpp + WebCore::SelectionController* s = oldDoc->frame()->selection(); + if (!s->isNone()) + s->clear(); + } + //setFocus on things that WebCore doesn't recognize as supporting focus + //for instance, if there is an onclick element that does not support focus + node->document()->setFocusedNode(node); + } + } else { // !donotChangeDOMFocus + if (!node || !valid) + return false; } + DBG_NAV_LOGD("setFocusedNode node=%p", node); + builder.setLastFocus(node); m_lastFocused = node; m_lastFocusedBounds = node->getRect(); return true; @@ -1175,7 +1185,7 @@ WebCore::Frame* WebViewCore::changedKitFocus(WebCore::Frame* frame, WebCore::Node* current = FrameLoaderClientAndroid::get(m_mainFrame)->getCacheBuilder().currentFocus(); if (current == node) return frame; - return finalKitFocus(frame, node, x, y) ? frame : m_mainFrame; + return finalKitFocus(frame, node, x, y, false) ? frame : m_mainFrame; } static int findTextBoxIndex(WebCore::Node* node, const WebCore::IntPoint& pt) @@ -1470,6 +1480,10 @@ public: // index is listIndex of the selected item, or -1 if nothing is selected. virtual void replyInt(int index) { + if (-2 == index) { + // Special value for cancel. Do nothing. + return; + } // If the select element no longer exists, do to a page change, etc, silently return. if (!m_select || !FrameLoaderClientAndroid::get(m_viewImpl->m_mainFrame)->getCacheBuilder().validNode(m_frame, m_select)) return; @@ -1493,8 +1507,8 @@ public: } // Response if the listbox allows multiple selection. array stores the listIndices - // of selected positions. - virtual void replyIntArray(const int* array, int count) + // of selected positions. + virtual void replyIntArray(const int* array, int count) { // If the select element no longer exists, do to a page change, etc, silently return. if (!m_select || !FrameLoaderClientAndroid::get(m_viewImpl->m_mainFrame)->getCacheBuilder().validNode(m_frame, m_select)) @@ -1540,9 +1554,9 @@ static jobjectArray makeLabelArray(JNIEnv* env, const uint16_t** labels, size_t void WebViewCore::listBoxRequest(WebCoreReply* reply, const uint16_t** labels, size_t count, const int enabled[], size_t enabledCount, bool multiple, const int selected[], size_t selectedCountOrSelection) { - // Reuse m_popupReply - Release(m_popupReply); - m_popupReply = 0; + // If m_popupReply is not null, then we already have a list showing. + if (m_popupReply != 0) + return; LOG_ASSERT(m_javaGlue->m_obj, "No java widget associated with this view!"); @@ -1661,7 +1675,7 @@ void WebViewCore::touchUp(int touchGeneration, int buildGeneration, return; // short circuit if a newer touch has been generated } if (retry) - finalKitFocus(frame, node, x, y); + finalKitFocus(frame, node, x, y, true); // don't change DOM focus else if (!commonKitFocus(touchGeneration, buildGeneration, frame, node, x, y, false)) { return; @@ -1692,7 +1706,7 @@ bool WebViewCore::handleMouseClick(WebCore::Frame* framePtr, WebCore::Node* node // so when attempting to get the default, the point chosen would be follow the wrong link. if (nodePtr->hasTagName(WebCore::HTMLNames::areaTag)) { webFrame->setUserInitiatedClick(true); - WebCore::EventTargetNodeCast(nodePtr)->dispatchSimulatedClick(0, + WebCore::EventTargetNodeCast(nodePtr)->dispatchSimulatedClick(0, true, true); webFrame->setUserInitiatedClick(false); return true; @@ -1940,7 +1954,7 @@ static void SetScrollOffset(JNIEnv *env, jobject obj, jint dx, jint dy) viewImpl->setScrollOffset(dx, dy); } -static void SetGlobalBounds(JNIEnv *env, jobject obj, jint x, jint y, jint h, +static void SetGlobalBounds(JNIEnv *env, jobject obj, jint x, jint y, jint h, jint v) { WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj); @@ -1949,7 +1963,7 @@ static void SetGlobalBounds(JNIEnv *env, jobject obj, jint x, jint y, jint h, viewImpl->setGlobalBounds(x, y, h, v); } -static jboolean Key(JNIEnv *env, jobject obj, jint keyCode, jint unichar, +static jboolean Key(JNIEnv *env, jobject obj, jint keyCode, jint unichar, jint repeatCount, jboolean isShift, jboolean isAlt, jboolean isDown) { #ifdef ANDROID_INSTRUMENT diff --git a/WebKit/android/jni/WebViewCore.h b/WebKit/android/jni/WebViewCore.h index fcd5574..29bdf37 100644 --- a/WebKit/android/jni/WebViewCore.h +++ b/WebKit/android/jni/WebViewCore.h @@ -119,9 +119,11 @@ namespace android { */ void contentDraw(); - // invalidate the view/display, NOT the content/DOM + /** Invalidate the view/screen, NOT the content/DOM, but expressed in + * content/DOM coordinates (i.e. they need to eventually be scaled, + * by webview into view.java coordinates + */ void viewInvalidate(const WebCore::IntRect& rect); - void viewInvalidate(const SkIRect& rect); /** * Invalidate part of the content that may be offscreen at the moment @@ -381,6 +383,7 @@ namespace android { WebCore::Node* m_snapAnchorNode; int m_screenWidth; int m_scale; + unsigned m_domtree_version; SkTDArray<PluginWidgetAndroid*> m_plugins; WebCore::Timer<WebViewCore> m_pluginInvalTimer; @@ -393,7 +396,7 @@ namespace android { bool commonKitFocus(int generation, int buildGeneration, WebCore::Frame* frame, WebCore::Node* node, int x, int y, bool ignoreNullFocus); - bool finalKitFocus(WebCore::Frame* frame, WebCore::Node* node, int x, int y); + bool finalKitFocus(WebCore::Frame* frame, WebCore::Node* node, int x, int y, bool donotChangeDOMFocus); void doMaxScroll(CacheBuilder::Direction dir); SkPicture* rebuildPicture(const SkIRect& inval); void rebuildPictureSet(PictureSet* ); diff --git a/WebKit/android/nav/CacheBuilder.cpp b/WebKit/android/nav/CacheBuilder.cpp index 1323581..9efcbd7 100644 --- a/WebKit/android/nav/CacheBuilder.cpp +++ b/WebKit/android/nav/CacheBuilder.cpp @@ -453,14 +453,16 @@ void CacheBuilder::Debug::groups() { } else print("\"\""); RenderObject* renderer = node->renderer(); + int tabindex = node->isElementNode() ? node->tabIndex() : 0; if (renderer) { const IntRect& absB = renderer->absoluteBoundingBoxRect(); - snprintf(scratch, sizeof(scratch), ", {%d, %d, %d, %d}, %s},", - absB.x(), absB.y(), absB.width(), absB.height(), - renderer->hasOverflowClip() ? "true" : "false"); + snprintf(scratch, sizeof(scratch), ", {%d, %d, %d, %d}, %s" + ", %d},",absB.x(), absB.y(), absB.width(), absB.height(), + renderer->hasOverflowClip() ? "true" : "false", tabindex); print(scratch); } else - print(", {0, 0, 0, 0}, false},"); + print(", {0, 0, 0, 0}, false, 0},"); + flush(); snprintf(scratch, sizeof(scratch), "// %d: ", count); mPrefix = "\n// "; @@ -945,6 +947,11 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame, ClipColumnTracker* baseTracker = clipTracker.data(); // sentinel bzero(baseTracker, sizeof(ClipColumnTracker)); } + WTF::Vector<TabIndexTracker> tabIndexTracker(1); + { + TabIndexTracker* baseTracker = tabIndexTracker.data(); // sentinel + bzero(baseTracker, sizeof(TabIndexTracker)); + } #if DUMP_NAV_CACHE char* frameNamePtr = cachedFrame->mDebug.mFrameName; Builder(frame)->mDebug.frameName(frameNamePtr, frameNamePtr + @@ -964,8 +971,10 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame, Node* node = parent; int cacheIndex = 1; Node* focused = doc->focusedNode(); - if (focused) + if (focused) { setLastFocus(focused); + cachedRoot->setFocusBounds(mLastKnownFocusBounds); + } int globalOffsetX, globalOffsetY; GetGlobalOffset(frame, &globalOffsetX, &globalOffsetY); while (walk.mMore || (node = node->traverseNextNode()) != NULL) { @@ -989,6 +998,12 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame, break; clipTracker.removeLast(); } while (true); + do { + const TabIndexTracker* lastTabIndex = &tabIndexTracker.last(); + if (node != lastTabIndex->mLastChild) + break; + tabIndexTracker.removeLast(); + } while (true); Frame* child = HasFrame(node); CachedNode cachedNode; if (child != NULL) { @@ -1014,6 +1029,17 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame, BuildFrame(root, child, cachedRoot, childPtr); continue; } + int tabIndex = node->tabIndex(); + Node* lastChild = node->lastChild(); + if (tabIndex <= 0) + tabIndex = tabIndexTracker.last().mTabIndex; + else if (tabIndex > 0 && lastChild) { + DBG_NAV_LOGD("tabIndex=%d node=%p", tabIndex, node); + tabIndexTracker.grow(tabIndexTracker.size() + 1); + TabIndexTracker& indexTracker = tabIndexTracker.last(); + indexTracker.mTabIndex = tabIndex; + indexTracker.mLastChild = OneAfter(lastChild); + } RenderObject* nodeRenderer = node->renderer(); bool isTransparent = false; bool hasFocusRing = true; @@ -1066,7 +1092,6 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame, CachedNodeType type = NORMAL_CACHEDNODETYPE; IntRect bounds; IntRect absBounds; - Node* lastChild = node->lastChild(); WTF::Vector<IntRect>* columns = NULL; if (isArea) { HTMLAreaElement* area = static_cast<HTMLAreaElement*>(node); @@ -1171,7 +1196,7 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame, else if (node->hasTagName(HTMLNames::aTag)) { const HTMLAnchorElement* anchorNode = (const HTMLAnchorElement*) node; - if (anchorNode->isFocusable() == false) + if (!anchorNode->isFocusable() && !HasTriggerEvent(node)) continue; EventTargetNode* target = (EventTargetNode*) node; if (target->disabled()) @@ -1290,6 +1315,7 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame, if (last->mParentLastChild == NULL) last->mParentLastChild = OneAfter(node->parentNode()->lastChild()); cachedNode.setParentGroup(last->mParentLastChild); + cachedNode.setTabIndex(tabIndex); cachedNode.setTextSize(textSize); cachedNode.setType(type); cachedNode.setWantsKeyEvents(wantsKeyEvents); @@ -1316,8 +1342,6 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame, } } cacheIndex++; -tryNextNode: - ; } while (tracker.size() > 1) { Tracker* last = &tracker.last(); @@ -2961,7 +2985,8 @@ bool CacheBuilder::ConstructPartRects(Node* node, const IntRect& bounds, clip.mNode = test; } while (test != last && (test = test->traverseNextNode()) != NULL); } - if (result->size() == 0) { + if (result->size() == 0 || focusBounds->width() < MINIMUM_FOCUSABLE_WIDTH + || focusBounds->height() < MINIMUM_FOCUSABLE_HEIGHT) { if (bounds.width() < MINIMUM_FOCUSABLE_WIDTH) return false; if (bounds.height() < MINIMUM_FOCUSABLE_HEIGHT) diff --git a/WebKit/android/nav/CacheBuilder.h b/WebKit/android/nav/CacheBuilder.h index 7d5404d..07040e2 100644 --- a/WebKit/android/nav/CacheBuilder.h +++ b/WebKit/android/nav/CacheBuilder.h @@ -177,8 +177,13 @@ private: TextDirection mDirection; bool mHasClip; }; + struct TabIndexTracker { + int mTabIndex; + Node* mLastChild; + }; struct Tracker { int mCachedNodeIndex; + int mTabIndex; Node* mLastChild; Node* mParentLastChild; bool mSomeParentTakesFocus; diff --git a/WebKit/android/nav/CachedDebug.h b/WebKit/android/nav/CachedDebug.h index 42c6363..3127112 100644 --- a/WebKit/android/nav/CachedDebug.h +++ b/WebKit/android/nav/CachedDebug.h @@ -43,19 +43,8 @@ #endif #if DEBUG_NAV_UI -#define DBG_NAV_LOGD_NO_PARAM 0 /* needed so we can call (format, ...) */ -#define DBG_NAV_LOG_THROTTLE_INTERVAL 1000 #define DBG_NAV_LOG(message) LOGD("%s %s", __FUNCTION__, message) #define DBG_NAV_LOGD(format, ...) LOGD("%s " format, __FUNCTION__, __VA_ARGS__) -#define DBG_NAV_LOGD_THROTTLE(format, ...) \ -do { \ - static uint32_t gPrevLogTime = 0; \ - uint32_t curTime = SkTime::GetMSecs(); \ - if (curTime - gPrevLogTime > DBG_NAV_LOG_THROTTLE_INTERVAL) { \ - LOGD("%s " format, __FUNCTION__, __VA_ARGS__); \ - gPrevLogTime = curTime; \ - } \ -} while (false) #define DEBUG_NAV_UI_LOGD(...) LOGD(__VA_ARGS__) #else #define DBG_NAV_LOG(message) ((void)0) diff --git a/WebKit/android/nav/CachedFrame.cpp b/WebKit/android/nav/CachedFrame.cpp index 0231394..4db9e40 100644 --- a/WebKit/android/nav/CachedFrame.cpp +++ b/WebKit/android/nav/CachedFrame.cpp @@ -125,6 +125,14 @@ void CachedFrame::clearFocus() // returns 0 if test is preferable to best, 1 if not preferable, or -1 if unknown int CachedFrame::compare(BestData& testData, const BestData& bestData, const CachedNode* focus) const { + if (testData.mNode->tabIndex() != bestData.mNode->tabIndex()) { + if (testData.mNode->tabIndex() < bestData.mNode->tabIndex() + || (focus && focus->tabIndex() < bestData.mNode->tabIndex())) { + testData.mNode->setCondition(CachedNode::HIGHER_TAB_INDEX); + return REJECT_TEST; + } + return TEST_IS_BEST; + } // start here; // if the test minor axis line intersects the line segment between focus center and best center, choose it // give more weight to exact major axis alignment (rows, columns) @@ -662,7 +670,7 @@ int CachedFrame::frameNodeCommon(BestData& testData, const CachedNode* test, Bes testData.mNode->setCondition(CachedNode::NOT_FOCUS_NODE); return REJECT_TEST; } -// if (test->bounds().contains(history()->focusBounds())) { +// if (test->bounds().contains(mRoot->focusBounds())) { // testData.mNode->setCondition(CachedNode::NOT_ENCLOSING_FOCUS); // return REJECT_TEST; // } @@ -733,7 +741,7 @@ int CachedFrame::frameNodeCommon(BestData& testData, const CachedNode* test, Bes int CachedFrame::framePartCommon(BestData& testData, const CachedNode* test, BestData* bestData, const CachedNode* focus) const { - if (testData.mNodeBounds.contains(history()->focusBounds())) { + if (testData.mNodeBounds.contains(mRoot->focusBounds())) { testData.mNode->setCondition(CachedNode::NOT_ENCLOSING_FOCUS); return REJECT_TEST; } diff --git a/WebKit/android/nav/CachedHistory.cpp b/WebKit/android/nav/CachedHistory.cpp index ba94c72..f75f237 100644 --- a/WebKit/android/nav/CachedHistory.cpp +++ b/WebKit/android/nav/CachedHistory.cpp @@ -82,7 +82,7 @@ void CachedHistory::reset() { memset(mVisited, 0, sizeof(mVisited)); // mLastScroll = 0; - mPriorBounds = mFocusBounds = WebCore::IntRect(0, 0, 0, 0); + mPriorBounds = WebCore::IntRect(0, 0, 0, 0); mDirectionChange = false; mFocusIsInput = false; mPriorIsInput = false; @@ -107,12 +107,11 @@ void CachedHistory::setWorking(CachedFrame::Direction newMove, if (focus != NULL) { WebCore::IntRect focusBounds; focus->getBounds(&focusBounds); - if (focusBounds.isEmpty() == false && focusBounds != mFocusBounds) - mNavBounds = mFocusBounds = focusBounds; + if (focusBounds.isEmpty() == false) + mNavBounds = focusBounds; mPriorIsInput = mFocusIsInput; mFocusIsInput = focus->isInput(); // focus->localName() == "input"; - } else - mFocusBounds = WebCore::IntRect(0, 0, 0, 0); + } if (change) { // uninitialized or change in direction if (lastAxis != CachedFrame::LEFT && navBounds->height() > 0) { mMinWorkingHorizontal = navBounds->y(); @@ -177,7 +176,6 @@ void CachedHistory::Debug::print(CachedRoot* root) const } DUMP_NAV_LOGD("// };\n"); // DUMP_NAV_LOGD("// int mLastScroll=%d;\n", b->mLastScroll); - DEBUG_PRINT_RECT(mFocusBounds); DEBUG_PRINT_RECT(mNavBounds); DEBUG_PRINT_RECT(mPriorBounds); DEBUG_PRINT_BOOL(mDirectionChange); diff --git a/WebKit/android/nav/CachedHistory.h b/WebKit/android/nav/CachedHistory.h index 490ed67..e48d44b 100644 --- a/WebKit/android/nav/CachedHistory.h +++ b/WebKit/android/nav/CachedHistory.h @@ -43,7 +43,6 @@ public: bool checkVisited(const CachedNode* , CachedFrame::Direction ) const; bool didFirstLayout() const { return mDidFirstLayout; } bool directionChange() const { return mDirectionChange; } - const WebCore::IntRect& focusBounds() const { return mFocusBounds; } int minWorkingHorizontal() const { return mMinWorkingHorizontal; } int minWorkingVertical() const { return mMinWorkingVertical; } int maxWorkingHorizontal() const { return mMaxWorkingHorizontal; } @@ -61,7 +60,6 @@ private: const CachedNode* mNode; CachedFrame::Direction mDirection; } mVisited[NAVIGATION_VISIT_DEPTH]; - WebCore::IntRect mFocusBounds; // chosen focus ring WebCore::IntRect mMouseBounds; // constricted bounds, if focus ring is partially visible WebCore::IntRect mNavBounds; // focus ring bounds plus optional keystroke movement WebCore::IntRect mPriorBounds; // prior chosen focus ring (for reversing narrowing) diff --git a/WebKit/android/nav/CachedNode.cpp b/WebKit/android/nav/CachedNode.cpp index e6ade3e..b786677 100644 --- a/WebKit/android/nav/CachedNode.cpp +++ b/WebKit/android/nav/CachedNode.cpp @@ -263,6 +263,7 @@ const char* CachedNode::Debug::condition(Condition t) const case BEST_DIRECTION: return "BEST_DIRECTION"; break; case CHILD: return "CHILD"; break; case DISABLED: return "DISABLED"; break; + case HIGHER_TAB_INDEX: return "HIGHER_TAB_INDEX"; break; case IN_FOCUS: return "IN_FOCUS"; break; case IN_FOCUS_CHILDREN: return "IN_FOCUS_CHILDREN"; break; case NOT_ENCLOSING_FOCUS: return "NOT_ENCLOSING_FOCUS"; break; @@ -300,6 +301,7 @@ void CachedNode::Debug::print() const scratch[index++] = *ch++; DUMP_NAV_LOGD("%.*s\"\n", index, scratch); DEBUG_PRINT_RECT(mBounds); + DEBUG_PRINT_RECT(mHitBounds); const WTF::Vector<WebCore::IntRect>& rects = b->focusRings(); size_t size = rects.size(); DUMP_NAV_LOGD("// IntRect focusRings={ // size=%d\n", size); @@ -315,11 +317,13 @@ void CachedNode::Debug::print() const DUMP_NAV_LOGD("// int mNavableRects=%d;\n", b->mNavableRects); DUMP_NAV_LOGD("// int mParentIndex=%d;\n", b->mParentIndex); DUMP_NAV_LOGD("// int mTextSize=%d;\n", b->mTextSize); + DUMP_NAV_LOGD("// int mTabIndex=%d;\n", b->mTabIndex); DUMP_NAV_LOGD("// Condition mCondition=%s;\n", condition(b->mCondition)); DUMP_NAV_LOGD("// Type mType=%s;\n", type(b->mType)); DEBUG_PRINT_BOOL(mClippedOut); DEBUG_PRINT_BOOL(mDisabled); DEBUG_PRINT_BOOL(mFixedUpFocusRects); + DEBUG_PRINT_BOOL(mHasFocusRing); DEBUG_PRINT_BOOL(mHasMouseOver); DEBUG_PRINT_BOOL(mIsAnchor); DEBUG_PRINT_BOOL(mIsArea); @@ -327,11 +331,13 @@ void CachedNode::Debug::print() const DEBUG_PRINT_BOOL(mIsInput); DEBUG_PRINT_BOOL(mIsParentAnchor); DEBUG_PRINT_BOOL(mIsPassword); + DEBUG_PRINT_BOOL(mIsRtlText); DEBUG_PRINT_BOOL(mIsTextArea); DEBUG_PRINT_BOOL(mIsTextField); DEBUG_PRINT_BOOL(mIsTransparent); DEBUG_PRINT_BOOL(mIsUnclipped); DEBUG_PRINT_BOOL(mLast); + DEBUG_PRINT_BOOL(mWantsKeyEvents); DUMP_NAV_LOGD("\n"); } diff --git a/WebKit/android/nav/CachedNode.h b/WebKit/android/nav/CachedNode.h index 6cb1ca3..aa64982 100644 --- a/WebKit/android/nav/CachedNode.h +++ b/WebKit/android/nav/CachedNode.h @@ -69,6 +69,7 @@ public: BEST_DIRECTION, // can be reached by another direction CHILD, DISABLED, + HIGHER_TAB_INDEX, IN_FOCUS, IN_FOCUS_CHILDREN, NOT_ENCLOSING_FOCUS, @@ -160,9 +161,11 @@ public: void setNavableRects() { mNavableRects = mFocusRing.size(); } void setParentGroup(void* group) { mParentGroup = group; } void setParentIndex(int parent) { mParentIndex = parent; } + void setTabIndex(int index) { mTabIndex = index; } void setTextSize(int textSize) { mTextSize = textSize; } void setType(CachedNodeType type) { mType = type; } void setWantsKeyEvents(bool wantsKeys) { mWantsKeyEvents = wantsKeys; } + int tabIndex() const { return mTabIndex; } const CachedNode* traverseNextNode() const { return mLast ? NULL : &this[1]; } int textSize() const { return mTextSize; } CachedNodeType type() const { return mType; } @@ -180,6 +183,7 @@ private: int mNavableRects; // FIXME: could be bitfield once I limit max number of rects int mParentIndex; int mTextSize; + int mTabIndex; mutable Condition mCondition : 5; // why the node was not chosen on the first pass CachedNodeType mType : 3; bool mClippedOut : 1; diff --git a/WebKit/android/nav/CachedRoot.cpp b/WebKit/android/nav/CachedRoot.cpp index 8e0833d..4a50c80 100644 --- a/WebKit/android/nav/CachedRoot.cpp +++ b/WebKit/android/nav/CachedRoot.cpp @@ -670,8 +670,8 @@ bool CachedRoot::innerDown(const CachedNode* test, BestData* bestData) const mScrolledBounds.setHeight(mScrolledBounds.height() + mMaxYScroll); int testTop = mScrolledBounds.y(); int viewBottom = mViewBounds.bottom(); - if (mHistory->mFocusBounds.isEmpty() == false && - mHistory->mFocusBounds.bottom() > viewBottom && viewBottom < mContents.height()) + if (mFocusBounds.isEmpty() == false && + mFocusBounds.bottom() > viewBottom && viewBottom < mContents.height()) return false; if (mHistory->mNavBounds.isEmpty() == false) { int navTop = mHistory->mNavBounds.y(); @@ -694,8 +694,8 @@ bool CachedRoot::innerLeft(const CachedNode* test, BestData* bestData) const mScrolledBounds.setWidth(mScrolledBounds.width() + mMaxXScroll); int testRight = mScrolledBounds.right(); int viewLeft = mViewBounds.x(); - if (mHistory->mFocusBounds.isEmpty() == false && - mHistory->mFocusBounds.x() < viewLeft && viewLeft > mContents.x()) + if (mFocusBounds.isEmpty() == false && + mFocusBounds.x() < viewLeft && viewLeft > mContents.x()) return false; if (mHistory->mNavBounds.isEmpty() == false) { int navRight = mHistory->mNavBounds.right(); @@ -721,7 +721,11 @@ void CachedRoot::innerMove(const CachedNode* node, BestData* bestData, #endif if (firstTime) mHistory->reset(); - mHistory->setWorking(direction, currentFocus(), mViewBounds); + const CachedNode* focus = currentFocus(); + mHistory->setWorking(direction, focus, mViewBounds); + mFocusBounds = WebCore::IntRect(0, 0, 0, 0); + if (focus != NULL) + focus->getBounds(&mFocusBounds); bool findClosest = false; if (mScrollOnly == false) { switch (direction) { @@ -761,7 +765,7 @@ void CachedRoot::innerMove(const CachedNode* node, BestData* bestData, return; if (bestData->mNode != NULL) { mHistory->addToVisited(bestData->mNode, direction); - mHistory->mNavBounds = mHistory->mFocusBounds = bestData->mNodeBounds; + mHistory->mNavBounds = mFocusBounds = bestData->mNodeBounds; mHistory->mMouseBounds = bestData->mMouseBounds; } else if (scroll->x() != 0 || scroll->y() != 0) { WebCore::IntRect newBounds = mHistory->mNavBounds; @@ -790,8 +794,8 @@ bool CachedRoot::innerRight(const CachedNode* test, BestData* bestData) const mScrolledBounds.setWidth(mScrolledBounds.width() + mMaxXScroll); int testLeft = mScrolledBounds.x(); int viewRight = mViewBounds.right(); - if (mHistory->mFocusBounds.isEmpty() == false && - mHistory->mFocusBounds.right() > viewRight && viewRight < mContents.width()) + if (mFocusBounds.isEmpty() == false && + mFocusBounds.right() > viewRight && viewRight < mContents.width()) return false; if (mHistory->mNavBounds.isEmpty() == false) { int navLeft = mHistory->mNavBounds.x(); @@ -814,8 +818,8 @@ bool CachedRoot::innerUp(const CachedNode* test, BestData* bestData) const mScrolledBounds.setHeight(mScrolledBounds.height() + mMaxYScroll); int testBottom = mScrolledBounds.bottom(); int viewTop = mViewBounds.y(); - if (mHistory->mFocusBounds.isEmpty() == false && - mHistory->mFocusBounds.y() < viewTop && viewTop > mContents.y()) + if (mFocusBounds.isEmpty() == false && + mFocusBounds.y() < viewTop && viewTop > mContents.y()) return false; if (mHistory->mNavBounds.isEmpty() == false) { int navBottom = mHistory->mNavBounds.bottom(); @@ -972,7 +976,7 @@ void CachedRoot::reset() mMaxXScroll = mMaxYScroll = 0; mSelectionStart = mSelectionEnd = -1; mScrollOnly = false; -// resetNavClipBounds(); + mFocusBounds = WebCore::IntRect(0, 0, 0, 0); } bool CachedRoot::scrollDelta(WebCore::IntRect& newOutset, Direction direction, int* delta) @@ -1046,6 +1050,11 @@ void CachedRoot::setupScrolledBounds() const #define DEBUG_PRINT_BOOL(field) \ DUMP_NAV_LOGD("// bool " #field "=%s;\n", b->field ? "true" : "false") +#define DEBUG_PRINT_RECT(field) \ + { const WebCore::IntRect& r = b->field; \ + DUMP_NAV_LOGD("// IntRect " #field "={%d, %d, %d, %d};\n", \ + r.x(), r.y(), r.width(), r.height()); } + CachedRoot* CachedRoot::Debug::base() const { CachedRoot* nav = (CachedRoot*) ((char*) this - OFFSETOF(CachedRoot, mDebug)); return nav; @@ -1061,6 +1070,7 @@ void CachedRoot::Debug::print() const CachedRoot* b = base(); b->CachedFrame::mDebug.print(); b->mHistory->mDebug.print(b); + DEBUG_PRINT_RECT(mFocusBounds); DUMP_NAV_LOGD("// int mMaxXScroll=%d, mMaxYScroll=%d;\n", b->mMaxXScroll, b->mMaxYScroll); DEBUG_PRINT_BOOL(mFocusChild); diff --git a/WebKit/android/nav/CachedRoot.h b/WebKit/android/nav/CachedRoot.h index 85ddf95..ab1b823 100644 --- a/WebKit/android/nav/CachedRoot.h +++ b/WebKit/android/nav/CachedRoot.h @@ -47,6 +47,7 @@ public: int documentWidth() { return mContents.width(); } const CachedNode* findAt(const WebCore::IntRect& , const CachedFrame** , int* x, int* y) const; + const WebCore::IntRect& focusBounds() const { return mFocusBounds; } bool focusChild() const { return mFocusChild; } WebCore::IntPoint focusLocation() const; int generation() const { return mGeneration; } @@ -72,6 +73,7 @@ public: bool scrollDelta(WebCore::IntRect& focusRingBounds, Direction , int* delta); const WebCore::IntRect& scrolledBounds() const { return mScrolledBounds; } void setCachedFocus(CachedFrame* , CachedNode* ); + void setFocusBounds(const WebCore::IntRect& r) { mFocusBounds = r; } void setGeneration(int generation) { mGeneration = generation; } void setTextGeneration(int textGeneration) { mTextGeneration = textGeneration; } void setFocusChild(bool state) const { mFocusChild = state; } @@ -87,7 +89,7 @@ public: private: CachedHistory* mHistory; SkPicture* mPicture; - // WebCore::IntRect mClippedBounds; + WebCore::IntRect mFocusBounds; // chosen focus ring mutable WebCore::IntRect mScrolledBounds; // view bounds + amount visible as result of scroll int mGeneration; int mTextGeneration; diff --git a/WebKit/android/nav/WebView.cpp b/WebKit/android/nav/WebView.cpp index 64876ab..fc34c84 100644 --- a/WebKit/android/nav/WebView.cpp +++ b/WebKit/android/nav/WebView.cpp @@ -191,8 +191,11 @@ int count() m_start += triggerSize(); if (m_start == m_end) break; - if (m_start >= limit) - m_start -= sizeof(m_buffer); + if (m_start < limit) + continue; + m_start -= sizeof(m_buffer); + if (m_start == m_end) + break; } m_start = saveStart; DBG_NAV_LOGD("count=%d", result); @@ -671,24 +674,23 @@ void drawFocusRing(SkCanvas* canvas) { const CachedRoot* root = getFrameCache(AllowNewer); if (!root) { - DBG_NAV_LOGD_THROTTLE("!root", DBG_NAV_LOGD_NO_PARAM); + DBG_NAV_LOG("!root"); m_followedLink = false; return; } const CachedNode* node = root->currentFocus(); if (!node) { - DBG_NAV_LOGD_THROTTLE("!node", DBG_NAV_LOGD_NO_PARAM); + DBG_NAV_LOG("!node"); m_followedLink = false; return; } if (!node->hasFocusRing()) { - DBG_NAV_LOGD_THROTTLE("!node->hasFocusRing()", - DBG_NAV_LOGD_NO_PARAM); + DBG_NAV_LOG("!node->hasFocusRing()"); return; } const WTF::Vector<WebCore::IntRect>& rings = node->focusRings(); if (!rings.size()) { - DBG_NAV_LOGD_THROTTLE("!rings.size()", DBG_NAV_LOGD_NO_PARAM); + DBG_NAV_LOG("!rings.size()"); return; } @@ -714,7 +716,8 @@ void drawFocusRing(SkCanvas* canvas) SkRect sbounds; android_setrect(&sbounds, bounds); if (canvas->quickReject(sbounds, SkCanvas::kAA_EdgeType)) { - DBG_NAV_LOGD_THROTTLE("canvas->quickReject", DBG_NAV_LOGD_NO_PARAM); + DBG_NAV_LOG("canvas->quickReject"); + m_followedLink = false; return; } FocusRing::Flavor flavor = FocusRing::NORMAL_FLAVOR; @@ -727,7 +730,7 @@ void drawFocusRing(SkCanvas* canvas) } #if DEBUG_NAV_UI const WebCore::IntRect& ring = rings[0]; - DBG_NAV_LOGD_THROTTLE("cachedFocusNode=%d (nodePointer=%p) flavor=%s rings=%d" + DBG_NAV_LOGD("cachedFocusNode=%d (nodePointer=%p) flavor=%s rings=%d" " (%d, %d, %d, %d)", node->index(), node->nodePointer(), flavor == FocusRing::FAKE_FLAVOR ? "FAKE_FLAVOR" : flavor == FocusRing::INVALID_FLAVOR ? "INVALID_FLAVOR" : @@ -773,9 +776,16 @@ OutOfFocusFix fixOutOfDateFocus(bool useReplay) if (uiWidth != webWidth) { DBG_NAV_LOGD("uiWidth=%d webWidth=%d", uiWidth, webWidth); } else { - const WebCore::IntRect& cachedBounds = m_frameCacheUI->rootHistory()->focusBounds(); + const WebCore::IntRect& cachedBounds = m_frameCacheUI->focusBounds(); const CachedFrame* webFrame = 0; const CachedNode* webFocusNode = webRoot->currentFocus(&webFrame); + DBG_NAV_LOGD("cachedBounds=(%d,%d,w=%d,h=%d) cachedFrame=%p (%d)" + " webFocusNode=%p (%d) webFrame=%p (%d)", + cachedBounds.x(), cachedBounds.y(), + cachedBounds.width(), cachedBounds.height(), + cachedFrame, cachedFrame ? cachedFrame->indexInParent() : -1, + webFocusNode, webFocusNode ? webFocusNode->index() : -1, + webFrame, webFrame ? webFrame->indexInParent() : -1); if (webFocusNode && webFrame && webFrame->sameFrame(cachedFrame)) { if (useReplay && !m_replay.count()) { DBG_NAV_LOG("!m_replay.count()"); @@ -785,7 +795,10 @@ OutOfFocusFix fixOutOfDateFocus(bool useReplay) DBG_NAV_LOG("index =="); return DoNothing; } - const WebCore::IntRect& webBounds = webRoot->rootHistory()->focusBounds(); + const WebCore::IntRect& webBounds = webRoot->focusBounds(); + DBG_NAV_LOGD("webBounds=(%d,%d,w=%d,h=%d)", + webBounds.x(), webBounds.y(), + webBounds.width(), webBounds.height()); if (cachedBounds.contains(webBounds)) { DBG_NAV_LOG("contains"); return DoNothing; @@ -794,18 +807,7 @@ OutOfFocusFix fixOutOfDateFocus(bool useReplay) DBG_NAV_LOG("webBounds contains"); return DoNothing; } - DBG_NAV_LOGD("cachedBounds=(%d,%d,w=%d,h=%d) webBounds=(%d,%d,w=%d," - "%h=d)", cachedBounds.x(), cachedBounds.y(), - cachedBounds.width(), cachedBounds.height(), webBounds.x(), - webBounds.y(), webBounds.width(), webBounds.height()); - } else - DBG_NAV_LOGD("cachedBounds=(%d,%d,w=%d,h=%d) cachedFrame=%p (%d)" - " webFocusNode=%p (%d) webFrame=%p (%d)", - cachedBounds.x(), cachedBounds.y(), - cachedBounds.width(), cachedBounds.height(), - cachedFrame, cachedFrame ? cachedFrame->indexInParent() : -1, - webFocusNode, webFocusNode ? webFocusNode->index() : -1, - webFrame, webFrame ? webFrame->indexInParent() : -1); + } const CachedFrame* foundFrame = 0; int x, y; const CachedNode* found = findAt(webRoot, cachedBounds, &foundFrame, &x, &y); @@ -1023,7 +1025,8 @@ bool moveFocus(int keyCode, int count, bool ignoreScroll, bool inval, int dx = 0; int dy = 0; int counter = count; - root->setScrollOnly(m_followedLink); + if (!focus || !focus->isInput() || !m_followedLink) + root->setScrollOnly(m_followedLink); while (--counter >= 0) { WebCore::IntPoint scroll = WebCore::IntPoint(0, 0); cachedNode = root->moveFocus(direction, &cachedFrame, &scroll); @@ -1086,7 +1089,7 @@ bool moveFocus(int keyCode, int count, bool ignoreScroll, bool inval, m_replay.add(params.d.d, sizeof(params)); } } else { - if (visibleRect.intersects(root->rootHistory()->focusBounds()) == false) { + if (visibleRect.intersects(root->focusBounds()) == false) { setFocusData(root->generation(), 0, 0, 0, 0, true); sendKitFocus(); // will build cache and retry } diff --git a/WebKit/android/plugins/ANPCanvasInterface.cpp b/WebKit/android/plugins/ANPCanvasInterface.cpp index 96498ef..ba79691 100644 --- a/WebKit/android/plugins/ANPCanvasInterface.cpp +++ b/WebKit/android/plugins/ANPCanvasInterface.cpp @@ -69,6 +69,31 @@ static void anp_clipPath(ANPCanvas* canvas, const ANPPath* path) { canvas->skcanvas->clipPath(*path); } +static void anp_getTotalMatrix(ANPCanvas* canvas, ANPMatrix* matrix) { + const SkMatrix& src = canvas->skcanvas->getTotalMatrix(); + *matrix = *reinterpret_cast<const ANPMatrix*>(&src); +} + +static bool anp_getLocalClipBounds(ANPCanvas* canvas, ANPRectF* r, + bool antialias) { + SkRect bounds; + if (canvas->skcanvas->getClipBounds(&bounds, + antialias ? SkCanvas::kAA_EdgeType : SkCanvas::kBW_EdgeType)) { + SkANP::SetRect(r, bounds); + return true; + } + return false; +} + +static bool anp_getDeviceClipBounds(ANPCanvas* canvas, ANPRectI* r) { + const SkRegion& clip = canvas->skcanvas->getTotalClip(); + if (!clip.isEmpty()) { + SkANP::SetRect(r, clip.getBounds()); + return true; + } + return false; +} + static void anp_drawColor(ANPCanvas* canvas, ANPColor color) { canvas->skcanvas->drawColor(color); } @@ -146,6 +171,9 @@ void ANPCanvasInterfaceV0_Init(ANPInterface* value) { ASSIGN(i, skew); ASSIGN(i, clipRect); ASSIGN(i, clipPath); + ASSIGN(i, getTotalMatrix); + ASSIGN(i, getLocalClipBounds); + ASSIGN(i, getDeviceClipBounds); ASSIGN(i, drawColor); ASSIGN(i, drawPaint); ASSIGN(i, drawRect); diff --git a/WebKit/android/plugins/ANPMatrixInterface.cpp b/WebKit/android/plugins/ANPMatrixInterface.cpp new file mode 100644 index 0000000..815b954 --- /dev/null +++ b/WebKit/android/plugins/ANPMatrixInterface.cpp @@ -0,0 +1,168 @@ +/* + * Copyright 2009, 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 APPLE COMPUTER, INC. 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. + */ + +// must include config.h first for webkit to fiddle with new/delete +#include "config.h" +#include "SkANP.h" + +#ifdef SK_SCALAR_IS_FIXED +static void fromFloat(SkScalar dst[], const float src[], int n) { + for (int i = 0; i < n; i++) { + dst[i] = SkFloatToScalar(src[i]); + } +} + +static void toFloat(float dst[], const SkScalar src[], int n) { + for (int i = 0; i < n; i++) { + dst[i] = SkScalarToFloat(src[i]); + } +} +#endif + +static ANPMatrix* anp_newMatrix() { + return new ANPMatrix; +} + +static void anp_deleteMatrix(ANPMatrix* matrix) { + delete matrix; +} + +static ANPMatrixFlag anp_getFlags(const ANPMatrix* matrix) { + return matrix->getType(); +} + +static void anp_copy(ANPMatrix* dst, const ANPMatrix* src) { + *dst = *src; +} + +static void anp_get3x3(const ANPMatrix* matrix, float dst[9]) { + for (int i = 0; i < 9; i++) { + dst[i] = SkScalarToFloat(matrix->get(i)); + } +} + +static void anp_set3x3(ANPMatrix* matrix, const float src[9]) { + for (int i = 0; i < 9; i++) { + matrix->set(i, SkFloatToScalar(src[i])); + } +} + +static void anp_setIdentity(ANPMatrix* matrix) { + matrix->reset(); +} + +static void anp_preTranslate(ANPMatrix* matrix, float tx, float ty) { + matrix->preTranslate(SkFloatToScalar(tx), SkFloatToScalar(ty)); +} + +static void anp_postTranslate(ANPMatrix* matrix, float tx, float ty) { + matrix->postTranslate(SkFloatToScalar(tx), SkFloatToScalar(ty)); +} + +static void anp_preScale(ANPMatrix* matrix, float sx, float sy) { + matrix->preScale(SkFloatToScalar(sx), SkFloatToScalar(sy)); +} + +static void anp_postScale(ANPMatrix* matrix, float sx, float sy) { + matrix->postScale(SkFloatToScalar(sx), SkFloatToScalar(sy)); +} + +static void anp_preSkew(ANPMatrix* matrix, float kx, float ky) { + matrix->preSkew(SkFloatToScalar(kx), SkFloatToScalar(ky)); +} + +static void anp_postSkew(ANPMatrix* matrix, float kx, float ky) { + matrix->postSkew(SkFloatToScalar(kx), SkFloatToScalar(ky)); +} + +static void anp_preRotate(ANPMatrix* matrix, float degrees) { + matrix->preRotate(SkFloatToScalar(degrees)); +} + +static void anp_postRotate(ANPMatrix* matrix, float degrees) { + matrix->postRotate(SkFloatToScalar(degrees)); +} + +static void anp_preConcat(ANPMatrix* matrix, const ANPMatrix* other) { + matrix->preConcat(*other); +} + +static void anp_postConcat(ANPMatrix* matrix, const ANPMatrix* other) { + matrix->postConcat(*other); +} + +static bool anp_invert(ANPMatrix* dst, const ANPMatrix* src) { + return src->invert(dst); +} + +static void anp_mapPoints(ANPMatrix* matrix, float dst[], const float src[], + int32_t count) { +#ifdef SK_SCALAR_IS_FLOAT + matrix->mapPoints(reinterpret_cast<SkPoint*>(dst), + reinterpret_cast<const SkPoint*>(src), count); +#else + const int N = 64; + SkPoint tmp[N]; + do { + int n = count; + if (n > N) { + n = N; + } + fromFloat(&tmp[0].fX, src, n*2); + matrix->mapPoints(tmp, n); + toFloat(dst, &tmp[0].fX, n*2); + count -= n; + } while (count > 0); +#endif +} + +/////////////////////////////////////////////////////////////////////////////// + +#define ASSIGN(obj, name) (obj)->name = anp_##name + +void ANPMatrixInterfaceV0_Init(ANPInterface* value) { + ANPMatrixInterfaceV0* i = reinterpret_cast<ANPMatrixInterfaceV0*>(value); + + ASSIGN(i, newMatrix); + ASSIGN(i, deleteMatrix); + ASSIGN(i, getFlags); + ASSIGN(i, copy); + ASSIGN(i, get3x3); + ASSIGN(i, set3x3); + ASSIGN(i, setIdentity); + ASSIGN(i, preTranslate); + ASSIGN(i, postTranslate); + ASSIGN(i, preScale); + ASSIGN(i, postScale); + ASSIGN(i, preSkew); + ASSIGN(i, postSkew); + ASSIGN(i, preRotate); + ASSIGN(i, postRotate); + ASSIGN(i, preConcat); + ASSIGN(i, postConcat); + ASSIGN(i, invert); + ASSIGN(i, mapPoints); +} + diff --git a/WebKit/android/plugins/ANPPaintInterface.cpp b/WebKit/android/plugins/ANPPaintInterface.cpp index 2a74b7f..4b561f0 100644 --- a/WebKit/android/plugins/ANPPaintInterface.cpp +++ b/WebKit/android/plugins/ANPPaintInterface.cpp @@ -158,6 +158,19 @@ static int anp_getTextWidths(ANPPaint* paint, const void* text, reinterpret_cast<SkRect*>(bounds)); } +static float anp_getFontMetrics(ANPPaint* paint, ANPFontMetrics* metrics) { + SkPaint::FontMetrics fm; + SkScalar spacing = paint->getFontMetrics(&fm); + if (metrics) { + metrics->fTop = SkScalarToFloat(fm.fTop); + metrics->fAscent = SkScalarToFloat(fm.fAscent); + metrics->fDescent = SkScalarToFloat(fm.fDescent); + metrics->fBottom = SkScalarToFloat(fm.fBottom); + metrics->fLeading = SkScalarToFloat(fm.fLeading); + } + return SkScalarToFloat(spacing); +} + /////////////////////////////////////////////////////////////////////////////// #define ASSIGN(obj, name) (obj)->name = anp_##name @@ -195,5 +208,6 @@ void ANPPaintInterfaceV0_Init(ANPInterface* value) { ASSIGN(i, setTypeface); ASSIGN(i, measureText); ASSIGN(i, getTextWidths); + ASSIGN(i, getFontMetrics); } diff --git a/WebKit/android/plugins/SkANP.cpp b/WebKit/android/plugins/SkANP.cpp index 276dd8d..3912f99 100644 --- a/WebKit/android/plugins/SkANP.cpp +++ b/WebKit/android/plugins/SkANP.cpp @@ -48,6 +48,14 @@ ANPRectI* SkANP::SetRect(ANPRectI* dst, const SkIRect& src) { return dst; } +ANPRectF* SkANP::SetRect(ANPRectF* dst, const SkRect& src) { + dst->left = SkScalarToFloat(src.fLeft); + dst->top = SkScalarToFloat(src.fTop); + dst->right = SkScalarToFloat(src.fRight); + dst->bottom = SkScalarToFloat(src.fBottom); + return dst; +} + SkBitmap* SkANP::SetBitmap(SkBitmap* dst, const ANPBitmap& src) { SkBitmap::Config config = SkBitmap::kNo_Config; diff --git a/WebKit/android/plugins/SkANP.h b/WebKit/android/plugins/SkANP.h index 2389f0d..f319c9b 100644 --- a/WebKit/android/plugins/SkANP.h +++ b/WebKit/android/plugins/SkANP.h @@ -28,10 +28,14 @@ #include "android_npapi.h" #include "SkCanvas.h" +#include "SkMatrix.h" #include "SkPaint.h" #include "SkPath.h" #include "SkTypeface.h" +struct ANPMatrix : SkMatrix { +}; + struct ANPPath : SkPath { }; @@ -65,6 +69,7 @@ public: static SkRect* SetRect(SkRect* dst, const ANPRectF& src); static SkIRect* SetRect(SkIRect* dst, const ANPRectI& src); static ANPRectI* SetRect(ANPRectI* dst, const SkIRect& src); + static ANPRectF* SetRect(ANPRectF* dst, const SkRect& src); static SkBitmap* SetBitmap(SkBitmap* dst, const ANPBitmap& src); static bool SetBitmap(ANPBitmap* dst, const SkBitmap& src); diff --git a/WebKit/android/plugins/android_npapi.h b/WebKit/android/plugins/android_npapi.h index 8b05d0a..f64c8ce 100644 --- a/WebKit/android/plugins/android_npapi.h +++ b/WebKit/android/plugins/android_npapi.h @@ -72,11 +72,21 @@ struct ANPRectI { }; struct ANPCanvas; +struct ANPMatrix; struct ANPPaint; struct ANPPath; struct ANPRegion; struct ANPTypeface; +enum ANPMatrixFlags { + kIdentity_ANPMatrixFlag = 0, + kTranslate_ANPMatrixFlag = 0x01, + kScale_ANPMatrixFlag = 0x02, + kAffine_ANPMatrixFlag = 0x04, + kPerspective_ANPMatrixFlag = 0x08, +}; +typedef uint32_t ANPMatrixFlag; + /////////////////////////////////////////////////////////////////////////////// // NPN_GetValue @@ -89,9 +99,10 @@ struct ANPTypeface; #define kLogInterfaceV0_ANPGetValue ((NPNVariable)1000) #define kAudioTrackInterfaceV0_ANPGetValue ((NPNVariable)1001) #define kCanvasInterfaceV0_ANPGetValue ((NPNVariable)1002) -#define kPaintInterfaceV0_ANPGetValue ((NPNVariable)1003) -#define kTypefaceInterfaceV0_ANPGetValue ((NPNVariable)1004) -#define kWindowInterfaceV0_ANPGetValue ((NPNVariable)1005) +#define kMatrixInterfaceV0_ANPGetValue ((NPNVariable)1003) +#define kPaintInterfaceV0_ANPGetValue ((NPNVariable)1004) +#define kTypefaceInterfaceV0_ANPGetValue ((NPNVariable)1005) +#define kWindowInterfaceV0_ANPGetValue ((NPNVariable)1006) /* queries for which drawing model is desired (for the draw event) @@ -148,6 +159,59 @@ struct ANPLogInterfaceV0 : ANPInterface { void (*log)(NPP instance, ANPLogType, const char format[], ...); }; +struct ANPMatrixInterfaceV0 : ANPInterface { + /* Return a new identity matrix + */ + ANPMatrix* (*newMatrix)(); + /* Delete a matrix previously allocated by newMatrix() + */ + void (*deleteMatrix)(ANPMatrix*); + + ANPMatrixFlag (*getFlags)(const ANPMatrix*); + + void (*copy)(ANPMatrix* dst, const ANPMatrix* src); + + /* Return the matrix values in a float array (allcoated by the caller), + where the values are treated as follows: + w = x * [6] + y * [7] + [8]; + x' = (x * [0] + y * [1] + [2]) / w; + y' = (x * [3] + y * [4] + [5]) / w; + */ + void (*get3x3)(const ANPMatrix*, float[9]); + /* Initialize the matrix from values in a float array, + where the values are treated as follows: + w = x * [6] + y * [7] + [8]; + x' = (x * [0] + y * [1] + [2]) / w; + y' = (x * [3] + y * [4] + [5]) / w; + */ + void (*set3x3)(ANPMatrix*, const float[9]); + + void (*setIdentity)(ANPMatrix*); + void (*preTranslate)(ANPMatrix*, float tx, float ty); + void (*postTranslate)(ANPMatrix*, float tx, float ty); + void (*preScale)(ANPMatrix*, float sx, float sy); + void (*postScale)(ANPMatrix*, float sx, float sy); + void (*preSkew)(ANPMatrix*, float kx, float ky); + void (*postSkew)(ANPMatrix*, float kx, float ky); + void (*preRotate)(ANPMatrix*, float degrees); + void (*postRotate)(ANPMatrix*, float degrees); + void (*preConcat)(ANPMatrix*, const ANPMatrix*); + void (*postConcat)(ANPMatrix*, const ANPMatrix*); + + /* Return true if src is invertible, and if so, return its inverse in dst. + If src is not invertible, return false and ignore dst. + */ + bool (*invert)(ANPMatrix* dst, const ANPMatrix* src); + + /* Transform the x,y pairs in src[] by this matrix, and store the results + in dst[]. The count parameter is treated as the number of pairs in the + array. It is legal for src and dst to point to the same memory, but + illegal for the two arrays to partially overlap. + */ + void (*mapPoints)(ANPMatrix*, float dst[], const float src[], + int32_t count); +}; + typedef uint32_t ANPColor; #define ANP_MAKE_COLOR(a, r, g, b) \ (((a) << 24) | ((r) << 16) | ((g) << 8) | (b)) @@ -202,6 +266,19 @@ enum ANPTypefaceStyles { }; typedef uint32_t ANPTypefaceStyle; +struct ANPFontMetrics { + //! The greatest distance above the baseline for any glyph (will be <= 0) + float fTop; + //! The recommended distance above the baseline (will be <= 0) + float fAscent; + //! The recommended distance below the baseline (will be >= 0) + float fDescent; + //! The greatest distance below the baseline for any glyph (will be >= 0) + float fBottom; + //! The recommended distance to add between lines of text (will be >= 0) + float fLeading; +}; + struct ANPTypefaceInterfaceV0 : ANPInterface { /** Return a new reference to the typeface that most closely matches the requested name and style. Pass null as the name to return @@ -311,6 +388,12 @@ struct ANPPaintInterfaceV0 : ANPInterface { */ int (*getTextWidths)(ANPPaint*, const void* text, uint32_t byteLength, float widths[], ANPRectF bounds[]); + + /** Return in metrics the spacing values for text, respecting the paint's + typeface and pointsize, and return the spacing between lines + (descent - ascent + leading). If metrics is NULL, it will be ignored. + */ + float (*getFontMetrics)(ANPPaint*, ANPFontMetrics* metrics); }; struct ANPCanvasInterfaceV0 : ANPInterface { @@ -334,8 +417,22 @@ struct ANPCanvasInterfaceV0 : ANPInterface { void (*scale)(ANPCanvas*, float sx, float sy); void (*rotate)(ANPCanvas*, float degrees); void (*skew)(ANPCanvas*, float kx, float ky); + void (*concat)(ANPCanvas*, const ANPMatrix*); void (*clipRect)(ANPCanvas*, const ANPRectF*); void (*clipPath)(ANPCanvas*, const ANPPath*); + + /* Return the current matrix on the canvas + */ + void (*getTotalMatrix)(ANPCanvas*, ANPMatrix*); + /* Return the current clip bounds in local coordinates, expanding it to + account for antialiasing edge effects if aa is true. If the + current clip is empty, return false and ignore the bounds argument. + */ + bool (*getLocalClipBounds)(ANPCanvas*, ANPRectF* bounds, bool aa); + /* Return the current clip bounds in device coordinates in bounds. If the + current clip is empty, return false and ignore the bounds argument. + */ + bool (*getDeviceClipBounds)(ANPCanvas*, ANPRectI* bounds); void (*drawColor)(ANPCanvas*, ANPColor); void (*drawPaint)(ANPCanvas*, const ANPPaint*); diff --git a/WebKit/android/plugins/sample/pluginGraphics.cpp b/WebKit/android/plugins/sample/pluginGraphics.cpp index 4c0e6f8..ffa43e5 100644 --- a/WebKit/android/plugins/sample/pluginGraphics.cpp +++ b/WebKit/android/plugins/sample/pluginGraphics.cpp @@ -145,9 +145,12 @@ void BallAnimation::draw(ANPCanvas* canvas) { bounce(&m_y, &m_dy, obj->window->height - OH); if (obj->mUnichar) { + ANPFontMetrics fm; + gPaintI.getFontMetrics(m_paint, &fm); + gPaintI.setColor(m_paint, 0xFF0000FF); char c = static_cast<char>(obj->mUnichar); - gCanvasI.drawText(canvas, &c, 1, 10, 30, m_paint); + gCanvasI.drawText(canvas, &c, 1, 10, -fm.fTop, m_paint); } } |