diff options
Diffstat (limited to 'Source/WebCore')
12 files changed, 496 insertions, 287 deletions
diff --git a/Source/WebCore/Android.mk b/Source/WebCore/Android.mk index 5d1273b..075dd71 100644 --- a/Source/WebCore/Android.mk +++ b/Source/WebCore/Android.mk @@ -646,6 +646,7 @@ LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \ platform/graphics/android/FontPlatformDataAndroid.cpp \ platform/graphics/android/GaneshContext.cpp \ platform/graphics/android/GaneshRenderer.cpp \ + platform/graphics/android/GLExtras.cpp \ platform/graphics/android/GLUtils.cpp \ platform/graphics/android/GLWebViewState.cpp \ platform/graphics/android/GlyphMapAndroid.cpp \ diff --git a/Source/WebCore/platform/graphics/android/GLExtras.cpp b/Source/WebCore/platform/graphics/android/GLExtras.cpp new file mode 100644 index 0000000..540ca16 --- /dev/null +++ b/Source/WebCore/platform/graphics/android/GLExtras.cpp @@ -0,0 +1,222 @@ +/* + * 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 + * 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. + */ + +#include "config.h" + +#include "DrawExtra.h" +#include "FindCanvas.h" +#include "GLExtras.h" +#include "IntRect.h" +#include "TilesManager.h" +#include "android_graphics.h" + +#include <cutils/log.h> +#include <wtf/text/CString.h> + +#undef XLOGC +#define XLOGC(...) android_printLog(ANDROID_LOG_DEBUG, "GLExtras", __VA_ARGS__) + +#ifdef DEBUG + +#undef XLOG +#define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "GLExtras", __VA_ARGS__) + +#else + +#undef XLOG +#define XLOG(...) + +#endif // DEBUG + +// Touch ring border width. This is doubled if the ring is not pressed +#define RING_BORDER_WIDTH 1 +// Color of the ring is 0x6633b5e5 (copied from framework's holo_light) +#define COLOR_HOLO_LIGHT &m_lightRingTexture, 0x33, 0xb5, 0xe5, 0.4f +// Color of the ring is 0x660099cc (copied from framework's holo_dark) +#define COLOR_HOLO_DARK &m_darkRingTexture, 0x00, 0x99, 0xcc, 0.6f +// Put a cap on the number of matches to draw. If the current page has more +// matches than this, only draw the focused match. This both prevents clutter +// on the page and keeps the performance happy +#define MAX_NUMBER_OF_MATCHES_TO_DRAW 101 + +GLExtras::GLExtras() + : m_findOnPage(0) + , m_ring(0) + , m_drawExtra(0) + , m_lightRingTexture(-1) + , m_darkRingTexture(-1) +{ +} + +GLExtras::~GLExtras() +{ +} + +void GLExtras::drawRing(SkRect& srcRect, int* texture, int r, int g, int b, float a) +{ + if (*texture == -1) + *texture = GLUtils::createSampleColorTexture(r, g, b); + + if (srcRect.fRight <= srcRect.fLeft || srcRect.fBottom <= srcRect.fTop) { + // Invalid rect, reject it + return; + } + XLOG("drawQuad [%fx%f, %f, %f]", srcRect.fLeft, srcRect.fTop, + srcRect.width(), srcRect.height()); + TilesManager::instance()->shader()->drawQuad(srcRect, *texture, a); +} + +void GLExtras::drawRegion(const SkRegion& region, bool fill, + bool drawBorder, bool useDark) +{ + if (region.isEmpty()) + return; + if (fill) { + SkRegion::Iterator rgnIter(region); + while (!rgnIter.done()) { + const SkIRect& ir = rgnIter.rect(); + SkRect r; + r.set(ir.fLeft, ir.fTop, ir.fRight, ir.fBottom); + if (useDark) + drawRing(r, COLOR_HOLO_DARK); + else + drawRing(r, COLOR_HOLO_LIGHT); + rgnIter.next(); + } + } + if (fill && !drawBorder) + return; + SkPath path; + if (!region.getBoundaryPath(&path)) + return; + SkPath::Iter iter(path, true); + SkPath::Verb verb; + SkPoint pts[4]; + SkRegion clip; + SkIRect startRect; + while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { + if (verb == SkPath::kLine_Verb) { + SkRect r; + r.set(pts, 2); + SkIRect line; + int borderWidth = RING_BORDER_WIDTH; + if (!fill) + borderWidth *= 2; + line.fLeft = r.fLeft - borderWidth; + line.fRight = r.fRight + borderWidth; + line.fTop = r.fTop - borderWidth; + line.fBottom = r.fBottom + borderWidth; + if (clip.intersects(line)) { + clip.op(line, SkRegion::kReverseDifference_Op); + if (clip.isEmpty()) + continue; // Nothing to draw, continue + line = clip.getBounds(); + if (SkIRect::Intersects(startRect, line)) { + clip.op(startRect, SkRegion::kDifference_Op); + if (clip.isEmpty()) + continue; // Nothing to draw, continue + line = clip.getBounds(); + } + } else { + clip.setRect(line); + } + r.set(line.fLeft, line.fTop, line.fRight, line.fBottom); + if (useDark) + drawRing(r, COLOR_HOLO_DARK); + else + drawRing(r, COLOR_HOLO_LIGHT); + if (startRect.isEmpty()) { + startRect.set(line.fLeft, line.fTop, line.fRight, line.fBottom); + } + } + if (verb == SkPath::kMove_Verb) { + startRect.setEmpty(); + } + } +} + +void GLExtras::drawCursorRings() +{ + SkRegion region; + for (size_t i = 0; i < m_ring->rings().size(); i++) { + IntRect rect = m_ring->rings().at(i); + if (i == 0) + region.setRect(rect); + else + region.op(rect, SkRegion::kUnion_Op); + } + drawRegion(region, m_ring->m_isPressed, !m_ring->m_isButton, false); +} + +void GLExtras::drawFindOnPage(SkRect& viewport) +{ + WTF::Vector<MatchInfo>* matches = m_findOnPage->matches(); + XLOG("drawFindOnPage, matches: %p", matches); + if (!matches || !m_findOnPage->isCurrentLocationValid()) + return; + int count = matches->size(); + int current = m_findOnPage->currentMatchIndex(); + XLOG("match count: %d", count); + if (count < MAX_NUMBER_OF_MATCHES_TO_DRAW) + for (int i = 0; i < count; i++) { + MatchInfo& info = matches->at(i); + const SkRegion& region = info.getLocation(); + SkIRect rect = region.getBounds(); + if (rect.intersect(viewport.fLeft, viewport.fTop, + viewport.fRight, viewport.fBottom)) + drawRegion(region, i == current, false, true); +#ifdef DEBUG + else + XLOG("Quick rejecting [%dx%d, %d, %d", rect.fLeft, rect.fTop, + rect.width(), rect.height()); +#endif // DEBUG + } + else { + MatchInfo& info = matches->at(current); + drawRegion(info.getLocation(), true, false, true); + } +} + +void GLExtras::drawGL(IntRect& webViewRect, SkRect& viewport, int titleBarHeight) +{ + if (m_drawExtra) { + // Update the clip. We want to use the screen clip + FloatRect glclip; + glclip.setX(webViewRect.x()); + glclip.setY(webViewRect.y() + titleBarHeight); + glclip.setWidth(webViewRect.width()); + glclip.setHeight(webViewRect.height()); + XLOG("Setting clip [%fx%f, %f, %f]", glclip.x(), glclip.y(), + glclip.width(), glclip.height()); + TilesManager::instance()->shader()->clip(glclip); + if (m_drawExtra == m_ring) + drawCursorRings(); + else if (m_drawExtra == m_findOnPage) + drawFindOnPage(viewport); + else + XLOGC("m_drawExtra %p is unknown! (cursor: %p, find: %p", + m_drawExtra, m_ring, m_findOnPage); + } +} diff --git a/Source/WebCore/platform/graphics/android/GLExtras.h b/Source/WebCore/platform/graphics/android/GLExtras.h new file mode 100644 index 0000000..c52e951 --- /dev/null +++ b/Source/WebCore/platform/graphics/android/GLExtras.h @@ -0,0 +1,68 @@ +/* + * 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 + * 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 GLExtras_h +#define GLExtras_h + +#include "SkRect.h" +#include "SkRegion.h" + +namespace android { + class FindOnPage; + class CursorRing; + class DrawExtra; +} + +namespace WebCore { + +class GLExtras { +public: + GLExtras(); + virtual ~GLExtras(); + + void drawGL(IntRect& webViewRect, SkRect& viewport, int titleBarHeight); + void setFindOnPageExtra(android::FindOnPage* findOnPage) { + m_findOnPage = findOnPage; + } + void setCursorRingExtra(android::CursorRing* ring) { m_ring = ring; } + void setDrawExtra(android::DrawExtra* extra) { m_drawExtra = extra; } + +private: + void drawRing(SkRect& srcRect, int* texture, int r, int g, int b, float a); + void drawRegion(const SkRegion& region, bool fill, bool drawBorder, + bool useDark = false); + void drawCursorRings(); + void drawFindOnPage(SkRect& viewport); + + android::FindOnPage* m_findOnPage; + android::CursorRing* m_ring; + android::DrawExtra* m_drawExtra; + int m_lightRingTexture; + int m_darkRingTexture; +}; + +} // namespace WebCore + +#endif // GLExtras_h diff --git a/Source/WebCore/platform/graphics/android/GLWebViewState.cpp b/Source/WebCore/platform/graphics/android/GLWebViewState.cpp index c273c5c..9f266d2 100644 --- a/Source/WebCore/platform/graphics/android/GLWebViewState.cpp +++ b/Source/WebCore/platform/graphics/android/GLWebViewState.cpp @@ -60,14 +60,6 @@ #define FRAMERATE_CAP 0.01666 // We cap at 60 fps -// Touch ring border width. This is doubled if the ring is not pressed -#define RING_BORDER_WIDTH 1 -// Color of the ring is 0x6633b5e5 (copied from framework) -#define RING_COLOR_ALPHA 0.4 -#define RING_COLOR_R 0x33 -#define RING_COLOR_G 0xb5 -#define RING_COLOR_B 0xe5 - // log warnings if scale goes outside this range #define MIN_SCALE_WARNING 0.1 #define MAX_SCALE_WARNING 10 @@ -88,8 +80,6 @@ GLWebViewState::GLWebViewState(android::Mutex* buttonMutex) , m_globalButtonMutex(buttonMutex) , m_baseLayerUpdate(true) , m_backgroundColor(SK_ColorWHITE) - , m_displayRings(false) - , m_focusRingTexture(-1) , m_isScrolling(false) , m_goingDown(true) , m_goingLeft(false) @@ -171,7 +161,7 @@ void GLWebViewState::setBaseLayer(BaseLayerAndroid* layer, const SkRegion& inval SkSafeUnref(m_currentBaseLayer); m_currentBaseLayer = layer; } - m_displayRings = false; + m_glExtras.setDrawExtra(0); invalRegion(inval); #ifdef MEASURES_PERF @@ -183,21 +173,6 @@ void GLWebViewState::setBaseLayer(BaseLayerAndroid* layer, const SkRegion& inval TilesManager::instance()->setShowVisualIndicator(showVisualIndicator); } -void GLWebViewState::setRings(Vector<IntRect>& rings, bool isPressed, bool isButton) -{ - android::Mutex::Autolock lock(m_baseLayerLock); - m_displayRings = true; - m_rings.setEmpty(); - for (size_t i = 0; i < rings.size(); i++) { - if (i == 0) - m_rings.setRect(rings.at(i)); - else - m_rings.op(rings.at(i), SkRegion::kUnion_Op); - } - m_ringsIsPressed = isPressed; - m_ringsIsButton = isButton; -} - void GLWebViewState::invalRegion(const SkRegion& region) { SkRegion::Iterator iterator(region); @@ -223,26 +198,6 @@ void GLWebViewState::unlockBaseLayerUpdate() { m_invalidateRegion.setEmpty(); } -void GLWebViewState::setExtra(BaseLayerAndroid* layer, SkPicture& picture, - const IntRect& rect, bool allowSame) -{ - android::Mutex::Autolock lock(m_baseLayerLock); - if (!m_baseLayerUpdate) - return; - - layer->setExtra(picture); - - if (!allowSame && m_lastInval == rect) - return; - - if (!rect.isEmpty()) - inval(rect); - if (!m_lastInval.isEmpty()) - inval(m_lastInval); - m_lastInval = rect; - m_displayRings = false; -} - void GLWebViewState::inval(const IntRect& rect) { if (m_baseLayerUpdate) { @@ -266,105 +221,6 @@ void GLWebViewState::inval(const IntRect& rect) TilesManager::instance()->getProfiler()->nextInval(rect, zoomManager()->currentScale()); } -void GLWebViewState::resetRings() -{ - m_displayRings = false; -} - -void GLWebViewState::drawFocusRing(SkRect& srcRect) -{ - if (m_focusRingTexture == -1) - m_focusRingTexture = GLUtils::createSampleColorTexture(RING_COLOR_R, - RING_COLOR_G, - RING_COLOR_B); - - if (srcRect.fRight <= srcRect.fLeft || srcRect.fBottom <= srcRect.fTop) { - // Invalid rect, reject it - return; - } - TilesManager::instance()->shader()->drawQuad(srcRect, m_focusRingTexture, - RING_COLOR_ALPHA); -} - -void GLWebViewState::paintExtras() -{ - if (m_displayRings && !m_rings.isEmpty()) { - // Update the clip - SkIRect skbounds = m_rings.getBounds(); - if (skbounds.isEmpty()) - return; - FloatRect glclip; - glclip.setX(skbounds.fLeft); - glclip.setY(skbounds.fTop); - glclip.setWidth(skbounds.fRight - skbounds.fLeft); - glclip.setHeight(skbounds.fBottom - skbounds.fTop); - TilesManager::instance()->shader()->clip(glclip); - if (m_ringsIsPressed) { - SkRegion::Iterator rgnIter(m_rings); - while (!rgnIter.done()) { - SkIRect ir = rgnIter.rect(); - SkRect r; - r.set(ir.fLeft, ir.fTop, ir.fRight, ir.fBottom); - drawFocusRing(r); - rgnIter.next(); - } - } - if (m_ringsIsButton && m_ringsIsPressed) - return; - SkPath path; - if (!m_rings.getBoundaryPath(&path)) - return; - SkPath::Iter iter(path, true); - SkPath::Verb verb; - SkPoint pts[4]; - SkRegion clip; - SkIRect startRect; - while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { - if (verb == SkPath::kLine_Verb) { - SkRect r; - r.set(pts, 2); - SkIRect line; - int borderWidth = RING_BORDER_WIDTH; - if (!m_ringsIsPressed) - borderWidth *= 2; - line.fLeft = r.fLeft - borderWidth; - line.fRight = r.fRight + borderWidth; - line.fTop = r.fTop - borderWidth; - line.fBottom = r.fBottom + borderWidth; - if (clip.intersects(line)) { - clip.op(line, SkRegion::kReverseDifference_Op); - if (clip.isEmpty()) - continue; // Nothing to draw, continue - line = clip.getBounds(); - if (SkIRect::Intersects(startRect, line)) { - clip.op(startRect, SkRegion::kDifference_Op); - if (clip.isEmpty()) - continue; // Nothing to draw, continue - line = clip.getBounds(); - } - } else { - clip.setRect(line); - } - r.set(line.fLeft, line.fTop, line.fRight, line.fBottom); - drawFocusRing(r); - if (!m_ringsIsPressed) { - r.fLeft += RING_BORDER_WIDTH; - r.fRight -= RING_BORDER_WIDTH; - r.fTop += RING_BORDER_WIDTH; - r.fBottom -= RING_BORDER_WIDTH; - drawFocusRing(r); - } - if (startRect.isEmpty()) { - startRect.set(line.fLeft, line.fTop, line.fRight, line.fBottom); - } - } - if (verb == SkPath::kMove_Verb) { - startRect.setEmpty(); - } - } - } -} - unsigned int GLWebViewState::paintBaseLayerContent(SkCanvas* canvas) { android::Mutex::Autolock lock(m_baseLayerLock); @@ -604,7 +460,7 @@ bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect, double currentTime = setupDrawing(rect, viewport, webViewRect, titleBarHeight, clip, scale); bool ret = baseLayer->drawGL(currentTime, compositedRoot, rect, viewport, scale, buffersSwappedPtr); - paintExtras(); + m_glExtras.drawGL(webViewRect, viewport, titleBarHeight); glBindBuffer(GL_ARRAY_BUFFER, 0); diff --git a/Source/WebCore/platform/graphics/android/GLWebViewState.h b/Source/WebCore/platform/graphics/android/GLWebViewState.h index 27e8148..23d7de2 100644 --- a/Source/WebCore/platform/graphics/android/GLWebViewState.h +++ b/Source/WebCore/platform/graphics/android/GLWebViewState.h @@ -30,6 +30,7 @@ #include "Color.h" #include "DrawExtra.h" +#include "GLExtras.h" #include "IntRect.h" #include "SkCanvas.h" #include "SkRect.h" @@ -174,12 +175,9 @@ public: unsigned int paintBaseLayerContent(SkCanvas* canvas); void setBaseLayer(BaseLayerAndroid* layer, const SkRegion& inval, bool showVisualIndicator, bool isPictureAfterFirstLayout); - void setExtra(BaseLayerAndroid*, SkPicture&, const IntRect&, bool allowSame); void paintExtras(); - void setRings(Vector<IntRect>& rings, bool isPressed, bool isButton); - void resetRings(); - void drawFocusRing(SkRect& rect); + GLExtras* glExtras() { return &m_glExtras; } TiledPage* sibling(TiledPage* page); TiledPage* frontPage(); @@ -268,11 +266,7 @@ private: double m_delayTimes[MAX_MEASURES_PERF]; bool m_measurePerfs; #endif - bool m_displayRings; - SkRegion m_rings; - bool m_ringsIsPressed; - bool m_ringsIsButton; - int m_focusRingTexture; + GLExtras m_glExtras; bool m_isScrolling; bool m_goingDown; diff --git a/Source/WebCore/platform/graphics/android/MediaLayer.cpp b/Source/WebCore/platform/graphics/android/MediaLayer.cpp index 85fb92f..500fbfc 100644 --- a/Source/WebCore/platform/graphics/android/MediaLayer.cpp +++ b/Source/WebCore/platform/graphics/android/MediaLayer.cpp @@ -42,10 +42,8 @@ namespace WebCore { MediaLayer::MediaLayer(jobject webViewRef) : LayerAndroid((RenderLayer*) NULL) { - m_contentTexture = new MediaTexture(webViewRef); - m_contentTexture->incStrong(this); - m_videoTexture = new MediaTexture(webViewRef); - m_videoTexture->incStrong(this); + m_mediaTexture = new MediaTexture(webViewRef); + m_mediaTexture->incStrong(this); m_isCopy = false; m_isContentInverted = false; @@ -55,10 +53,8 @@ MediaLayer::MediaLayer(jobject webViewRef) : LayerAndroid((RenderLayer*) NULL) MediaLayer::MediaLayer(const MediaLayer& layer) : LayerAndroid(layer) { - m_contentTexture = layer.m_contentTexture; - m_contentTexture->incStrong(this); - m_videoTexture = layer.m_videoTexture; - m_videoTexture->incStrong(this); + m_mediaTexture = layer.m_mediaTexture; + m_mediaTexture->incStrong(this); m_isCopy = true; m_isContentInverted = layer.m_isContentInverted; @@ -69,8 +65,7 @@ MediaLayer::MediaLayer(const MediaLayer& layer) : LayerAndroid(layer) MediaLayer::~MediaLayer() { XLOG("Deleting Media Layer"); - m_contentTexture->decStrong(this); - m_videoTexture->decStrong(this); + m_mediaTexture->decStrong(this); } bool MediaLayer::drawGL(GLWebViewState* glWebViewState, SkMatrix& matrix) @@ -85,10 +80,8 @@ bool MediaLayer::drawGL(GLWebViewState* glWebViewState, SkMatrix& matrix) mediaBounds.set(0, 0, getSize().width(), getSize().height()); mediaBounds.inset(m_outlineSize, m_outlineSize); - // check to see if we need to create a video texture - m_videoTexture->initNativeWindowIfNeeded(); - // draw any video content if present - m_videoTexture->drawVideo(m_drawTransform, mediaBounds); + // check to see if we need to create a content or video texture + m_mediaTexture->initNativeWindowIfNeeded(); // the layer's shader draws the content inverted so we must undo // that change in the transformation matrix @@ -98,50 +91,37 @@ bool MediaLayer::drawGL(GLWebViewState* glWebViewState, SkMatrix& matrix) m.translate(0, -getSize().height()); } - // check to see if we need to create a content texture - m_contentTexture->initNativeWindowIfNeeded(); - // draw any content if present - m_contentTexture->setDimensions(mediaBounds); - m_contentTexture->drawContent(m); + // draw any content or video if present + m_mediaTexture->draw(m, m_drawTransform, mediaBounds); return drawChildrenGL(glWebViewState, matrix); } ANativeWindow* MediaLayer::acquireNativeWindowForContent() { - ANativeWindow* anw = m_contentTexture->getNativeWindow(); - if (!anw) { - anw = m_contentTexture->requestNewWindow(); - } - return anw; + return m_mediaTexture->getNativeWindowForContent(); } ANativeWindow* MediaLayer::acquireNativeWindowForVideo() { - return m_videoTexture->requestNewWindow(); + return m_mediaTexture->requestNativeWindowForVideo(); } void MediaLayer::setWindowDimensionsForVideo(const ANativeWindow* window, const SkRect& dimensions) { - if (window != m_videoTexture->getNativeWindow()) - return; - //TODO validate that the dimensions do not exceed the plugin's bounds - m_videoTexture->setDimensions(dimensions); + m_mediaTexture->setDimensions(window, dimensions); } void MediaLayer::releaseNativeWindowForVideo(ANativeWindow* window) { - if (window == m_videoTexture->getNativeWindow()) - m_videoTexture->releaseNativeWindow(); + m_mediaTexture->releaseNativeWindow(window); } void MediaLayer::setFramerateCallback(const ANativeWindow* window, FramerateCallbackProc callback) { - if (window != m_videoTexture->getNativeWindow()) - return; - m_videoTexture->setFramerateCallback(callback); + m_mediaTexture->setFramerateCallback(window, callback); } } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/MediaLayer.h b/Source/WebCore/platform/graphics/android/MediaLayer.h index cd15d9e..30a293d 100644 --- a/Source/WebCore/platform/graphics/android/MediaLayer.h +++ b/Source/WebCore/platform/graphics/android/MediaLayer.h @@ -61,8 +61,7 @@ private: int m_outlineSize; // SurfaceTexture member variables - MediaTexture* m_contentTexture; - MediaTexture* m_videoTexture; + MediaTexture* m_mediaTexture; }; } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/MediaTexture.cpp b/Source/WebCore/platform/graphics/android/MediaTexture.cpp index 0de7dfa..1a5e2cc 100644 --- a/Source/WebCore/platform/graphics/android/MediaTexture.cpp +++ b/Source/WebCore/platform/graphics/android/MediaTexture.cpp @@ -46,6 +46,12 @@ #endif // DEBUG +// Limits the number of ANativeWindows that can be allocated for video playback. +// The limit is currently set to 2 as that is the current max number of +// simultaneous HW decodes that our OMX implementation allows. This forces the +// media producer to use their own SW decoders for subsequent video streams. +#define MAX_WINDOW_COUNT 2 + namespace WebCore { MediaTexture::MediaTexture(jobject webViewRef) : android::LightRefBase<MediaTexture>() @@ -57,17 +63,17 @@ MediaTexture::MediaTexture(jobject webViewRef) : android::LightRefBase<MediaText m_weakWebViewRef = 0; } - m_textureId = 0; - m_dimensions.setEmpty(); + m_contentTexture = 0; m_newWindowRequest = false; - m_newWindowReady = false; } MediaTexture::~MediaTexture() { - releaseNativeWindow(); - if (m_textureId) - glDeleteTextures(1, &m_textureId); + deleteTexture(m_contentTexture); + for (unsigned int i = 0; i < m_videoTextures.size(); i++) { + deleteTexture(m_videoTextures[i], true); + } + if (m_weakWebViewRef) { JNIEnv* env = JSC::Bindings::getJNIEnv(); env->DeleteWeakGlobalRef(m_weakWebViewRef); @@ -79,39 +85,76 @@ void MediaTexture::initNativeWindowIfNeeded() { android::Mutex::Autolock lock(m_mediaLock); - if(!m_newWindowRequest) - return; + // check to see if there are any unused textures to delete + if (m_unusedTextures.size() != 0) { + for (unsigned int i = 0; i < m_unusedTextures.size(); i++) { + glDeleteTextures(1, &m_unusedTextures[i]); + } + m_unusedTextures.clear(); + } - // reuse an existing texture if possible - if (!m_textureId) - glGenTextures(1, &m_textureId); + // create a content texture if none exists + if (!m_contentTexture) { + m_contentTexture = createTexture(); + } - m_surfaceTexture = new android::SurfaceTexture(m_textureId); - m_surfaceTextureClient = new android::SurfaceTextureClient(m_surfaceTexture); + // finally create a video texture if needed + if (!m_newWindowRequest) + return; - //setup callback - m_mediaListener = new MediaListener(m_weakWebViewRef, - m_surfaceTexture, - m_surfaceTextureClient); - m_surfaceTexture->setFrameAvailableListener(m_mediaListener); + // add the texture and add it to the list + TextureWrapper* videoTexture = createTexture(); + m_videoTextures.append(videoTexture); + // setup the state variables to signal the other thread m_newWindowRequest = false; - m_newWindowReady = true; + m_newWindow = videoTexture->nativeWindow; } m_newMediaRequestCond.signal(); } -void MediaTexture::drawContent(const TransformationMatrix& matrix) +void MediaTexture::draw(const TransformationMatrix& contentMatrix, + const TransformationMatrix& videoMatrix, + const SkRect& mediaBounds) { android::Mutex::Autolock lock(m_mediaLock); - if(!m_surfaceTexture.get() || m_dimensions.isEmpty() - || !m_mediaListener->isFrameAvailable()) + if (mediaBounds.isEmpty()) return; - m_surfaceTexture->updateTexImage(); + // draw all the video textures first + for (unsigned int i = 0; i < m_videoTextures.size(); i++) { + + TextureWrapper* video = m_videoTextures[i]; - sp<GraphicBuffer> buf = m_surfaceTexture->getCurrentBuffer(); + if (!video->surfaceTexture.get() || video->dimensions.isEmpty() + || !video->mediaListener->isFrameAvailable()) + return; + + video->surfaceTexture->updateTexImage(); + + float surfaceMatrix[16]; + video->surfaceTexture->getTransformMatrix(surfaceMatrix); + + SkRect dimensions = video->dimensions; + dimensions.offset(mediaBounds.fLeft, mediaBounds.fTop); + +#ifdef DEBUG + if (!mediaBounds.contains(dimensions)) { + XLOG("The video exceeds is parent's bounds."); + } +#endif // DEBUG + + TilesManager::instance()->shader()->drawVideoLayerQuad(videoMatrix, + surfaceMatrix, dimensions, video->textureId); + } + + if (!m_contentTexture->mediaListener->isFrameAvailable()) + return; + + m_contentTexture->surfaceTexture->updateTexImage(); + + sp<GraphicBuffer> buf = m_contentTexture->surfaceTexture->getCurrentBuffer(); PixelFormat f = buf->getPixelFormat(); // only attempt to use alpha blending if alpha channel exists @@ -121,49 +164,25 @@ void MediaTexture::drawContent(const TransformationMatrix& matrix) PIXEL_FORMAT_RGB_565 == f || PIXEL_FORMAT_RGB_332 == f); - TilesManager::instance()->shader()->drawLayerQuad(matrix, m_dimensions, - m_textureId, 1.0f, - forceAlphaBlending, + TilesManager::instance()->shader()->drawLayerQuad(contentMatrix, + mediaBounds, + m_contentTexture->textureId, + 1.0f, forceAlphaBlending, GL_TEXTURE_EXTERNAL_OES); } -void MediaTexture::drawVideo(const TransformationMatrix& matrix, const SkRect& parentBounds) -{ - android::Mutex::Autolock lock(m_mediaLock); - - if(!m_surfaceTexture.get() || m_dimensions.isEmpty() - || !m_mediaListener->isFrameAvailable()) - return; - - m_surfaceTexture->updateTexImage(); - - float surfaceMatrix[16]; - m_surfaceTexture->getTransformMatrix(surfaceMatrix); - - SkRect dimensions = m_dimensions; - dimensions.offset(parentBounds.fLeft, parentBounds.fTop); - -#ifdef DEBUG - if (!parentBounds.contains(dimensions)) { - XLOG("The video exceeds is parent's bounds."); - } -#endif // DEBUG - - TilesManager::instance()->shader()->drawVideoLayerQuad(matrix, surfaceMatrix, - dimensions, m_textureId); -} - -ANativeWindow* MediaTexture::requestNewWindow() +ANativeWindow* MediaTexture::requestNativeWindowForVideo() { android::Mutex::Autolock lock(m_mediaLock); // the window was not ready before the timeout so return it this time - if (m_newWindowReady) { - m_newWindowReady = false; - return m_surfaceTextureClient.get(); + if (ANativeWindow* window = m_newWindow.get()) { + m_newWindow.clear(); + return window; } - // we only allow for one texture, so if one already exists return null - else if (m_surfaceTextureClient.get()) { + + // we only allow for so many textures, so return NULL if we exceed that limit + else if (m_videoTextures.size() >= MAX_WINDOW_COUNT) { return 0; } @@ -190,42 +209,94 @@ ANativeWindow* MediaTexture::requestNewWindow() timedOut = ret == TIMED_OUT; } - if (m_surfaceTextureClient.get()) - m_newWindowReady = false; - - return m_surfaceTextureClient.get(); + // if the window is ready then return it otherwise return NULL + if (ANativeWindow* window = m_newWindow.get()) { + m_newWindow.clear(); + return window; + } + return 0; } -ANativeWindow* MediaTexture::getNativeWindow() +ANativeWindow* MediaTexture::getNativeWindowForContent() { android::Mutex::Autolock lock(m_mediaLock); - return m_surfaceTextureClient.get(); + if (m_contentTexture) + return m_contentTexture->nativeWindow.get(); + else + return 0; } -void MediaTexture::releaseNativeWindow() +void MediaTexture::releaseNativeWindow(const ANativeWindow* window) { android::Mutex::Autolock lock(m_mediaLock); - m_dimensions.setEmpty(); - - if (m_surfaceTexture.get()) - m_surfaceTexture->setFrameAvailableListener(0); - - // clear the strong pointer references - m_mediaListener.clear(); - m_surfaceTextureClient.clear(); - m_surfaceTexture.clear(); + for (unsigned int i = 0; i < m_videoTextures.size(); i++) { + if (m_videoTextures[i]->nativeWindow.get() == window) { + deleteTexture(m_videoTextures[i]); + m_videoTextures.remove(i); + break; + } + } } -void MediaTexture::setDimensions(const SkRect& dimensions) +void MediaTexture::setDimensions(const ANativeWindow* window, + const SkRect& dimensions) { android::Mutex::Autolock lock(m_mediaLock); - m_dimensions = dimensions; + for (unsigned int i = 0; i < m_videoTextures.size(); i++) { + if (m_videoTextures[i]->nativeWindow.get() == window) { + m_videoTextures[i]->dimensions = dimensions; + break; + } + } } -void MediaTexture::setFramerateCallback(FramerateCallbackProc callback) +void MediaTexture::setFramerateCallback(const ANativeWindow* window, + FramerateCallbackProc callback) { android::Mutex::Autolock lock(m_mediaLock); - m_mediaListener->setFramerateCallback(callback); + for (unsigned int i = 0; i < m_videoTextures.size(); i++) { + if (m_videoTextures[i]->nativeWindow.get() == window) { + m_videoTextures[i]->mediaListener->setFramerateCallback(callback); + break; + } + } +} + +MediaTexture::TextureWrapper* MediaTexture::createTexture() +{ + TextureWrapper* wrapper = new TextureWrapper(); + + // populate the wrapper + glGenTextures(1, &wrapper->textureId); + wrapper->surfaceTexture = new android::SurfaceTexture(wrapper->textureId); + wrapper->nativeWindow = new android::SurfaceTextureClient(wrapper->surfaceTexture); + wrapper->dimensions.setEmpty(); + + // setup callback + wrapper->mediaListener = new MediaListener(m_weakWebViewRef, + wrapper->surfaceTexture, + wrapper->nativeWindow); + wrapper->surfaceTexture->setFrameAvailableListener(wrapper->mediaListener); + + return wrapper; +} + +void MediaTexture::deleteTexture(TextureWrapper* texture, bool force) +{ + if (texture->surfaceTexture.get()) + texture->surfaceTexture->setFrameAvailableListener(0); + + if (force) + glDeleteTextures(1, &texture->textureId); + else + m_unusedTextures.append(texture->textureId); + + // clear the strong pointer references + texture->mediaListener.clear(); + texture->nativeWindow.clear(); + texture->surfaceTexture.clear(); + + delete texture; } } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/MediaTexture.h b/Source/WebCore/platform/graphics/android/MediaTexture.h index d5ecd7b..964b87b 100644 --- a/Source/WebCore/platform/graphics/android/MediaTexture.h +++ b/Source/WebCore/platform/graphics/android/MediaTexture.h @@ -20,8 +20,10 @@ #if USE(ACCELERATED_COMPOSITING) #include "RefPtr.h" -#include "DoubleBufferedTexture.h" #include "LayerAndroid.h" +#include "Vector.h" +#include <GLES2/gl2.h> +#include <ui/GraphicBuffer.h> #include <utils/RefBase.h> #include <jni.h> @@ -42,24 +44,37 @@ public: ~MediaTexture(); void initNativeWindowIfNeeded(); - void drawContent(const TransformationMatrix& matrix); - void drawVideo(const TransformationMatrix& matrix, const SkRect& parentBounds); + void draw(const TransformationMatrix& contentMatrix, + const TransformationMatrix& videoMatrix, + const SkRect& mediaBounds); - ANativeWindow* requestNewWindow(); - ANativeWindow* getNativeWindow(); - void releaseNativeWindow(); - void setDimensions(const SkRect& dimensions); - void setFramerateCallback(FramerateCallbackProc callback); + ANativeWindow* getNativeWindowForContent(); + ANativeWindow* requestNativeWindowForVideo(); + void releaseNativeWindow(const ANativeWindow* window); + void setDimensions(const ANativeWindow* window, const SkRect& dimensions); + void setFramerateCallback(const ANativeWindow* window, + FramerateCallbackProc callback); private: - GLuint m_textureId; - sp<android::SurfaceTexture> m_surfaceTexture; - sp<ANativeWindow> m_surfaceTextureClient; - sp<MediaListener> m_mediaListener; - SkRect m_dimensions; + struct TextureWrapper { + GLuint textureId; + sp<android::SurfaceTexture> surfaceTexture; + sp<ANativeWindow> nativeWindow; + sp<MediaListener> mediaListener; + SkRect dimensions; // only used by the video layer + }; + + TextureWrapper* createTexture(); + void deleteTexture(TextureWrapper* item, bool force = false); + + TextureWrapper* m_contentTexture; + Vector<TextureWrapper*> m_videoTextures; + Vector<GLuint> m_unusedTextures; + + // used to generate new video textures bool m_newWindowRequest; - bool m_newWindowReady; + sp<ANativeWindow> m_newWindow; jobject m_weakWebViewRef; diff --git a/Source/WebCore/platform/graphics/android/ShaderProgram.cpp b/Source/WebCore/platform/graphics/android/ShaderProgram.cpp index 797da52..0aad081 100644 --- a/Source/WebCore/platform/graphics/android/ShaderProgram.cpp +++ b/Source/WebCore/platform/graphics/android/ShaderProgram.cpp @@ -543,8 +543,9 @@ void ShaderProgram::drawLayerQuadInternal(const GLfloat* projectionMatrix, void ShaderProgram::drawLayerQuad(const TransformationMatrix& drawMatrix, - SkRect& geometry, int textureId, float opacity, - bool forceBlending, GLenum textureTarget) + const SkRect& geometry, int textureId, + float opacity, bool forceBlending, + GLenum textureTarget) { TransformationMatrix modifiedDrawMatrix = drawMatrix; diff --git a/Source/WebCore/platform/graphics/android/ShaderProgram.h b/Source/WebCore/platform/graphics/android/ShaderProgram.h index bfb1fb6..dbacd57 100644 --- a/Source/WebCore/platform/graphics/android/ShaderProgram.h +++ b/Source/WebCore/platform/graphics/android/ShaderProgram.h @@ -54,7 +54,7 @@ public: GLenum textureTarget = GL_TEXTURE_2D, GLint texFilter = GL_LINEAR); void drawLayerQuad(const TransformationMatrix& drawMatrix, - SkRect& geometry, int textureId, float opacity, + const SkRect& geometry, int textureId, float opacity, bool forceBlending = false, GLenum textureTarget = GL_TEXTURE_2D); void drawVideoLayerQuad(const TransformationMatrix& drawMatrix, diff --git a/Source/WebCore/platform/graphics/android/android_graphics.h b/Source/WebCore/platform/graphics/android/android_graphics.h index 89312b5..60ac115 100644 --- a/Source/WebCore/platform/graphics/android/android_graphics.h +++ b/Source/WebCore/platform/graphics/android/android_graphics.h @@ -33,6 +33,7 @@ namespace WebCore { class GraphicsContext; + class GLExtras; } SkCanvas* android_gc2canvas(GraphicsContext* gc); @@ -59,6 +60,7 @@ public: WTF::Vector<IntRect>& rings() { return m_rings; } private: friend class WebView; + friend class WebCore::GLExtras; WebViewCore* m_viewImpl; // copy for convenience WTF::Vector<IntRect> m_rings; IntRect m_bounds; |