diff options
31 files changed, 494 insertions, 389 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/BaseLayerAndroid.cpp b/WebCore/platform/graphics/android/BaseLayerAndroid.cpp index 1786d64..cf8b6fa 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); } diff --git a/WebCore/platform/graphics/android/BaseTile.cpp b/WebCore/platform/graphics/android/BaseTile.cpp index 391e87b..be0ccf6 100644 --- a/WebCore/platform/graphics/android/BaseTile.cpp +++ b/WebCore/platform/graphics/android/BaseTile.cpp @@ -66,6 +66,7 @@ BaseTile::BaseTile() , m_texture(0) , m_scale(1) , m_dirty(true) + , m_repaintPending(false) , m_usable(true) , m_lastDirtyPicture(0) , m_fullRepaintA(true) @@ -166,12 +167,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) { if (m_x < 0 || m_y < 0) diff --git a/WebCore/platform/graphics/android/BaseTile.h b/WebCore/platform/graphics/android/BaseTile.h index c50f6f5..709e3cf 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); @@ -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 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/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/LayerAndroid.cpp b/WebCore/platform/graphics/android/LayerAndroid.cpp index 6a43745..becfe02 100644 --- a/WebCore/platform/graphics/android/LayerAndroid.cpp +++ b/WebCore/platform/graphics/android/LayerAndroid.cpp @@ -890,7 +890,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); 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/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 21afe24..0251b03 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); } } - -#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.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/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/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/nav/WebView.cpp b/WebKit/android/nav/WebView.cpp index 3a156de..053f2a9 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(); @@ -1463,6 +1470,7 @@ private: // local state for WebView #if USE(ACCELERATED_COMPOSITING) GLWebViewState* m_glWebViewState; #endif + const RenderSkinButton* m_buttonSkin; }; // end of WebView class @@ -1573,9 +1581,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); } @@ -2489,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 }, |