diff options
Diffstat (limited to 'WebKit/android')
| -rw-r--r-- | WebKit/android/RenderSkinAndroid.cpp | 2 | ||||
| -rw-r--r-- | WebKit/android/RenderSkinCombo.cpp | 94 | ||||
| -rw-r--r-- | WebKit/android/RenderSkinCombo.h | 20 | ||||
| -rwxr-xr-x | WebKit/android/jni/MockGeolocation.cpp | 2 | ||||
| -rw-r--r-- | WebKit/android/jni/WebViewCore.cpp | 74 | ||||
| -rw-r--r-- | WebKit/android/jni/WebViewCore.h | 6 | ||||
| -rw-r--r-- | WebKit/android/nav/CachedFrame.cpp | 29 | ||||
| -rw-r--r-- | WebKit/android/nav/CachedFrame.h | 12 | ||||
| -rw-r--r-- | WebKit/android/nav/CachedRoot.cpp | 9 | ||||
| -rw-r--r-- | WebKit/android/nav/CachedRoot.h | 8 | ||||
| -rw-r--r-- | WebKit/android/nav/WebView.cpp | 22 | ||||
| -rw-r--r-- | WebKit/android/plugins/ANPSurfaceInterface.cpp | 2 | ||||
| -rw-r--r-- | WebKit/android/plugins/PluginTimer.cpp | 19 | ||||
| -rw-r--r-- | WebKit/android/plugins/PluginTimer.h | 3 |
14 files changed, 192 insertions, 110 deletions
diff --git a/WebKit/android/RenderSkinAndroid.cpp b/WebKit/android/RenderSkinAndroid.cpp index d148262..31c327a 100644 --- a/WebKit/android/RenderSkinAndroid.cpp +++ b/WebKit/android/RenderSkinAndroid.cpp @@ -45,7 +45,7 @@ RenderSkinAndroid::RenderSkinAndroid() void RenderSkinAndroid::Init(android::AssetManager* am, String drawableDirectory) { RenderSkinButton::Init(am, drawableDirectory); - RenderSkinCombo::Init(am); + RenderSkinCombo::Init(am, drawableDirectory); RenderSkinRadio::Init(am, drawableDirectory); } diff --git a/WebKit/android/RenderSkinCombo.cpp b/WebKit/android/RenderSkinCombo.cpp index 6f88ee3..4378371 100644 --- a/WebKit/android/RenderSkinCombo.cpp +++ b/WebKit/android/RenderSkinCombo.cpp @@ -26,6 +26,7 @@ #include "config.h" #include "RenderSkinCombo.h" +#include "CString.h" #include "Document.h" #include "Element.h" #include "Node.h" @@ -36,43 +37,85 @@ namespace WebCore { -static SkBitmap s_bitmap[2]; // Collection of assets for a combo box -static bool s_decoded; // True if all assets were decoded -static const int s_margin = 2; -static const SkIRect s_mar = { s_margin, s_margin, - RenderSkinCombo::extraWidth(), s_margin }; -static SkIRect s_subset; +// Indicates if the entire asset is being drawn, or if the border is being +// excluded and just the arrow drawn. +enum BorderStyle { + FullAsset, + NoBorder +}; +// There are 2.5 different concepts of a 'border' here, which results +// in rather a lot of magic constants. In each case, there are 2 +// numbers, one for medium res and one for high-res. All sizes are in pixels. -RenderSkinCombo::RenderSkinCombo() -{ -} +// Firstly, we have the extra padding that webkit needs to know about, +// which defines how much bigger this element is made by the +// asset. This is actually a bit broader than the actual border on the +// asset, to make things look less cramped. The border is the same +// width on all sides, except on the right when it's significantly +// wider to allow for the arrow. +const int RenderSkinCombo::arrowMargin[2] = {22, 34}; +const int RenderSkinCombo::padMargin[2] = {2, 5}; + +// Then we have the borders used for the 9-patch stretch. The +// rectangle at the centre of these borders is entirely below and to +// the left of the arrow in the asset. Hence the border widths are the +// same for the bottom and left, but are different for the top. The +// right hand border width happens to be the same as arrowMargin +// defined above. +static const int stretchMargin[2] = {3, 5}; // border width for the bottom and left of the 9-patch +static const int stretchTop[2] = {15, 23}; // border width for the top of the 9-patch + +// Finally, if the border is defined by the CSS, we only draw the +// arrow and not the border. We do this by drawing the relevant subset +// of the bitmap, which must now be precisely determined by what's in +// the asset with no extra padding to make things look properly +// spaced. The border to remove at the top, right and bottom of the +// image is the same as stretchMargin above, but we need to know the width +// of the arrow. +static const int arrowWidth[2] = {22, 31}; + +RenderSkinCombo::Resolution RenderSkinCombo::resolution = MedRes; + +const SkIRect RenderSkinCombo::margin[2][2] = {{{ stretchMargin[MedRes], stretchTop[MedRes], + RenderSkinCombo::arrowMargin[MedRes] + stretchMargin[MedRes], stretchMargin[MedRes] }, + {0, stretchTop[MedRes], 0, stretchMargin[MedRes]}}, + {{ stretchMargin[HighRes], stretchTop[HighRes], + RenderSkinCombo::arrowMargin[HighRes] + stretchMargin[HighRes], stretchMargin[HighRes] }, + {0, stretchTop[HighRes], 0, stretchMargin[HighRes]}}}; +static SkBitmap bitmaps[2][2]; // Collection of assets for a combo box +static bool isDecoded; // True if all assets were decoded -void RenderSkinCombo::Init(android::AssetManager* am) +void RenderSkinCombo::Init(android::AssetManager* am, String drawableDirectory) { - if (s_decoded) + if (isDecoded) return; - // Maybe short circuiting is fine, since I don't even draw if one state is not decoded properly - // but is that necessary in the final version? - s_decoded = RenderSkinAndroid::DecodeBitmap(am, "images/combobox-noHighlight.png", &s_bitmap[kNormal]); - s_decoded = RenderSkinAndroid::DecodeBitmap(am, "images/combobox-disabled.png", &s_bitmap[kDisabled]) && s_decoded; - - int width = s_bitmap[kNormal].width(); - int height = s_bitmap[kNormal].height(); - s_subset.set(width - RenderSkinCombo::extraWidth() + s_margin, 0, width, height); + + if (drawableDirectory[drawableDirectory.length() - 5] == 'h') + resolution = HighRes; + + isDecoded = RenderSkinAndroid::DecodeBitmap(am, (drawableDirectory + "combobox_nohighlight.png").utf8().data(), &bitmaps[kNormal][FullAsset]); + isDecoded &= RenderSkinAndroid::DecodeBitmap(am, (drawableDirectory + "combobox_disabled.png").utf8().data(), &bitmaps[kDisabled][FullAsset]); + + int width = bitmaps[kNormal][FullAsset].width(); + int height = bitmaps[kNormal][FullAsset].height(); + SkIRect subset; + subset.set(width - arrowWidth[resolution], 0, width, height); + bitmaps[kNormal][FullAsset].extractSubset(&bitmaps[kNormal][NoBorder], subset); + bitmaps[kDisabled][FullAsset].extractSubset(&bitmaps[kDisabled][NoBorder], subset); } bool RenderSkinCombo::Draw(SkCanvas* canvas, Node* element, int x, int y, int width, int height) { - if (!s_decoded) + if (!isDecoded) return true; State state = (element->isElementNode() && static_cast<Element*>(element)->isEnabledFormControl()) ? kNormal : kDisabled; - if (height < (s_margin<<1) + 1) { - height = (s_margin<<1) + 1; - } + height = std::max(height, (stretchMargin[resolution]<<1) + 1); + SkRect bounds; + BorderStyle drawBorder = FullAsset; bounds.set(SkIntToScalar(x+1), SkIntToScalar(y+1), SkIntToScalar(x + width-1), SkIntToScalar(y + height-1)); RenderStyle* style = element->renderStyle(); @@ -90,10 +133,9 @@ bool RenderSkinCombo::Draw(SkCanvas* canvas, Node* element, int x, int y, int wi bounds.fRight -= SkIntToScalar(style->borderRightWidth()); bounds.fTop += SkIntToScalar(style->borderTopWidth()); bounds.fBottom -= SkIntToScalar(style->borderBottomWidth()); - canvas->drawBitmapRect(s_bitmap[state], &s_subset, bounds); - } else { - SkNinePatch::DrawNine(canvas, bounds, s_bitmap[state], s_mar); + drawBorder = NoBorder; } + SkNinePatch::DrawNine(canvas, bounds, bitmaps[state][drawBorder], margin[resolution][drawBorder]); return false; } diff --git a/WebKit/android/RenderSkinCombo.h b/WebKit/android/RenderSkinCombo.h index 91c9367..38cd048 100644 --- a/WebKit/android/RenderSkinCombo.h +++ b/WebKit/android/RenderSkinCombo.h @@ -37,13 +37,10 @@ namespace WebCore { class RenderSkinCombo : public RenderSkinAndroid { public: - RenderSkinCombo(); - virtual ~RenderSkinCombo() {} - /** * Initialize the class before use. Uses the AssetManager to initialize any bitmaps the class may use. */ - static void Init(android::AssetManager*); + static void Init(android::AssetManager*, String drawableDirectory); /** * Draw the provided Node on the SkCanvas, using the dimensions provided by @@ -53,11 +50,18 @@ public: static bool Draw(SkCanvas* , Node* , int x, int y, int w, int h); // The image is wider than the RenderObject, so this accounts for that. - static int extraWidth() { return arrowMargin; } - + static int extraWidth() { return arrowMargin[resolution]; } + static int padding() { return padMargin[resolution]; } + + enum Resolution { + MedRes, + HighRes + }; private: - - static const int arrowMargin = 22; + static Resolution resolution; + const static int arrowMargin[2]; + const static int padMargin[2]; + const static SkIRect margin[2][2]; }; } // WebCore diff --git a/WebKit/android/jni/MockGeolocation.cpp b/WebKit/android/jni/MockGeolocation.cpp index df580c3..1c236c3 100755 --- a/WebKit/android/jni/MockGeolocation.cpp +++ b/WebKit/android/jni/MockGeolocation.cpp @@ -53,7 +53,7 @@ static void setPosition(JNIEnv* env, jobject, double latitude, double longitude, false, 0.0, // altitudeAccuracy, false, 0.0, // heading false, 0.0); // speed - RefPtr<Geoposition> position = Geoposition::create(coordinates.release(), WTF::currentTime()); + RefPtr<Geoposition> position = Geoposition::create(coordinates.release(), WTF::currentTimeMS()); GeolocationServiceMock::setPosition(position.release()); } diff --git a/WebKit/android/jni/WebViewCore.cpp b/WebKit/android/jni/WebViewCore.cpp index 8dc58d2..14fd44e 100644 --- a/WebKit/android/jni/WebViewCore.cpp +++ b/WebKit/android/jni/WebViewCore.cpp @@ -252,6 +252,7 @@ struct WebViewCore::JavaGlue { jmethodID m_sendFindAgain; jmethodID m_showRect; jmethodID m_centerFitRect; + jmethodID m_setScrollbarModes; AutoJObject object(JNIEnv* env) { return getRealObject(env, m_obj); } @@ -342,6 +343,7 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m m_javaGlue->m_sendFindAgain = GetJMethod(env, clazz, "sendFindAgain", "()V"); m_javaGlue->m_showRect = GetJMethod(env, clazz, "showRect", "(IIIIIIFFFF)V"); m_javaGlue->m_centerFitRect = GetJMethod(env, clazz, "centerFitRect", "(IIII)V"); + m_javaGlue->m_setScrollbarModes = GetJMethod(env, clazz, "setScrollbarModes", "(II)V"); env->SetIntField(javaWebViewCore, gWebViewCoreFields.m_nativeClass, (jint)this); @@ -1220,37 +1222,37 @@ void WebViewCore::setSizeScreenWidthAndScale(int width, int height, r->setNeedsLayoutAndPrefWidthsRecalc(); m_mainFrame->view()->forceLayout(); // scroll to restore current screen center - if (!node) - return; - const WebCore::IntRect& newBounds = node->getRect(); - DBG_NAV_LOGD("nb:(x=%d,y=%d,w=%d," - "h=%d)", newBounds.x(), newBounds.y(), - newBounds.width(), newBounds.height()); - if ((orsw && osh && bounds.width() && bounds.height()) - && (bounds != newBounds)) { - WebCore::FrameView* view = m_mainFrame->view(); - // force left align if width is not changed while height changed. - // the anchorPoint is probably at some white space in the node - // which is affected by text wrap around the screen width. - const bool leftAlign = (osw != m_screenWidth) - && (bounds.width() == newBounds.width()) - && (bounds.height() != newBounds.height()); - const float xPercentInDoc = - leftAlign ? 0.0 : (float) (anchorX - bounds.x()) / bounds.width(); - const float xPercentInView = - leftAlign ? 0.0 : (float) (anchorX - m_scrollOffsetX) / orsw; - const float yPercentInDoc = (float) (anchorY - bounds.y()) / bounds.height(); - const float yPercentInView = (float) (anchorY - m_scrollOffsetY) / osh; - showRect(newBounds.x(), newBounds.y(), newBounds.width(), - newBounds.height(), view->contentsWidth(), - view->contentsHeight(), - xPercentInDoc, xPercentInView, - yPercentInDoc, yPercentInView); + if (node) { + const WebCore::IntRect& newBounds = node->getRect(); + DBG_NAV_LOGD("nb:(x=%d,y=%d,w=%d," + "h=%d)", newBounds.x(), newBounds.y(), + newBounds.width(), newBounds.height()); + if ((orsw && osh && bounds.width() && bounds.height()) + && (bounds != newBounds)) { + WebCore::FrameView* view = m_mainFrame->view(); + // force left align if width is not changed while height changed. + // the anchorPoint is probably at some white space in the node + // which is affected by text wrap around the screen width. + const bool leftAlign = (osw != m_screenWidth) + && (bounds.width() == newBounds.width()) + && (bounds.height() != newBounds.height()); + const float xPercentInDoc = + leftAlign ? 0.0 : (float) (anchorX - bounds.x()) / bounds.width(); + const float xPercentInView = + leftAlign ? 0.0 : (float) (anchorX - m_scrollOffsetX) / orsw; + const float yPercentInDoc = (float) (anchorY - bounds.y()) / bounds.height(); + const float yPercentInView = (float) (anchorY - m_scrollOffsetY) / osh; + showRect(newBounds.x(), newBounds.y(), newBounds.width(), + newBounds.height(), view->contentsWidth(), + view->contentsHeight(), + xPercentInDoc, xPercentInView, + yPercentInDoc, yPercentInView); + } } } } - // update the currently visible screen + // update the currently visible screen as perceived by the plugin sendPluginVisibleScreen(); } @@ -1528,6 +1530,10 @@ void WebViewCore::notifyPluginsOnFrameLoad(const Frame* frame) { void WebViewCore::sendPluginVisibleScreen() { + /* We may want to cache the previous values and only send the notification + to the plugin in the event that one of the values has changed. + */ + ANPRectI visibleRect; visibleRect.left = m_scrollOffsetX; visibleRect.top = m_scrollOffsetY; @@ -2069,11 +2075,6 @@ bool WebViewCore::handleTouchEvent(int action, int x, int y, int metaState) // Track previous touch and if stationary set the state. WebCore::IntPoint pt(x - m_scrollOffsetX, y - m_scrollOffsetY); - if (type == WebCore::TouchMove && pt == m_lastTouchPoint) - touchState = WebCore::PlatformTouchPoint::TouchStationary; - - m_lastTouchPoint = pt; - WebCore::PlatformTouchEvent te(pt, type, touchState, metaState); preventDefault = m_mainFrame->eventHandler()->handleTouchEvent(te); #endif @@ -2524,6 +2525,15 @@ void WebViewCore::centerFitRect(int x, int y, int width, int height) checkException(env); } + +void WebViewCore::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode) +{ + JNIEnv* env = JSC::Bindings::getJNIEnv(); + env->CallVoidMethod(m_javaGlue->object(env).get(), m_javaGlue->m_setScrollbarModes, + horizontalMode, verticalMode); + checkException(env); +} + //---------------------------------------------------------------------- // Native JNI methods //---------------------------------------------------------------------- diff --git a/WebKit/android/jni/WebViewCore.h b/WebKit/android/jni/WebViewCore.h index 8c885e6..4ed17bf 100644 --- a/WebKit/android/jni/WebViewCore.h +++ b/WebKit/android/jni/WebViewCore.h @@ -249,6 +249,11 @@ namespace android { void addMessageToConsole(const String& message, unsigned int lineNumber, const String& sourceID, int msgLevel); + /** + * Tell the Java side of the scrollbar mode + */ + void setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode); + // // Followings support calls from Java to native WebCore // @@ -553,7 +558,6 @@ namespace android { #if ENABLE(TOUCH_EVENTS) bool m_forwardingTouchEvents; - IntPoint m_lastTouchPoint; #endif #if DEBUG_NAV_UI diff --git a/WebKit/android/nav/CachedFrame.cpp b/WebKit/android/nav/CachedFrame.cpp index 21a4115..ce5600b 100644 --- a/WebKit/android/nav/CachedFrame.cpp +++ b/WebKit/android/nav/CachedFrame.cpp @@ -928,28 +928,27 @@ int CachedFrame::maxWorkingVertical() const } const CachedNode* CachedFrame::nextTextField(const CachedNode* start, - const CachedFrame** framePtr) const + const CachedFrame** framePtr, bool* startFound) const { - CachedNode* test; - if (start) { - test = const_cast<CachedNode*>(start); - test++; - } else { - test = const_cast<CachedNode*>(mCachedNodes.begin()); - } - while (test != mCachedNodes.end()) { - CachedFrame* frame = const_cast<CachedFrame*>(hasFrame(test)); + const CachedNode* test = mCachedNodes.begin(); + while ((test = test->traverseNextNode())) { + const CachedFrame* frame = hasFrame(test); if (frame) { + if (!frame->validDocument()) + continue; const CachedNode* node - = frame->nextTextField(0, framePtr); + = frame->nextTextField(start, framePtr, startFound); if (node) return node; } else if (test->isTextInput()) { - if (framePtr) - *framePtr = this; - return test; + if (test == start) + *startFound = true; + else if (*startFound) { + if (framePtr) + *framePtr = this; + return test; + } } - test++; } return 0; } diff --git a/WebKit/android/nav/CachedFrame.h b/WebKit/android/nav/CachedFrame.h index ed76583..9334707 100644 --- a/WebKit/android/nav/CachedFrame.h +++ b/WebKit/android/nav/CachedFrame.h @@ -120,16 +120,6 @@ public: #endif WebCore::IntRect localBounds(const CachedNode* , const WebCore::IntRect& ) const; - /** - * Find the next textfield/textarea - * @param start Must be a CachedNode in this CachedFrame's tree, or - * null, in which case we start from the beginning. - * @param framePtr If not null, and a textfield/textarea is found, its - * CachedFrame will be pointed to by this pointer. - * @return CachedNode* Next textfield (or area) - */ - const CachedNode* nextTextField(const CachedNode* start, - const CachedFrame** framePtr) const; const CachedFrame* parent() const { return mParent; } CachedFrame* parent() { return mParent; } SkPicture* picture(const CachedNode* ) const; @@ -152,6 +142,8 @@ public: } const CachedNode* validDocument() const; protected: + const CachedNode* nextTextField(const CachedNode* start, + const CachedFrame** framePtr, bool* found) const; struct BestData { int mDistance; int mSideDistance; diff --git a/WebKit/android/nav/CachedRoot.cpp b/WebKit/android/nav/CachedRoot.cpp index 71c0993..2d37a2a 100644 --- a/WebKit/android/nav/CachedRoot.cpp +++ b/WebKit/android/nav/CachedRoot.cpp @@ -1083,7 +1083,7 @@ WebCore::String CachedRoot::imageURI(int x, int y) const bool CachedRoot::maskIfHidden(BestData* best) const { const CachedNode* bestNode = best->mNode; - if (bestNode->isUnclipped()) + if (bestNode->isUnclipped() || bestNode->isTransparent()) return false; const CachedFrame* frame = best->mFrame; SkPicture* picture = frame->picture(bestNode); @@ -1288,6 +1288,13 @@ const CachedNode* CachedRoot::moveCursor(Direction direction, const CachedFrame* return const_cast<CachedNode*>(bestData.mNode); } +const CachedNode* CachedRoot::nextTextField(const CachedNode* start, + const CachedFrame** framePtr) const +{ + bool startFound = false; + return CachedFrame::nextTextField(start, framePtr, &startFound); +} + SkPicture* CachedRoot::pictureAt(int x, int y) const { #if USE(ACCELERATED_COMPOSITING) diff --git a/WebKit/android/nav/CachedRoot.h b/WebKit/android/nav/CachedRoot.h index 735f23b..6e9fff0 100644 --- a/WebKit/android/nav/CachedRoot.h +++ b/WebKit/android/nav/CachedRoot.h @@ -75,6 +75,14 @@ public: WebCore::String imageURI(int x, int y) const; bool maskIfHidden(BestData* ) const; const CachedNode* moveCursor(Direction , const CachedFrame** , WebCore::IntPoint* scroll); + /** + * Find the next textfield/textarea + * @param start The textfield/textarea to search from. + * @param framePtr If non-zero, returns CachedFrame* containing result. + * @return CachedNode* Next textfield/textarea or null (0) if none. + */ + const CachedNode* nextTextField(const CachedNode* start, + const CachedFrame** framePtr) const; SkPicture* pictureAt(int x, int y) const; void reset(); CachedHistory* rootHistory() const { return mHistory; } diff --git a/WebKit/android/nav/WebView.cpp b/WebKit/android/nav/WebView.cpp index 0ac6bd6..bdcafbf 100644 --- a/WebKit/android/nav/WebView.cpp +++ b/WebKit/android/nav/WebView.cpp @@ -1223,10 +1223,15 @@ static const CachedNode* getFocusCandidate(JNIEnv *env, jobject obj, static bool focusCandidateHasNextTextfield(JNIEnv *env, jobject obj) { - const CachedFrame* frame; - const CachedNode* cursor = getFocusCandidate(env, obj, &frame); + WebView* view = GET_NATIVE_VIEW(env, obj); + CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); + if (!root) + return false; + const CachedNode* cursor = root->currentCursor(); + if (!cursor || !cursor->isTextInput()) + cursor = root->currentFocus(); if (!cursor || !cursor->isTextInput()) return false; - return frame->nextTextField(cursor, 0); + return root->nextTextField(cursor, 0); } static const CachedNode* getFocusNode(JNIEnv *env, jobject obj) @@ -1760,14 +1765,13 @@ static bool nativeMoveCursorToNextTextInput(JNIEnv *env, jobject obj) CachedRoot* root = view->getFrameCache(WebView::DontAllowNewer); if (!root) return false; - const CachedFrame* containingFrame; - const CachedNode* current = root->currentCursor(&containingFrame); - if (!current) - current = root->currentFocus(&containingFrame); - if (!current) + const CachedNode* current = root->currentCursor(); + if (!current || !current->isTextInput()) + current = root->currentFocus(); + if (!current || !current->isTextInput()) return false; const CachedFrame* frame; - const CachedNode* next = containingFrame->nextTextField(current, &frame); + const CachedNode* next = root->nextTextField(current, &frame); if (!next) return false; const WebCore::IntRect& bounds = next->bounds(frame); diff --git a/WebKit/android/plugins/ANPSurfaceInterface.cpp b/WebKit/android/plugins/ANPSurfaceInterface.cpp index cb32ed5..c78fe32 100644 --- a/WebKit/android/plugins/ANPSurfaceInterface.cpp +++ b/WebKit/android/plugins/ANPSurfaceInterface.cpp @@ -64,7 +64,7 @@ static inline sp<Surface> getSurface(JNIEnv* env, jobject view) { jclass surfaceClass = env->FindClass("android/view/Surface"); gSurfaceJavaGlue.surfacePointer = env->GetFieldID(surfaceClass, - "mSurface", "I"); + ANDROID_VIEW_SURFACE_JNI_ID, "I"); env->DeleteLocalRef(surfaceClass); env->DeleteLocalRef(surfaceViewClass); diff --git a/WebKit/android/plugins/PluginTimer.cpp b/WebKit/android/plugins/PluginTimer.cpp index cdcde9c..a813d25 100644 --- a/WebKit/android/plugins/PluginTimer.cpp +++ b/WebKit/android/plugins/PluginTimer.cpp @@ -36,7 +36,8 @@ namespace WebCore { : m_list(list), m_instance(instance), m_timerFunc(timerFunc), - m_repeat(repeat) + m_repeat(repeat), + m_unscheduled(false) { m_timerID = ++gTimerID; @@ -62,10 +63,11 @@ namespace WebCore { void PluginTimer::fired() { - m_timerFunc(m_instance, m_timerID); - if (!m_repeat) { + if (!m_unscheduled) + m_timerFunc(m_instance, m_timerID); + + if (!m_repeat || m_unscheduled) delete this; - } } // may return null if timerID is not found @@ -106,7 +108,14 @@ namespace WebCore { void PluginTimerList::unschedule(NPP instance, uint32 timerID) { - delete PluginTimer::Find(m_list, timerID); + // Although it looks like simply deleting the timer would work here + // (stop() will be executed by the dtor), we cannot do this, as + // the plugin can call us while we are in the fired() method, + // (when we execute the timerFunc callback). Deleting the object + // we are in would then be a rather bad move... + PluginTimer* timer = PluginTimer::Find(m_list, timerID); + if (timer) + timer->unschedule(); } } // namespace WebCore diff --git a/WebKit/android/plugins/PluginTimer.h b/WebKit/android/plugins/PluginTimer.h index 3fbe728..2ffe437 100644 --- a/WebKit/android/plugins/PluginTimer.h +++ b/WebKit/android/plugins/PluginTimer.h @@ -42,6 +42,8 @@ namespace WebCore { uint32 timerID() const { return m_timerID; } + void unschedule() { m_unscheduled = true; } + static PluginTimer* Find(PluginTimer* list, uint32 timerID); private: @@ -58,6 +60,7 @@ namespace WebCore { void (*m_timerFunc)(NPP, uint32); uint32 m_timerID; bool m_repeat; + bool m_unscheduled; }; class PluginTimerList { |
