diff options
47 files changed, 740 insertions, 485 deletions
@@ -451,7 +451,6 @@ endif # JAVASCRIPT_ENGINE == jsc # will strip out any unused code from the entry point. include $(CLEAR_VARS) # if you need to make webcore huge (for debugging), enable this line -#LOCAL_PRELINK_MODULE := false LOCAL_MODULE := libwebcore LOCAL_LDLIBS := $(WEBKIT_LDLIBS) LOCAL_SHARED_LIBRARIES := $(WEBKIT_SHARED_LIBRARIES) diff --git a/WebCore/Android.mk b/WebCore/Android.mk index feeb56b..5bc6d83 100644 --- a/WebCore/Android.mk +++ b/WebCore/Android.mk @@ -620,6 +620,7 @@ LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \ platform/graphics/android/MediaLayer.cpp \ platform/graphics/android/MediaTexture.cpp \ platform/graphics/android/PaintLayerOperation.cpp \ + platform/graphics/android/PaintTileOperation.cpp \ platform/graphics/android/PathAndroid.cpp \ platform/graphics/android/PatternAndroid.cpp \ platform/graphics/android/PlatformGraphicsContext.cpp \ @@ -630,7 +631,6 @@ LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \ platform/graphics/android/TexturesGenerator.cpp \ platform/graphics/android/TilesManager.cpp \ platform/graphics/android/TiledPage.cpp \ - platform/graphics/android/TileSet.cpp \ platform/graphics/android/VideoLayerAndroid.cpp \ platform/graphics/android/android_graphics.cpp \ diff --git a/WebCore/platform/android/RenderThemeAndroid.cpp b/WebCore/platform/android/RenderThemeAndroid.cpp index 944504e..113fa63 100644 --- a/WebCore/platform/android/RenderThemeAndroid.cpp +++ b/WebCore/platform/android/RenderThemeAndroid.cpp @@ -44,6 +44,7 @@ #include "RenderSkinRadio.h" #include "SkCanvas.h" #include "UserAgentStyleSheets.h" +#include "WebCoreFrameBridge.h" namespace WebCore { @@ -67,6 +68,13 @@ static SkCanvas* getCanvasFromInfo(const PaintInfo& info) return info.context->platformContext()->mCanvas; } +static android::WebFrame* getWebFrame(const Node* node) +{ + if (!node) + return 0; + return android::WebFrame::getWebFrame(node->document()->frame()); +} + RenderTheme* theme() { DEFINE_STATIC_LOCAL(RenderThemeAndroid, androidTheme, ()); @@ -223,9 +231,15 @@ bool RenderThemeAndroid::paintButton(RenderObject* obj, const PaintInfo& info, c // If it is a disabled button, simply paint it to the master picture. Node* node = obj->node(); Element* formControlElement = static_cast<Element*>(node); - if (formControlElement && !formControlElement->isEnabledFormControl()) - RenderSkinButton::Draw(getCanvasFromInfo(info), rect, RenderSkinAndroid::kDisabled); - else + if (formControlElement && !formControlElement->isEnabledFormControl()) { + android::WebFrame* webFrame = getWebFrame(node); + if (webFrame) { + const RenderSkinAndroid* skins = webFrame->renderSkins(); + if (skins) + skins->renderSkinButton()->draw(getCanvasFromInfo(info), rect, + RenderSkinAndroid::kDisabled); + } + } else // Store all the important information in the platform context. info.context->platformContext()->storeButtonInfo(node, rect); diff --git a/WebCore/platform/graphics/android/BackedDoubleBufferedTexture.cpp b/WebCore/platform/graphics/android/BackedDoubleBufferedTexture.cpp index dc0962c..964422a 100644 --- a/WebCore/platform/graphics/android/BackedDoubleBufferedTexture.cpp +++ b/WebCore/platform/graphics/android/BackedDoubleBufferedTexture.cpp @@ -137,6 +137,7 @@ void BackedDoubleBufferedTexture::setNotBusy() m_delayedRelease = false; m_delayedReleaseOwner = 0; } + m_busyCond.signal(); } bool BackedDoubleBufferedTexture::busy() @@ -189,7 +190,7 @@ void BackedDoubleBufferedTexture::producerUpdate(TextureInfo* textureInfo) producerReleaseAndSwap(); } -bool BackedDoubleBufferedTexture::acquire(TextureOwner* owner) +bool BackedDoubleBufferedTexture::acquire(TextureOwner* owner, bool force) { if (m_owner == owner) { if (m_delayedRelease) { @@ -199,7 +200,7 @@ bool BackedDoubleBufferedTexture::acquire(TextureOwner* owner) return true; } - return setOwner(owner); + return setOwner(owner, force); } bool BackedDoubleBufferedTexture::tryAcquire(TextureOwner* owner, TiledPage* currentPage, TiledPage* nextPage) @@ -216,13 +217,16 @@ bool BackedDoubleBufferedTexture::tryAcquire(TextureOwner* owner, TiledPage* cur return false; } -bool BackedDoubleBufferedTexture::setOwner(TextureOwner* owner) +bool BackedDoubleBufferedTexture::setOwner(TextureOwner* owner, bool force) { // if the writable texture is busy (i.e. currently being written to) then we // can't change the owner out from underneath that texture m_busyLock.lock(); + while (m_busy && force) + m_busyCond.wait(m_busyLock); bool busy = m_busy; m_busyLock.unlock(); + if (!busy) { // if we are not busy we can try to remove the texture from the layer; // LayerAndroid::removeTexture() is protected by the same lock as diff --git a/WebCore/platform/graphics/android/BackedDoubleBufferedTexture.h b/WebCore/platform/graphics/android/BackedDoubleBufferedTexture.h index 8bfae59..7c2ea90 100644 --- a/WebCore/platform/graphics/android/BackedDoubleBufferedTexture.h +++ b/WebCore/platform/graphics/android/BackedDoubleBufferedTexture.h @@ -88,12 +88,12 @@ public: // allows consumer thread to assign ownership of the texture to the tile. It // returns false if ownership cannot be transferred because the tile is busy - bool acquire(TextureOwner* owner); + bool acquire(TextureOwner* owner, bool force = false); bool release(TextureOwner* owner); bool tryAcquire(TextureOwner* owner, TiledPage* currentPage, TiledPage* nextPage); // set the texture owner if not busy. Return false if busy, true otherwise. - bool setOwner(TextureOwner* owner); + bool setOwner(TextureOwner* owner, bool force = false); // private member accessor functions TextureOwner* owner() { return m_owner; } // only used by the consumer thread @@ -136,6 +136,9 @@ private: // We mutex protect the reads/writes of m_busy to ensure that we are reading // the most up-to-date value even across processors in an SMP system. android::Mutex m_busyLock; + // We use this condition variable to signal that the texture + // is not busy anymore + android::Condition m_busyCond; }; } // namespace WebCore diff --git a/WebCore/platform/graphics/android/BaseLayerAndroid.cpp b/WebCore/platform/graphics/android/BaseLayerAndroid.cpp index c59a5a5..ebf8c88 100644 --- a/WebCore/platform/graphics/android/BaseLayerAndroid.cpp +++ b/WebCore/platform/graphics/android/BaseLayerAndroid.cpp @@ -163,13 +163,19 @@ bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale, double zooming = true; } + // Display the current page + TiledPage* tiledPage = m_glWebViewState->frontPage(); + tiledPage->setScale(m_glWebViewState->currentScale()); + // Let's prepare the page if needed if (prepareNextTiledPage) { TiledPage* nextTiledPage = m_glWebViewState->backPage(); nextTiledPage->setScale(scale); m_glWebViewState->setFutureViewport(viewportTileBounds); m_glWebViewState->lockBaseLayerUpdate(); - nextTiledPage->prepare(goingDown, goingLeft, viewportTileBounds, true); + nextTiledPage->prepare(goingDown, goingLeft, viewportTileBounds); + // Cancel pending paints for the foreground page + TilesManager::instance()->removePaintOperationsForPage(tiledPage, false); } float transparency = 1; @@ -205,9 +211,6 @@ bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale, double } } - // Display the current page - TiledPage* tiledPage = m_glWebViewState->frontPage(); - tiledPage->setScale(m_glWebViewState->currentScale()); const SkIRect& preZoomBounds = m_glWebViewState->preZoomBounds(); TiledPage* nextTiledPage = m_glWebViewState->backPage(); @@ -240,7 +243,8 @@ bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale, double if (!zooming) m_glWebViewState->unlockBaseLayerUpdate(); - tiledPage->prepare(goingDown, goingLeft, preZoomBounds, true); + if (!prepareNextTiledPage) + tiledPage->prepare(goingDown, goingLeft, preZoomBounds); tiledPage->draw(transparency, preZoomBounds); } @@ -254,6 +258,7 @@ bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale, double m_glWebViewState->unlockBaseLayerUpdate(); } + m_glWebViewState->paintExtras(); return needsRedraw; } #endif // USE(ACCELERATED_COMPOSITING) diff --git a/WebCore/platform/graphics/android/BaseTile.cpp b/WebCore/platform/graphics/android/BaseTile.cpp index d58c549..c74a278 100644 --- a/WebCore/platform/graphics/android/BaseTile.cpp +++ b/WebCore/platform/graphics/android/BaseTile.cpp @@ -66,11 +66,11 @@ BaseTile::BaseTile() , m_texture(0) , m_scale(1) , m_dirty(true) + , m_repaintPending(false) , m_usable(true) , m_lastDirtyPicture(0) , m_fullRepaintA(true) , m_fullRepaintB(true) - , m_painting(false) , m_lastPaintedPicture(0) { #ifdef DEBUG_COUNT @@ -105,8 +105,7 @@ void BaseTile::reserveTexture() BackedDoubleBufferedTexture* texture = TilesManager::instance()->getAvailableTexture(this); android::AutoMutex lock(m_atomicSync); - if (texture && !m_painting && - m_texture != texture) { + if (texture && m_texture != texture) { m_lastPaintedPicture = 0; fullInval(); m_texture = texture; @@ -118,8 +117,6 @@ bool BaseTile::removeTexture(BackedDoubleBufferedTexture* texture) XLOG("%x removeTexture res: %x... page %x", this, m_texture, m_page); // We update atomically, so paintBitmap() can see the correct value android::AutoMutex lock(m_atomicSync); - if (m_painting) - return false; if (m_texture == texture) m_texture = 0; return true; @@ -166,12 +163,31 @@ bool BaseTile::isDirty() return m_dirty; } +bool BaseTile::isRepaintPending() +{ + android::AutoMutex lock(m_atomicSync); + return m_repaintPending; +} + +void BaseTile::setRepaintPending(bool pending) +{ + android::AutoMutex lock(m_atomicSync); + m_repaintPending = pending; +} + void BaseTile::setUsedLevel(int usedLevel) { if (m_texture) m_texture->setUsedLevel(usedLevel); } +int BaseTile::usedLevel() +{ + if (m_texture) + return m_texture->usedLevel(); + return -1; +} + void BaseTile::draw(float transparency, SkRect& rect, float scale) { if (m_x < 0 || m_y < 0 || m_scale != scale) @@ -261,14 +277,12 @@ void BaseTile::paintBitmap() bool dirty = m_dirty; BackedDoubleBufferedTexture* texture = m_texture; SkRegion dirtyArea = *m_currentDirtyArea; - m_painting = true; float scale = m_scale; const int x = m_x; const int y = m_y; m_atomicSync.unlock(); if (!dirty || !texture) { - m_painting = false; return; } @@ -281,7 +295,6 @@ void BaseTile::paintBitmap() // transferred to another BaseTile under us) if (texture->owner() != this || texture->usedLevel() > 1) { texture->producerRelease(); - m_painting = false; return; } @@ -359,40 +372,40 @@ void BaseTile::paintBitmap() texture->setTile(textureInfo, x, y, scale, pictureCount); texture->producerReleaseAndSwap(); - m_lastPaintedPicture = pictureCount; - - // set the fullrepaint flags + if (texture == m_texture) { + m_lastPaintedPicture = pictureCount; - if ((m_currentDirtyArea == &m_dirtyAreaA) && m_fullRepaintA) - m_fullRepaintA = false; + // set the fullrepaint flags - if ((m_currentDirtyArea == &m_dirtyAreaB) && m_fullRepaintB) - m_fullRepaintB = false; + if ((m_currentDirtyArea == &m_dirtyAreaA) && m_fullRepaintA) + m_fullRepaintA = false; - // The various checks to see if we are still dirty... + if ((m_currentDirtyArea == &m_dirtyAreaB) && m_fullRepaintB) + m_fullRepaintB = false; - m_dirty = false; + // The various checks to see if we are still dirty... - if (m_scale != scale) - m_dirty = true; + m_dirty = false; - if (!fullRepaint) - m_currentDirtyArea->op(dirtyArea, SkRegion::kDifference_Op); + if (m_scale != scale) + m_dirty = true; - if (!m_currentDirtyArea->isEmpty()) - m_dirty = true; + if (!fullRepaint) + m_currentDirtyArea->op(dirtyArea, SkRegion::kDifference_Op); - // Now we can swap the dirty areas + if (!m_currentDirtyArea->isEmpty()) + m_dirty = true; - m_currentDirtyArea = m_currentDirtyArea == &m_dirtyAreaA ? &m_dirtyAreaB : &m_dirtyAreaA; + // Now we can swap the dirty areas - if (!m_currentDirtyArea->isEmpty()) - m_dirty = true; + m_currentDirtyArea = m_currentDirtyArea == &m_dirtyAreaA ? &m_dirtyAreaB : &m_dirtyAreaA; - if (!m_dirty) - m_usable = true; + if (!m_currentDirtyArea->isEmpty()) + m_dirty = true; - m_painting = false; + if (!m_dirty) + m_usable = true; + } m_atomicSync.unlock(); } diff --git a/WebCore/platform/graphics/android/BaseTile.h b/WebCore/platform/graphics/android/BaseTile.h index b832eee..7b28f76 100644 --- a/WebCore/platform/graphics/android/BaseTile.h +++ b/WebCore/platform/graphics/android/BaseTile.h @@ -72,6 +72,7 @@ public: void reserveTexture(); void setUsedLevel(int); + int usedLevel(); bool isTileReady(); void draw(float transparency, SkRect& rect, float scale); @@ -89,6 +90,8 @@ public: void markAsDirty(const unsigned int pictureCount, const SkRegion& dirtyArea); bool isDirty(); + bool isRepaintPending(); + void setRepaintPending(bool pending); void setUsable(bool usable); float scale() const { return m_scale; } void setScale(float scale); @@ -114,6 +117,8 @@ private: float m_scale; // used to signal that the that the tile is out-of-date and needs to be redrawn bool m_dirty; + // used to signal that a repaint is pending + bool m_repaintPending; // used to signal whether or not the draw can use this tile. bool m_usable; // stores the id of the latest picture from webkit that caused this tile to @@ -127,7 +132,6 @@ private: bool m_fullRepaintA; bool m_fullRepaintB; SkRegion* m_currentDirtyArea; - bool m_painting; // stores the id of the latest picture painted to the tile. If the id is 0 // then we know that the picture has not yet been painted an there is nothing diff --git a/WebCore/platform/graphics/android/FontAndroid.cpp b/WebCore/platform/graphics/android/FontAndroid.cpp index ffaeded..e896a46 100644 --- a/WebCore/platform/graphics/android/FontAndroid.cpp +++ b/WebCore/platform/graphics/android/FontAndroid.cpp @@ -83,8 +83,9 @@ static bool setupForText(SkPaint* paint, GraphicsContext* gc, float shadowBlur; Color shadowColor; bool hasShadow = gc->getShadow(shadowOffset, shadowBlur, shadowColor); - - if (hasShadow || (mode == (cTextStroke & cTextFill))) { + bool hasBothStrokeAndFill = + (mode & (cTextStroke | cTextFill)) == (cTextStroke | cTextFill); + if (hasShadow || hasBothStrokeAndFill) { SkLayerDrawLooper* looper = new SkLayerDrawLooper; paint->setLooper(looper)->unref(); diff --git a/WebCore/platform/graphics/android/FontPlatformDataAndroid.cpp b/WebCore/platform/graphics/android/FontPlatformDataAndroid.cpp index 352516b..337a94d 100644 --- a/WebCore/platform/graphics/android/FontPlatformDataAndroid.cpp +++ b/WebCore/platform/graphics/android/FontPlatformDataAndroid.cpp @@ -163,11 +163,15 @@ void FontPlatformData::setupPaint(SkPaint* paint) const if (!(ts > 0)) ts = 12; + if (hashTableDeletedFontValue() == mTypeface) + paint->setTypeface(0); + else + paint->setTypeface(mTypeface); + paint->setAntiAlias(true); paint->setSubpixelText(true); paint->setHinting(SkPaint::kSlight_Hinting); paint->setTextSize(SkFloatToScalar(ts)); - paint->setTypeface(mTypeface); paint->setFakeBoldText(mFakeBold); paint->setTextSkewX(mFakeItalic ? -SK_Scalar1/4 : 0); #ifndef SUPPORT_COMPLEX_SCRIPTS @@ -177,7 +181,10 @@ void FontPlatformData::setupPaint(SkPaint* paint) const uint32_t FontPlatformData::uniqueID() const { - return mTypeface->uniqueID(); + if (hashTableDeletedFontValue() == mTypeface) + return SkTypeface::UniqueID(0); + else + return SkTypeface::UniqueID(mTypeface); } bool FontPlatformData::operator==(const FontPlatformData& a) const @@ -207,7 +214,10 @@ unsigned FontPlatformData::hash() const bool FontPlatformData::isFixedPitch() const { - return mTypeface ? mTypeface->isFixedWidth() : false; + if (mTypeface && (mTypeface != hashTableDeletedFontValue())) + return mTypeface->isFixedWidth(); + else + return false; } HB_FaceRec_* FontPlatformData::harfbuzzFace() const diff --git a/WebCore/platform/graphics/android/GLUtils.cpp b/WebCore/platform/graphics/android/GLUtils.cpp index 23bf525..5eabb85 100644 --- a/WebCore/platform/graphics/android/GLUtils.cpp +++ b/WebCore/platform/graphics/android/GLUtils.cpp @@ -289,6 +289,25 @@ void GLUtils::deleteTexture(GLuint* texture) *texture = 0; } +GLuint GLUtils::createSampleColorTexture(int r, int g, int b) { + GLuint texture; + glGenTextures(1, &texture); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + GLubyte pixels[4 *3] = { + r, g, b, + r, g, b, + r, g, b, + r, g, b + }; + glBindTexture(GL_TEXTURE_2D, texture); + GLUtils::checkGlError("glBindTexture"); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels); + GLUtils::checkGlError("glTexImage2D"); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + return texture; +} + GLuint GLUtils::createSampleTexture() { GLuint texture; @@ -375,8 +394,8 @@ void GLUtils::updateTextureWithBitmap(GLuint texture, int x, int y, SkBitmap& bi bitmap.unlockPixels(); if (GLUtils::checkGlError("glTexSubImage2D")) { XLOG("GL ERROR: glTexSubImage2D parameters are : bitmap.width() %d, bitmap.height() %d," - " internalformat 0x%x, type 0x%x, bitmap.getPixels() %p", - bitmap.width(), bitmap.height(), internalformat, type, bitmap.getPixels()); + " x %d, y %d, internalformat 0x%x, type 0x%x, bitmap.getPixels() %p", + bitmap.width(), bitmap.height(), x, y, internalformat, type, bitmap.getPixels()); } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); diff --git a/WebCore/platform/graphics/android/GLUtils.h b/WebCore/platform/graphics/android/GLUtils.h index 64aedbb..1e8df39 100644 --- a/WebCore/platform/graphics/android/GLUtils.h +++ b/WebCore/platform/graphics/android/GLUtils.h @@ -59,6 +59,7 @@ public: // Texture utilities static EGLContext createBackgroundContext(EGLContext sharedContext); static void deleteTexture(GLuint* texture); + static GLuint createSampleColorTexture(int r, int g, int b); static GLuint createSampleTexture(); static void createTextureWithBitmap(GLuint texture, SkBitmap& bitmap, GLint filter = GL_LINEAR); static void updateTextureWithBitmap(GLuint texture, SkBitmap& bitmap, GLint filter = GL_LINEAR); diff --git a/WebCore/platform/graphics/android/GLWebViewState.cpp b/WebCore/platform/graphics/android/GLWebViewState.cpp index 6f95836..74f03f5 100644 --- a/WebCore/platform/graphics/android/GLWebViewState.cpp +++ b/WebCore/platform/graphics/android/GLWebViewState.cpp @@ -30,6 +30,7 @@ #include "BaseLayerAndroid.h" #include "ClassTracker.h" +#include "GLUtils.h" #include "LayerAndroid.h" #include "TilesManager.h" #include <wtf/CurrentTime.h> @@ -78,6 +79,8 @@ GLWebViewState::GLWebViewState(android::Mutex* buttonMutex) , m_baseLayerUpdate(true) , m_backgroundColor(SK_ColorWHITE) , m_prevDrawTime(0) + , m_displayRings(false) + , m_focusRingTexture(-1) { m_viewport.setEmpty(); m_previousViewport.setEmpty(); @@ -144,6 +147,7 @@ void GLWebViewState::setBaseLayer(BaseLayerAndroid* layer, const SkRegion& inval SkSafeUnref(m_currentBaseLayer); m_currentBaseLayer = layer; } + m_displayRings = false; invalRegion(inval); #ifdef MEASURES_PERF @@ -155,6 +159,13 @@ void GLWebViewState::setBaseLayer(BaseLayerAndroid* layer, const SkRegion& inval TilesManager::instance()->setShowVisualIndicator(showVisualIndicator); } +void GLWebViewState::setRings(Vector<IntRect>& rings) +{ + android::Mutex::Autolock lock(m_baseLayerLock); + m_displayRings = true; + m_rings = rings; +} + void GLWebViewState::invalRegion(const SkRegion& region) { SkRegion::Iterator iterator(region); @@ -197,6 +208,7 @@ void GLWebViewState::setExtra(BaseLayerAndroid* layer, SkPicture& picture, if (!m_lastInval.isEmpty()) inval(m_lastInval); m_lastInval = rect; + m_displayRings = false; } void GLWebViewState::inval(const IntRect& rect) @@ -220,6 +232,64 @@ void GLWebViewState::inval(const IntRect& rect) } } +void GLWebViewState::resetRings() +{ + m_displayRings = false; +} + +void GLWebViewState::drawFocusRing(IntRect& srcRect) +{ + // TODO: use a 9-patch texture to draw the focus ring + // instead of plain colors + const int border = 1; + const int fuzzyBorder = border * 2; + const int padding = 4; + const float alpha = 0.3; + const float borderAlpha = 0.40; + + const int r = 104; + const int g = 153; + const int b = 255; + + if (m_focusRingTexture == -1) + m_focusRingTexture = GLUtils::createSampleColorTexture(r, g, b); + + SkRect rLeft, rTop, rRight, rBottom, rOverlay; + + IntRect rect(srcRect.x() - padding, srcRect.y() - padding, + srcRect.width() + (padding * 2), srcRect.height() + (padding * 2)); + rLeft.set(rect.x() - border, rect.y(), + rect.x(), rect.y() + rect.height()); + rTop.set(rect.x() - border, rect.y() - border, + rect.x() + rect.width() + border, rect.y()); + rRight.set(rect.x() + rect.width(), rect.y(), + rect.x() + rect.width() + border, + rect.y() + rect.height()); + rBottom.set(rect.x() - border, rect.y() + rect.height(), + rect.x() + rect.width() + border, + rect.y() + rect.height() + border); + rOverlay.set(rect.x() - fuzzyBorder, rect.y() - fuzzyBorder, + rect.x() + rect.width() + fuzzyBorder, + rect.y() + rect.height() + fuzzyBorder); + + TilesManager::instance()->shader()->drawQuad(rLeft, m_focusRingTexture, borderAlpha); + TilesManager::instance()->shader()->drawQuad(rTop, m_focusRingTexture, borderAlpha); + TilesManager::instance()->shader()->drawQuad(rRight, m_focusRingTexture, borderAlpha); + TilesManager::instance()->shader()->drawQuad(rBottom, m_focusRingTexture, borderAlpha); + TilesManager::instance()->shader()->drawQuad(rOverlay, m_focusRingTexture, alpha); +} + +void GLWebViewState::paintExtras() +{ + if (m_displayRings) { + // TODO: handles correctly the multi-rings case + for (int i=0; i<m_rings.size(); i++) { + IntRect rect = m_rings.at(i); + drawFocusRing(rect); + } + } +} + unsigned int GLWebViewState::paintBaseLayerContent(SkCanvas* canvas) { android::Mutex::Autolock lock(m_baseLayerLock); diff --git a/WebCore/platform/graphics/android/GLWebViewState.h b/WebCore/platform/graphics/android/GLWebViewState.h index ac75605..7892337 100644 --- a/WebCore/platform/graphics/android/GLWebViewState.h +++ b/WebCore/platform/graphics/android/GLWebViewState.h @@ -179,6 +179,11 @@ public: bool isPictureAfterFirstLayout); void setExtra(BaseLayerAndroid*, SkPicture&, const IntRect&, bool allowSame); void scheduleUpdate(const double& currentTime, const SkIRect& viewport, float scale); + void paintExtras(); + + void setRings(Vector<IntRect>& rings); + void resetRings(); + void drawFocusRing(IntRect& rect); TiledPage* sibling(TiledPage* page); TiledPage* frontPage(); @@ -283,6 +288,9 @@ private: double m_delayTimes[MAX_MEASURES_PERF]; bool m_measurePerfs; #endif + bool m_displayRings; + Vector<IntRect> m_rings; + int m_focusRingTexture; }; } // namespace WebCore diff --git a/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp b/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp index 1a32ef5..64b6ad3 100644 --- a/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp +++ b/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp @@ -101,10 +101,16 @@ static bool setBitmapDash(SkPaint* paint, int width) { // Is Color premultiplied or not? If it is, then I can't blindly pass it to paint.setColor() struct ShadowRec { - SkScalar blur; // >0 means valid shadow + SkScalar blur; SkScalar dx; SkScalar dy; - SkColor color; + SkColor color; // alpha>0 means valid shadow + ShadowRec(SkScalar b = 0, + SkScalar x = 0, + SkScalar y = 0, + SkColor c = 0) // by default, alpha=0, so no shadow + : blur(b), dx(x), dy(y), color(c) + {}; }; class GraphicsContextPlatformPrivate { @@ -141,7 +147,6 @@ public: , strokeColor(SK_ColorBLACK) , useAA(true) { - shadow.blur = 0; } State(const State& other) @@ -283,7 +288,7 @@ public: paint->setAntiAlias(m_state->useAA); paint->setDither(true); paint->setXfermodeMode(m_state->mode); - if (m_state->shadow.blur > 0) { + if (SkColorGetA(m_state->shadow.color) > 0) { SkDrawLooper* looper = new SkBlurDrawLooper(m_state->shadow.blur, m_state->shadow.dx, m_state->shadow.dy, diff --git a/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp b/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp index 96cfd3d..59f8408 100644 --- a/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp +++ b/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp @@ -120,6 +120,8 @@ GraphicsLayerAndroid::GraphicsLayerAndroid(GraphicsLayerClient* client) : m_needsNotifyClient(false), m_haveContents(false), m_haveImage(false), + m_newImage(false), + m_imageRef(0), m_foregroundLayer(0), m_foregroundClipLayer(0) { @@ -623,6 +625,14 @@ bool GraphicsLayerAndroid::repaint() return true; } + if (m_needsRepaint && m_haveImage && m_newImage) { + // We need to tell the GL thread that we will need to repaint the + // texture. Only do so if we effectively have a new image! + m_contentLayer->needsRepaint(); + m_newImage = false; + m_needsRepaint = false; + return true; + } return false; } @@ -834,9 +844,15 @@ void GraphicsLayerAndroid::setContentsToImage(Image* image) if (image) { m_haveContents = true; m_haveImage = true; - m_contentLayer->setContentsImage(image->nativeImageForCurrentFrame()); - setNeedsDisplay(); - askForSync(); + // Only pass the new image if it's a different one + if (image->nativeImageForCurrentFrame() != m_imageRef) { + m_newImage = true; + m_contentLayer->setContentsImage(image->nativeImageForCurrentFrame()); + // remember the passed image. + m_imageRef = image->nativeImageForCurrentFrame(); + setNeedsDisplay(); + askForSync(); + } } } diff --git a/WebCore/platform/graphics/android/GraphicsLayerAndroid.h b/WebCore/platform/graphics/android/GraphicsLayerAndroid.h index da247ca..94b828b 100644 --- a/WebCore/platform/graphics/android/GraphicsLayerAndroid.h +++ b/WebCore/platform/graphics/android/GraphicsLayerAndroid.h @@ -25,10 +25,12 @@ #include "GraphicsLayerClient.h" #include "LayerAndroid.h" #include "RefPtr.h" +#include "SkBitmapRef.h" #include "Vector.h" class FloatPoint3D; class Image; +class SkBitmapRef; namespace WebCore { @@ -142,6 +144,8 @@ private: bool m_haveContents; bool m_haveImage; + bool m_newImage; + SkBitmapRef* m_imageRef; // only used to remember previously passed images Vector<FloatRect> m_invalidatedRects; diff --git a/WebCore/platform/graphics/android/LayerAndroid.cpp b/WebCore/platform/graphics/android/LayerAndroid.cpp index 78e55c1..e616041 100644 --- a/WebCore/platform/graphics/android/LayerAndroid.cpp +++ b/WebCore/platform/graphics/android/LayerAndroid.cpp @@ -44,19 +44,12 @@ static int gUniqueId; class OpacityDrawFilter : public SkDrawFilter { public: OpacityDrawFilter(int opacity) : m_opacity(opacity) { } - virtual bool filter(SkCanvas* canvas, SkPaint* paint, Type) + virtual void filter(SkPaint* paint, Type) { - m_previousOpacity = paint->getAlpha(); paint->setAlpha(m_opacity); - return true; - } - virtual void restore(SkCanvas* canvas, SkPaint* paint, Type) - { - paint->setAlpha(m_previousOpacity); } private: int m_opacity; - int m_previousOpacity; }; /////////////////////////////////////////////////////////////////////////////// @@ -92,6 +85,7 @@ LayerAndroid::LayerAndroid(RenderLayer* owner) : SkLayer(), LayerAndroid::LayerAndroid(const LayerAndroid& layer) : SkLayer(layer), m_haveClip(layer.m_haveClip), m_isIframe(layer.m_isIframe), + m_contentsImage(0), m_extra(0), // deliberately not copied m_uniqueId(layer.m_uniqueId), m_drawingTexture(0), @@ -100,8 +94,7 @@ LayerAndroid::LayerAndroid(const LayerAndroid& layer) : SkLayer(layer), m_owningLayer(layer.m_owningLayer) { m_isFixed = layer.m_isFixed; - m_contentsImage = layer.m_contentsImage; - SkSafeRef(m_contentsImage); + copyBitmap(layer.m_contentsImage); m_renderLayerPos = layer.m_renderLayerPos; m_transform = layer.m_transform; m_backgroundColor = layer.m_backgroundColor; @@ -202,7 +195,7 @@ LayerAndroid::~LayerAndroid() removeTexture(0); removeChildren(); delete m_extra; - SkSafeUnref(m_contentsImage); + delete m_contentsImage; SkSafeUnref(m_recordingPicture); m_animations.clear(); #ifdef DEBUG_COUNT @@ -650,9 +643,23 @@ void LayerAndroid::updateGLPositions(const TransformationMatrix& parentMatrix, this->getChild(i)->updateGLPositions(localMatrix, drawClip(), opacity); } +void LayerAndroid::copyBitmap(SkBitmap* bitmap) +{ + if (!bitmap) + return; + + delete m_contentsImage; + m_contentsImage = new SkBitmap(); + SkBitmap::Config config = bitmap->config(); + int w = bitmap->width(); + int h = bitmap->height(); + m_contentsImage->setConfig(config, w, h); + bitmap->copyTo(m_contentsImage, config); +} + void LayerAndroid::setContentsImage(SkBitmapRef* img) { - SkRefCnt_SafeAssign(m_contentsImage, img); + copyBitmap(&img->bitmap()); } bool LayerAndroid::needsTexture() @@ -889,7 +896,7 @@ void LayerAndroid::createGLTextures() uniqueId(), this, m_dirty, m_reservedTexture, m_reservedTexture->rect().width(), m_reservedTexture->rect().height()); PaintLayerOperation* operation = new PaintLayerOperation(this); - TilesManager::instance()->scheduleOperation(operation, !m_drawingTexture); + TilesManager::instance()->scheduleOperation(operation); } else { XLOG("We don't schedule a paint for layer %d (%x), because we already sent a request", uniqueId(), this); @@ -930,9 +937,8 @@ bool LayerAndroid::drawGL(GLWebViewState* glWebViewState, SkMatrix& matrix) if (m_drawingTexture) { TextureInfo* textureInfo = m_drawingTexture->consumerLock(); - if (!m_drawingTexture->readyFor(this)) - m_dirty = true; - if (textureInfo) { + bool ready = m_drawingTexture->readyFor(this); + if (textureInfo && (!m_contentsImage || (ready && m_contentsImage))) { SkRect bounds; bounds.set(m_drawingTexture->rect()); XLOG("LayerAndroid %d %x (%.2f, %.2f) drawGL (texture %x, %d, %d, %d, %d)", @@ -944,6 +950,8 @@ bool LayerAndroid::drawGL(GLWebViewState* glWebViewState, SkMatrix& matrix) textureInfo->m_textureId, m_drawOpacity, true); } + if (!ready) + m_dirty = true; m_drawingTexture->consumerRelease(); } else if (needsTexture()) { m_dirty = true; @@ -1034,14 +1042,18 @@ void LayerAndroid::paintBitmapGL() IntRect textureRect = texture->rect(); canvas->drawARGB(0, 0, 0, 0, SkXfermode::kClear_Mode); - SkPicture picture; - SkCanvas* nCanvas = picture.beginRecording(textureRect.width(), - textureRect.height()); - nCanvas->scale(scale, scale); - nCanvas->translate(-textureRect.x(), -textureRect.y()); - contentDraw(nCanvas); - picture.endRecording(); - picture.draw(canvas); + if (m_contentsImage) { + contentDraw(canvas); + } else { + SkPicture picture; + SkCanvas* nCanvas = picture.beginRecording(textureRect.width(), + textureRect.height()); + nCanvas->scale(scale, scale); + nCanvas->translate(-textureRect.x(), -textureRect.y()); + contentDraw(nCanvas); + picture.endRecording(); + picture.draw(canvas); + } extraDraw(canvas); m_atomicSync.lock(); @@ -1071,7 +1083,7 @@ void LayerAndroid::contentDraw(SkCanvas* canvas) if (m_contentsImage) { SkRect dest; dest.set(0, 0, getSize().width(), getSize().height()); - canvas->drawBitmapRect(m_contentsImage->bitmap(), 0, dest); + canvas->drawBitmapRect(*m_contentsImage, 0, dest); } else { canvas->drawPicture(*m_recordingPicture); } diff --git a/WebCore/platform/graphics/android/LayerAndroid.h b/WebCore/platform/graphics/android/LayerAndroid.h index 0846930..e01a9a7 100644 --- a/WebCore/platform/graphics/android/LayerAndroid.h +++ b/WebCore/platform/graphics/android/LayerAndroid.h @@ -234,6 +234,7 @@ public: */ void setContentsImage(SkBitmapRef* img); bool hasContentsImage() { return m_contentsImage; } + void copyBitmap(SkBitmap*); void bounds(SkRect*) const; @@ -304,7 +305,7 @@ private: // it is a much faster method than using m_recordingPicture. SkPicture* m_recordingPicture; - SkBitmapRef* m_contentsImage; + SkBitmap* m_contentsImage; typedef HashMap<pair<String, int>, RefPtr<AndroidAnimation> > KeyframesMap; KeyframesMap m_animations; diff --git a/WebCore/platform/graphics/android/TileSet.cpp b/WebCore/platform/graphics/android/PaintTileOperation.cpp index 1214aa2..222b69b 100644 --- a/WebCore/platform/graphics/android/TileSet.cpp +++ b/WebCore/platform/graphics/android/PaintTileOperation.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2010, The Android Open Source Project + * Copyright 2011, The Android Open Source Project * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -24,64 +24,58 @@ */ #include "config.h" -#include "TileSet.h" - -#if USE(ACCELERATED_COMPOSITING) - -#include "ClassTracker.h" -#include "TilesManager.h" - -#ifdef DEBUG - -#include <cutils/log.h> -#include <wtf/CurrentTime.h> -#include <wtf/text/CString.h> - -#undef XLOG -#define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "TileSet", __VA_ARGS__) - -#else - -#undef XLOG -#define XLOG(...) - -#endif // DEBUG +#include "PaintTileOperation.h" namespace WebCore { -TileSet::TileSet(TiledPage* tiledPage, int rows, int cols) - : m_tiledPage(tiledPage) - , m_nbRows(rows) - , m_nbCols(cols) +PaintTileOperation::PaintTileOperation(BaseTile* tile) + : QueuedOperation(QueuedOperation::PaintTile, tile->page()) + , m_tile(tile) { -#ifdef DEBUG_COUNT - ClassTracker::instance()->increment("TileSet"); -#endif + if (m_tile) + m_tile->setRepaintPending(true); } -TileSet::~TileSet() +PaintTileOperation::~PaintTileOperation() { -#ifdef DEBUG_COUNT - ClassTracker::instance()->decrement("TileSet"); -#endif + if (m_tile) { + m_tile->setRepaintPending(false); + m_tile = 0; + } } -bool TileSet::operator==(const TileSet& set) +bool PaintTileOperation::operator==(const QueuedOperation* operation) { - return m_tiledPage == set.m_tiledPage - && m_nbRows == set.m_nbRows - && m_nbCols == set.m_nbCols; + if (operation->type() != type()) + return false; + const PaintTileOperation* op = static_cast<const PaintTileOperation*>(operation); + return op->m_tile == m_tile; } - -void TileSet::paint() +void PaintTileOperation::run() { - XLOG("%x, painting %d tiles", this, m_tiles.size()); - for (unsigned int i = 0; i < m_tiles.size(); i++) - m_tiles[i]->paintBitmap(); - XLOG("%x, end of painting %d tiles", this, m_tiles.size()); + if (m_tile) { + m_tile->paintBitmap(); + m_tile->setRepaintPending(false); + m_tile = 0; + } } -} // namespace WebCore +int PaintTileOperation::priority() +{ + if (!m_tile || m_tile->usedLevel() < 0) + return -1; + bool goingDown = m_tile->page()->scrollingDown(); + SkIRect *rect = m_tile->page()->expandedTileBounds(); + int firstTileX = rect->fLeft; + int nbTilesWidth = rect->width(); + int priority = m_tile->x() - firstTileX; + if (goingDown) + priority += (rect->fBottom - m_tile->y()) * nbTilesWidth; + else + priority += (m_tile->y() - rect->fTop) * nbTilesWidth; + priority += m_tile->usedLevel() * 100000; + return priority; +} -#endif // USE(ACCELERATED_COMPOSITING) +} diff --git a/WebCore/platform/graphics/android/PaintTileSetOperation.h b/WebCore/platform/graphics/android/PaintTileOperation.h index fba7220..0920f32 100644 --- a/WebCore/platform/graphics/android/PaintTileSetOperation.h +++ b/WebCore/platform/graphics/android/PaintTileOperation.h @@ -27,33 +27,19 @@ #define PaintTileSetOperation_h #include "QueuedOperation.h" -#include "TileSet.h" namespace WebCore { -class PaintTileSetOperation : public QueuedOperation { +class PaintTileOperation : public QueuedOperation { public: - PaintTileSetOperation(TileSet* set) - : QueuedOperation(QueuedOperation::PaintTileSet, set->page()) - , m_set(set) {} - virtual ~PaintTileSetOperation() - { - delete m_set; - } - virtual bool operator==(const QueuedOperation* operation) - { - if (operation->type() != type()) - return false; - const PaintTileSetOperation* op = static_cast<const PaintTileSetOperation*>(operation); - return op->m_set == m_set; - } - virtual void run() - { - if (m_set) - m_set->paint(); - } + PaintTileOperation(BaseTile* tile); + virtual ~PaintTileOperation(); + virtual bool operator==(const QueuedOperation* operation); + virtual void run(); + virtual int priority(); + private: - TileSet* m_set; + BaseTile* m_tile; }; } diff --git a/WebCore/platform/graphics/android/PlatformGraphicsContext.h b/WebCore/platform/graphics/android/PlatformGraphicsContext.h index 8d0df36..0ce86d2 100644 --- a/WebCore/platform/graphics/android/PlatformGraphicsContext.h +++ b/WebCore/platform/graphics/android/PlatformGraphicsContext.h @@ -106,7 +106,8 @@ public: // corresponds to the focused node passed in. If its state has changed, // re-record to the subpicture, so the master picture will reflect the // change. - void updateFocusState(WebCore::RenderSkinAndroid::State state) + void updateFocusState(WebCore::RenderSkinAndroid::State state, + const WebCore::RenderSkinButton* buttonSkin) { if (state == m_state) return; @@ -117,8 +118,8 @@ public: state == WebCore::RenderSkinAndroid::kFocused) return; m_state = state; - SkCanvas* canvas = m_picture->beginRecording(m_rect.width(), m_rect.height()); - WebCore::RenderSkinButton::Draw(canvas, m_rect, state); + SkCanvas* canvas = m_picture->beginRecording(m_rect.right(), m_rect.bottom()); + buttonSkin->draw(canvas, m_rect, state); m_picture->endRecording(); } private: diff --git a/WebCore/platform/graphics/android/QueuedOperation.h b/WebCore/platform/graphics/android/QueuedOperation.h index 089483d..98f3e2f 100644 --- a/WebCore/platform/graphics/android/QueuedOperation.h +++ b/WebCore/platform/graphics/android/QueuedOperation.h @@ -32,13 +32,14 @@ namespace WebCore { class QueuedOperation { public: - enum OperationType { Undefined, PaintTileSet, PaintLayer, DeleteTexture }; + enum OperationType { Undefined, PaintTile, PaintLayer, DeleteTexture }; QueuedOperation(OperationType type, TiledPage* page) : m_type(type) , m_page(page) {} virtual ~QueuedOperation() {} virtual void run() = 0; virtual bool operator==(const QueuedOperation* operation) = 0; + virtual int priority() { return -1; } OperationType type() const { return m_type; } TiledPage* page() const { return m_page; } private: @@ -65,6 +66,20 @@ class PageFilter : public OperationFilter { TiledPage* m_page; }; +class PagePaintFilter : public OperationFilter { + public: + PagePaintFilter(TiledPage* page) : m_page(page) {} + virtual bool check(QueuedOperation* operation) + { + if (operation->type() == QueuedOperation::PaintTile + && operation->page() == m_page) + return true; + return false; + } + private: + TiledPage* m_page; +}; + } #endif // QueuedOperation_h diff --git a/WebCore/platform/graphics/android/SharedTexture.cpp b/WebCore/platform/graphics/android/SharedTexture.cpp index 495fdd0..040a28a 100644 --- a/WebCore/platform/graphics/android/SharedTexture.cpp +++ b/WebCore/platform/graphics/android/SharedTexture.cpp @@ -156,8 +156,9 @@ void SharedTexture::releaseSource() m_targetTexture.copyAttributes(&m_sourceTexture); } - // create an image from the texture - if (m_eglImage == EGL_NO_IMAGE_KHR) { + // create an image from the texture, only when the texture is valid + if (m_eglImage == EGL_NO_IMAGE_KHR && m_sourceTexture.m_width + && m_sourceTexture.m_height) { GLUtils::createEGLImageFromTexture(m_sourceTexture.m_textureId, &m_eglImage); LOGV("Generating Image (%d) 0x%x", m_sourceTexture.m_textureId, m_eglImage); diff --git a/WebCore/platform/graphics/android/TexturesGenerator.cpp b/WebCore/platform/graphics/android/TexturesGenerator.cpp index ad5de1f..e6bef6a 100644 --- a/WebCore/platform/graphics/android/TexturesGenerator.cpp +++ b/WebCore/platform/graphics/android/TexturesGenerator.cpp @@ -51,27 +51,11 @@ namespace WebCore { -void TexturesGenerator::scheduleOperation(QueuedOperation* operation, bool scheduleFirst) +void TexturesGenerator::scheduleOperation(QueuedOperation* operation) { { android::Mutex::Autolock lock(mRequestedOperationsLock); - for (unsigned int i = 0; i < mRequestedOperations.size(); i++) { - QueuedOperation** s = &mRequestedOperations[i]; - // A similar operation is already in the queue. The newer operation may - // have additional dirty tiles so delete the existing operation and - // replace it with the new one. - if (*s && *s == operation) { - QueuedOperation* oldOperation = *s; - *s = operation; - delete oldOperation; - return; - } - } - - if (scheduleFirst) - mRequestedOperations.prepend(operation); - else - mRequestedOperations.append(operation); + mRequestedOperations.append(operation); } mRequestedOperationsCond.signal(); } @@ -81,6 +65,11 @@ void TexturesGenerator::removeOperationsForPage(TiledPage* page) removeOperationsForFilter(new PageFilter(page)); } +void TexturesGenerator::removePaintOperationsForPage(TiledPage* page, bool waitForRunning) +{ + removeOperationsForFilter(new PagePaintFilter(page), waitForRunning); +} + void TexturesGenerator::removeOperationsForBaseLayer(BaseLayerAndroid* layer) { removeOperationsForFilter(new PaintLayerBaseFilter(layer)); @@ -93,6 +82,11 @@ void TexturesGenerator::removeOperationsForTexture(LayerTexture* texture) void TexturesGenerator::removeOperationsForFilter(OperationFilter* filter) { + removeOperationsForFilter(filter, true); +} + +void TexturesGenerator::removeOperationsForFilter(OperationFilter* filter, bool waitForRunning) +{ android::Mutex::Autolock lock(mRequestedOperationsLock); for (unsigned int i = 0; i < mRequestedOperations.size();) { QueuedOperation* operation = mRequestedOperations[i]; @@ -104,18 +98,22 @@ void TexturesGenerator::removeOperationsForFilter(OperationFilter* filter) } } - QueuedOperation* operation = m_currentOperation; - if (operation && filter->check(operation)) - m_waitForCompletion = true; - - delete filter; - - // At this point, it means that we are currently executing an operation that - // we want to be removed -- we should wait until it is done, so that - // when we return our caller can be sure that there is no more operations - // in the queue matching the given filter. - while (m_waitForCompletion) - mRequestedOperationsCond.wait(mRequestedOperationsLock); + if (waitForRunning) { + QueuedOperation* operation = m_currentOperation; + if (operation && filter->check(operation)) + m_waitForCompletion = true; + + delete filter; + + // At this point, it means that we are currently executing an operation that + // we want to be removed -- we should wait until it is done, so that + // when we return our caller can be sure that there is no more operations + // in the queue matching the given filter. + while (m_waitForCompletion) + mRequestedOperationsCond.wait(mRequestedOperationsLock); + } else { + delete filter; + } } status_t TexturesGenerator::readyToRun() @@ -125,6 +123,37 @@ status_t TexturesGenerator::readyToRun() return NO_ERROR; } +// Must be called from within a lock! +QueuedOperation* TexturesGenerator::popNext() +{ + // Priority can change between when it was added and now + // Hence why the entire queue is rescanned + QueuedOperation* current = mRequestedOperations.last(); + int currentPriority = current->priority(); + if (currentPriority < 0) { + mRequestedOperations.removeLast(); + return current; + } + int currentIndex = mRequestedOperations.size() - 1; + // Scan from the back to make removing faster (less items to copy) + for (int i = mRequestedOperations.size() - 2; i >= 0; i--) { + QueuedOperation *next = mRequestedOperations[i]; + int nextPriority = next->priority(); + if (nextPriority < 0) { + // Found a very high priority item, go ahead and just handle it now + mRequestedOperations.remove(i); + return next; + } + if (nextPriority < currentPriority) { + current = next; + currentPriority = nextPriority; + currentIndex = i; + } + } + mRequestedOperations.remove(currentIndex); + return current; +} + bool TexturesGenerator::threadLoop() { // Check if we have any pending operations. @@ -138,20 +167,14 @@ bool TexturesGenerator::threadLoop() m_currentOperation = 0; bool stop = false; while (!stop) { - XLOG("threadLoop evaluating the requests"); mRequestedOperationsLock.lock(); - if (mRequestedOperations.size()) { - m_currentOperation = mRequestedOperations.first(); - mRequestedOperations.remove(0); - XLOG("threadLoop, popping the first request (%d requests left)", - mRequestedOperations.size()); - } + if (mRequestedOperations.size()) + m_currentOperation = popNext(); mRequestedOperationsLock.unlock(); if (m_currentOperation) { - XLOG("threadLoop, painting the request"); + XLOG("threadLoop, painting the request with priority %d", m_currentOperation->priority()); m_currentOperation->run(); - XLOG("threadLoop, painting the request - DONE"); } mRequestedOperationsLock.lock(); @@ -168,6 +191,7 @@ bool TexturesGenerator::threadLoop() mRequestedOperationsLock.unlock(); } + XLOG("threadLoop empty"); return true; } diff --git a/WebCore/platform/graphics/android/TexturesGenerator.h b/WebCore/platform/graphics/android/TexturesGenerator.h index 169471c..b03f52d 100644 --- a/WebCore/platform/graphics/android/TexturesGenerator.h +++ b/WebCore/platform/graphics/android/TexturesGenerator.h @@ -30,7 +30,6 @@ #include "LayerTexture.h" #include "QueuedOperation.h" -#include "TileSet.h" #include "TiledPage.h" #include <utils/threads.h> @@ -52,11 +51,14 @@ public: void removeOperationsForPage(TiledPage* page); void removeOperationsForBaseLayer(BaseLayerAndroid* layer); void removeOperationsForTexture(LayerTexture* texture); + void removePaintOperationsForPage(TiledPage* page, bool waitForRunning); void removeOperationsForFilter(OperationFilter* filter); + void removeOperationsForFilter(OperationFilter* filter, bool waitForRunning); - void scheduleOperation(QueuedOperation* operation, bool scheduleFirst); + void scheduleOperation(QueuedOperation* operation); private: + QueuedOperation* popNext(); virtual bool threadLoop(); Vector<QueuedOperation*> mRequestedOperations; android::Mutex mRequestedOperationsLock; diff --git a/WebCore/platform/graphics/android/TileSet.h b/WebCore/platform/graphics/android/TileSet.h deleted file mode 100644 index aa0f2ed..0000000 --- a/WebCore/platform/graphics/android/TileSet.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2010, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TileSet_h -#define TileSet_h - -#if USE(ACCELERATED_COMPOSITING) - -#include "BaseTile.h" -#include "Vector.h" - -namespace WebCore { - -/** - * This purpose of this class is to act as a container for BaseTiles that need - * to upload their contents to the GPU. A TiledPage creates a new TileSet and - * provides the set with identifying characteristics of the TiledPage's current - * state (see constructor). This information allows the consumer of the TileSet - * to determine if an equivalent TileSet already exists in the upload pipeline. - */ -class TileSet { -public: - TileSet(TiledPage* tiledPage, int nbRows, int nbCols); - ~TileSet(); - - bool operator==(const TileSet& set); - void paint(); - - void add(BaseTile* texture) - { - m_tiles.append(texture); - } - - TiledPage* page() - { - return m_tiledPage; - } - - unsigned int size() - { - return m_tiles.size(); - } - -private: - Vector<BaseTile*> m_tiles; - - TiledPage* m_tiledPage; - int m_nbRows; - int m_nbCols; -}; - -} // namespace WebCore - -#endif // USE(ACCELERATED_COMPOSITING) -#endif // TileSet_h diff --git a/WebCore/platform/graphics/android/TiledPage.cpp b/WebCore/platform/graphics/android/TiledPage.cpp index 6f910a3..5212871 100644 --- a/WebCore/platform/graphics/android/TiledPage.cpp +++ b/WebCore/platform/graphics/android/TiledPage.cpp @@ -30,7 +30,7 @@ #include "GLUtils.h" #include "IntRect.h" -#include "PaintTileSetOperation.h" +#include "PaintTileOperation.h" #include "TilesManager.h" #ifdef DEBUG @@ -82,7 +82,6 @@ void TiledPage::updateBaseTileSize() int baseTileSize = TilesManager::instance()->maxTextureCount() + 1; if (baseTileSize > m_baseTileSize) m_baseTileSize = baseTileSize; - XLOG("Allocate %d tiles", m_baseTileSize); } TiledPage::~TiledPage() @@ -126,6 +125,7 @@ void TiledPage::invalidateRect(const IntRect& inval, const unsigned int pictureC const int lastDirtyTileX = static_cast<int>(ceilf(inval.right() * invTileContentWidth)); const int lastDirtyTileY = static_cast<int>(ceilf(inval.bottom() * invTileContentHeight)); + XLOG("Marking X %d-%d and Y %d-%d dirty", firstDirtyTileX, lastDirtyTileX, firstDirtyTileY, lastDirtyTileY); // We defer marking the tile as dirty until the next time we need to prepare // to draw. m_invalRegion.op(firstDirtyTileX, firstDirtyTileY, lastDirtyTileX, lastDirtyTileY, SkRegion::kUnion_Op); @@ -133,12 +133,10 @@ void TiledPage::invalidateRect(const IntRect& inval, const unsigned int pictureC m_latestPictureInval = pictureCount; } -void TiledPage::prepareRow(bool goingLeft, int tilesInRow, int firstTileX, int y, TileSet* set) +void TiledPage::prepareRow(bool goingLeft, int tilesInRow, int firstTileX, int y, const SkIRect& tileBounds) { if (y < 0) return; - if (!set) - return; for (int i = 0; i < tilesInRow; i++) { int x = firstTileX; @@ -177,12 +175,41 @@ void TiledPage::prepareRow(bool goingLeft, int tilesInRow, int firstTileX, int y // ensure there is a texture associated with the tile and then check to // see if the texture is dirty and in need of repainting currentTile->reserveTexture(); - if (currentTile->isDirty()) - set->add(currentTile); + updateTileUsedLevel(tileBounds, *currentTile); + if (currentTile->isDirty() && !currentTile->isRepaintPending()) { + PaintTileOperation *operation = new PaintTileOperation(currentTile); + TilesManager::instance()->scheduleOperation(operation); + } else if (currentTile->isDirty()) { + XLOG("Tile %dx%d is dirty, but awaiting repaint", currentTile->x(), currentTile->y()); + } } } } +void TiledPage::updateTileUsedLevel(const SkIRect& tileBounds, BaseTile& tile) +{ + const int lastTileX = tileBounds.fRight - 1; + const int lastTileY = tileBounds.fBottom - 1; + + // set the used level of the tile (e.g. distance from the viewport) + int dx = 0; + int dy = 0; + + if (tileBounds.fLeft > tile.x()) + dx = tileBounds.fLeft - tile.x(); + else if (lastTileX < tile.x()) + dx = tile.x() - lastTileX; + + if (tileBounds.fTop > tile.y()) + dy = tileBounds.fTop - tile.y(); + else if (lastTileY < tile.y()) + dy = tile.y() - lastTileY; + + int d = std::max(dx, dy); + + tile.setUsedLevel(d); +} + void TiledPage::updateTileState(const SkIRect& tileBounds) { if (!m_glWebViewState || tileBounds.isEmpty()) { @@ -191,41 +218,19 @@ void TiledPage::updateTileState(const SkIRect& tileBounds) return; } - const int nbTilesWidth = tileBounds.width() - 1; - const int nbTilesHeight = tileBounds.height() - 1; - - const int lastTileX = tileBounds.fRight - 1; - const int lastTileY = tileBounds.fBottom - 1; - for (int x = 0; x < m_baseTileSize; x++) { BaseTile& tile = m_baseTiles[x]; - // if the tile is in the dirty region then we must invalidate it - if (m_invalRegion.contains(tile.x(), tile.y())) - tile.markAsDirty(m_latestPictureInval, m_invalTilesRegion); - // if the tile no longer has a texture then proceed to the next tile if (tile.isAvailable()) continue; - // set the used level of the tile (e.g. distance from the viewport) - int dx = 0; - int dy = 0; - - if (tileBounds.fLeft > tile.x()) - dx = tileBounds.fLeft - tile.x(); - else if (lastTileX < tile.x()) - dx = tile.x() - lastTileX; - - if (tileBounds.fTop > tile.y()) - dy = tileBounds.fTop - tile.y(); - else if (lastTileY < tile.y()) - dy = tile.y() - lastTileY; - - int d = std::max(dx, dy); + // if the tile is in the dirty region then we must invalidate it + if (m_invalRegion.contains(tile.x(), tile.y())) + tile.markAsDirty(m_latestPictureInval, m_invalTilesRegion); - tile.setUsedLevel(d); + updateTileUsedLevel(tileBounds, tile); } // clear the invalidated region as all tiles within that region have now @@ -234,8 +239,7 @@ void TiledPage::updateTileState(const SkIRect& tileBounds) m_invalTilesRegion.setEmpty(); } -void TiledPage::prepare(bool goingDown, bool goingLeft, const SkIRect& tileBounds, - bool scheduleFirst) +void TiledPage::prepare(bool goingDown, bool goingLeft, const SkIRect& tileBounds) { if (!m_glWebViewState) return; @@ -243,6 +247,7 @@ void TiledPage::prepare(bool goingDown, bool goingLeft, const SkIRect& tileBound // update the tiles distance from the viewport updateTileState(tileBounds); m_prepare = true; + m_scrollingDown = goingDown; int firstTileX = tileBounds.fLeft; int firstTileY = tileBounds.fTop; @@ -255,43 +260,29 @@ void TiledPage::prepare(bool goingDown, bool goingLeft, const SkIRect& tileBound const int baseContentHeight = m_glWebViewState->baseContentHeight(); const int baseContentWidth = m_glWebViewState->baseContentWidth(); - TileSet* set = new TileSet(this, nbTilesHeight, nbTilesWidth); - - if (!scheduleFirst) { - // Expand number of tiles to allow tiles outside of viewport to be prepared for - // smoother scrolling. - int nTilesToPrepare = nbTilesWidth * nbTilesHeight; - int nMaxTilesPerPage = m_baseTileSize / 2; - int expandX = TilesManager::instance()->expandedTileBoundsX(); - int expandY = TilesManager::instance()->expandedTileBoundsY(); - if (nTilesToPrepare + (nbTilesHeight * expandX * 2) <= nMaxTilesPerPage) { - firstTileX -= expandX; - lastTileX += expandX; - nbTilesWidth += expandX * 2; - } - if (nTilesToPrepare + (nbTilesWidth * expandY * 2) <= nMaxTilesPerPage) { - firstTileY -= expandY; - lastTileY += expandY; - nbTilesHeight += expandY * 2; - } + // Expand number of tiles to allow tiles outside of viewport to be prepared for + // smoother scrolling. + int nTilesToPrepare = nbTilesWidth * nbTilesHeight; + int nMaxTilesPerPage = m_baseTileSize / 2; + int expandX = TilesManager::instance()->expandedTileBoundsX(); + int expandY = TilesManager::instance()->expandedTileBoundsY(); + if (nTilesToPrepare + (nbTilesHeight * expandX * 2) <= nMaxTilesPerPage) { + firstTileX -= expandX; + lastTileX += expandX; + nbTilesWidth += expandX * 2; } - - // We chose to prepare tiles depending on the scroll direction. Tiles are - // appended to the list and the texture uploader goes through the list front - // to back. So we append tiles in reverse order because the last additions - // to the are processed first. - if (goingDown) { - for (int i = 0; i < nbTilesHeight; i++) - prepareRow(goingLeft, nbTilesWidth, firstTileX, lastTileY - i, set); - } else { - for (int i = 0; i < nbTilesHeight; i++) - prepareRow(goingLeft, nbTilesWidth, firstTileX, firstTileY + i, set); + if (nTilesToPrepare + (nbTilesWidth * expandY * 2) <= nMaxTilesPerPage) { + firstTileY -= expandY; + lastTileY += expandY; + nbTilesHeight += expandY * 2; } + m_expandedTileBounds.fLeft = firstTileX; + m_expandedTileBounds.fTop = firstTileY; + m_expandedTileBounds.fRight = lastTileX; + m_expandedTileBounds.fBottom = lastTileY; - // The paint operation will take ownership of the tileSet here, so no delete - // is necessary. - PaintTileSetOperation* operation = new PaintTileSetOperation(set); - TilesManager::instance()->scheduleOperation(operation, scheduleFirst); + for (int i = 0; i < nbTilesHeight; i++) + prepareRow(goingLeft, nbTilesWidth, firstTileX, firstTileY + i, tileBounds); } bool TiledPage::ready(const SkIRect& tileBounds, float scale) @@ -330,7 +321,6 @@ void TiledPage::draw(float transparency, const SkIRect& tileBounds) actualTileBounds.fLeft -= TilesManager::instance()->expandedTileBoundsX(); actualTileBounds.fRight += TilesManager::instance()->expandedTileBoundsX(); - XLOG("WE DRAW %x (%.2f) with transparency %.2f", this, scale(), transparency); for (int j = 0; j < m_baseTileSize; j++) { BaseTile& tile = m_baseTiles[j]; if (actualTileBounds.contains(tile.x(), tile.y())) { @@ -344,11 +334,6 @@ void TiledPage::draw(float transparency, const SkIRect& tileBounds) tile.draw(transparency, rect, m_scale); } } - -#ifdef DEBUG - XLOG("FINISHED WE DRAW %x (%.2f) with transparency %.2f", this, scale(), transparency); - TilesManager::instance()->printTextures(); -#endif // DEBUG } unsigned int TiledPage::paintBaseLayerContent(SkCanvas* canvas) diff --git a/WebCore/platform/graphics/android/TiledPage.h b/WebCore/platform/graphics/android/TiledPage.h index 7e0bb2e..1aa3e61 100644 --- a/WebCore/platform/graphics/android/TiledPage.h +++ b/WebCore/platform/graphics/android/TiledPage.h @@ -31,7 +31,6 @@ #include "BaseTile.h" #include "SkCanvas.h" #include "SkRegion.h" -#include "TileSet.h" namespace WebCore { @@ -57,8 +56,7 @@ public: TiledPage* sibling(); // prepare the page for display on the screen - void prepare(bool goingDown, bool goingLeft, const SkIRect& tileBounds, - bool scheduleFirst = false); + void prepare(bool goingDown, bool goingLeft, const SkIRect& tileBounds); // check to see if the page is ready for display bool ready(const SkIRect& tileBounds, float scale); // draw the page on the screen @@ -75,10 +73,13 @@ public: void invalidateRect(const IntRect& invalRect, const unsigned int pictureCount); void setUsable(bool usable); void updateBaseTileSize(); + bool scrollingDown() { return m_scrollingDown; } + SkIRect* expandedTileBounds() { return &m_expandedTileBounds; } private: void updateTileState(const SkIRect& tileBounds); - void prepareRow(bool goingLeft, int tilesInRow, int firstTileX, int y, TileSet* set); + void prepareRow(bool goingLeft, int tilesInRow, int firstTileX, int y, const SkIRect& tileBounds); + void updateTileUsedLevel(const SkIRect& tileBounds, BaseTile& tile); BaseTile* getBaseTile(int x, int y) const; @@ -103,6 +104,8 @@ private: SkRegion m_invalTilesRegion; unsigned int m_latestPictureInval; bool m_prepare; + bool m_scrollingDown; + SkIRect m_expandedTileBounds; }; } // namespace WebCore diff --git a/WebCore/platform/graphics/android/TilesManager.cpp b/WebCore/platform/graphics/android/TilesManager.cpp index afc53eb..5a9a164 100644 --- a/WebCore/platform/graphics/android/TilesManager.cpp +++ b/WebCore/platform/graphics/android/TilesManager.cpp @@ -249,7 +249,7 @@ LayerTexture* TilesManager::getExistingTextureForLayer(LayerAndroid* layer, layer->uniqueId(), layer); } - if (best && best->acquire(layer)) + if (best && best->acquire(layer, any)) return best; return 0; } diff --git a/WebCore/platform/graphics/android/TilesManager.h b/WebCore/platform/graphics/android/TilesManager.h index 5a4e28a..6d49cca 100644 --- a/WebCore/platform/graphics/android/TilesManager.h +++ b/WebCore/platform/graphics/android/TilesManager.h @@ -39,8 +39,6 @@ namespace WebCore { -class TileSet; - class TilesManager { public: static TilesManager* instance(); @@ -57,6 +55,11 @@ public: m_pixmapsGenerationThread->removeOperationsForPage(page); } + void removePaintOperationsForPage(TiledPage* page, bool waitForCompletion) + { + m_pixmapsGenerationThread->removePaintOperationsForPage(page, waitForCompletion); + } + void removeOperationsForBaseLayer(BaseLayerAndroid* layer) { m_pixmapsGenerationThread->removeOperationsForBaseLayer(layer); @@ -67,9 +70,9 @@ public: m_pixmapsGenerationThread->removeOperationsForTexture(texture); } - void scheduleOperation(QueuedOperation* operation, bool scheduleFirst = false) + void scheduleOperation(QueuedOperation* operation) { - m_pixmapsGenerationThread->scheduleOperation(operation, scheduleFirst); + m_pixmapsGenerationThread->scheduleOperation(operation); } ShaderProgram* shader() { return &m_shader; } diff --git a/WebCore/platform/graphics/android/android_graphics.h b/WebCore/platform/graphics/android/android_graphics.h index be309a6..89312b5 100644 --- a/WebCore/platform/graphics/android/android_graphics.h +++ b/WebCore/platform/graphics/android/android_graphics.h @@ -56,6 +56,7 @@ public: virtual void draw(SkCanvas* , LayerAndroid* , IntRect* ); void setIsButton(const CachedNode* ); bool setup(); + WTF::Vector<IntRect>& rings() { return m_rings; } private: friend class WebView; WebViewCore* m_viewImpl; // copy for convenience diff --git a/WebCore/rendering/RenderLayerCompositor.cpp b/WebCore/rendering/RenderLayerCompositor.cpp index 6578d1d..c0dba6f 100644 --- a/WebCore/rendering/RenderLayerCompositor.cpp +++ b/WebCore/rendering/RenderLayerCompositor.cpp @@ -535,8 +535,17 @@ bool RenderLayerCompositor::overlapsCompositedLayers(OverlapMap& overlapMap, con RenderLayerCompositor::OverlapMap::const_iterator end = overlapMap.end(); for (RenderLayerCompositor::OverlapMap::const_iterator it = overlapMap.begin(); it != end; ++it) { const IntRect& bounds = it->second; - if (layerBounds.intersects(bounds)) + if (layerBounds.intersects(bounds)) { +#if ENABLE(COMPOSITED_FIXED_ELEMENTS) + RenderLayer* intersectedLayer = it->first; + if (intersectedLayer && intersectedLayer->isFixed()) { + if (bounds.contains(layerBounds)) { + continue; + } + } +#endif return true; + } } return false; @@ -1170,15 +1179,6 @@ bool RenderLayerCompositor::needsToBeComposited(const RenderLayer* layer) const if (!canBeComposited(layer)) return false; -#if ENABLE(COMPOSITED_FIXED_ELEMENTS) - // if an ancestor is fixed positioned, we need to be composited... - const RenderLayer* currLayer = layer; - while ((currLayer = currLayer->parent())) { - if (currLayer->isComposited() && currLayer->isFixed()) - return true; - } -#endif - // The root layer always has a compositing layer, but it may not have backing. return requiresCompositingLayer(layer) || layer->mustOverlapCompositedLayers() || (inCompositingMode() && layer->isRootLayer()); } diff --git a/WebKit/Android.mk b/WebKit/Android.mk index 88defda..5998227 100644 --- a/WebKit/Android.mk +++ b/WebKit/Android.mk @@ -53,6 +53,7 @@ LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \ android/RenderSkinButton.cpp \ android/RenderSkinCombo.cpp \ android/RenderSkinMediaButton.cpp \ + android/RenderSkinNinePatch.cpp \ android/RenderSkinRadio.cpp \ android/TimeCounter.cpp \ \ diff --git a/WebKit/android/RenderSkinAndroid.cpp b/WebKit/android/RenderSkinAndroid.cpp index 00f2b96..9383a9c 100644 --- a/WebKit/android/RenderSkinAndroid.cpp +++ b/WebKit/android/RenderSkinAndroid.cpp @@ -37,15 +37,14 @@ #include "utils/Asset.h" namespace WebCore { - -RenderSkinAndroid::RenderSkinAndroid() - : m_height(0) - , m_width(0) -{} -void RenderSkinAndroid::Init(android::AssetManager* am, String drawableDirectory) +RenderSkinAndroid::~RenderSkinAndroid() { - RenderSkinButton::Init(am, drawableDirectory); + delete m_button; +} +RenderSkinAndroid::RenderSkinAndroid(android::AssetManager* am, String drawableDirectory) +{ + m_button = new RenderSkinButton(am, drawableDirectory); RenderSkinCombo::Init(am, drawableDirectory); RenderSkinMediaButton::Init(am, drawableDirectory); RenderSkinRadio::Init(am, drawableDirectory); diff --git a/WebKit/android/RenderSkinAndroid.h b/WebKit/android/RenderSkinAndroid.h index b877ff2..73773ea 100644 --- a/WebKit/android/RenderSkinAndroid.h +++ b/WebKit/android/RenderSkinAndroid.h @@ -36,17 +36,11 @@ class SkBitmap; namespace WebCore { class Node; -class PlatformGraphicsContext; +class RenderSkinButton; -/* RenderSkinAndroid is the base class for all RenderSkins. Form elements each have a - * subclass for drawing themselves. - */ class RenderSkinAndroid { public: - RenderSkinAndroid(); - virtual ~RenderSkinAndroid() {} - enum State { kDisabled, kNormal, @@ -60,7 +54,8 @@ public: * Initialize the Android skinning system. The AssetManager may be used to find resources used * in rendering. */ - static void Init(android::AssetManager*, String drawableDirectory); + RenderSkinAndroid(android::AssetManager*, String drawableDirectory); + ~RenderSkinAndroid(); /* DecodeBitmap determines which file to use, with the given fileName of the form * "images/bitmap.png", and uses the asset manager to select the exact one. It @@ -68,24 +63,10 @@ public: */ static bool DecodeBitmap(android::AssetManager* am, const char* fileName, SkBitmap* bitmap); - /* draw() tells the skin to draw itself, and returns true if the skin needs - * a redraw to animations, false otherwise - */ - virtual bool draw(PlatformGraphicsContext*) { return false; } - - /* notifyState() checks to see if the element is checked, focused, and enabled - * it must be implemented in the subclass - */ - virtual void notifyState(Node* element) { } - - /* setDim() tells the skin its width and height - */ - virtual void setDim(int width, int height) { m_width = width; m_height = height; } - -protected: - int m_height; - int m_width; + const RenderSkinButton* renderSkinButton() const { return m_button; } +private: + RenderSkinButton* m_button; }; } // WebCore diff --git a/WebKit/android/RenderSkinButton.cpp b/WebKit/android/RenderSkinButton.cpp index 1dc6560..6a0ae54 100644 --- a/WebKit/android/RenderSkinButton.cpp +++ b/WebKit/android/RenderSkinButton.cpp @@ -31,47 +31,36 @@ #include "IntRect.h" #include "Node.h" #include "RenderSkinButton.h" +#include "RenderSkinNinePatch.h" #include "SkCanvas.h" #include "SkNinePatch.h" #include "SkRect.h" +#include <utils/Asset.h> +#include <utils/AssetManager.h> #include <utils/Debug.h> #include <utils/Log.h> +#include <utils/ResourceTypes.h> #include <wtf/text/CString.h> -struct PatchData { - const char* name; - int8_t outset, margin; -}; - -static const PatchData gFiles[] = - { - { "btn_default_disabled_holo.9.png", 2, 7 }, - { "btn_default_normal_holo.9.png", 2, 7 }, - { "btn_default_focused_holo.9.png", 2, 7 }, - { "btn_default_pressed_holo.9.png", 2, 7 } +static const char* gFiles[] = { + "btn_default_disabled_holo.9.png", + "btn_default_normal_holo.9.png", + "btn_default_focused_holo.9.png", + "btn_default_pressed_holo.9.png" }; -static SkBitmap gButton[sizeof(gFiles)/sizeof(gFiles[0])]; -static bool gDecoded; -static bool gHighRes; - namespace WebCore { -void RenderSkinButton::Init(android::AssetManager* am, String drawableDirectory) +RenderSkinButton::RenderSkinButton(android::AssetManager* am, String drawableDirectory) { - static bool gInited; - if (gInited) - return; - - gInited = true; - gDecoded = true; - gHighRes = drawableDirectory[drawableDirectory.length() - 5] == 'h'; - for (size_t i = 0; i < sizeof(gFiles)/sizeof(gFiles[0]); i++) { - String path = drawableDirectory + gFiles[i].name; - if (!RenderSkinAndroid::DecodeBitmap(am, path.utf8().data(), &gButton[i])) { - gDecoded = false; - LOGD("RenderSkinButton::Init: button assets failed to decode\n\tBrowser buttons will not draw"); - break; + m_decoded = true; + for (size_t i = 0; i < 4; i++) { + String path = String(drawableDirectory.impl()); + path.append(String(gFiles[i])); + if (!RenderSkinNinePatch::decodeAsset(am, path.utf8().data(), &m_buttons[i])) { + m_decoded = false; + LOGE("RenderSkinButton::Init: button assets failed to decode\n\tBrowser buttons will not draw"); + return; } } @@ -82,11 +71,12 @@ void RenderSkinButton::Init(android::AssetManager* am, String drawableDirectory) android::CompileTimeAssert<(RenderSkinAndroid::kPressed == 3)> a4; } -void RenderSkinButton::Draw(SkCanvas* canvas, const IntRect& r, RenderSkinAndroid::State newState) +void RenderSkinButton::draw(SkCanvas* canvas, const IntRect& r, + RenderSkinAndroid::State newState) const { // If we failed to decode, do nothing. This way the browser still works, // and webkit will still draw the label and layout space for us. - if (!gDecoded) { + if (!m_decoded) { return; } @@ -94,26 +84,7 @@ void RenderSkinButton::Draw(SkCanvas* canvas, const IntRect& r, RenderSkinAndroi SkASSERT(static_cast<unsigned>(newState) < static_cast<unsigned>(RenderSkinAndroid::kNumStates)); - // Set up the ninepatch information for drawing. - SkRect bounds(r); - const PatchData& pd = gFiles[newState]; - int marginValue = pd.margin + pd.outset; - - SkIRect margin; - - margin.set(marginValue, marginValue, marginValue, marginValue); - if (gHighRes) { - /* FIXME: it shoudn't be necessary to offset the button here, - but gives the right results. */ - bounds.offset(0, SK_Scalar1 * 2); - /* FIXME: This temporarily gets around the fact that the margin values and - positioning were created for a low res asset, which was used on - g1-like devices. A better fix would be to read the offset information - out of the png. */ - margin.set(10, 9, 10, 14); - } - // Draw to the canvas. - SkNinePatch::DrawNine(canvas, bounds, gButton[newState], margin); + RenderSkinNinePatch::DrawNinePatch(canvas, SkRect(r), m_buttons[newState]); } } //WebCore diff --git a/WebKit/android/RenderSkinButton.h b/WebKit/android/RenderSkinButton.h index e9cf0ec..e9db74c 100644 --- a/WebKit/android/RenderSkinButton.h +++ b/WebKit/android/RenderSkinButton.h @@ -27,24 +27,28 @@ #define RenderSkinButton_h #include "RenderSkinAndroid.h" +#include "RenderSkinNinePatch.h" class SkCanvas; namespace WebCore { class IntRect; -class RenderSkinButton -{ + +class RenderSkinButton { public: /** * Initialize the class before use. Uses the AssetManager to initialize any * bitmaps the class may use. */ - static void Init(android::AssetManager*, String drawableDirectory); + RenderSkinButton(android::AssetManager*, String drawableDirectory); /** * Draw the skin to the canvas, using the rectangle for its bounds and the * State to determine which skin to use, i.e. focused or not focused. */ - static void Draw(SkCanvas* , const IntRect& , RenderSkinAndroid::State); + void draw(SkCanvas* , const IntRect& , RenderSkinAndroid::State) const; +private: + bool m_decoded; + NinePatch m_buttons[4]; }; } // WebCore diff --git a/WebKit/android/RenderSkinMediaButton.cpp b/WebKit/android/RenderSkinMediaButton.cpp index 745fa88..090d55e 100644 --- a/WebKit/android/RenderSkinMediaButton.cpp +++ b/WebKit/android/RenderSkinMediaButton.cpp @@ -58,8 +58,8 @@ static const PatchData gFiles[] = { "spinner_76_inner_holo.png", 0, 0 }, // SPINNER_INNER { "ic_media_video_poster.png", 0, 0 }, // VIDEO { "btn_media_player_disabled.9.png", 0, 0 }, // BACKGROUND_SLIDER - { "scrubber_track_holo_dark.9.png", 0, 0 }, // SLIDER_TRACK - { "scrubber_control_holo.png", 0, 0 } // SLIDER_THUMB + { "scrubber_track_holo_dark.9.png", 0, 0 }, // SLIDER_TRACK + { "scrubber_control_holo.png", 0, 0 } // SLIDER_THUMB }; static SkBitmap gButton[sizeof(gFiles)/sizeof(gFiles[0])]; @@ -112,6 +112,7 @@ void RenderSkinMediaButton::Draw(SkCanvas* canvas, const IntRect& r, int buttonT alpha = 190; SkColor backgroundColor = SkColorSetARGB(alpha, 34, 34, 34); + SkColor trackBackgroundColor = SkColorSetARGB(255, 100, 100, 100); paint.setColor(backgroundColor); paint.setFlags(SkPaint::kFilterBitmap_Flag); diff --git a/WebKit/android/RenderSkinNinePatch.cpp b/WebKit/android/RenderSkinNinePatch.cpp new file mode 100644 index 0000000..0c915c0 --- /dev/null +++ b/WebKit/android/RenderSkinNinePatch.cpp @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "config.h" + +#include "RenderSkinNinePatch.h" +#include "NinePatchPeeker.h" +#include "SkCanvas.h" +#include "SkImageDecoder.h" +#include "SkRect.h" +#include "SkStream.h" +#include "SkTemplates.h" +#include <utils/Asset.h> +#include <utils/AssetManager.h> +#include <utils/Log.h> +#include <utils/ResourceTypes.h> + +class SkPaint; +class SkRegion; + +using namespace android; + +extern void NinePatch_Draw(SkCanvas* canvas, const SkRect& bounds, + const SkBitmap& bitmap, const Res_png_9patch& chunk, + const SkPaint* paint, SkRegion** outRegion); + +bool RenderSkinNinePatch::decodeAsset(AssetManager* am, const char* filename, NinePatch* ninepatch) { + Asset* asset = am->open(filename, android::Asset::ACCESS_BUFFER); + if (!asset) { + asset = am->openNonAsset(filename, android::Asset::ACCESS_BUFFER); + if (!asset) { + return false; + } + } + + SkImageDecoder::Mode mode = SkImageDecoder::kDecodePixels_Mode; + SkBitmap::Config prefConfig = SkBitmap::kNo_Config; + SkStream* stream = new SkMemoryStream(asset->getBuffer(false), asset->getLength()); + SkImageDecoder* decoder = SkImageDecoder::Factory(stream); + if (!decoder) { + asset->close(); + LOGE("RenderSkinNinePatch::Failed to create an image decoder"); + return false; + } + + decoder->setSampleSize(1); + decoder->setDitherImage(true); + decoder->setPreferQualityOverSpeed(false); + + NinePatchPeeker peeker(decoder); + + SkAutoTDelete<SkImageDecoder> add(decoder); + + decoder->setPeeker(&peeker); + if (!decoder->decode(stream, &ninepatch->m_bitmap, prefConfig, mode, true)) { + asset->close(); + LOGE("RenderSkinNinePatch::Failed to decode nine patch asset"); + return false; + } + + asset->close(); + if (!peeker.fPatchIsValid) { + LOGE("RenderSkinNinePatch::Patch data not valid"); + return false; + } + void** data = &ninepatch->m_serializedPatchData; + *data = malloc(peeker.fPatch->serializedSize()); + peeker.fPatch->serialize(*data); + return true; +} + +void RenderSkinNinePatch::DrawNinePatch(SkCanvas* canvas, const SkRect& bounds, + const NinePatch& patch) { + Res_png_9patch* data = Res_png_9patch::deserialize(patch.m_serializedPatchData); + NinePatch_Draw(canvas, bounds, patch.m_bitmap, *data, 0, 0); +} diff --git a/WebKit/android/RenderSkinNinePatch.h b/WebKit/android/RenderSkinNinePatch.h new file mode 100644 index 0000000..e4db260 --- /dev/null +++ b/WebKit/android/RenderSkinNinePatch.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef RenderSkinNinePatch_h +#define RenderSkinNinePatch_h + +#include "SkBitmap.h" +#include "utils/Asset.h" + +namespace android { + class AssetManager; +} + +class SkCanvas; +class SkRect; + +struct NinePatch { + SkBitmap m_bitmap; + void* m_serializedPatchData; + NinePatch() { + m_serializedPatchData = 0; + } + ~NinePatch() { + if (m_serializedPatchData) + free(m_serializedPatchData); + } +}; + +class RenderSkinNinePatch { +public: + static bool decodeAsset(android::AssetManager*, const char* fileName, NinePatch*); + static void DrawNinePatch(SkCanvas*, const SkRect&, const NinePatch&); +}; + +#endif // RenderSkinNinePatch_h diff --git a/WebKit/android/WebCoreSupport/UrlInterceptResponse.cpp b/WebKit/android/WebCoreSupport/UrlInterceptResponse.cpp index 875b222..3779ba8 100644 --- a/WebKit/android/WebCoreSupport/UrlInterceptResponse.cpp +++ b/WebKit/android/WebCoreSupport/UrlInterceptResponse.cpp @@ -40,11 +40,11 @@ public: : m_inputStream(env->NewGlobalRef(inputStream)) , m_buffer(0) { LOG_ALWAYS_FATAL_IF(!inputStream); - m_inputStreamClass = env->FindClass("java/io/InputStream"); - LOG_ALWAYS_FATAL_IF(!m_inputStreamClass); - m_read = env->GetMethodID(m_inputStreamClass, "read", "([B)I"); + jclass inputStreamClass = env->FindClass("java/io/InputStream"); + LOG_ALWAYS_FATAL_IF(!inputStreamClass); + m_read = env->GetMethodID(inputStreamClass, "read", "([B)I"); LOG_ALWAYS_FATAL_IF(!m_read); - m_close = env->GetMethodID(m_inputStreamClass, "close", "()V"); + m_close = env->GetMethodID(inputStreamClass, "close", "()V"); LOG_ALWAYS_FATAL_IF(!m_close); } @@ -76,7 +76,6 @@ public: private: jobject m_inputStream; jbyteArray m_buffer; - jclass m_inputStreamClass; jmethodID m_read; jmethodID m_close; }; diff --git a/WebKit/android/WebCoreSupport/WebUrlLoaderClient.cpp b/WebKit/android/WebCoreSupport/WebUrlLoaderClient.cpp index fcfb4ca..cf218e7 100644 --- a/WebKit/android/WebCoreSupport/WebUrlLoaderClient.cpp +++ b/WebKit/android/WebCoreSupport/WebUrlLoaderClient.cpp @@ -180,14 +180,29 @@ bool WebUrlLoaderClient::start(bool isMainResource, bool isMainFrame, bool sync, thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request.get(), &WebRequest::start)); // Run callbacks until the queue is exhausted and m_finished is true. + // Sometimes, a sync load can wait forever and lock up the WebCore thread, + // here we use TimedWait() with multiple tries to avoid locking. + const int kMaxNumTimeout = 3; + const int kCallbackWaitingTime = 10; + int num_timeout = 0; while(!m_finished) { while (!m_queue.empty()) { OwnPtr<Task> task(m_queue.front()); m_queue.pop_front(); task->Run(); } - if (m_queue.empty() && !m_finished) { - syncCondition()->Wait(); + if (m_finished) break; + + syncCondition()->TimedWait(base::TimeDelta::FromSeconds(kCallbackWaitingTime)); + if (m_queue.empty()) { + LOGE("Synchronous request timed out after %d seconds for the %dth try, URL: %s", + kCallbackWaitingTime, num_timeout, m_request->getUrl().c_str()); + num_timeout++; + if (num_timeout >= kMaxNumTimeout) { + cancel(); + m_resourceHandle = 0; + return false; + } } } diff --git a/WebKit/android/jni/WebCoreFrameBridge.cpp b/WebKit/android/jni/WebCoreFrameBridge.cpp index 7d1adb0..d59a53b 100644 --- a/WebKit/android/jni/WebCoreFrameBridge.cpp +++ b/WebKit/android/jni/WebCoreFrameBridge.cpp @@ -334,6 +334,7 @@ WebFrame::WebFrame(JNIEnv* env, jobject obj, jobject historyList, WebCore::Page* mUserAgent = WTF::String(); mUserInitiatedAction = false; mBlockNetworkLoads = false; + m_renderSkins = 0; } WebFrame::~WebFrame() @@ -345,6 +346,7 @@ WebFrame::~WebFrame() mJavaFrame->mObj = 0; } delete mJavaFrame; + delete m_renderSkins; } WebFrame* WebFrame::getWebFrame(const WebCore::Frame* frame) @@ -1261,7 +1263,7 @@ static void CreateFrame(JNIEnv* env, jobject obj, jobject javaview, jobject jAss // Setup the asset manager. AssetManager* am = assetManagerForJavaObject(env, jAssetManager); // Initialize our skinning classes - WebCore::RenderSkinAndroid::Init(am, directory); + webFrame->setRenderSkins(new WebCore::RenderSkinAndroid(am, directory)); } for (int i = WebCore::PlatformBridge::FileUploadLabel; i <= WebCore::PlatformBridge::FileUploadNoFileChosenLabel; i++) diff --git a/WebKit/android/jni/WebCoreFrameBridge.h b/WebKit/android/jni/WebCoreFrameBridge.h index 25232e4..6522a5f 100644 --- a/WebKit/android/jni/WebCoreFrameBridge.h +++ b/WebKit/android/jni/WebCoreFrameBridge.h @@ -43,6 +43,7 @@ namespace WebCore { class Image; class Page; class RenderPart; + class RenderSkinAndroid; class ResourceHandle; class ResourceLoaderAndroid; class ResourceRequest; @@ -155,6 +156,8 @@ class WebFrame : public WebCoreRefObject { bool shouldSaveFormData(); void saveFormData(WebCore::HTMLFormElement*); + const WebCore::RenderSkinAndroid* renderSkins() const { return m_renderSkins; } + void setRenderSkins(const WebCore::RenderSkinAndroid* skins) { m_renderSkins = skins; } private: struct JavaBrowserFrame; JavaBrowserFrame* mJavaFrame; @@ -162,6 +165,7 @@ private: WTF::String mUserAgent; bool mBlockNetworkLoads; bool mUserInitiatedAction; + const WebCore::RenderSkinAndroid* m_renderSkins; }; } // namespace android diff --git a/WebKit/android/jni/WebViewCore.cpp b/WebKit/android/jni/WebViewCore.cpp index c038ccd..4bba71a 100644 --- a/WebKit/android/jni/WebViewCore.cpp +++ b/WebKit/android/jni/WebViewCore.cpp @@ -3079,7 +3079,7 @@ bool WebViewCore::handleTouchEvent(int action, Vector<int>& ids, Vector<IntPoint return 0; } - for (unsigned c = 0; c < points.size(); c++) { + for (int c = 0; c < static_cast<int>(points.size()); c++) { points[c].setX(points[c].x() - m_scrollOffsetX); points[c].setY(points[c].y() - m_scrollOffsetY); @@ -3993,10 +3993,8 @@ static jstring FindAddress(JNIEnv *env, jobject obj, jstring addr, bool success = CacheBuilder::FindAddress(addrChars, length, &start, &end, caseInsensitive) == CacheBuilder::FOUND_COMPLETE; jstring ret = 0; - if (success) { + if (success) ret = env->NewString(addrChars + start, end - start); - env->DeleteLocalRef(ret); - } env->ReleaseStringChars(addr, addrChars); return ret; } diff --git a/WebKit/android/nav/WebView.cpp b/WebKit/android/nav/WebView.cpp index 09fcd67..fe69eae 100644 --- a/WebKit/android/nav/WebView.cpp +++ b/WebKit/android/nav/WebView.cpp @@ -71,7 +71,9 @@ #include <JNIUtility.h> #include <JNIHelp.h> #include <jni.h> +#include <android_runtime/android_util_AssetManager.h> #include <ui/KeycodeLabels.h> +#include <utils/AssetManager.h> #include <wtf/text/AtomicString.h> #include <wtf/text/CString.h> @@ -138,7 +140,7 @@ struct JavaGlue { } } m_javaGlue; -WebView(JNIEnv* env, jobject javaWebView, int viewImpl) : +WebView(JNIEnv* env, jobject javaWebView, int viewImpl, WTF::String drawableDir, AssetManager* am) : m_ring((WebViewCore*) viewImpl) { jclass clazz = env->FindClass("android/webkit/WebView"); @@ -190,6 +192,10 @@ WebView(JNIEnv* env, jobject javaWebView, int viewImpl) : m_ringAnimationEnd = 0; m_baseLayer = 0; m_glDrawFunctor = 0; + if (drawableDir.isEmpty()) + m_buttonSkin = 0; + else + m_buttonSkin = new RenderSkinButton(am, drawableDir); #if USE(ACCELERATED_COMPOSITING) m_glWebViewState = 0; #endif @@ -213,6 +219,7 @@ WebView(JNIEnv* env, jobject javaWebView, int viewImpl) : delete m_navPictureUI; SkSafeUnref(m_baseLayer); delete m_glDrawFunctor; + delete m_buttonSkin; } void stopGL() @@ -279,7 +286,7 @@ void nativeRecordButtons(bool hasFocus, bool pressed, bool invalidate) const CachedNode* cachedCursor = 0; // Lock the mutex, since we now share with the WebCore thread. m_viewImpl->gButtonMutex.lock(); - if (m_viewImpl->m_buttons.size()) { + if (m_viewImpl->m_buttons.size() && m_buttonSkin) { // FIXME: In a future change, we should keep track of whether the selection // has changed to short circuit (note that we would still need to update // if we received new buttons from the WebCore thread). @@ -308,7 +315,7 @@ void nativeRecordButtons(bool hasFocus, bool pressed, bool invalidate) state = RenderSkinAndroid::kFocused; } } - ptr->updateFocusState(state); + ptr->updateFocusState(state, m_buttonSkin); } } m_viewImpl->gButtonMutex.unlock(); @@ -478,13 +485,18 @@ bool drawGL(WebCore::IntRect& viewRect, WebCore::IntRect* invalRect, WebCore::In SkPicture picture; IntRect rect(0, 0, 0, 0); bool allowSame = false; + m_glWebViewState->resetRings(); if (extra) { - LayerAndroid mainPicture(m_navPictureUI); - PictureSet* content = m_baseLayer->content(); - SkCanvas* canvas = picture.beginRecording(content->width(), - content->height()); - extra->draw(canvas, &mainPicture, &rect); - picture.endRecording(); + if (extra == &m_ring) { + m_glWebViewState->setRings(m_ring.rings()); + } else { + LayerAndroid mainPicture(m_navPictureUI); + PictureSet* content = m_baseLayer->content(); + SkCanvas* canvas = picture.beginRecording(content->width(), + content->height()); + extra->draw(canvas, &mainPicture, &rect); + picture.endRecording(); + } } else if (extras == DrawExtrasCursorRing && m_ring.m_isButton) { const CachedFrame* cachedFrame; const CachedNode* cachedCursor = root->currentCursor(&cachedFrame); @@ -1465,6 +1477,7 @@ private: // local state for WebView #if USE(ACCELERATED_COMPOSITING) GLWebViewState* m_glWebViewState; #endif + const RenderSkinButton* m_buttonSkin; }; // end of WebView class @@ -1576,9 +1589,12 @@ static void nativeClearCursor(JNIEnv *env, jobject obj) view->clearCursor(); } -static void nativeCreate(JNIEnv *env, jobject obj, int viewImpl) +static void nativeCreate(JNIEnv *env, jobject obj, int viewImpl, jstring drawableDir, + jobject jAssetManager) { - WebView* webview = new WebView(env, obj, viewImpl); + AssetManager* am = assetManagerForJavaObject(env, jAssetManager); + WTF::String dir = jstringToWtfString(env, drawableDir); + WebView* webview = new WebView(env, obj, viewImpl, dir, am); // NEED THIS OR SOMETHING LIKE IT! //Release(obj); } @@ -2484,7 +2500,7 @@ static JNINativeMethod gJavaWebViewMethods[] = { (void*) nativeCacheHitNodePointer }, { "nativeClearCursor", "()V", (void*) nativeClearCursor }, - { "nativeCreate", "(I)V", + { "nativeCreate", "(ILjava/lang/String;Landroid/content/res/AssetManager;)V", (void*) nativeCreate }, { "nativeCursorFramePointer", "()I", (void*) nativeCursorFramePointer }, |