diff options
141 files changed, 4684 insertions, 2529 deletions
@@ -333,6 +333,11 @@ WEBKIT_LDLIBS := $(LOCAL_LDLIBS) WEBKIT_SHARED_LIBRARIES := $(LOCAL_SHARED_LIBRARIES) WEBKIT_STATIC_LIBRARIES := $(LOCAL_STATIC_LIBRARIES) +ifneq ($(strip $(WITH_ADDRESS_SANITIZER)),) + LOCAL_MODULE_PATH := $(TARGET_OUT_STATIC_LIBRARIES)/asan + LOCAL_ADDRESS_SANITIZER := true +endif + # Build the library all at once include $(BUILD_STATIC_LIBRARY) @@ -374,6 +379,12 @@ endif # We make all of our object files depend on those files so that they are built # before we try to compile the file. LOCAL_ADDITIONAL_DEPENDENCIES := $(filter %.h, $(WEBKIT_GENERATED_SOURCES)) + +ifneq ($(strip $(WITH_ADDRESS_SANITIZER)),) + LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/asan + LOCAL_ADDRESS_SANITIZER := true +endif + include $(BUILD_SHARED_LIBRARY) # Build the wds client diff --git a/Source/JavaScriptCore/wtf/Platform.h b/Source/JavaScriptCore/wtf/Platform.h index a1db9d6..41850ee 100644 --- a/Source/JavaScriptCore/wtf/Platform.h +++ b/Source/JavaScriptCore/wtf/Platform.h @@ -726,6 +726,7 @@ #define ENABLE_OFFLINE_WEB_APPLICATIONS 1 #define ENABLE_TOUCH_EVENTS 1 #define ENABLE_GEOLOCATION 1 +#define ENABLE_CLIENT_BASED_GEOLOCATION 1 #define ENABLE_INSPECTOR 0 #define ENABLE_EVENT_SOURCE 0 #define ENABLE_DEVICE_ORIENTATION 1 @@ -779,8 +780,6 @@ #define ANDROID_ANIMATED_GIF // apple-touch-icon support in <link> tags #define ANDROID_APPLE_TOUCH_ICON -// track changes to the style that may change what is drawn -#define ANDROID_STYLE_VERSION // This is present in JavaScriptCore/config.h, which Android does not use. #define WTF_CHANGES 1 diff --git a/Source/WebCore/Android.mk b/Source/WebCore/Android.mk index 742fade..10eb822 100644 --- a/Source/WebCore/Android.mk +++ b/Source/WebCore/Android.mk @@ -496,6 +496,7 @@ LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \ page/FrameTree.cpp \ page/FrameView.cpp \ page/Geolocation.cpp \ + page/GeolocationController.cpp \ page/GeolocationPositionCache.cpp \ page/GroupSettings.cpp \ page/History.cpp \ @@ -545,7 +546,6 @@ LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \ platform/FileChooser.cpp \ platform/FileStream.cpp \ platform/FileSystem.cpp \ - platform/GeolocationService.cpp \ platform/KURL.cpp \ platform/KURLGoogle.cpp \ platform/KillRingNone.cpp \ @@ -576,8 +576,6 @@ LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \ platform/android/EventLoopAndroid.cpp \ platform/android/FileChooserAndroid.cpp \ platform/android/FileSystemAndroid.cpp \ - platform/android/GeolocationServiceAndroid.cpp \ - platform/android/GeolocationServiceBridge.cpp \ platform/android/KeyEventAndroid.cpp \ platform/android/LanguageAndroid.cpp \ platform/android/LocalizedStringsAndroid.cpp \ @@ -644,10 +642,12 @@ LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \ platform/graphics/android/SharedBufferStream.cpp \ \ platform/graphics/android/context/GraphicsContextAndroid.cpp \ - platform/graphics/android/context/GraphicsOperationCollection.cpp \ + platform/graphics/android/context/GraphicsOperation.cpp \ platform/graphics/android/context/PlatformGraphicsContext.cpp \ platform/graphics/android/context/PlatformGraphicsContextRecording.cpp \ platform/graphics/android/context/PlatformGraphicsContextSkia.cpp \ + platform/graphics/android/context/RecordingContextCanvasProxy.cpp \ + platform/graphics/android/context/RTree.cpp \ \ platform/graphics/android/fonts/FontAndroid.cpp \ platform/graphics/android/fonts/FontCacheAndroid.cpp \ @@ -699,7 +699,8 @@ LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \ platform/graphics/android/rendering/TilesProfiler.cpp \ platform/graphics/android/rendering/TransferQueue.cpp \ \ - platform/graphics/android/utils/ClassTracker.cpp + platform/graphics/android/utils/ClassTracker.cpp \ + platform/graphics/android/utils/LinearAllocator.cpp ifeq ($(ENABLE_SVG), true) LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \ @@ -757,7 +758,6 @@ LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \ \ platform/mock/DeviceOrientationClientMock.cpp \ platform/mock/GeolocationClientMock.cpp \ - platform/mock/GeolocationServiceMock.cpp \ platform/mock/SpeechInputClientMock.cpp \ \ platform/network/AuthenticationChallengeBase.cpp \ diff --git a/Source/WebCore/dom/Document.cpp b/Source/WebCore/dom/Document.cpp index b6a1393..063b8a2 100644 --- a/Source/WebCore/dom/Document.cpp +++ b/Source/WebCore/dom/Document.cpp @@ -387,9 +387,6 @@ Document::Document(Frame* frame, const KURL& url, bool isXHTML, bool isHTML) , m_compatibilityMode(NoQuirksMode) , m_compatibilityModeLocked(false) , m_domTreeVersion(++s_globalTreeVersion) -#ifdef ANDROID_STYLE_VERSION - , m_styleVersion(0) -#endif , m_styleSheets(StyleSheetList::create(this)) , m_readyState(Complete) , m_styleRecalcTimer(this, &Document::styleRecalcTimerFired) @@ -4880,11 +4877,6 @@ void Document::webkitCancelFullScreen() return; page()->chrome()->client()->exitFullScreenForElement(m_fullScreenElement.get()); -#if PLATFORM(ANDROID) - // The next time we try to enter full screen, we need this change to know - // we are not in full screen any more. - m_fullScreenElement = 0; -#endif } void Document::webkitWillEnterFullScreenForElement(Element* element) diff --git a/Source/WebCore/dom/Document.h b/Source/WebCore/dom/Document.h index ce82b2e..c4ccb9c 100644 --- a/Source/WebCore/dom/Document.h +++ b/Source/WebCore/dom/Document.h @@ -905,11 +905,6 @@ public: void incDOMTreeVersion() { m_domTreeVersion = ++s_globalTreeVersion; } uint64_t domTreeVersion() const { return m_domTreeVersion; } -#ifdef ANDROID_STYLE_VERSION - void incStyleVersion() { ++m_styleVersion; } - unsigned styleVersion() const { return m_styleVersion; } -#endif - void setDocType(PassRefPtr<DocumentType>); #if ENABLE(XPATH) @@ -1223,9 +1218,6 @@ private: uint64_t m_domTreeVersion; static uint64_t s_globalTreeVersion; -#ifdef ANDROID_STYLE_VERSION - unsigned m_styleVersion; -#endif HashSet<NodeIterator*> m_nodeIterators; HashSet<Range*> m_ranges; diff --git a/Source/WebCore/dom/Element.cpp b/Source/WebCore/dom/Element.cpp index 64d3eed..5fb6cdc 100644 --- a/Source/WebCore/dom/Element.cpp +++ b/Source/WebCore/dom/Element.cpp @@ -1069,21 +1069,6 @@ bool Element::pseudoStyleCacheIsInvalid(const RenderStyle* currentStyle, RenderS return false; } -#ifdef ANDROID_STYLE_VERSION -static bool displayDiff(const RenderStyle* s1, const RenderStyle* s2) -{ - if (!s1 && !s2) - return false; - else if ((!s1 && s2) || (s1 && !s2)) - return true; - - return s1->display() != s2->display() - || s1->left() != s2->left() || s1->top() != s2->top() - || s1->right() != s2->right() || s1->bottom() != s2->bottom() - || s1->width() != s2->width() || s1->height() != s2->height(); -} -#endif - void Element::recalcStyle(StyleChange change) { // Ref currentStyle in case it would otherwise be deleted when setRenderStyle() is called. @@ -1092,11 +1077,6 @@ void Element::recalcStyle(StyleChange change) bool hasDirectAdjacentRules = currentStyle && currentStyle->childrenAffectedByDirectAdjacentRules(); if ((change > NoChange || needsStyleRecalc())) { -#ifdef ANDROID_STYLE_VERSION - RefPtr<RenderStyle> newStyle = document()->styleForElementIgnoringPendingStylesheets(this); - if (displayDiff(currentStyle.get(), newStyle.get())) - document()->incStyleVersion(); -#endif if (hasRareData()) rareData()->resetComputedStyle(); } diff --git a/Source/WebCore/html/HTMLInputElement.cpp b/Source/WebCore/html/HTMLInputElement.cpp index 36cdf51..27b29a8 100644 --- a/Source/WebCore/html/HTMLInputElement.cpp +++ b/Source/WebCore/html/HTMLInputElement.cpp @@ -444,10 +444,6 @@ void HTMLInputElement::setType(const String& type) void HTMLInputElement::updateType() { OwnPtr<InputType> newType = InputType::create(this, fastGetAttribute(typeAttr)); -#ifdef ANDROID_ACCEPT_CHANGES_TO_FOCUSED_TEXTFIELDS - if (newType->isPasswordField() && document()->focusedNode() == this) - PlatformBridge::updateTextfield(document()->view(), this, true, String()); -#endif bool hadType = m_hasType; m_hasType = true; if (m_inputType->formControlType() == newType->formControlType()) @@ -912,7 +908,7 @@ void HTMLInputElement::setValue(const String& value, bool sendChangeEvent) unsigned max = m_data.value().length(); #ifdef ANDROID_ACCEPT_CHANGES_TO_FOCUSED_TEXTFIELDS // Make sure our UI side textfield changes to match the RenderTextControl - PlatformBridge::updateTextfield(document()->view(), this, false, value); + PlatformBridge::updateTextfield(document()->view(), this, value); #endif if (document()->focusedNode() == this) InputElement::updateSelectionRange(this, this, max, max); @@ -1573,7 +1569,11 @@ bool HTMLInputElement::hasSpinButton() const bool HTMLInputElement::supportsPlaceholder() const { +#if PLATFORM(ANDROID) + return isTextType() || isNumberField(); +#else return isTextType(); +#endif } CheckedRadioButtons& HTMLInputElement::checkedRadioButtons() const diff --git a/Source/WebCore/html/HTMLMediaElement.cpp b/Source/WebCore/html/HTMLMediaElement.cpp index 328b6db..f3cc170 100644 --- a/Source/WebCore/html/HTMLMediaElement.cpp +++ b/Source/WebCore/html/HTMLMediaElement.cpp @@ -185,9 +185,9 @@ HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document* docum document->registerForDocumentActivationCallbacks(this); document->registerForMediaVolumeCallbacks(this); document->registerForPrivateBrowsingStateChangedCallbacks(this); -#if PLATFORM(ANDROID) && ENABLE(TOUCH_EVENTS) - m_restrictions |= RequireUserGestureForRateChangeRestriction; -#endif + + if (document->settings() && document->settings()->mediaPlaybackRequiresUserGesture()) + m_restrictions |= RequireUserGestureForRateChangeRestriction; } HTMLMediaElement::~HTMLMediaElement() @@ -1036,7 +1036,10 @@ void HTMLMediaElement::setReadyState(MediaPlayer::ReadyState state) if (isPotentiallyPlaying && oldState <= HAVE_CURRENT_DATA) scheduleEvent(eventNames().playingEvent); - +#if PLATFORM(ANDROID) + // autoplay should not be honored if we require user gesture. + if (!(m_restrictions & RequireUserGestureForRateChangeRestriction)) +#endif if (m_autoplaying && m_paused && autoplay()) { m_paused = false; invalidateCachedTime(); @@ -2272,8 +2275,11 @@ void HTMLMediaElement::stopPeriodicTimers() void HTMLMediaElement::userCancelledLoad() { LOG(Media, "HTMLMediaElement::userCancelledLoad"); - +#if PLATFORM(ANDROID) + if (m_networkState == NETWORK_EMPTY) +#else if (m_networkState == NETWORK_EMPTY || m_completelyLoaded) +#endif return; // If the media data fetching process is aborted by the user: diff --git a/Source/WebCore/html/HTMLMetaElement.cpp b/Source/WebCore/html/HTMLMetaElement.cpp index cb7f4c0..4f65065 100644 --- a/Source/WebCore/html/HTMLMetaElement.cpp +++ b/Source/WebCore/html/HTMLMetaElement.cpp @@ -32,10 +32,6 @@ #include "Settings.h" #endif -#if ENABLE(ANDROID_INSTALLABLE_WEB_APPS) -#include "ChromeClient.h" -#endif - namespace WebCore { using namespace HTMLNames; @@ -89,16 +85,6 @@ void HTMLMetaElement::process() } #endif -#if ENABLE(ANDROID_INSTALLABLE_WEB_APPS) - // If this web site is informing us it is possible for it to be installed, inform the chrome - // client so it can offer this to the user. - if (equalIgnoringCase(name(), "fullscreen-web-app-capable") - && equalIgnoringCase(m_content, "yes")) { - if (Page* page = document()->page()) - page->chrome()->client()->webAppCanBeInstalled(); - } -#endif - // Get the document to process the tag, but only if we're actually part of DOM tree (changing a meta tag while // it's not in the tree shouldn't have any effect on the document) if (!m_equiv.isNull()) diff --git a/Source/WebCore/html/HTMLTextAreaElement.cpp b/Source/WebCore/html/HTMLTextAreaElement.cpp index 5b12a14..50471d1 100644 --- a/Source/WebCore/html/HTMLTextAreaElement.cpp +++ b/Source/WebCore/html/HTMLTextAreaElement.cpp @@ -329,7 +329,7 @@ void HTMLTextAreaElement::setValueCommon(const String& value) if (document()->focusedNode() == this) { #ifdef ANDROID_ACCEPT_CHANGES_TO_FOCUSED_TEXTFIELDS // Make sure our UI side textfield changes to match the RenderTextControl - PlatformBridge::updateTextfield(document()->view(), this, false, value); + PlatformBridge::updateTextfield(document()->view(), this, value); #endif unsigned endOfString = m_value.length(); setSelectionRange(endOfString, endOfString); diff --git a/Source/WebCore/loader/EmptyClients.h b/Source/WebCore/loader/EmptyClients.h index 45df6ec..058db37 100644 --- a/Source/WebCore/loader/EmptyClients.h +++ b/Source/WebCore/loader/EmptyClients.h @@ -97,10 +97,6 @@ public: virtual float scaleFactor() { return 1.f; } -#if ENABLE(ANDROID_INSTALLABLE_WEB_APPS) - virtual void webAppCanBeInstalled() { } -#endif - virtual void focus() { } virtual void unfocus() { } diff --git a/Source/WebCore/page/ChromeClient.h b/Source/WebCore/page/ChromeClient.h index 91511ac..0ec366b 100644 --- a/Source/WebCore/page/ChromeClient.h +++ b/Source/WebCore/page/ChromeClient.h @@ -319,10 +319,6 @@ namespace WebCore { }; virtual void willRunModalDialogDuringPageDismissal(const DialogType&) const { } -#if ENABLE(ANDROID_INSTALLABLE_WEB_APPS) - virtual void webAppCanBeInstalled() = 0; -#endif - protected: virtual ~ChromeClient() { } }; diff --git a/Source/WebCore/page/Geolocation.cpp b/Source/WebCore/page/Geolocation.cpp index f0dd76a..352e06b 100644 --- a/Source/WebCore/page/Geolocation.cpp +++ b/Source/WebCore/page/Geolocation.cpp @@ -708,20 +708,8 @@ bool Geolocation::startUpdating(GeoNotifier* notifier) page->geolocationController()->addObserver(this, notifier->m_options->enableHighAccuracy()); return true; #else -#if PLATFORM(ANDROID) - // TODO: Upstream to webkit.org. See https://bugs.webkit.org/show_bug.cgi?id=34082 - // Note that the correct fix is to use a 'paused' flag in WebCore, rather - // than calling into PlatformBridge. - if (!m_frame) - return false; - FrameView* view = m_frame->view(); - if (!view) - return false; - return m_service->startUpdating(notifier->m_options.get(), PlatformBridge::isWebViewPaused(view)); -#else return m_service->startUpdating(notifier->m_options.get()); #endif -#endif } void Geolocation::stopUpdating() diff --git a/Source/WebCore/page/GeolocationController.cpp b/Source/WebCore/page/GeolocationController.cpp index b9533ca..56c11a5 100644 --- a/Source/WebCore/page/GeolocationController.cpp +++ b/Source/WebCore/page/GeolocationController.cpp @@ -59,7 +59,10 @@ void GeolocationController::addObserver(Geolocation* observer, bool enableHighAc if (m_client) { if (enableHighAccuracy) m_client->setEnableHighAccuracy(true); +// See https://bugs.webkit.org/show_bug.cgi?id=87030 +#if !PLATFORM(ANDROID) if (wasEmpty) +#endif m_client->startUpdating(); } } diff --git a/Source/WebCore/page/Settings.cpp b/Source/WebCore/page/Settings.cpp index f668f3e..79e38d1 100644 --- a/Source/WebCore/page/Settings.cpp +++ b/Source/WebCore/page/Settings.cpp @@ -201,6 +201,8 @@ Settings::Settings(Page* page) #else , m_passwordEchoEnabled(false) #endif + , m_mediaPlaybackRequiresUserGesture(false) + , m_mediaPlaybackAllowsInline(true) { // A Frame may not have been created yet, so we initialize the AtomicString // hash before trying to use it. diff --git a/Source/WebCore/page/Settings.h b/Source/WebCore/page/Settings.h index 2cf7715..84828ab 100644 --- a/Source/WebCore/page/Settings.h +++ b/Source/WebCore/page/Settings.h @@ -479,6 +479,12 @@ namespace WebCore { bool blockNetworkImage() const { return m_blockNetworkImage; } #endif + void setMediaPlaybackRequiresUserGesture(bool flag) { m_mediaPlaybackRequiresUserGesture = flag; }; + bool mediaPlaybackRequiresUserGesture() const { return m_mediaPlaybackRequiresUserGesture; } + + void setMediaPlaybackAllowsInline(bool flag) { m_mediaPlaybackAllowsInline = flag; }; + bool mediaPlaybackAllowsInline() const { return m_mediaPlaybackAllowsInline; } + private: Page* m_page; @@ -633,6 +639,8 @@ namespace WebCore { #ifdef ANDROID_PLUGINS bool m_pluginsOnDemand : 1; #endif + bool m_mediaPlaybackRequiresUserGesture : 1; + bool m_mediaPlaybackAllowsInline : 1; bool m_passwordEchoEnabled : 1; #if USE(SAFARI_THEME) diff --git a/Source/WebCore/platform/GeolocationService.h b/Source/WebCore/platform/GeolocationService.h index 27be6c3..1045bb3 100644 --- a/Source/WebCore/platform/GeolocationService.h +++ b/Source/WebCore/platform/GeolocationService.h @@ -48,12 +48,7 @@ public: static GeolocationService* create(GeolocationServiceClient*); virtual ~GeolocationService() { } -#if PLATFORM(ANDROID) - // TODO: Upstream to webkit.org. See https://bugs.webkit.org/show_bug.cgi?id=34082 - virtual bool startUpdating(PositionOptions*, bool suspend) { return false; } -#else virtual bool startUpdating(PositionOptions*) { return false; } -#endif virtual void stopUpdating() { } virtual void suspend() { } diff --git a/Source/WebCore/platform/android/GeolocationServiceAndroid.cpp b/Source/WebCore/platform/android/GeolocationServiceAndroid.cpp deleted file mode 100644 index 0f07722..0000000 --- a/Source/WebCore/platform/android/GeolocationServiceAndroid.cpp +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright 2009, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 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 "GeolocationServiceAndroid.h" - -#include "Geolocation.h" -#include "GeolocationServiceBridge.h" -#include "Geoposition.h" -#include "PositionError.h" -#include "PositionOptions.h" - -#if PLATFORM(ANDROID) -// Required for sim-eng build -#include <math.h> -#endif -#include <wtf/CurrentTime.h> - -using JSC::Bindings::getJNIEnv; -using namespace std; - -namespace WebCore { - -// GeolocationServiceAndroid is the Android implmentation of Geolocation -// service. Each object of this class owns an object of type -// GeolocationServiceBridge, which in turn owns a Java GeolocationService -// object. Therefore, there is a 1:1 mapping between Geolocation, -// GeolocationServiceAndroid, GeolocationServiceBridge and Java -// GeolocationService objects. In the case where multiple Geolocation objects -// exist simultaneously, the corresponsing Java GeolocationService objects all -// register with the platform location service. It is the platform service that -// handles making sure that updates are passed to all Geolocation objects. -GeolocationService* GeolocationServiceAndroid::create(GeolocationServiceClient* client) -{ - return new GeolocationServiceAndroid(client); -} - -GeolocationService::FactoryFunction* GeolocationService::s_factoryFunction = &GeolocationServiceAndroid::create; - -GeolocationServiceAndroid::GeolocationServiceAndroid(GeolocationServiceClient* client) - : GeolocationService(client) - , m_timer(this, &GeolocationServiceAndroid::timerFired) - , m_javaBridge(0) -{ -} - -// ANDROID -// TODO: Upstream to webkit.org. See https://bugs.webkit.org/show_bug.cgi?id=34082 -bool GeolocationServiceAndroid::startUpdating(PositionOptions* options, bool suspend) -{ - // ANDROID - // This is an ugly hack. A correct fix would require a change to WebCore, - // but this isn't worth the effort as we're in the process of switching to a - // client-based implementation. See https://bugs.webkit.org/show_bug.cgi?id=40373 - Frame* frame = reinterpret_cast<Geolocation*>(geolocationServiceClient())->frame(); - if (!frame) - return false; - - // This method is called every time a new watch or one-shot position request - // is started. If we already have a position or an error, call back - // immediately. - if (m_lastPosition || m_lastError) { - ASSERT(m_javaBridge); - m_timer.startOneShot(0); - } - - // Lazilly create the Java object. - bool haveJavaBridge = m_javaBridge; - if (!haveJavaBridge) - m_javaBridge.set(new GeolocationServiceBridge(this, frame)); - ASSERT(m_javaBridge); - - // On Android, high power == GPS. Set whether to use GPS before we start the - // implementation. - ASSERT(options); - if (options->enableHighAccuracy()) - m_javaBridge->setEnableGps(true); - - // We need only start the service when it's first created. - if (!haveJavaBridge) { - // If the browser is paused, don't start the service. It will be started - // when we get the call to resume. - // ANDROID - // TODO: Upstream to webkit.org. See https://bugs.webkit.org/show_bug.cgi?id=34082 - if (!suspend) - return m_javaBridge->start(); - } - - return true; -} - -void GeolocationServiceAndroid::stopUpdating() -{ - // Called when the Geolocation object has no watches or one shots in - // progress. This may be called repeatedly. - m_javaBridge.clear(); - // Reset last position and error to make sure that we always try to get a - // new position from the system service when a request is first made. - m_lastPosition = 0; - m_lastError = 0; - // remove the pending timer - if (m_timer.isActive()) - m_timer.stop(); -} - -void GeolocationServiceAndroid::suspend() -{ - if (m_javaBridge) - m_javaBridge->stop(); -} - -void GeolocationServiceAndroid::resume() -{ - if (m_javaBridge) - m_javaBridge->start(); -} - -// Note that there is no guarantee that subsequent calls to this method offer a -// more accurate or updated position. -void GeolocationServiceAndroid::newPositionAvailable(PassRefPtr<Geoposition> position) -{ - ASSERT(position); - if (!m_lastPosition - || isPositionMovement(m_lastPosition.get(), position.get()) - || isPositionMoreAccurate(m_lastPosition.get(), position.get()) - || isPositionMoreTimely(m_lastPosition.get(), position.get())) { - m_lastPosition = position; - // Remove the last error. - m_lastError = 0; - positionChanged(); - } -} - -void GeolocationServiceAndroid::newErrorAvailable(PassRefPtr<PositionError> error) -{ - ASSERT(error); - // We leave the last position - m_lastError = error; - errorOccurred(); -} - -void GeolocationServiceAndroid::timerFired(Timer<GeolocationServiceAndroid>* timer) -{ - ASSERT(&m_timer == timer); - ASSERT(m_lastPosition || m_lastError); - if (m_lastPosition) - positionChanged(); - else if (m_lastError) - errorOccurred(); -} - -bool GeolocationServiceAndroid::isPositionMovement(Geoposition* position1, Geoposition* position2) -{ - ASSERT(position1 && position2); - // For the small distances in which we are likely concerned, it's reasonable - // to approximate the distance between the two positions as the sum of the - // differences in latitude and longitude. - double delta = fabs(position1->coords()->latitude() - position2->coords()->latitude()) - + fabs(position1->coords()->longitude() - position2->coords()->longitude()); - // Approximate conversion from degrees of arc to metres. - delta *= 60 * 1852; - // The threshold is when the distance between the two positions exceeds the - // worse (larger) of the two accuracies. - int maxAccuracy = max(position1->coords()->accuracy(), position2->coords()->accuracy()); - return delta > maxAccuracy; -} - -bool GeolocationServiceAndroid::isPositionMoreAccurate(Geoposition* position1, Geoposition* position2) -{ - ASSERT(position1 && position2); - return position2->coords()->accuracy() < position1->coords()->accuracy(); -} - -bool GeolocationServiceAndroid::isPositionMoreTimely(Geoposition* position1, Geoposition* position2) -{ - ASSERT(position1 && position2); - DOMTimeStamp currentTime = convertSecondsToDOMTimeStamp(WTF::currentTime()); - DOMTimeStamp maximumAge = convertSecondsToDOMTimeStamp(10 * 60); // 10 minutes - return currentTime - position1->timestamp() > maximumAge; -} - -} // namespace WebCore diff --git a/Source/WebCore/platform/android/GeolocationServiceAndroid.h b/Source/WebCore/platform/android/GeolocationServiceAndroid.h deleted file mode 100644 index 72532f6..0000000 --- a/Source/WebCore/platform/android/GeolocationServiceAndroid.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2009, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 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 GeolocationServiceAndroid_h -#define GeolocationServiceAndroid_h - -#include "GeolocationService.h" -#include "Timer.h" -#include <wtf/OwnPtr.h> -#include <wtf/PassRefPtr.h> -#include <wtf/RefPtr.h> - -namespace WebCore { - -// The GeolocationServiceBridge is the bridge to the Java implementation of -// the Geolocation service. It is an implementation detail of -// GeolocationServiceAndroid. -class GeolocationServiceBridge; - -class GeolocationServiceAndroid : public GeolocationService { -public: - static GeolocationService* create(GeolocationServiceClient*); - - virtual ~GeolocationServiceAndroid() { }; - - // ANDROID - // TODO: Upstream to webkit.org. See https://bugs.webkit.org/show_bug.cgi?id=34082 - virtual bool startUpdating(PositionOptions*, bool suspend); - virtual void stopUpdating(); - - virtual Geoposition* lastPosition() const { return m_lastPosition.get(); } - virtual PositionError* lastError() const { return m_lastError.get(); } - - virtual void suspend(); - virtual void resume(); - - // Android-specific - void newPositionAvailable(PassRefPtr<Geoposition>); - void newErrorAvailable(PassRefPtr<PositionError>); - void timerFired(Timer<GeolocationServiceAndroid>* timer); - -private: - GeolocationServiceAndroid(GeolocationServiceClient*); - - static bool isPositionMovement(Geoposition* position1, Geoposition* position2); - static bool isPositionMoreAccurate(Geoposition* position1, Geoposition* position2); - static bool isPositionMoreTimely(Geoposition* position1, Geoposition* position2); - - Timer<GeolocationServiceAndroid> m_timer; - RefPtr<Geoposition> m_lastPosition; - RefPtr<PositionError> m_lastError; - OwnPtr<GeolocationServiceBridge> m_javaBridge; -}; - -} // namespace WebCore - -#endif // GeolocationServiceAndroid_h diff --git a/Source/WebCore/platform/android/PlatformBridge.h b/Source/WebCore/platform/android/PlatformBridge.h index a4c1048..5af5d2d 100644 --- a/Source/WebCore/platform/android/PlatformBridge.h +++ b/Source/WebCore/platform/android/PlatformBridge.h @@ -124,10 +124,6 @@ public: }; static String* globalLocalizedName(rawResId resId); - // Whether the WebView is paused. - // ANDROID - // TODO: Upstream to webkit.org. See https://bugs.webkit.org/show_bug.cgi?id=34082 - static bool isWebViewPaused(const FrameView*); static String resolveFilePathForContentUri(const String&); static int screenDepth(); @@ -136,7 +132,7 @@ public: // Update the viewport meta data. static void updateViewport(FrameView*); - static void updateTextfield(FrameView*, Node*, bool changeToPassword, const WTF::String& text); + static void updateTextfield(FrameView*, Node*, const WTF::String& text); static void setScrollPosition(ScrollView*, int x, int y); diff --git a/Source/WebCore/platform/android/RenderThemeAndroid.cpp b/Source/WebCore/platform/android/RenderThemeAndroid.cpp index 86380e7..eaf4593 100644 --- a/Source/WebCore/platform/android/RenderThemeAndroid.cpp +++ b/Source/WebCore/platform/android/RenderThemeAndroid.cpp @@ -39,6 +39,7 @@ #endif #include "RenderSkinAndroid.h" #include "RenderSkinMediaButton.h" +#include "RenderSlider.h" #include "RoundedIntRect.h" #include "SkCanvas.h" #include "UserAgentStyleSheets.h" @@ -85,12 +86,6 @@ const float scaleFactor[RenderSkinAndroid::ResolutionCount] = { 2.0f // extra high res }; - -static SkCanvas* getCanvasFromInfo(const PaintInfo& info) -{ - return info.context->platformContext()->getCanvas(); -} - static android::WebFrame* getWebFrame(const Node* node) { if (!node) @@ -341,9 +336,7 @@ bool RenderThemeAndroid::paintMediaFullscreenButton(RenderObject* o, const Paint bool translucent = false; if (o && toParentMediaElement(o) && toParentMediaElement(o)->hasTagName(HTMLNames::videoTag)) translucent = true; - if (!getCanvasFromInfo(paintInfo)) - return true; - RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, RenderSkinMediaButton::FULLSCREEN, translucent); + paintInfo.context->platformContext()->drawMediaButton(rect, RenderSkinMediaButton::FULLSCREEN, translucent); return false; } @@ -352,9 +345,7 @@ bool RenderThemeAndroid::paintMediaMuteButton(RenderObject* o, const PaintInfo& bool translucent = false; if (o && toParentMediaElement(o) && toParentMediaElement(o)->hasTagName(HTMLNames::videoTag)) translucent = true; - if (!getCanvasFromInfo(paintInfo)) - return true; - RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, RenderSkinMediaButton::MUTE, translucent); + paintInfo.context->platformContext()->drawMediaButton(rect, RenderSkinMediaButton::MUTE, translucent); return false; } @@ -364,12 +355,10 @@ bool RenderThemeAndroid::paintMediaPlayButton(RenderObject* o, const PaintInfo& if (o && toParentMediaElement(o) && toParentMediaElement(o)->hasTagName(HTMLNames::videoTag)) translucent = true; if (MediaControlPlayButtonElement* btn = static_cast<MediaControlPlayButtonElement*>(o->node())) { - if (!getCanvasFromInfo(paintInfo)) - return true; if (btn->displayType() == MediaPlayButton) - RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, RenderSkinMediaButton::PLAY, translucent); + paintInfo.context->platformContext()->drawMediaButton(rect, RenderSkinMediaButton::PLAY, translucent); else - RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, RenderSkinMediaButton::PAUSE, translucent); + paintInfo.context->platformContext()->drawMediaButton(rect, RenderSkinMediaButton::PAUSE, translucent); return false; } return true; @@ -380,9 +369,7 @@ bool RenderThemeAndroid::paintMediaSeekBackButton(RenderObject* o, const PaintIn bool translucent = false; if (o && toParentMediaElement(o) && toParentMediaElement(o)->hasTagName(HTMLNames::videoTag)) translucent = true; - if (!getCanvasFromInfo(paintInfo)) - return true; - RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, RenderSkinMediaButton::REWIND, translucent); + paintInfo.context->platformContext()->drawMediaButton(rect, RenderSkinMediaButton::REWIND, translucent); return false; } @@ -391,9 +378,7 @@ bool RenderThemeAndroid::paintMediaSeekForwardButton(RenderObject* o, const Pain bool translucent = false; if (o && toParentMediaElement(o) && toParentMediaElement(o)->hasTagName(HTMLNames::videoTag)) translucent = true; - if (!getCanvasFromInfo(paintInfo)) - return true; - RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, RenderSkinMediaButton::FORWARD, translucent); + paintInfo.context->platformContext()->drawMediaButton(rect, RenderSkinMediaButton::FORWARD, translucent); return false; } @@ -402,11 +387,9 @@ bool RenderThemeAndroid::paintMediaControlsBackground(RenderObject* o, const Pai bool translucent = false; if (o && toParentMediaElement(o) && toParentMediaElement(o)->hasTagName(HTMLNames::videoTag)) translucent = true; - if (!getCanvasFromInfo(paintInfo)) - return true; - RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, + paintInfo.context->platformContext()->drawMediaButton(rect, RenderSkinMediaButton::BACKGROUND_SLIDER, - translucent, 0, false); + translucent, false); return false; } @@ -415,10 +398,11 @@ bool RenderThemeAndroid::paintMediaSliderTrack(RenderObject* o, const PaintInfo& bool translucent = false; if (o && toParentMediaElement(o) && toParentMediaElement(o)->hasTagName(HTMLNames::videoTag)) translucent = true; - if (!getCanvasFromInfo(paintInfo)) - return true; - RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, - RenderSkinMediaButton::SLIDER_TRACK, translucent, o); + IntRect thumb; + if (o && o->isSlider()) + thumb = toRenderSlider(o)->thumbRect(); + paintInfo.context->platformContext()->drawMediaButton(rect, + RenderSkinMediaButton::SLIDER_TRACK, translucent, true, thumb); return false; } @@ -427,11 +411,9 @@ bool RenderThemeAndroid::paintMediaSliderThumb(RenderObject* o, const PaintInfo& bool translucent = false; if (o && toParentMediaElement(o) && toParentMediaElement(o)->hasTagName(HTMLNames::videoTag)) translucent = true; - if (!getCanvasFromInfo(paintInfo)) - return true; - RenderSkinMediaButton::Draw(getCanvasFromInfo(paintInfo), rect, + paintInfo.context->platformContext()->drawMediaButton(rect, RenderSkinMediaButton::SLIDER_THUMB, - translucent, 0, false); + translucent, false); return false; } @@ -647,25 +629,19 @@ bool RenderThemeAndroid::paintMenuListButton(RenderObject* obj, const PaintInfo& bool RenderThemeAndroid::paintSliderTrack(RenderObject* o, const PaintInfo& i, const IntRect& r) { - SkCanvas* canvas = getCanvasFromInfo(i); - if (!canvas) - return true; static const bool translucent = true; - RenderSkinMediaButton::Draw(canvas, r, + i.context->platformContext()->drawMediaButton(r, RenderSkinMediaButton::SLIDER_TRACK, - translucent, o, false); + translucent, false); return false; } bool RenderThemeAndroid::paintSliderThumb(RenderObject* o, const PaintInfo& i, const IntRect& r) { - SkCanvas* canvas = getCanvasFromInfo(i); - if (!canvas) - return true; static const bool translucent = true; - RenderSkinMediaButton::Draw(canvas, r, + i.context->platformContext()->drawMediaButton(r, RenderSkinMediaButton::SLIDER_THUMB, - translucent, 0, false); + translucent, false); return false; } diff --git a/Source/WebCore/platform/graphics/MediaPlayer.cpp b/Source/WebCore/platform/graphics/MediaPlayer.cpp index a7e4b90..4e00382 100644 --- a/Source/WebCore/platform/graphics/MediaPlayer.cpp +++ b/Source/WebCore/platform/graphics/MediaPlayer.cpp @@ -689,6 +689,14 @@ void MediaPlayer::exitFullscreen() } #endif +#if PLATFORM(ANDROID) +void MediaPlayer::enterFullscreenMode() +{ + // Tell the player to enter full screen mode. + m_private->enterFullscreenMode(); +} +#endif + #if USE(ACCELERATED_COMPOSITING) void MediaPlayer::acceleratedRenderingStateChanged() { diff --git a/Source/WebCore/platform/graphics/MediaPlayer.h b/Source/WebCore/platform/graphics/MediaPlayer.h index 41cb6d2..884f915 100644 --- a/Source/WebCore/platform/graphics/MediaPlayer.h +++ b/Source/WebCore/platform/graphics/MediaPlayer.h @@ -190,6 +190,7 @@ public: enum MediaElementType { Video, Audio }; void setMediaElementType(MediaElementType type) { m_mediaElementType = type; } MediaElementType mediaElementType() { return m_mediaElementType; } + void enterFullscreenMode(); #endif void setFrameView(FrameView* frameView) { m_frameView = frameView; } diff --git a/Source/WebCore/platform/graphics/MediaPlayerPrivate.h b/Source/WebCore/platform/graphics/MediaPlayerPrivate.h index b4490bc..fa92e06 100644 --- a/Source/WebCore/platform/graphics/MediaPlayerPrivate.h +++ b/Source/WebCore/platform/graphics/MediaPlayerPrivate.h @@ -113,7 +113,9 @@ public: virtual void enterFullscreen() { } virtual void exitFullscreen() { } #endif - +#if PLATFORM(ANDROID) + virtual void enterFullscreenMode() { } +#endif #if USE(ACCELERATED_COMPOSITING) // whether accelerated rendering is supported by the media engine for the current media. virtual bool supportsAcceleratedRendering() const { return false; } diff --git a/Source/WebCore/platform/graphics/android/GLWebViewState.cpp b/Source/WebCore/platform/graphics/android/GLWebViewState.cpp index 55c4eec..256a678 100644 --- a/Source/WebCore/platform/graphics/android/GLWebViewState.cpp +++ b/Source/WebCore/platform/graphics/android/GLWebViewState.cpp @@ -353,10 +353,8 @@ int GLWebViewState::drawGL(IntRect& invScreenRect, SkRect& visibleContentRect, if (ImagesManager::instance()->prepareTextures(this)) returnFlags |= DrawGlInfo::kStatusDraw; - if (scale < MIN_SCALE_WARNING || scale > MAX_SCALE_WARNING) { + if (scale < MIN_SCALE_WARNING || scale > MAX_SCALE_WARNING) ALOGW("WARNING, scale seems corrupted after update: %e", scale); - scale = 1.0f; // WORKAROUND for corrupted scale: use 1.0 - } double currentTime = setupDrawing(invScreenRect, visibleContentRect, screenRect, titleBarHeight, screenClip, scale); diff --git a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp index 779dba5..25441f4 100644 --- a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp @@ -41,6 +41,7 @@ #include "Length.h" #include "MediaLayer.h" #include "PictureLayerContent.h" +#include "PicturePileLayerContent.h" #include "PlatformBridge.h" #include "PlatformGraphicsContextSkia.h" #include "RenderLayerBacking.h" @@ -828,22 +829,9 @@ bool GraphicsLayerAndroid::repaint() return false; } -SkPicture* GraphicsLayerAndroid::paintPicture(const IntRect& rect) +void GraphicsLayerAndroid::paintContents(GraphicsContext* gc, IntRect& dirty) { - SkPicture* picture = new SkPicture(); - SkCanvas* canvas = picture->beginRecording(rect.width(), rect.height(), 0); - if (!canvas) { - picture->endRecording(); - SkSafeUnref(picture); - return 0; - } - - PlatformGraphicsContextSkia platformContext(canvas); - GraphicsContext graphicsContext(&platformContext); - - paintGraphicsLayerContents(graphicsContext, rect); - - return picture; + paintGraphicsLayerContents(*gc, dirty); } bool GraphicsLayerAndroid::paintContext(LayerAndroid* layer, @@ -853,19 +841,22 @@ bool GraphicsLayerAndroid::paintContext(LayerAndroid* layer, if (!layer) return false; - SkPicture* picture = paintPicture(rect); - if (!picture) - return false; - picture->endRecording(); + TRACE_METHOD(); + + // TODO: we might be able to reuse an existing picture instead of recreating it. + // we can't do that because of transparency -- for now, we just create + // a new picture every time. + WebCore::PicturePile picture; + picture.setSize(IntSize(m_size.width(), m_size.height())); + + // TODO: add content checks (text, opacity, etc.) + picture.updatePicturesIfNeeded(this); + + // store the newly painted content in the layer if it's not empty + PicturePileLayerContent* content = new PicturePileLayerContent(picture); + layer->setContent(content->isEmpty() ? 0 : content); + SkSafeUnref(content); - PictureLayerContent* layerContent = new PictureLayerContent(picture); - if (checkOptimisations) - layerContent->checkForOptimisations(); - else - layerContent->setCheckForOptimisations(false); - layer->setContent(layerContent); - SkSafeUnref(layerContent); - SkSafeUnref(picture); return true; } diff --git a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.h b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.h index 460e00f..b40459d 100644 --- a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.h +++ b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.h @@ -24,6 +24,7 @@ #include "GraphicsLayer.h" #include "GraphicsLayerClient.h" #include "LayerContent.h" +#include "PicturePile.h" #include "RefPtr.h" #include "ScrollableLayerAndroid.h" #include "SkBitmapRef.h" @@ -40,12 +41,18 @@ class LayerAndroid; class FixedBackgroundImageLayerAndroid; class ScrollableLayerAndroid; -class GraphicsLayerAndroid : public GraphicsLayer { +class GraphicsLayerAndroid : public GraphicsLayer, PicturePainter { public: GraphicsLayerAndroid(GraphicsLayerClient*); virtual ~GraphicsLayerAndroid(); + // PicturePainter + + virtual void paintContents(GraphicsContext* gc, IntRect& dirty); + + ///// + virtual void setName(const String&); // for hosting this GraphicsLayer in a native layer hierarchy @@ -147,7 +154,6 @@ private: bool repaint(); void needsNotifyClient(); - SkPicture* paintPicture(const IntRect& rect); bool paintContext(LayerAndroid* layer, const IntRect& rect, bool checkOptimisations = true); diff --git a/Source/WebCore/platform/graphics/android/ImageAndroid.cpp b/Source/WebCore/platform/graphics/android/ImageAndroid.cpp index 08f72e0..4958622 100644 --- a/Source/WebCore/platform/graphics/android/ImageAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/ImageAndroid.cpp @@ -34,7 +34,6 @@ #include "PlatformString.h" #include "SharedBuffer.h" -#include "android_graphics.h" #include "SkBitmapRef.h" #include "SkCanvas.h" #include "SkColorPriv.h" diff --git a/Source/WebCore/platform/graphics/android/ImageBufferAndroid.cpp b/Source/WebCore/platform/graphics/android/ImageBufferAndroid.cpp index e56f424..f36200d 100644 --- a/Source/WebCore/platform/graphics/android/ImageBufferAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/ImageBufferAndroid.cpp @@ -33,6 +33,7 @@ #include "NotImplemented.h" #include "PlatformBridge.h" #include "PlatformGraphicsContext.h" +#include "PlatformGraphicsContextSkia.h" #include "SkBitmapRef.h" #include "SkCanvas.h" #include "SkColorPriv.h" @@ -41,12 +42,21 @@ #include "SkImageEncoder.h" #include "SkStream.h" #include "SkUnPreMultiply.h" -#include "android_graphics.h" using namespace std; namespace WebCore { +SkCanvas* imageBufferCanvas(const ImageBuffer* buffer) +{ + // We know that our PlatformGraphicsContext is a PlatformGraphicsContextSkia + // because that is what we create in GraphicsContext::createOffscreenContext + if (!buffer || !buffer->context()) + return 0; + PlatformGraphicsContext* pc = buffer->context()->platformContext(); + return static_cast<PlatformGraphicsContextSkia*>(pc)->canvas(); +} + ImageBufferData::ImageBufferData(const IntSize&) { } @@ -82,7 +92,7 @@ PassRefPtr<Image> ImageBuffer::copyImage() const { ASSERT(context()); - SkCanvas* canvas = context()->platformContext()->getCanvas(); + SkCanvas* canvas = imageBufferCanvas(this); if (!canvas) return 0; @@ -123,7 +133,7 @@ PassRefPtr<ByteArray> ImageBuffer::getUnmultipliedImageData(const IntRect& rect) return 0; } - const SkBitmap& src = android_gc2canvas(gc)->getDevice()->accessBitmap(false); + const SkBitmap& src = imageBufferCanvas(this)->getDevice()->accessBitmap(false); SkAutoLockPixels alp(src); if (!src.getPixels()) { return 0; @@ -185,7 +195,7 @@ void ImageBuffer::putUnmultipliedImageData(ByteArray* source, const IntSize& sou return; } - const SkBitmap& dst = android_gc2canvas(gc)->getDevice()->accessBitmap(true); + const SkBitmap& dst = imageBufferCanvas(this)->getDevice()->accessBitmap(true); SkAutoLockPixels alp(dst); if (!dst.getPixels()) { return; @@ -240,7 +250,7 @@ String ImageBuffer::toDataURL(const String&, const double*) const { // Encode the image into a vector. SkDynamicMemoryWStream pngStream; - const SkBitmap& dst = android_gc2canvas(context())->getDevice()->accessBitmap(true); + const SkBitmap& dst = imageBufferCanvas(this)->getDevice()->accessBitmap(true); SkImageEncoder::EncodeStream(&pngStream, dst, SkImageEncoder::kPNG_Type, 100); // Convert it into base64. diff --git a/Source/WebCore/platform/graphics/android/ImageBufferDataAndroid.h b/Source/WebCore/platform/graphics/android/ImageBufferDataAndroid.h index 80cf79f..eeade6e 100644 --- a/Source/WebCore/platform/graphics/android/ImageBufferDataAndroid.h +++ b/Source/WebCore/platform/graphics/android/ImageBufferDataAndroid.h @@ -26,9 +26,14 @@ #ifndef ImageBufferDataAndroid_h #define ImageBufferDataAndroid_h +class SkCanvas; + namespace WebCore { class IntSize; +class ImageBuffer; + +SkCanvas* imageBufferCanvas(const ImageBuffer* buffer); class ImageBufferData { public: diff --git a/Source/WebCore/platform/graphics/android/PathAndroid.cpp b/Source/WebCore/platform/graphics/android/PathAndroid.cpp index 554e187..e70f983 100644 --- a/Source/WebCore/platform/graphics/android/PathAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/PathAndroid.cpp @@ -37,7 +37,6 @@ #include "SkRegion.h" #include "StrokeStyleApplier.h" #include "TransformationMatrix.h" -#include "android_graphics.h" namespace WebCore { diff --git a/Source/WebCore/platform/graphics/android/PatternAndroid.cpp b/Source/WebCore/platform/graphics/android/PatternAndroid.cpp index 568036c..ed3265b 100644 --- a/Source/WebCore/platform/graphics/android/PatternAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/PatternAndroid.cpp @@ -26,7 +26,6 @@ #include "config.h" #include "Pattern.h" -#include "android_graphics.h" #include "GraphicsContext.h" #include "SkBitmapRef.h" #include "SkCanvas.h" @@ -51,6 +50,8 @@ SkShader* Pattern::platformPattern(const AffineTransform&) if (m_pattern) return m_pattern; + if (!tileImage()) + return 0; SkBitmapRef* ref = tileImage()->nativeImageForCurrentFrame(); if (!ref) return 0; diff --git a/Source/WebCore/platform/graphics/android/context/GraphicsContextAndroid.cpp b/Source/WebCore/platform/graphics/android/context/GraphicsContextAndroid.cpp index 3b93d51..23b22e6 100644 --- a/Source/WebCore/platform/graphics/android/context/GraphicsContextAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/context/GraphicsContextAndroid.cpp @@ -46,7 +46,6 @@ #include "SkString.h" #include "SkiaUtils.h" #include "TransformationMatrix.h" -#include "android_graphics.h" using namespace std; @@ -110,7 +109,7 @@ GraphicsContext* GraphicsContext::createOffscreenContext(int width, int height) bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height); bitmap.allocPixels(); bitmap.eraseColor(0); - pgc->getCanvas()->setBitmapDevice(bitmap); + pgc->canvas()->setBitmapDevice(bitmap); GraphicsContext* ctx = new GraphicsContext(pgc); return ctx; @@ -511,6 +510,8 @@ void GraphicsContext::translate(float x, float y) { if (paintingDisabled()) return; + if (!x && !y) + return; platformContext()->translate(x, y); } @@ -660,10 +661,3 @@ void GraphicsContext::drawHighlightForText(const Font& font, const TextRun& run, } } // namespace WebCore - -/////////////////////////////////////////////////////////////////////////////// - -SkCanvas* android_gc2canvas(WebCore::GraphicsContext* gc) -{ - return gc->platformContext()->getCanvas(); -} diff --git a/Source/WebCore/platform/graphics/android/context/android_graphics.h b/Source/WebCore/platform/graphics/android/context/GraphicsOperation.cpp index 7faa781..ab6e676 100644 --- a/Source/WebCore/platform/graphics/android/context/android_graphics.h +++ b/Source/WebCore/platform/graphics/android/context/GraphicsOperation.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2007, The Android Open Source Project + * Copyright 2012, The Android Open Source Project * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -22,21 +22,34 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#define LOG_TAG "GraphicsOperation" -#ifndef android_graphics_DEFINED -#define android_graphics_DEFINED +#include "config.h" +#include "GraphicsOperation.h" + +#include "AndroidLog.h" +#include "LinearAllocator.h" namespace WebCore { - class GraphicsContext; -} -class SkCanvas; +namespace GraphicsOperation { -// TODO: Move this somewhere else. The implementation for this is actually in -// GraphicsContextAndroid.cpp, but this is used by a handful of other files -SkCanvas* android_gc2canvas(WebCore::GraphicsContext* gc); +void* Operation::operator new(size_t size, LinearAllocator* allocator) +{ + return allocator->alloc(size); +} -// used to inflate node cache entry -#define CURSOR_RING_HIT_TEST_RADIUS 5 +void* Operation::operator new(size_t size) +{ + ALOGE("Cannot allocate a new Operation directly!"); + CRASH(); + return (void*) 0xBADBEEF; +} +void Operation::operator delete(void*) +{ + ALOGE("Cannot call delete on an Operation!"); + CRASH(); +} -#endif +} // namespace GraphicsOperation +} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/context/GraphicsOperation.h b/Source/WebCore/platform/graphics/android/context/GraphicsOperation.h index 927ff0a..c9c382a 100644 --- a/Source/WebCore/platform/graphics/android/context/GraphicsOperation.h +++ b/Source/WebCore/platform/graphics/android/context/GraphicsOperation.h @@ -26,8 +26,6 @@ #ifndef GraphicsOperation_h #define GraphicsOperation_h -#if USE(ACCELERATED_COMPOSITING) - #include "Color.h" #include "FloatRect.h" #include "GlyphBuffer.h" @@ -44,37 +42,54 @@ #define TYPE_CASE(type) case type: return #type; +#define DEBUG_GRAPHICS_OPERATIONS false + +#if DEBUG_GRAPHICS_OPERATIONS +#define TYPE(x) virtual OperationType type() { return x; } +#else +#define TYPE(x) +#endif + namespace WebCore { +class CanvasState; +class LinearAllocator; + namespace GraphicsOperation { -class Operation : public SkRefCnt { +class Operation { public: + Operation() + : m_state(0) + , m_canvasState(0) + {} + + void* operator new(size_t size, LinearAllocator* allocator); + + // Purposely not implemented - use a LinearAllocator please + void* operator new(size_t size); + void operator delete(void* ptr); + + // This m_state is applied by ourselves + PlatformGraphicsContext::State* m_state; + // This is the canvas state that this operation needs + // Only used for drawing operations, state operations will be undefined + CanvasState* m_canvasState; + + bool apply(PlatformGraphicsContext* context) { + if (m_state) + context->setRawState(m_state); + return applyImpl(context); + } + virtual bool applyImpl(PlatformGraphicsContext* context) = 0; + virtual ~Operation() {} + + virtual const IntRect* opaqueRect() { return 0; } + virtual bool isOpaque() { return false; } + virtual void setOpaqueRect(const IntRect& bounds) {} + +#if DEBUG_GRAPHICS_OPERATIONS typedef enum { UndefinedOperation - // State management - , BeginTransparencyLayerOperation - , EndTransparencyLayerOperation - , SaveOperation - , RestoreOperation - // State setters - , SetAlphaOperation - , SetCompositeOpOperation - , SetFillColorOperation - , SetFillShaderOperation - , SetLineCapOperation - , SetLineDashOperation - , SetLineJoinOperation - , SetMiterLimitOperation - , SetShadowOperation - , SetShouldAntialiasOperation - , SetStrokeColorOperation - , SetStrokeShaderOperation - , SetStrokeStyleOperation - , SetStrokeThicknessOperation - // Paint setup - , SetupPaintFillOperation - , SetupPaintShadowOperation - , SetupPaintStrokeOperation // Matrix operations , ConcatCTMOperation , ScaleOperation @@ -89,7 +104,9 @@ public: // Drawing , DrawBitmapPatternOperation , DrawBitmapRectOperation + , DrawConvexPolygonQuadOperation , DrawEllipseOperation + , DrawFocusRingOperation , DrawLineOperation , DrawLineForTextOperation , DrawLineForTextCheckingOperation @@ -100,43 +117,15 @@ public: , StrokeArcOperation , StrokePathOperation , StrokeRectOperation + , DrawMediaButtonOperation // Text - , DrawComplexTextOperation - , DrawTextOperation + , DrawPosTextOperation } OperationType; - virtual void apply(PlatformGraphicsContext* context) = 0; - virtual ~Operation() {} - virtual OperationType type() { return UndefinedOperation; } - virtual String parameters() { return ""; } - String name() + const char* name() { switch (type()) { TYPE_CASE(UndefinedOperation) - // State management - TYPE_CASE(BeginTransparencyLayerOperation) - TYPE_CASE(EndTransparencyLayerOperation) - TYPE_CASE(SaveOperation) - TYPE_CASE(RestoreOperation) - // State setters - TYPE_CASE(SetAlphaOperation) - TYPE_CASE(SetCompositeOpOperation) - TYPE_CASE(SetFillColorOperation) - TYPE_CASE(SetFillShaderOperation) - TYPE_CASE(SetLineCapOperation) - TYPE_CASE(SetLineDashOperation) - TYPE_CASE(SetLineJoinOperation) - TYPE_CASE(SetMiterLimitOperation) - TYPE_CASE(SetShadowOperation) - TYPE_CASE(SetShouldAntialiasOperation) - TYPE_CASE(SetStrokeColorOperation) - TYPE_CASE(SetStrokeShaderOperation) - TYPE_CASE(SetStrokeStyleOperation) - TYPE_CASE(SetStrokeThicknessOperation) - // Paint setup - TYPE_CASE(SetupPaintFillOperation) - TYPE_CASE(SetupPaintShadowOperation) - TYPE_CASE(SetupPaintStrokeOperation) // Matrix operations TYPE_CASE(ConcatCTMOperation) TYPE_CASE(ScaleOperation) @@ -151,7 +140,9 @@ public: // Drawing TYPE_CASE(DrawBitmapPatternOperation) TYPE_CASE(DrawBitmapRectOperation) + TYPE_CASE(DrawConvexPolygonQuadOperation) TYPE_CASE(DrawEllipseOperation) + TYPE_CASE(DrawFocusRingOperation) TYPE_CASE(DrawLineOperation) TYPE_CASE(DrawLineForTextOperation) TYPE_CASE(DrawLineForTextCheckingOperation) @@ -162,258 +153,23 @@ public: TYPE_CASE(StrokeArcOperation) TYPE_CASE(StrokePathOperation) TYPE_CASE(StrokeRectOperation) + TYPE_CASE(DrawMediaButtonOperation) // Text - TYPE_CASE(DrawComplexTextOperation) - TYPE_CASE(DrawTextOperation) + TYPE_CASE(DrawPosTextOperation) } return "Undefined"; } +#endif + TYPE(UndefinedOperation) }; -//************************************** -// State management -//************************************** - -class BeginTransparencyLayer : public Operation { -public: - BeginTransparencyLayer(const float opacity) : m_opacity(opacity) {} - virtual void apply(PlatformGraphicsContext* context) { context->beginTransparencyLayer(m_opacity); } - virtual OperationType type() { return BeginTransparencyLayerOperation; } -private: - float m_opacity; -}; -class EndTransparencyLayer : public Operation { -public: - EndTransparencyLayer() {} - virtual void apply(PlatformGraphicsContext* context) { context->endTransparencyLayer(); } - virtual OperationType type() { return EndTransparencyLayerOperation; } -}; -class Save : public Operation { -public: - virtual void apply(PlatformGraphicsContext* context) { context->save(); } - virtual OperationType type() { return SaveOperation; } -}; -class Restore : public Operation { -public: - virtual void apply(PlatformGraphicsContext* context) { context->restore(); } - virtual OperationType type() { return RestoreOperation; } -}; - -//************************************** -// State setters -//************************************** - -class SetAlpha : public Operation { -public: - SetAlpha(const float alpha) : m_alpha(alpha) {} - virtual void apply(PlatformGraphicsContext* context) { context->setAlpha(m_alpha); } - virtual OperationType type() { return SetAlphaOperation; } -private: - float m_alpha; -}; - -class SetCompositeOperation : public Operation { -public: - SetCompositeOperation(CompositeOperator op) : m_operator(op) {} - virtual void apply(PlatformGraphicsContext* context) { - context->setCompositeOperation(m_operator); - } - virtual OperationType type() { return SetCompositeOpOperation; } -private: - CompositeOperator m_operator; -}; - -class SetFillColor : public Operation { -public: - SetFillColor(Color color) : m_color(color) {} - virtual void apply(PlatformGraphicsContext* context) { - context->setFillColor(m_color); - } - virtual OperationType type() { return SetFillColorOperation; } - virtual String parameters() { - return String::format("r: %d g: %d b: %d a: %d", - m_color.red(), - m_color.green(), - m_color.blue(), - m_color.alpha()); - } -private: - Color m_color; -}; - -class SetFillShader : public Operation { -public: - SetFillShader(SkShader* shader) : m_shader(shader) { - SkSafeRef(m_shader); - } - ~SetFillShader() { SkSafeUnref(m_shader); } - virtual void apply(PlatformGraphicsContext* context) { - context->setFillShader(m_shader); - } - virtual OperationType type() { return SetFillShaderOperation; } -private: - SkShader* m_shader; -}; - -class SetLineCap : public Operation { -public: - SetLineCap(LineCap cap) : m_cap(cap) {} - virtual void apply(PlatformGraphicsContext* context) { - context->setLineCap(m_cap); - } - virtual OperationType type() { return SetLineCapOperation; } -private: - LineCap m_cap; -}; - -class SetLineDash : public Operation { -public: - SetLineDash(const DashArray& dashes, float dashOffset) - : m_dashes(dashes), m_dashOffset(dashOffset) {} - virtual void apply(PlatformGraphicsContext* context) { - context->setLineDash(m_dashes, m_dashOffset); - } - virtual OperationType type() { return SetLineDashOperation; } -private: - DashArray m_dashes; - float m_dashOffset; -}; - -class SetLineJoin : public Operation { -public: - SetLineJoin(LineJoin join) : m_join(join) {} - virtual void apply(PlatformGraphicsContext* context) { - context->setLineJoin(m_join); - } - virtual OperationType type() { return SetLineJoinOperation; } -private: - LineJoin m_join; -}; - -class SetMiterLimit : public Operation { -public: - SetMiterLimit(float limit) : m_limit(limit) {} - virtual void apply(PlatformGraphicsContext* context) { - context->setMiterLimit(m_limit); - } - virtual OperationType type() { return SetMiterLimitOperation; } -private: - float m_limit; -}; - -class SetShadow : public Operation { -public: - SetShadow(int radius, int dx, int dy, SkColor c) - : m_radius(radius), m_dx(dx), m_dy(dy), m_color(c) {} - virtual void apply(PlatformGraphicsContext* context) { - context->setShadow(m_radius, m_dx, m_dy, m_color); - } - virtual OperationType type() { return SetShadowOperation; } -private: - int m_radius; - int m_dx; - int m_dy; - SkColor m_color; -}; - -class SetShouldAntialias : public Operation { -public: - SetShouldAntialias(bool useAA) : m_useAA(useAA) {} - virtual void apply(PlatformGraphicsContext* context) { - context->setShouldAntialias(m_useAA); - } - virtual OperationType type() { return SetShouldAntialiasOperation; } -private: - bool m_useAA; -}; - -class SetStrokeColor : public Operation { -public: - SetStrokeColor(const Color& c) : m_color(c) {} - virtual void apply(PlatformGraphicsContext* context) { - context->setStrokeColor(m_color); - } - virtual OperationType type() { return SetStrokeColorOperation; } -private: - Color m_color; -}; - -class SetStrokeShader : public Operation { -public: - SetStrokeShader(SkShader* strokeShader) : m_shader(strokeShader) { - SkSafeRef(m_shader); - } - ~SetStrokeShader() { SkSafeUnref(m_shader); } - virtual void apply(PlatformGraphicsContext* context) { - context->setStrokeShader(m_shader); - } - virtual OperationType type() { return SetStrokeShaderOperation; } -private: - SkShader* m_shader; -}; - -class SetStrokeStyle : public Operation { +class PossiblyOpaqueOperation : public Operation { public: - SetStrokeStyle(StrokeStyle style) : m_style(style) {} - virtual void apply(PlatformGraphicsContext* context) { - context->setStrokeStyle(m_style); - } - virtual OperationType type() { return SetStrokeStyleOperation; } -private: - StrokeStyle m_style; -}; - -class SetStrokeThickness : public Operation { -public: - SetStrokeThickness(float thickness) : m_thickness(thickness) {} - virtual void apply(PlatformGraphicsContext* context) { - context->setStrokeThickness(m_thickness); - } - virtual OperationType type() { return SetStrokeThicknessOperation; } -private: - float m_thickness; -}; - -//************************************** -// Paint setup -//************************************** - -class SetupPaintFill : public Operation { -public: - SetupPaintFill(SkPaint* paint) : m_paint(*paint) {} - virtual void apply(PlatformGraphicsContext* context) { - context->setupPaintFill(&m_paint); - } - virtual OperationType type() { return SetupPaintFillOperation; } -private: - SkPaint m_paint; -}; - -class SetupPaintShadow : public Operation { -public: - SetupPaintShadow(SkPaint* paint, SkPoint* offset) - : m_paint(*paint), m_offset(*offset) {} - virtual void apply(PlatformGraphicsContext* context) { - context->setupPaintShadow(&m_paint, &m_offset); - } - virtual OperationType type() { return SetupPaintShadowOperation; } -private: - SkPaint m_paint; - SkPoint m_offset; -}; + virtual const IntRect* opaqueRect() { return &m_absoluteOpaqueRect; } + virtual void setOpaqueRect(const IntRect& bounds) { m_absoluteOpaqueRect = bounds; } -class SetupPaintStroke : public Operation { -public: - SetupPaintStroke(SkPaint* paint, SkRect* rect, bool isHLine) - : m_paint(*paint), m_rect(*rect), m_isHLine(isHLine) {} - virtual void apply(PlatformGraphicsContext* context) { - context->setupPaintStroke(&m_paint, &m_rect, m_isHLine); - } - virtual OperationType type() { return SetupPaintStrokeOperation; } private: - SkPaint m_paint; - SkRect m_rect; - bool m_isHLine; + IntRect m_absoluteOpaqueRect; }; //************************************** @@ -423,10 +179,11 @@ private: class ConcatCTM : public Operation { public: ConcatCTM(const AffineTransform& affine) : m_matrix(affine) {} - virtual void apply(PlatformGraphicsContext* context) { + virtual bool applyImpl(PlatformGraphicsContext* context) { context->concatCTM(m_matrix); + return true; } - virtual OperationType type() { return ConcatCTMOperation; } + TYPE(ConcatCTMOperation) private: AffineTransform m_matrix; }; @@ -434,10 +191,11 @@ private: class Rotate : public Operation { public: Rotate(float angleInRadians) : m_angle(angleInRadians) {} - virtual void apply(PlatformGraphicsContext* context) { + virtual bool applyImpl(PlatformGraphicsContext* context) { context->rotate(m_angle); + return true; } - virtual OperationType type() { return RotateOperation; } + TYPE(RotateOperation) private: float m_angle; }; @@ -445,10 +203,11 @@ private: class Scale : public Operation { public: Scale(const FloatSize& size) : m_scale(size) {} - virtual void apply(PlatformGraphicsContext* context) { + virtual bool applyImpl(PlatformGraphicsContext* context) { context->scale(m_scale); + return true; } - virtual OperationType type() { return ScaleOperation; } + TYPE(ScaleOperation) private: FloatSize m_scale; }; @@ -456,10 +215,11 @@ private: class Translate : public Operation { public: Translate(float x, float y) : m_x(x), m_y(y) {} - virtual void apply(PlatformGraphicsContext* context) { + virtual bool applyImpl(PlatformGraphicsContext* context) { context->translate(m_x, m_y); + return true; } - virtual OperationType type() { return TranslateOperation; } + TYPE(TranslateOperation) private: float m_x; float m_y; @@ -473,10 +233,11 @@ class InnerRoundedRectClip : public Operation { public: InnerRoundedRectClip(const IntRect& rect, int thickness) : m_rect(rect), m_thickness(thickness) {} - virtual void apply(PlatformGraphicsContext* context) { + virtual bool applyImpl(PlatformGraphicsContext* context) { context->addInnerRoundedRectClip(m_rect, m_thickness); + return true; } - virtual OperationType type() { return InnerRoundedRectClipOperation; } + TYPE(InnerRoundedRectClipOperation) private: IntRect m_rect; int m_thickness; @@ -485,10 +246,10 @@ private: class Clip : public Operation { public: Clip(const FloatRect& rect) : m_rect(rect) {} - virtual void apply(PlatformGraphicsContext* context) { - context->clip(m_rect); + virtual bool applyImpl(PlatformGraphicsContext* context) { + return context->clip(m_rect); } - virtual OperationType type() { return ClipOperation; } + TYPE(ClipOperation) private: const FloatRect m_rect; }; @@ -498,17 +259,16 @@ public: ClipPath(const Path& path, bool clipout = false) : m_path(path), m_clipOut(clipout), m_hasWindRule(false) {} void setWindRule(WindRule rule) { m_windRule = rule; m_hasWindRule = true; } - virtual void apply(PlatformGraphicsContext* context) { + virtual bool applyImpl(PlatformGraphicsContext* context) { if (m_hasWindRule) { - context->clipPath(m_path, m_windRule); - return; + return context->clipPath(m_path, m_windRule); } if (m_clipOut) - context->clipOut(m_path); + return context->clipOut(m_path); else - context->clip(m_path); + return context->clip(m_path); } - virtual OperationType type() { return ClipPathOperation; } + TYPE(ClipPathOperation) private: const Path m_path; bool m_clipOut; @@ -519,10 +279,10 @@ private: class ClipOut : public Operation { public: ClipOut(const IntRect& rect) : m_rect(rect) {} - virtual void apply(PlatformGraphicsContext* context) { - context->clipOut(m_rect); + virtual bool applyImpl(PlatformGraphicsContext* context) { + return context->clipOut(m_rect); } - virtual OperationType type() { return ClipOutOperation; } + TYPE(ClipOutOperation) private: const IntRect m_rect; }; @@ -530,10 +290,11 @@ private: class ClearRect : public Operation { public: ClearRect(const FloatRect& rect) : m_rect(rect) {} - virtual void apply(PlatformGraphicsContext* context) { + virtual bool applyImpl(PlatformGraphicsContext* context) { context->clearRect(m_rect); + return true; } - virtual OperationType type() { return ClearRectOperation; } + TYPE(ClearRectOperation) private: FloatRect m_rect; }; @@ -542,63 +303,101 @@ private: // Drawing //************************************** -class DrawBitmapPattern : public Operation { +class DrawBitmapPattern : public PossiblyOpaqueOperation { public: DrawBitmapPattern(const SkBitmap& bitmap, const SkMatrix& matrix, CompositeOperator op, const FloatRect& destRect) : m_bitmap(bitmap), m_matrix(matrix), m_operator(op), m_destRect(destRect) {} - virtual void apply(PlatformGraphicsContext* context) { + virtual bool applyImpl(PlatformGraphicsContext* context) { context->drawBitmapPattern(m_bitmap, m_matrix, m_operator, m_destRect); + return true; } - virtual OperationType type() { return DrawBitmapPatternOperation; } + virtual bool isOpaque() { return m_bitmap.isOpaque(); } + TYPE(DrawBitmapPatternOperation) + private: - // TODO: use refcounted bitmap - const SkBitmap m_bitmap; + SkBitmap m_bitmap; SkMatrix m_matrix; CompositeOperator m_operator; FloatRect m_destRect; }; -class DrawBitmapRect : public Operation { +class DrawBitmapRect : public PossiblyOpaqueOperation { public: DrawBitmapRect(const SkBitmap& bitmap, const SkIRect& srcR, const SkRect& dstR, CompositeOperator op) : m_bitmap(bitmap), m_srcR(srcR), m_dstR(dstR), m_operator(op) {} - virtual void apply(PlatformGraphicsContext* context) { + virtual bool applyImpl(PlatformGraphicsContext* context) { context->drawBitmapRect(m_bitmap, &m_srcR, m_dstR, m_operator); + return true; } - virtual OperationType type() { return DrawBitmapRectOperation; } - virtual String parameters() { - return String::format("%.2f, %.2f - %.2f x %.2f", - m_dstR.fLeft, m_dstR.fTop, - m_dstR.width(), m_dstR.height()); - } + virtual bool isOpaque() { return m_bitmap.isOpaque(); } + TYPE(DrawBitmapRectOperation) private: - const SkBitmap& m_bitmap; + SkBitmap m_bitmap; SkIRect m_srcR; SkRect m_dstR; CompositeOperator m_operator; }; +class DrawConvexPolygonQuad : public Operation { +public: + DrawConvexPolygonQuad(const FloatPoint* points, bool shouldAntiAlias) + : m_shouldAntiAlias(shouldAntiAlias) + { + memcpy(m_points, points, 4 * sizeof(FloatPoint)); + } + virtual bool applyImpl(PlatformGraphicsContext* context) { + context->drawConvexPolygon(4, m_points, m_shouldAntiAlias); + return true; + } + TYPE(DrawConvexPolygonQuadOperation) +private: + bool m_shouldAntiAlias; + FloatPoint m_points[4]; +}; + class DrawEllipse : public Operation { public: DrawEllipse(const IntRect& rect) : m_rect(rect) {} - virtual void apply(PlatformGraphicsContext* context) { + virtual bool applyImpl(PlatformGraphicsContext* context) { context->drawEllipse(m_rect); + return true; } - virtual OperationType type() { return DrawEllipseOperation; } + TYPE(DrawEllipseOperation) private: IntRect m_rect; }; +class DrawFocusRing : public Operation { +public: + DrawFocusRing(const Vector<IntRect>& rects, int width, int offset, const Color& color) + : m_rects(rects) + , m_width(width) + , m_offset(offset) + , m_color(color) + {} + virtual bool applyImpl(PlatformGraphicsContext* context) { + context->drawFocusRing(m_rects, m_width, m_offset, m_color); + return true; + } + TYPE(DrawFocusRingOperation) +private: + Vector<IntRect> m_rects; + int m_width; + int m_offset; + Color m_color; +}; + class DrawLine : public Operation { public: DrawLine(const IntPoint& point1, const IntPoint& point2) : m_point1(point1), m_point2(point2) {} - virtual void apply(PlatformGraphicsContext* context) { + virtual bool applyImpl(PlatformGraphicsContext* context) { context->drawLine(m_point1, m_point2); + return true; } - virtual OperationType type() { return DrawLineOperation; } + TYPE(DrawLineOperation) private: IntPoint m_point1; IntPoint m_point2; @@ -608,10 +407,11 @@ class DrawLineForText : public Operation { public: DrawLineForText(const FloatPoint& pt, float width) : m_point(pt), m_width(width) {} - virtual void apply(PlatformGraphicsContext* context) { + virtual bool applyImpl(PlatformGraphicsContext* context) { context->drawLineForText(m_point, m_width); + return true; } - virtual OperationType type() { return DrawLineForTextOperation; } + TYPE(DrawLineForTextOperation) private: FloatPoint m_point; float m_width; @@ -622,10 +422,11 @@ public: DrawLineForTextChecking(const FloatPoint& pt, float width, GraphicsContext::TextCheckingLineStyle lineStyle) : m_point(pt), m_width(width), m_lineStyle(lineStyle) {} - virtual void apply(PlatformGraphicsContext* context) { + virtual bool applyImpl(PlatformGraphicsContext* context) { context->drawLineForTextChecking(m_point, m_width, m_lineStyle); + return true; } - virtual OperationType type() { return DrawLineForTextCheckingOperation; } + TYPE(DrawLineForTextCheckingOperation) private: FloatPoint m_point; float m_width; @@ -635,10 +436,11 @@ private: class DrawRect : public Operation { public: DrawRect(const IntRect& rect) : m_rect(rect) {} - virtual void apply(PlatformGraphicsContext* context) { + virtual bool applyImpl(PlatformGraphicsContext* context) { context->drawRect(m_rect); + return true; } - virtual OperationType type() { return DrawRectOperation; } + TYPE(DrawRectOperation) private: IntRect m_rect; }; @@ -647,26 +449,30 @@ class FillPath : public Operation { public: FillPath(const Path& pathToFill, WindRule fillRule) : m_path(pathToFill), m_fillRule(fillRule) {} - virtual void apply(PlatformGraphicsContext* context) { + virtual bool applyImpl(PlatformGraphicsContext* context) { context->fillPath(m_path, m_fillRule); + return true; } - virtual OperationType type() { return FillPathOperation; } + TYPE(FillPathOperation) private: Path m_path; WindRule m_fillRule; }; -class FillRect : public Operation { +class FillRect : public PossiblyOpaqueOperation { public: FillRect(const FloatRect& rect) : m_rect(rect), m_hasColor(false) {} void setColor(Color c) { m_color = c; m_hasColor = true; } - virtual void apply(PlatformGraphicsContext* context) { + virtual bool applyImpl(PlatformGraphicsContext* context) { if (m_hasColor) context->fillRect(m_rect, m_color); else context->fillRect(m_rect); + return true; } - virtual OperationType type() { return FillRectOperation; } + virtual bool isOpaque() { return (m_hasColor && !m_color.hasAlpha()) + || (!m_hasColor && SkColorGetA(m_state->fillColor) == 0xFF); } + TYPE(FillRectOperation) private: FloatRect m_rect; Color m_color; @@ -688,12 +494,13 @@ public: , m_bottomRight(bottomRight) , m_color(color) {} - virtual void apply(PlatformGraphicsContext* context) { + virtual bool applyImpl(PlatformGraphicsContext* context) { context->fillRoundedRect(m_rect, m_topLeft, m_topRight, m_bottomLeft, m_bottomRight, m_color); + return true; } - virtual OperationType type() { return FillRoundedRectOperation; } + TYPE(FillRoundedRectOperation) private: IntRect m_rect; IntSize m_topLeft; @@ -710,10 +517,11 @@ public: , m_startAngle(startAngle) , m_angleSpan(angleSpan) {} - virtual void apply(PlatformGraphicsContext* context) { + virtual bool applyImpl(PlatformGraphicsContext* context) { context->strokeArc(m_rect, m_startAngle, m_angleSpan); + return true; } - virtual OperationType type() { return StrokeArcOperation; } + TYPE(StrokeArcOperation) private: IntRect m_rect; int m_startAngle; @@ -723,10 +531,11 @@ private: class StrokePath : public Operation { public: StrokePath(const Path& path) : m_path(path) {} - virtual void apply(PlatformGraphicsContext* context) { + virtual bool applyImpl(PlatformGraphicsContext* context) { context->strokePath(m_path); + return true; } - virtual OperationType type() { return StrokePathOperation; } + TYPE(StrokePathOperation) private: Path m_path; }; @@ -736,74 +545,72 @@ class StrokeRect : public Operation { public: StrokeRect(const FloatRect& rect, float lineWidth) : m_rect(rect), m_lineWidth(lineWidth) {} - virtual void apply(PlatformGraphicsContext* context) { + virtual bool applyImpl(PlatformGraphicsContext* context) { context->strokeRect(m_rect, m_lineWidth); + return true; } - virtual OperationType type() { return StrokeRectOperation; } + TYPE(StrokeRectOperation) private: FloatRect m_rect; float m_lineWidth; }; -//************************************** -// Text -//************************************** - -class DrawComplexText : public Operation { +class DrawMediaButton : public Operation { public: - DrawComplexText(SkPicture* picture) : m_picture(picture) { - SkSafeRef(m_picture); - } - ~DrawComplexText() { SkSafeUnref(m_picture); } - virtual void apply(PlatformGraphicsContext* context) { - if (!context->getCanvas()) - return; - context->getCanvas()->drawPicture(*m_picture); + DrawMediaButton(const IntRect& rect, RenderSkinMediaButton::MediaButton buttonType, + bool translucent, bool drawBackground, + const IntRect& thumb) + : m_rect(rect) + , m_thumb(thumb) + , m_buttonType(buttonType) + , m_translucent(translucent) + , m_drawBackground(drawBackground) + {} + virtual bool applyImpl(PlatformGraphicsContext* context) { + context->drawMediaButton(m_rect, m_buttonType, m_translucent, m_drawBackground, m_thumb); + return true; } - virtual OperationType type() { return DrawComplexTextOperation; } + TYPE(DrawMediaButtonOperation) private: - SkPicture* m_picture; + IntRect m_rect; + IntRect m_thumb; + RenderSkinMediaButton::MediaButton m_buttonType; + bool m_translucent : 1; + bool m_drawBackground : 1; }; -class DrawText : public Operation { +//************************************** +// Text +//************************************** + +class DrawPosText : public Operation { public: - DrawText(const Font* font, const SimpleFontData* simpleFont, - const GlyphBuffer& glyphBuffer, - int from, int numGlyphs, const FloatPoint& point) - : m_font(font), m_simpleFont(simpleFont) - , m_glyphBuffer(glyphBuffer), m_from(from) - , m_numGlyphs(numGlyphs), m_point(point) { - - SkPicture* picture = new SkPicture(); - SkCanvas* canvas = picture->beginRecording(0, 0, 0); - PlatformGraphicsContextSkia platformContext(canvas); - GraphicsContext graphicsContext(&platformContext); - m_font->drawGlyphs(&graphicsContext, m_simpleFont, - m_glyphBuffer, m_from, m_numGlyphs, m_point); - picture->endRecording(); - m_picture = picture; - } - ~DrawText() { SkSafeUnref(m_picture); } - virtual void apply(PlatformGraphicsContext* context) { - if (!context->getCanvas()) - return; - context->getCanvas()->drawPicture(*m_picture); - } - virtual OperationType type() { return DrawTextOperation; } -private: - SkPicture* m_picture; - const Font* m_font; - const SimpleFontData* m_simpleFont; - const GlyphBuffer m_glyphBuffer; - int m_from; - int m_numGlyphs; - const FloatPoint m_point; + DrawPosText(const void* text, size_t byteLength, + const SkPoint pos[], const SkPaint& paint) + : m_byteLength(byteLength) + , m_paint(paint) + { + size_t points = paint.countText(text, byteLength); + m_pos = new SkPoint[points]; + memcpy(m_pos, pos, sizeof(SkPoint) * points); + m_text = malloc(byteLength); + memcpy(m_text, text, byteLength); + } + ~DrawPosText() { delete m_pos; free(m_text); } + virtual bool applyImpl(PlatformGraphicsContext* context) { + context->drawPosText(m_text, m_byteLength, m_pos, m_paint); + return true; + } + TYPE(DrawPosTextOperation) +private: + void* m_text; + size_t m_byteLength; + SkPoint* m_pos; + SkPaint m_paint; }; } } -#endif // USE(ACCELERATED_COMPOSITING) - #endif // GraphicsOperation_h diff --git a/Source/WebCore/platform/graphics/android/context/GraphicsOperationCollection.cpp b/Source/WebCore/platform/graphics/android/context/GraphicsOperationCollection.cpp deleted file mode 100644 index 9e6208d..0000000 --- a/Source/WebCore/platform/graphics/android/context/GraphicsOperationCollection.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#define LOG_TAG "GraphicsOperationCollection" -#define LOG_NDEBUG 1 - -#include "config.h" -#include "GraphicsOperationCollection.h" - -#include "AndroidLog.h" -#include "GraphicsContext.h" -#include "PlatformGraphicsContext.h" -#include "PlatformGraphicsContextRecording.h" - -#if USE(ACCELERATED_COMPOSITING) - -namespace WebCore { - -GraphicsOperationCollection::GraphicsOperationCollection(const IntRect& drawArea) - : m_drawArea(drawArea) -{ -} - -GraphicsOperationCollection::~GraphicsOperationCollection() -{ - for (unsigned int i = 0; i < m_operations.size(); i++) - SkSafeUnref(m_operations[i]); -} - -void GraphicsOperationCollection::apply(PlatformGraphicsContext* context) -{ - ALOGD("\nApply GraphicsOperationCollection %x, %d operations", this, m_operations.size()); - for (unsigned int i = 0; i < m_operations.size(); i++) { - ALOGD("[%d] (%x) %s %s", i, this, m_operations[i]->name().ascii().data(), - m_operations[i]->parameters().ascii().data()); - m_operations[i]->apply(context); - } -} - -void GraphicsOperationCollection::append(GraphicsOperation::Operation* operation) -{ - m_operations.append(operation); -} - -bool GraphicsOperationCollection::isEmpty() -{ - return !m_operations.size(); -} - -AutoGraphicsOperationCollection::AutoGraphicsOperationCollection(const IntRect& area) -{ - m_graphicsOperationCollection = new GraphicsOperationCollection(area); - m_platformGraphicsContext = new PlatformGraphicsContextRecording(m_graphicsOperationCollection); - m_graphicsContext = new GraphicsContext(m_platformGraphicsContext); -} - -AutoGraphicsOperationCollection::~AutoGraphicsOperationCollection() -{ - SkSafeUnref(m_graphicsOperationCollection); - delete m_graphicsContext; - delete m_platformGraphicsContext; -} - -} // namespace WebCore - -#endif // USE(ACCELERATED_COMPOSITING) diff --git a/Source/WebCore/platform/graphics/android/context/PlatformGraphicsContext.cpp b/Source/WebCore/platform/graphics/android/context/PlatformGraphicsContext.cpp index ce9ce5a..367abda 100644 --- a/Source/WebCore/platform/graphics/android/context/PlatformGraphicsContext.cpp +++ b/Source/WebCore/platform/graphics/android/context/PlatformGraphicsContext.cpp @@ -82,6 +82,8 @@ static bool setBitmapDash(SkPaint* paint, int width) { s->setLocalMatrix(matrix); paint->setShader(s)->unref(); + paint->setFilterBitmap(true); + paint->setAntiAlias(true); return true; } @@ -159,7 +161,7 @@ bool PlatformGraphicsContext::State::setupShadowPaint(SkPaint* paint, SkPoint* o // HTMLCanvasElement have shadows ignore transforms set. This // allows us to distinguish between CSS and Canvas shadows which // have different rendering specifications. - uint32_t flags = SkBlurMaskFilter::kHighQuality_BlurFlag; + uint32_t flags = SkBlurMaskFilter::kNone_BlurFlag; if (shadowsIgnoreTransforms) { offset->fY = -offset->fY; flags |= SkBlurMaskFilter::kIgnoreTransform_BlurFlag; @@ -167,7 +169,7 @@ bool PlatformGraphicsContext::State::setupShadowPaint(SkPaint* paint, SkPoint* o if (shadow.blur > 0) { paint->setMaskFilter(SkBlurMaskFilter::Create(shadow.blur, - SkBlurMaskFilter::kNormal_BlurStyle))->unref(); + SkBlurMaskFilter::kNormal_BlurStyle, flags))->unref(); } return SkColorGetA(shadow.color) && (shadow.blur || shadow.dx || shadow.dy); } @@ -244,22 +246,31 @@ void PlatformGraphicsContext::setCompositeOperation(CompositeOperator op) m_state->mode = WebCoreCompositeToSkiaComposite(op); } -void PlatformGraphicsContext::setFillColor(const Color& c) +bool PlatformGraphicsContext::setFillColor(const Color& c) { - m_state->fillColor = c.rgb(); - setFillShader(0); + bool dirty = false; + if (m_state->fillColor != c.rgb()) { + m_state->fillColor = c.rgb(); + dirty = true; + } + return setFillShader(0) || dirty; } -void PlatformGraphicsContext::setFillShader(SkShader* fillShader) +bool PlatformGraphicsContext::setFillShader(SkShader* fillShader) { - if (fillShader) + bool dirty = false; + if (fillShader && m_state->fillColor != Color::black) { m_state->fillColor = Color::black; + dirty = true; + } if (fillShader != m_state->fillShader) { SkSafeUnref(m_state->fillShader); m_state->fillShader = fillShader; SkSafeRef(m_state->fillShader); + dirty = true; } + return dirty; } void PlatformGraphicsContext::setLineCap(LineCap cap) @@ -331,22 +342,31 @@ void PlatformGraphicsContext::setShouldAntialias(bool useAA) m_state->useAA = useAA; } -void PlatformGraphicsContext::setStrokeColor(const Color& c) +bool PlatformGraphicsContext::setStrokeColor(const Color& c) { - m_state->strokeColor = c.rgb(); - setStrokeShader(0); + bool dirty = false; + if (m_state->strokeColor != c.rgb()) { + m_state->strokeColor = c.rgb(); + dirty = true; + } + return setStrokeShader(0) || dirty; } -void PlatformGraphicsContext::setStrokeShader(SkShader* strokeShader) +bool PlatformGraphicsContext::setStrokeShader(SkShader* strokeShader) { - if (strokeShader) + bool dirty = false; + if (strokeShader && m_state->strokeColor != Color::black) { m_state->strokeColor = Color::black; + dirty = true; + } if (strokeShader != m_state->strokeShader) { SkSafeUnref(m_state->strokeShader); m_state->strokeShader = strokeShader; SkSafeRef(m_state->strokeShader); + dirty = true; } + return dirty; } void PlatformGraphicsContext::setStrokeStyle(StrokeStyle style) @@ -375,7 +395,7 @@ void PlatformGraphicsContext::setupPaintCommon(SkPaint* paint) const // allows us to distinguish between CSS and Canvas shadows which // have different rendering specifications. SkScalar dy = m_state->shadow.dy; - uint32_t flags = SkBlurDrawLooper::kHighQuality_BlurFlag; + uint32_t flags = SkBlurDrawLooper::kNone_BlurFlag; if (shadowsIgnoreTransforms()) { dy = -dy; flags |= SkBlurDrawLooper::kIgnoreTransform_BlurFlag; diff --git a/Source/WebCore/platform/graphics/android/context/PlatformGraphicsContext.h b/Source/WebCore/platform/graphics/android/context/PlatformGraphicsContext.h index 1916014..56aceff 100644 --- a/Source/WebCore/platform/graphics/android/context/PlatformGraphicsContext.h +++ b/Source/WebCore/platform/graphics/android/context/PlatformGraphicsContext.h @@ -29,6 +29,7 @@ #include "IntRect.h" #include "GraphicsContext.h" #include "RenderSkinAndroid.h" +#include "RenderSkinMediaButton.h" #include "SkCanvas.h" #include "SkPicture.h" #include "SkTDArray.h" @@ -40,10 +41,11 @@ namespace WebCore { class PlatformGraphicsContext { public: + class State; + PlatformGraphicsContext(); virtual ~PlatformGraphicsContext(); virtual bool isPaintingDisabled() = 0; - virtual SkCanvas* getCanvas() = 0; void setGraphicsContext(GraphicsContext* gc) { m_gc = gc; } virtual bool deleteUs() const { return false; } @@ -61,16 +63,16 @@ public: virtual void setAlpha(float alpha); int getNormalizedAlpha() const; virtual void setCompositeOperation(CompositeOperator op); - virtual void setFillColor(const Color& c); - virtual void setFillShader(SkShader* fillShader); + virtual bool setFillColor(const Color& c); + virtual bool setFillShader(SkShader* fillShader); virtual void setLineCap(LineCap cap); virtual void setLineDash(const DashArray& dashes, float dashOffset); virtual void setLineJoin(LineJoin join); virtual void setMiterLimit(float limit); virtual void setShadow(int radius, int dx, int dy, SkColor c); virtual void setShouldAntialias(bool useAA); - virtual void setStrokeColor(const Color& c); - virtual void setStrokeShader(SkShader* strokeShader); + virtual bool setStrokeColor(const Color& c); + virtual bool setStrokeShader(SkShader* strokeShader); virtual void setStrokeStyle(StrokeStyle style); virtual void setStrokeThickness(float f); @@ -92,19 +94,20 @@ public: // Clipping virtual void addInnerRoundedRectClip(const IntRect& rect, int thickness) = 0; virtual void canvasClip(const Path& path) = 0; - virtual void clip(const FloatRect& rect) = 0; - virtual void clip(const Path& path) = 0; - virtual void clipConvexPolygon(size_t numPoints, const FloatPoint*, bool antialias) = 0; - virtual void clipOut(const IntRect& r) = 0; - virtual void clipOut(const Path& p) = 0; - virtual void clipPath(const Path& pathToClip, WindRule clipRule) = 0; + virtual bool clip(const FloatRect& rect) = 0; + virtual bool clip(const Path& path) = 0; + virtual bool clipConvexPolygon(size_t numPoints, const FloatPoint*, bool antialias) = 0; + virtual bool clipOut(const IntRect& r) = 0; + virtual bool clipOut(const Path& p) = 0; + virtual bool clipPath(const Path& pathToClip, WindRule clipRule) = 0; + virtual SkIRect getTotalClipBounds() = 0; // Drawing virtual void clearRect(const FloatRect& rect) = 0; virtual void drawBitmapPattern(const SkBitmap& bitmap, const SkMatrix& matrix, CompositeOperator compositeOp, const FloatRect& destRect) = 0; virtual void drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src, - const SkRect& dst, CompositeOperator op) = 0; + const SkRect& dst, CompositeOperator op = CompositeSourceOver) = 0; virtual void drawConvexPolygon(size_t numPoints, const FloatPoint* points, bool shouldAntialias) = 0; virtual void drawEllipse(const IntRect& rect) = 0; @@ -117,7 +120,7 @@ public: virtual void drawLine(const IntPoint& point1, const IntPoint& point2) = 0; virtual void drawLineForText(const FloatPoint& pt, float width) = 0; virtual void drawLineForTextChecking(const FloatPoint& pt, float width, - GraphicsContext::TextCheckingLineStyle) = 0; + GraphicsContext::TextCheckingLineStyle) = 0; virtual void drawRect(const IntRect& rect) = 0; virtual void fillPath(const Path& pathToFill, WindRule fillRule) = 0; virtual void fillRect(const FloatRect& rect) = 0; @@ -138,10 +141,15 @@ public: virtual void strokePath(const Path& pathToStroke) = 0; virtual void strokeRect(const FloatRect& rect, float lineWidth) = 0; + virtual void drawPosText(const void* text, size_t byteLength, + const SkPoint pos[], const SkPaint& paint) = 0; + virtual void drawMediaButton(const IntRect& rect, RenderSkinMediaButton::MediaButton buttonType, + bool translucent = false, bool drawBackground = true, + const IntRect& thumb = IntRect()) = 0; + virtual SkCanvas* recordingCanvas() = 0; - virtual void endRecording(int type = 0) = 0; -protected: + void setRawState(State* state) { m_state = state; } struct ShadowRec { SkScalar blur; @@ -192,11 +200,11 @@ protected: friend class PlatformGraphicsContextSkia; }; +protected: virtual bool shadowsIgnoreTransforms() const = 0; void setupPaintCommon(SkPaint* paint) const; GraphicsContext* m_gc; // Back-ptr to our parent - struct State; WTF::Vector<State> m_stateStack; State* m_state; }; diff --git a/Source/WebCore/platform/graphics/android/context/PlatformGraphicsContextRecording.cpp b/Source/WebCore/platform/graphics/android/context/PlatformGraphicsContextRecording.cpp index d96124d..6c033b6 100644 --- a/Source/WebCore/platform/graphics/android/context/PlatformGraphicsContextRecording.cpp +++ b/Source/WebCore/platform/graphics/android/context/PlatformGraphicsContextRecording.cpp @@ -1,3 +1,28 @@ +/* + * Copyright 2012, 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. + */ + #define LOG_TAG "PlatformGraphicsContextRecording" #define LOG_NDEBUG 1 @@ -5,71 +30,470 @@ #include "PlatformGraphicsContextRecording.h" #include "AndroidLog.h" +#include "FloatRect.h" +#include "FloatQuad.h" #include "Font.h" #include "GraphicsContext.h" -#include "GraphicsOperationCollection.h" #include "GraphicsOperation.h" +#include "LinearAllocator.h" +#include "PlatformGraphicsContextSkia.h" +#include "RTree.h" + +#include "wtf/NonCopyingSort.h" +#include "wtf/HashSet.h" +#include "wtf/StringHasher.h" + +#define NEW_OP(X) new (operationHeap()) GraphicsOperation::X + +#define USE_CLIPPING_PAINTER true namespace WebCore { +static FloatRect approximateTextBounds(size_t numGlyphs, + const SkPoint pos[], const SkPaint& paint) +{ + if (!numGlyphs || !pos) { + return FloatRect(); + } + + // get glyph position bounds + SkScalar minX = pos[0].x(); + SkScalar maxX = minX; + SkScalar minY = pos[0].y(); + SkScalar maxY = minY; + for (size_t i = 1; i < numGlyphs; ++i) { + SkScalar x = pos[i].x(); + SkScalar y = pos[i].y(); + minX = std::min(minX, x); + maxX = std::max(maxX, x); + minY = std::min(minY, y); + maxY = std::max(maxY, y); + } + + // build final rect + SkPaint::FontMetrics metrics; + SkScalar bufY = paint.getFontMetrics(&metrics); + SkScalar bufX = bufY * 2; + SkScalar adjY = metrics.fAscent / 2; + minY += adjY; + maxY += adjY; + SkRect rect; + rect.set(minX - bufX, minY - bufY, maxX + bufX, maxY + bufY); + return rect; +} + +class StateHash { +public: + static unsigned hash(PlatformGraphicsContext::State* const& state) + { + return StringHasher::hashMemory(state, sizeof(PlatformGraphicsContext::State)); + } + + static bool equal(PlatformGraphicsContext::State* const& a, + PlatformGraphicsContext::State* const& b) + { + return a && b && !memcmp(a, b, sizeof(PlatformGraphicsContext::State)); + } + + static const bool safeToCompareToEmptyOrDeleted = false; +}; + +typedef HashSet<PlatformGraphicsContext::State*, StateHash> StateHashSet; + +class CanvasState { +public: + CanvasState(CanvasState* parent) + : m_parent(parent) + , m_isTransparencyLayer(false) + {} + + CanvasState(CanvasState* parent, float opacity) + : m_parent(parent) + , m_isTransparencyLayer(true) + , m_opacity(opacity) + {} + + ~CanvasState() { + ALOGV("Delete %p", this); + for (size_t i = 0; i < m_operations.size(); i++) + delete m_operations[i]; + m_operations.clear(); + } + + bool isParentOf(CanvasState* other) { + while (other->m_parent) { + if (other->m_parent == this) + return true; + other = other->m_parent; + } + return false; + } + + void playback(PlatformGraphicsContext* context, size_t fromId, size_t toId) const { + ALOGV("playback %p from %d->%d", this, fromId, toId); + for (size_t i = 0; i < m_operations.size(); i++) { + RecordingData *data = m_operations[i]; + if (data->m_orderBy < fromId) + continue; + if (data->m_orderBy > toId) + break; + ALOGV("Applying operation[%d] %p->%s()", i, data->m_operation, + data->m_operation->name()); + data->m_operation->apply(context); + } + } + + CanvasState* parent() { return m_parent; } + + void enterState(PlatformGraphicsContext* context) { + ALOGV("enterState %p", this); + if (m_isTransparencyLayer) + context->beginTransparencyLayer(m_opacity); + else + context->save(); + } + + void exitState(PlatformGraphicsContext* context) { + ALOGV("exitState %p", this); + if (m_isTransparencyLayer) + context->endTransparencyLayer(); + else + context->restore(); + } + + void adoptAndAppend(RecordingData* data) { + m_operations.append(data); + } + + bool isTransparencyLayer() { + return m_isTransparencyLayer; + } + + void* operator new(size_t size, LinearAllocator* la) { + return la->alloc(size); + } + +private: + CanvasState *m_parent; + bool m_isTransparencyLayer; + float m_opacity; + Vector<RecordingData*> m_operations; +}; + +class RecordingImpl { +private: + // Careful, ordering matters here. Ordering is first constructed == last destroyed, + // so we have to make sure our Heap is the first thing listed so that it is + // the last thing destroyed. + LinearAllocator m_operationHeap; + LinearAllocator m_canvasStateHeap; + LinearAllocator m_stateHeap; +public: + RecordingImpl() + : m_canvasStateHeap(sizeof(CanvasState)) + , m_stateHeap(sizeof(PlatformGraphicsContext::State)) + , m_nodeCount(0) + { + } + + ~RecordingImpl() { + clearStates(); + clearCanvasStates(); + } + + PlatformGraphicsContext::State* getState(PlatformGraphicsContext::State* inState) { + StateHashSet::iterator it = m_states.find(inState); + if (it != m_states.end()) + return (*it); + void* buf = m_stateHeap.alloc(sizeof(PlatformGraphicsContext::State)); + PlatformGraphicsContext::State* state = new (buf) PlatformGraphicsContext::State(*inState); + m_states.add(state); + return state; + } + + void addCanvasState(CanvasState* state) { + m_canvasStates.append(state); + } + + void removeCanvasState(const CanvasState* state) { + if (m_canvasStates.last() == state) + m_canvasStates.removeLast(); + else { + size_t indx = m_canvasStates.find(state); + m_canvasStates.remove(indx); + } + } + + void applyState(PlatformGraphicsContext* context, + CanvasState* fromState, size_t fromId, + CanvasState* toState, size_t toId) { + ALOGV("applyState(%p->%p, %d-%d)", fromState, toState, fromId, toId); + if (fromState != toState && fromState) { + if (fromState->isParentOf(toState)) { + // Going down the tree, playback any parent operations then save + // before playing back our current operations + applyState(context, fromState, fromId, toState->parent(), toId); + toState->enterState(context); + } else if (toState->isParentOf(fromState)) { + // Going up the tree, pop some states + while (fromState != toState) { + fromState->exitState(context); + fromState = fromState->parent(); + } + } else { + // Siblings in the tree + fromState->exitState(context); + applyState(context, fromState->parent(), fromId, toState, toId); + return; + } + } else if (!fromState) { + if (toState->parent()) + applyState(context, fromState, fromId, toState->parent(), toId); + toState->enterState(context); + } + toState->playback(context, fromId, toId); + } + + LinearAllocator* operationHeap() { return &m_operationHeap; } + LinearAllocator* canvasStateHeap() { return &m_canvasStateHeap; } + + RTree::RTree m_tree; + int m_nodeCount; + +private: + + void clearStates() { + StateHashSet::iterator end = m_states.end(); + for (StateHashSet::iterator it = m_states.begin(); it != end; ++it) + (*it)->~State(); + m_states.clear(); + } + + void clearCanvasStates() { + for (size_t i = 0; i < m_canvasStates.size(); i++) + m_canvasStates[i]->~CanvasState(); + m_canvasStates.clear(); + } + + // TODO: Use a global pool? + StateHashSet m_states; + Vector<CanvasState*> m_canvasStates; +}; + +Recording::~Recording() +{ + delete m_recording; +} + +static bool CompareRecordingDataOrder(const RecordingData* a, const RecordingData* b) +{ + return a->m_orderBy < b->m_orderBy; +} + +static IntRect enclosedIntRect(const FloatRect& rect) +{ + float left = ceilf(rect.x()); + float top = ceilf(rect.y()); + float width = floorf(rect.maxX()) - left; + float height = floorf(rect.maxY()) - top; + + return IntRect(clampToInteger(left), clampToInteger(top), + clampToInteger(width), clampToInteger(height)); +} + +#if USE_CLIPPING_PAINTER +class ClippingPainter { +public: + ClippingPainter(RecordingImpl* recording, + PlatformGraphicsContextSkia& context, + const SkMatrix& initialMatrix, + Vector<RecordingData*> &nodes) + : m_recording(recording) + , m_context(context) + , m_initialMatrix(initialMatrix) + , m_nodes(nodes) + , m_lastOperationId(0) + , m_currState(0) + {} + + void draw(const SkIRect& bounds) { + SkRegion coveredArea(bounds); + + drawWithClipRecursive(static_cast<int>(m_nodes.size()) - 1, coveredArea); + + while (m_currState) { + m_currState->exitState(&m_context); + m_currState = m_currState->parent(); + } + } + +private: + void drawOperation(RecordingData* node, const SkRegion& covered) + { + GraphicsOperation::Operation* op = node->m_operation; + m_recording->applyState(&m_context, m_currState, + m_lastOperationId, op->m_canvasState, node->m_orderBy); + m_currState = op->m_canvasState; + m_lastOperationId = node->m_orderBy; + + // if other opaque operations will cover the current one, clip that area out + // (and restore the clip immediately after drawing) + if (!covered.isEmpty()) { + m_context.save(); + m_context.canvas()->clipRegion(covered, SkRegion::kIntersect_Op); + } + op->apply(&(m_context)); + if (!covered.isEmpty()) + m_context.restore(); + } + + void drawWithClipRecursive(int index, const SkRegion& covered) + { + if (index < 0) + return; + RecordingData* recordingData = m_nodes[index]; + GraphicsOperation::Operation* op = recordingData->m_operation; + if (index != 0) { + const IntRect* opaqueRect = op->opaqueRect(); + if (!opaqueRect || opaqueRect->isEmpty()) { + drawWithClipRecursive(index - 1, covered); + } else { + SkRegion newCovered = covered; + SkRect mappedRect = *opaqueRect; + m_initialMatrix.mapRect(&mappedRect); + newCovered.op(enclosedIntRect(mappedRect), SkRegion::kDifference_Op); + if (!newCovered.isEmpty()) + drawWithClipRecursive(index - 1, newCovered); + } + } + drawOperation(recordingData, covered); + } + + RecordingImpl* m_recording; + PlatformGraphicsContextSkia& m_context; + const SkMatrix& m_initialMatrix; + const Vector<RecordingData*>& m_nodes; + size_t m_lastOperationId; + CanvasState* m_currState; +}; +#endif // USE_CLIPPING_PAINTER + +void Recording::draw(SkCanvas* canvas) +{ + if (!m_recording) { + ALOGW("No recording!"); + return; + } + SkRect clip; + if (!canvas->getClipBounds(&clip)) { + ALOGW("Empty clip!"); + return; + } + Vector<RecordingData*> nodes; + + WebCore::IntRect iclip = enclosingIntRect(clip); + m_recording->m_tree.search(iclip, nodes); + + size_t count = nodes.size(); + ALOGV("Drawing %d nodes out of %d", count, m_recording->m_nodeCount); + if (count) { + int saveCount = canvas->getSaveCount(); + nonCopyingSort(nodes.begin(), nodes.end(), CompareRecordingDataOrder); + PlatformGraphicsContextSkia context(canvas); +#if USE_CLIPPING_PAINTER + ClippingPainter painter(recording(), context, canvas->getTotalMatrix(), nodes); + painter.draw(canvas->getTotalClip().getBounds()); +#else + CanvasState* currState = 0; + size_t lastOperationId = 0; + for (size_t i = 0; i < count; i++) { + GraphicsOperation::Operation* op = nodes[i]->m_operation; + m_recording->applyState(&context, currState, lastOperationId, + op->m_canvasState, nodes[i]->m_orderBy); + currState = op->m_canvasState; + lastOperationId = nodes[i]->m_orderBy; + ALOGV("apply: %p->%s()", op, op->name()); + op->apply(&context); + } + while (currState) { + currState->exitState(&context); + currState = currState->parent(); + } +#endif + if (saveCount != canvas->getSaveCount()) { + ALOGW("Save/restore mismatch! %d vs. %d", saveCount, canvas->getSaveCount()); + } + } +} + +void Recording::setRecording(RecordingImpl* impl) +{ + if (m_recording == impl) + return; + if (m_recording) + delete m_recording; + m_recording = impl; +} + //************************************** // PlatformGraphicsContextRecording //************************************** -PlatformGraphicsContextRecording::PlatformGraphicsContextRecording(GraphicsOperationCollection* picture) +PlatformGraphicsContextRecording::PlatformGraphicsContextRecording(Recording* recording) : PlatformGraphicsContext() - , mGraphicsOperationCollection(picture) , mPicture(0) + , mRecording(recording) + , mOperationState(0) + , m_hasText(false) + , m_isEmpty(true) + , m_canvasProxy(this) { + if (mRecording) + mRecording->setRecording(new RecordingImpl()); + mMatrixStack.append(SkMatrix::I()); + mCurrentMatrix = &(mMatrixStack.last()); + pushStateOperation(new (canvasStateHeap()) CanvasState(0)); } bool PlatformGraphicsContextRecording::isPaintingDisabled() { - return !mGraphicsOperationCollection; + return !mRecording; } SkCanvas* PlatformGraphicsContextRecording::recordingCanvas() { - SkSafeUnref(mPicture); - mPicture = new SkPicture(); - return mPicture->beginRecording(0, 0, 0); + m_hasText = true; + return &m_canvasProxy; } -void PlatformGraphicsContextRecording::endRecording(int type) -{ - if (!mPicture) - return; - mPicture->endRecording(); - GraphicsOperation::DrawComplexText* text = new GraphicsOperation::DrawComplexText(mPicture); - mGraphicsOperationCollection->append(text); - mPicture = 0; -} - - //************************************** // State management //************************************** void PlatformGraphicsContextRecording::beginTransparencyLayer(float opacity) { - mGraphicsOperationCollection->append(new GraphicsOperation::BeginTransparencyLayer(opacity)); + CanvasState* parent = mRecordingStateStack.last().mCanvasState; + pushStateOperation(new (canvasStateHeap()) CanvasState(parent, opacity)); } void PlatformGraphicsContextRecording::endTransparencyLayer() { - mGraphicsOperationCollection->append(new GraphicsOperation::EndTransparencyLayer()); + popStateOperation(); } void PlatformGraphicsContextRecording::save() { PlatformGraphicsContext::save(); - mGraphicsOperationCollection->append(new GraphicsOperation::Save()); + CanvasState* parent = mRecordingStateStack.last().mCanvasState; + pushStateOperation(new (canvasStateHeap()) CanvasState(parent)); + pushMatrix(); } void PlatformGraphicsContextRecording::restore() { PlatformGraphicsContext::restore(); - mGraphicsOperationCollection->append(new GraphicsOperation::Restore()); + popMatrix(); + popStateOperation(); } //************************************** @@ -79,86 +503,98 @@ void PlatformGraphicsContextRecording::restore() void PlatformGraphicsContextRecording::setAlpha(float alpha) { PlatformGraphicsContext::setAlpha(alpha); - mGraphicsOperationCollection->append(new GraphicsOperation::SetAlpha(alpha)); + mOperationState = 0; } void PlatformGraphicsContextRecording::setCompositeOperation(CompositeOperator op) { PlatformGraphicsContext::setCompositeOperation(op); - mGraphicsOperationCollection->append(new GraphicsOperation::SetCompositeOperation(op)); + mOperationState = 0; } -void PlatformGraphicsContextRecording::setFillColor(const Color& c) +bool PlatformGraphicsContextRecording::setFillColor(const Color& c) { - PlatformGraphicsContext::setFillColor(c); - mGraphicsOperationCollection->append(new GraphicsOperation::SetFillColor(c)); + if (PlatformGraphicsContext::setFillColor(c)) { + mOperationState = 0; + return true; + } + return false; } -void PlatformGraphicsContextRecording::setFillShader(SkShader* fillShader) +bool PlatformGraphicsContextRecording::setFillShader(SkShader* fillShader) { - PlatformGraphicsContext::setFillShader(fillShader); - mGraphicsOperationCollection->append(new GraphicsOperation::SetFillShader(fillShader)); + if (PlatformGraphicsContext::setFillShader(fillShader)) { + mOperationState = 0; + return true; + } + return false; } void PlatformGraphicsContextRecording::setLineCap(LineCap cap) { PlatformGraphicsContext::setLineCap(cap); - mGraphicsOperationCollection->append(new GraphicsOperation::SetLineCap(cap)); + mOperationState = 0; } void PlatformGraphicsContextRecording::setLineDash(const DashArray& dashes, float dashOffset) { PlatformGraphicsContext::setLineDash(dashes, dashOffset); - mGraphicsOperationCollection->append(new GraphicsOperation::SetLineDash(dashes, dashOffset)); + mOperationState = 0; } void PlatformGraphicsContextRecording::setLineJoin(LineJoin join) { PlatformGraphicsContext::setLineJoin(join); - mGraphicsOperationCollection->append(new GraphicsOperation::SetLineJoin(join)); + mOperationState = 0; } void PlatformGraphicsContextRecording::setMiterLimit(float limit) { PlatformGraphicsContext::setMiterLimit(limit); - mGraphicsOperationCollection->append(new GraphicsOperation::SetMiterLimit(limit)); + mOperationState = 0; } void PlatformGraphicsContextRecording::setShadow(int radius, int dx, int dy, SkColor c) { PlatformGraphicsContext::setShadow(radius, dx, dy, c); - mGraphicsOperationCollection->append(new GraphicsOperation::SetShadow(radius, dx, dy, c)); + mOperationState = 0; } void PlatformGraphicsContextRecording::setShouldAntialias(bool useAA) { m_state->useAA = useAA; PlatformGraphicsContext::setShouldAntialias(useAA); - mGraphicsOperationCollection->append(new GraphicsOperation::SetShouldAntialias(useAA)); + mOperationState = 0; } -void PlatformGraphicsContextRecording::setStrokeColor(const Color& c) +bool PlatformGraphicsContextRecording::setStrokeColor(const Color& c) { - PlatformGraphicsContext::setStrokeColor(c); - mGraphicsOperationCollection->append(new GraphicsOperation::SetStrokeColor(c)); + if (PlatformGraphicsContext::setStrokeColor(c)) { + mOperationState = 0; + return true; + } + return false; } -void PlatformGraphicsContextRecording::setStrokeShader(SkShader* strokeShader) +bool PlatformGraphicsContextRecording::setStrokeShader(SkShader* strokeShader) { - PlatformGraphicsContext::setStrokeShader(strokeShader); - mGraphicsOperationCollection->append(new GraphicsOperation::SetStrokeShader(strokeShader)); + if (PlatformGraphicsContext::setStrokeShader(strokeShader)) { + mOperationState = 0; + return true; + } + return false; } void PlatformGraphicsContextRecording::setStrokeStyle(StrokeStyle style) { PlatformGraphicsContext::setStrokeStyle(style); - mGraphicsOperationCollection->append(new GraphicsOperation::SetStrokeStyle(style)); + mOperationState = 0; } void PlatformGraphicsContextRecording::setStrokeThickness(float f) { PlatformGraphicsContext::setStrokeThickness(f); - mGraphicsOperationCollection->append(new GraphicsOperation::SetStrokeThickness(f)); + mOperationState = 0; } //************************************** @@ -167,32 +603,32 @@ void PlatformGraphicsContextRecording::setStrokeThickness(float f) void PlatformGraphicsContextRecording::concatCTM(const AffineTransform& affine) { - mCurrentMatrix.preConcat(affine); - mGraphicsOperationCollection->append(new GraphicsOperation::ConcatCTM(affine)); + mCurrentMatrix->preConcat(affine); + appendStateOperation(NEW_OP(ConcatCTM)(affine)); } void PlatformGraphicsContextRecording::rotate(float angleInRadians) { float value = angleInRadians * (180.0f / 3.14159265f); - mCurrentMatrix.preRotate(SkFloatToScalar(value)); - mGraphicsOperationCollection->append(new GraphicsOperation::Rotate(angleInRadians)); + mCurrentMatrix->preRotate(SkFloatToScalar(value)); + appendStateOperation(NEW_OP(Rotate)(angleInRadians)); } void PlatformGraphicsContextRecording::scale(const FloatSize& size) { - mCurrentMatrix.preScale(SkFloatToScalar(size.width()), SkFloatToScalar(size.height())); - mGraphicsOperationCollection->append(new GraphicsOperation::Scale(size)); + mCurrentMatrix->preScale(SkFloatToScalar(size.width()), SkFloatToScalar(size.height())); + appendStateOperation(NEW_OP(Scale)(size)); } void PlatformGraphicsContextRecording::translate(float x, float y) { - mCurrentMatrix.preTranslate(SkFloatToScalar(x), SkFloatToScalar(y)); - mGraphicsOperationCollection->append(new GraphicsOperation::Translate(x, y)); + mCurrentMatrix->preTranslate(SkFloatToScalar(x), SkFloatToScalar(y)); + appendStateOperation(NEW_OP(Translate)(x, y)); } const SkMatrix& PlatformGraphicsContextRecording::getTotalMatrix() { - return mCurrentMatrix; + return *mCurrentMatrix; } //************************************** @@ -202,50 +638,65 @@ const SkMatrix& PlatformGraphicsContextRecording::getTotalMatrix() void PlatformGraphicsContextRecording::addInnerRoundedRectClip(const IntRect& rect, int thickness) { - mGraphicsOperationCollection->append(new GraphicsOperation::InnerRoundedRectClip(rect, thickness)); + mRecordingStateStack.last().setHasComplexClip(); + appendStateOperation(NEW_OP(InnerRoundedRectClip)(rect, thickness)); } void PlatformGraphicsContextRecording::canvasClip(const Path& path) { + mRecordingStateStack.last().setHasComplexClip(); clip(path); } -void PlatformGraphicsContextRecording::clip(const FloatRect& rect) +bool PlatformGraphicsContextRecording::clip(const FloatRect& rect) { - mGraphicsOperationCollection->append(new GraphicsOperation::Clip(rect)); + clipState(rect); + appendStateOperation(NEW_OP(Clip)(rect)); + return true; } -void PlatformGraphicsContextRecording::clip(const Path& path) +bool PlatformGraphicsContextRecording::clip(const Path& path) { - mGraphicsOperationCollection->append(new GraphicsOperation::ClipPath(path)); + mRecordingStateStack.last().setHasComplexClip(); + clipState(path.boundingRect()); + appendStateOperation(NEW_OP(ClipPath)(path)); + return true; } -void PlatformGraphicsContextRecording::clipConvexPolygon(size_t numPoints, +bool PlatformGraphicsContextRecording::clipConvexPolygon(size_t numPoints, const FloatPoint*, bool antialias) { // TODO + return true; } -void PlatformGraphicsContextRecording::clipOut(const IntRect& r) +bool PlatformGraphicsContextRecording::clipOut(const IntRect& r) { - mGraphicsOperationCollection->append(new GraphicsOperation::ClipOut(r)); + mRecordingStateStack.last().setHasComplexClip(); + appendStateOperation(NEW_OP(ClipOut)(r)); + return true; } -void PlatformGraphicsContextRecording::clipOut(const Path& path) +bool PlatformGraphicsContextRecording::clipOut(const Path& path) { - mGraphicsOperationCollection->append(new GraphicsOperation::ClipPath(path, true)); + mRecordingStateStack.last().setHasComplexClip(); + appendStateOperation(NEW_OP(ClipPath)(path, true)); + return true; } -void PlatformGraphicsContextRecording::clipPath(const Path& pathToClip, WindRule clipRule) +bool PlatformGraphicsContextRecording::clipPath(const Path& pathToClip, WindRule clipRule) { - GraphicsOperation::ClipPath* operation = new GraphicsOperation::ClipPath(pathToClip); + mRecordingStateStack.last().setHasComplexClip(); + clipState(pathToClip.boundingRect()); + GraphicsOperation::ClipPath* operation = NEW_OP(ClipPath)(pathToClip); operation->setWindRule(clipRule); - mGraphicsOperationCollection->append(operation); + appendStateOperation(operation); + return true; } void PlatformGraphicsContextRecording::clearRect(const FloatRect& rect) { - mGraphicsOperationCollection->append(new GraphicsOperation::ClearRect(rect)); + appendDrawingOperation(NEW_OP(ClearRect)(rect), rect); } //************************************** @@ -256,33 +707,48 @@ void PlatformGraphicsContextRecording::drawBitmapPattern( const SkBitmap& bitmap, const SkMatrix& matrix, CompositeOperator compositeOp, const FloatRect& destRect) { - mGraphicsOperationCollection->append(new GraphicsOperation::DrawBitmapPattern(bitmap, matrix, compositeOp, destRect)); + appendDrawingOperation( + NEW_OP(DrawBitmapPattern)(bitmap, matrix, compositeOp, destRect), + destRect); } void PlatformGraphicsContextRecording::drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src, const SkRect& dst, CompositeOperator op) { - mGraphicsOperationCollection->append(new GraphicsOperation::DrawBitmapRect(bitmap, *src, dst, op)); + appendDrawingOperation(NEW_OP(DrawBitmapRect)(bitmap, *src, dst, op), dst); } void PlatformGraphicsContextRecording::drawConvexPolygon(size_t numPoints, const FloatPoint* points, bool shouldAntialias) { - // TODO + if (numPoints < 1) return; + if (numPoints != 4) { + // TODO: Build a path and call draw on that (webkit currently never calls this) + ALOGW("drawConvexPolygon with numPoints != 4 is not supported!"); + return; + } + FloatRect bounds; + bounds.fitToPoints(points[0], points[1], points[2], points[3]); + appendDrawingOperation(NEW_OP(DrawConvexPolygonQuad)(points, shouldAntialias), bounds); } void PlatformGraphicsContextRecording::drawEllipse(const IntRect& rect) { - mGraphicsOperationCollection->append(new GraphicsOperation::DrawEllipse(rect)); + appendDrawingOperation(NEW_OP(DrawEllipse)(rect), rect); } void PlatformGraphicsContextRecording::drawFocusRing(const Vector<IntRect>& rects, - int /* width */, int /* offset */, + int width, int offset, const Color& color) { - // TODO + if (!rects.size()) + return; + IntRect bounds = rects[0]; + for (size_t i = 1; i < rects.size(); i++) + bounds.unite(rects[i]); + appendDrawingOperation(NEW_OP(DrawFocusRing)(rects, width, offset, color), bounds); } void PlatformGraphicsContextRecording::drawHighlightForText( @@ -307,41 +773,47 @@ void PlatformGraphicsContextRecording::drawHighlightForText( void PlatformGraphicsContextRecording::drawLine(const IntPoint& point1, const IntPoint& point2) { - mGraphicsOperationCollection->append(new GraphicsOperation::DrawLine(point1, point2)); + FloatRect bounds = FloatQuad(point1, point1, point2, point2).boundingBox(); + float width = m_state->strokeThickness; + if (!width) width = 1; + bounds.inflate(width); + appendDrawingOperation(NEW_OP(DrawLine)(point1, point2), bounds); } void PlatformGraphicsContextRecording::drawLineForText(const FloatPoint& pt, float width) { - mGraphicsOperationCollection->append(new GraphicsOperation::DrawLineForText(pt, width)); + FloatRect bounds(pt.x(), pt.y(), width, m_state->strokeThickness); + appendDrawingOperation(NEW_OP(DrawLineForText)(pt, width), bounds); } void PlatformGraphicsContextRecording::drawLineForTextChecking(const FloatPoint& pt, float width, GraphicsContext::TextCheckingLineStyle lineStyle) { - mGraphicsOperationCollection->append(new GraphicsOperation::DrawLineForTextChecking(pt, width, lineStyle)); + FloatRect bounds(pt.x(), pt.y(), width, m_state->strokeThickness); + appendDrawingOperation(NEW_OP(DrawLineForTextChecking)(pt, width, lineStyle), bounds); } void PlatformGraphicsContextRecording::drawRect(const IntRect& rect) { - mGraphicsOperationCollection->append(new GraphicsOperation::DrawRect(rect)); + appendDrawingOperation(NEW_OP(DrawRect)(rect), rect); } void PlatformGraphicsContextRecording::fillPath(const Path& pathToFill, WindRule fillRule) { - mGraphicsOperationCollection->append(new GraphicsOperation::FillPath(pathToFill, fillRule)); + appendDrawingOperation(NEW_OP(FillPath)(pathToFill, fillRule), pathToFill.boundingRect()); } void PlatformGraphicsContextRecording::fillRect(const FloatRect& rect) { - mGraphicsOperationCollection->append(new GraphicsOperation::FillRect(rect)); + appendDrawingOperation(NEW_OP(FillRect)(rect), rect); } void PlatformGraphicsContextRecording::fillRect(const FloatRect& rect, const Color& color) { - GraphicsOperation::FillRect* operation = new GraphicsOperation::FillRect(rect); + GraphicsOperation::FillRect* operation = NEW_OP(FillRect)(rect); operation->setColor(color); - mGraphicsOperationCollection->append(operation); + appendDrawingOperation(operation, rect); } void PlatformGraphicsContextRecording::fillRoundedRect( @@ -349,25 +821,186 @@ void PlatformGraphicsContextRecording::fillRoundedRect( const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color) { - mGraphicsOperationCollection->append(new GraphicsOperation::FillRoundedRect(rect, topLeft, - topRight, bottomLeft, bottomRight, color)); + appendDrawingOperation(NEW_OP(FillRoundedRect)(rect, topLeft, + topRight, bottomLeft, bottomRight, color), rect); } void PlatformGraphicsContextRecording::strokeArc(const IntRect& r, int startAngle, int angleSpan) { - mGraphicsOperationCollection->append(new GraphicsOperation::StrokeArc(r, startAngle, angleSpan)); + appendDrawingOperation(NEW_OP(StrokeArc)(r, startAngle, angleSpan), r); } void PlatformGraphicsContextRecording::strokePath(const Path& pathToStroke) { - mGraphicsOperationCollection->append(new GraphicsOperation::StrokePath(pathToStroke)); + appendDrawingOperation(NEW_OP(StrokePath)(pathToStroke), pathToStroke.boundingRect()); } void PlatformGraphicsContextRecording::strokeRect(const FloatRect& rect, float lineWidth) { - mGraphicsOperationCollection->append(new GraphicsOperation::StrokeRect(rect, lineWidth)); + FloatRect bounds = rect; + bounds.inflate(lineWidth); + appendDrawingOperation(NEW_OP(StrokeRect)(rect, lineWidth), bounds); +} + +void PlatformGraphicsContextRecording::drawPosText(const void* text, size_t byteLength, + const SkPoint pos[], const SkPaint& paint) +{ + if (paint.getTextEncoding() != SkPaint::kGlyphID_TextEncoding) { + ALOGE("Unsupported text encoding! %d", paint.getTextEncoding()); + } + FloatRect bounds = approximateTextBounds(byteLength / sizeof(uint16_t), pos, paint); + appendDrawingOperation(NEW_OP(DrawPosText)(text, byteLength, pos, paint), bounds); +} + +void PlatformGraphicsContextRecording::drawMediaButton(const IntRect& rect, RenderSkinMediaButton::MediaButton buttonType, + bool translucent, bool drawBackground, + const IntRect& thumb) +{ + appendDrawingOperation(NEW_OP(DrawMediaButton)(rect, buttonType, + translucent, drawBackground, thumb), rect); +} + +void PlatformGraphicsContextRecording::clipState(const FloatRect& clip) +{ + if (mRecordingStateStack.size()) { + SkRect mapBounds; + mCurrentMatrix->mapRect(&mapBounds, clip); + mRecordingStateStack.last().clip(mapBounds); + } +} + +void PlatformGraphicsContextRecording::pushStateOperation(CanvasState* canvasState) +{ + ALOGV("pushStateOperation: %p(isLayer=%d)", canvasState, canvasState->isTransparencyLayer()); + mRecordingStateStack.append(canvasState); + mRecording->recording()->addCanvasState(canvasState); +} + +void PlatformGraphicsContextRecording::popStateOperation() +{ + RecordingState state = mRecordingStateStack.last(); + mRecordingStateStack.removeLast(); + if (!state.mHasDrawing) { + ALOGV("popStateOperation is deleting %p(isLayer=%d)", + state.mCanvasState, state.mCanvasState->isTransparencyLayer()); + mRecording->recording()->removeCanvasState(state.mCanvasState); + state.mCanvasState->~CanvasState(); + canvasStateHeap()->rewindTo(state.mCanvasState); + } else { + ALOGV("popStateOperation: %p(isLayer=%d)", + state.mCanvasState, state.mCanvasState->isTransparencyLayer()); + // Make sure we propagate drawing upwards so we don't delete our parent + mRecordingStateStack.last().mHasDrawing = true; + } +} + +void PlatformGraphicsContextRecording::pushMatrix() +{ + mMatrixStack.append(mMatrixStack.last()); + mCurrentMatrix = &(mMatrixStack.last()); +} + +void PlatformGraphicsContextRecording::popMatrix() +{ + mMatrixStack.removeLast(); + mCurrentMatrix = &(mMatrixStack.last()); +} + +IntRect PlatformGraphicsContextRecording::calculateFinalBounds(FloatRect bounds) +{ + if (bounds.isEmpty() && mRecordingStateStack.last().mHasClip) { + ALOGV("Empty bounds, but has clip so using that"); + return enclosingIntRect(mRecordingStateStack.last().mBounds); + } + if (m_gc->hasShadow()) { + const ShadowRec& shadow = m_state->shadow; + if (shadow.blur > 0) + bounds.inflate(ceilf(shadow.blur)); + bounds.setWidth(bounds.width() + abs(shadow.dx)); + bounds.setHeight(bounds.height() + abs(shadow.dy)); + if (shadow.dx < 0) + bounds.move(shadow.dx, 0); + if (shadow.dy < 0) + bounds.move(0, shadow.dy); + // Add a bit extra to deal with rounding and blurring + bounds.inflate(4); + } + if (m_state->strokeStyle != NoStroke) + bounds.inflate(std::min(1.0f, m_state->strokeThickness)); + SkRect translated; + mCurrentMatrix->mapRect(&translated, bounds); + FloatRect ftrect = translated; + if (mRecordingStateStack.last().mHasClip + && !translated.intersect(mRecordingStateStack.last().mBounds)) { + ALOGV("Operation bounds=" FLOAT_RECT_FORMAT " clipped out by clip=" FLOAT_RECT_FORMAT, + FLOAT_RECT_ARGS(ftrect), FLOAT_RECT_ARGS(mRecordingStateStack.last().mBounds)); + return IntRect(); + } + return enclosingIntRect(translated); +} + +IntRect PlatformGraphicsContextRecording::calculateCoveredBounds(FloatRect bounds) +{ + SkRect translated; + mCurrentMatrix->mapRect(&translated, bounds); + FloatRect ftrect = translated; + if (mRecordingStateStack.last().mHasClip + && !translated.intersect(mRecordingStateStack.last().mBounds)) { + ALOGV("Operation opaque area=" FLOAT_RECT_FORMAT " clipped out by clip=" FLOAT_RECT_FORMAT, + FLOAT_RECT_ARGS(ftrect), FLOAT_RECT_ARGS(mRecordingStateStack.last().mBounds)); + return IntRect(); + } + return enclosedIntRect(translated); +} + +void PlatformGraphicsContextRecording::appendDrawingOperation( + GraphicsOperation::Operation* operation, const FloatRect& untranslatedBounds) +{ + m_isEmpty = false; + RecordingState& state = mRecordingStateStack.last(); + state.mHasDrawing = true; + if (!mOperationState) + mOperationState = mRecording->recording()->getState(m_state); + operation->m_state = mOperationState; + operation->m_canvasState = state.mCanvasState; + + WebCore::IntRect ibounds = calculateFinalBounds(untranslatedBounds); + if (ibounds.isEmpty()) { + ALOGV("Operation %s() was clipped out", operation->name()); + operation->~Operation(); + operationHeap()->rewindTo(operation); + return; + } + if (operation->isOpaque() + && !untranslatedBounds.isEmpty() + && operation->m_state->alpha == 1.0f + && mCurrentMatrix->rectStaysRect() + && !state.mHasComplexClip) { + // if the operation maps to an opaque rect, record the area it will cover + operation->setOpaqueRect(calculateCoveredBounds(untranslatedBounds)); + } + ALOGV("appendOperation %p->%s() bounds " INT_RECT_FORMAT, operation, operation->name(), + INT_RECT_ARGS(ibounds)); + RecordingData* data = new RecordingData(operation, mRecording->recording()->m_nodeCount++); + mRecording->recording()->m_tree.insert(ibounds, data); +} + +void PlatformGraphicsContextRecording::appendStateOperation(GraphicsOperation::Operation* operation) +{ + ALOGV("appendOperation %p->%s()", operation, operation->name()); + RecordingData* data = new RecordingData(operation, mRecording->recording()->m_nodeCount++); + mRecordingStateStack.last().mCanvasState->adoptAndAppend(data); } +LinearAllocator* PlatformGraphicsContextRecording::operationHeap() +{ + return mRecording->recording()->operationHeap(); +} + +LinearAllocator* PlatformGraphicsContextRecording::canvasStateHeap() +{ + return mRecording->recording()->canvasStateHeap(); +} } // WebCore diff --git a/Source/WebCore/platform/graphics/android/context/PlatformGraphicsContextRecording.h b/Source/WebCore/platform/graphics/android/context/PlatformGraphicsContextRecording.h index ebb0075..0461749 100644 --- a/Source/WebCore/platform/graphics/android/context/PlatformGraphicsContextRecording.h +++ b/Source/WebCore/platform/graphics/android/context/PlatformGraphicsContextRecording.h @@ -28,21 +28,42 @@ #include "PlatformGraphicsContext.h" +#include "RecordingContextCanvasProxy.h" +#include "SkRefCnt.h" + namespace WebCore { -class GraphicsOperationCollection; +namespace GraphicsOperation { +class Operation; +} + +class CanvasState; +class LinearAllocator; +class RecordingImpl; +class PlatformGraphicsContextSkia; +class RecordingData; + +class Recording : public SkRefCnt { +public: + Recording() + : m_recording(0) + {} + ~Recording(); + + void draw(SkCanvas* canvas); + void setRecording(RecordingImpl* impl); + RecordingImpl* recording() { return m_recording; } + +private: + RecordingImpl* m_recording; +}; class PlatformGraphicsContextRecording : public PlatformGraphicsContext { public: - PlatformGraphicsContextRecording(GraphicsOperationCollection* picture); + PlatformGraphicsContextRecording(Recording* picture); virtual ~PlatformGraphicsContextRecording() {} virtual bool isPaintingDisabled(); - virtual SkCanvas* getCanvas() { return 0; } - - GraphicsOperationCollection* mGraphicsOperationCollection; - SkMatrix mCurrentMatrix; virtual SkCanvas* recordingCanvas(); - virtual void endRecording(int type = 0); virtual ContextType type() { return RecordingContext; } @@ -55,16 +76,16 @@ public: // State values virtual void setAlpha(float alpha); virtual void setCompositeOperation(CompositeOperator op); - virtual void setFillColor(const Color& c); - virtual void setFillShader(SkShader* fillShader); + virtual bool setFillColor(const Color& c); + virtual bool setFillShader(SkShader* fillShader); virtual void setLineCap(LineCap cap); virtual void setLineDash(const DashArray& dashes, float dashOffset); virtual void setLineJoin(LineJoin join); virtual void setMiterLimit(float limit); virtual void setShadow(int radius, int dx, int dy, SkColor c); virtual void setShouldAntialias(bool useAA); - virtual void setStrokeColor(const Color& c); - virtual void setStrokeShader(SkShader* strokeShader); + virtual bool setStrokeColor(const Color& c); + virtual bool setStrokeShader(SkShader* strokeShader); virtual void setStrokeStyle(StrokeStyle style); virtual void setStrokeThickness(float f); @@ -78,19 +99,20 @@ public: // Clipping virtual void addInnerRoundedRectClip(const IntRect& rect, int thickness); virtual void canvasClip(const Path& path); - virtual void clip(const FloatRect& rect); - virtual void clip(const Path& path); - virtual void clipConvexPolygon(size_t numPoints, const FloatPoint*, bool antialias); - virtual void clipOut(const IntRect& r); - virtual void clipOut(const Path& p); - virtual void clipPath(const Path& pathToClip, WindRule clipRule); + virtual bool clip(const FloatRect& rect); + virtual bool clip(const Path& path); + virtual bool clipConvexPolygon(size_t numPoints, const FloatPoint*, bool antialias); + virtual bool clipOut(const IntRect& r); + virtual bool clipOut(const Path& p); + virtual bool clipPath(const Path& pathToClip, WindRule clipRule); + virtual SkIRect getTotalClipBounds() { return enclosingIntRect(mRecordingStateStack.last().mBounds); } // Drawing virtual void clearRect(const FloatRect& rect); virtual void drawBitmapPattern(const SkBitmap& bitmap, const SkMatrix& matrix, CompositeOperator compositeOp, const FloatRect& destRect); virtual void drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src, - const SkRect& dst, CompositeOperator op); + const SkRect& dst, CompositeOperator op = CompositeSourceOver); virtual void drawConvexPolygon(size_t numPoints, const FloatPoint* points, bool shouldAntialias); virtual void drawEllipse(const IntRect& rect); @@ -103,7 +125,7 @@ public: virtual void drawLine(const IntPoint& point1, const IntPoint& point2); virtual void drawLineForText(const FloatPoint& pt, float width); virtual void drawLineForTextChecking(const FloatPoint& pt, float width, - GraphicsContext::TextCheckingLineStyle); + GraphicsContext::TextCheckingLineStyle); virtual void drawRect(const IntRect& rect); virtual void fillPath(const Path& pathToFill, WindRule fillRule); virtual void fillRect(const FloatRect& rect); @@ -115,13 +137,78 @@ public: virtual void strokePath(const Path& pathToStroke); virtual void strokeRect(const FloatRect& rect, float lineWidth); + virtual void drawPosText(const void* text, size_t byteLength, + const SkPoint pos[], const SkPaint& paint); + virtual void drawMediaButton(const IntRect& rect, RenderSkinMediaButton::MediaButton buttonType, + bool translucent = false, bool drawBackground = true, + const IntRect& thumb = IntRect()); + + bool hasText() { return m_hasText; } + bool isEmpty() { return m_isEmpty; } private: virtual bool shadowsIgnoreTransforms() const { return false; } + void clipState(const FloatRect& clip); + void appendDrawingOperation(GraphicsOperation::Operation* operation, const FloatRect& bounds); + void appendStateOperation(GraphicsOperation::Operation* operation); + void pushStateOperation(CanvasState* canvasState); + void popStateOperation(); + void pushMatrix(); + void popMatrix(); + IntRect calculateFinalBounds(FloatRect bounds); + IntRect calculateCoveredBounds(FloatRect bounds); + LinearAllocator* operationHeap(); + LinearAllocator* canvasStateHeap(); + SkPicture* mPicture; + SkMatrix* mCurrentMatrix; + + Recording* mRecording; + class RecordingState { + public: + RecordingState(CanvasState* state) + : mCanvasState(state) + , mHasDrawing(false) + , mHasClip(false) + , mHasComplexClip(false) + {} + + RecordingState(const RecordingState& other) + : mCanvasState(other.mCanvasState) + , mHasDrawing(other.mHasDrawing) + , mHasClip(other.mHasClip) + , mHasComplexClip(false) + , mBounds(other.mBounds) + {} + + void setHasComplexClip() { mHasComplexClip = true; } + + void clip(const FloatRect& rect) + { + if (mHasClip) + mBounds.intersect(rect); + else { + mBounds = rect; + mHasClip = true; + } + } + + CanvasState* mCanvasState; + bool mHasDrawing; + bool mHasClip; + bool mHasComplexClip; + FloatRect mBounds; + }; + Vector<RecordingState> mRecordingStateStack; + Vector<SkMatrix> mMatrixStack; + State* mOperationState; + + bool m_hasText; + bool m_isEmpty; + RecordingContextCanvasProxy m_canvasProxy; }; } diff --git a/Source/WebCore/platform/graphics/android/context/PlatformGraphicsContextSkia.cpp b/Source/WebCore/platform/graphics/android/context/PlatformGraphicsContextSkia.cpp index f00bb02..fcd9ade 100644 --- a/Source/WebCore/platform/graphics/android/context/PlatformGraphicsContextSkia.cpp +++ b/Source/WebCore/platform/graphics/android/context/PlatformGraphicsContextSkia.cpp @@ -174,43 +174,45 @@ void PlatformGraphicsContextSkia::canvasClip(const Path& path) clip(path); } -void PlatformGraphicsContextSkia::clip(const FloatRect& rect) +bool PlatformGraphicsContextSkia::clip(const FloatRect& rect) { - mCanvas->clipRect(rect); + return mCanvas->clipRect(rect); } -void PlatformGraphicsContextSkia::clip(const Path& path) +bool PlatformGraphicsContextSkia::clip(const Path& path) { - mCanvas->clipPath(*path.platformPath(), SkRegion::kIntersect_Op, true); + return mCanvas->clipPath(*path.platformPath(), SkRegion::kIntersect_Op, true); } -void PlatformGraphicsContextSkia::clipConvexPolygon(size_t numPoints, +bool PlatformGraphicsContextSkia::clipConvexPolygon(size_t numPoints, const FloatPoint*, bool antialias) { if (numPoints <= 1) - return; + return true; // This is only used if HAVE_PATH_BASED_BORDER_RADIUS_DRAWING is defined // in RenderObject.h which it isn't for us. TODO: Support that :) + return true; } -void PlatformGraphicsContextSkia::clipOut(const IntRect& r) +bool PlatformGraphicsContextSkia::clipOut(const IntRect& r) { - mCanvas->clipRect(r, SkRegion::kDifference_Op); + return mCanvas->clipRect(r, SkRegion::kDifference_Op); } -void PlatformGraphicsContextSkia::clipOut(const Path& path) +bool PlatformGraphicsContextSkia::clipOut(const Path& path) { - mCanvas->clipPath(*path.platformPath(), SkRegion::kDifference_Op); + return mCanvas->clipPath(*path.platformPath(), SkRegion::kDifference_Op); } -void PlatformGraphicsContextSkia::clipPath(const Path& pathToClip, WindRule clipRule) +bool PlatformGraphicsContextSkia::clipPath(const Path& pathToClip, WindRule clipRule) { SkPath path = *pathToClip.platformPath(); path.setFillType(clipRule == RULE_EVENODD ? SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType); - mCanvas->clipPath(path); + return mCanvas->clipPath(path); } + void PlatformGraphicsContextSkia::clearRect(const FloatRect& rect) { SkPaint paint; @@ -605,4 +607,17 @@ void PlatformGraphicsContextSkia::strokeRect(const FloatRect& rect, float lineWi mCanvas->drawRect(rect, paint); } +void PlatformGraphicsContextSkia::drawPosText(const void* text, size_t byteLength, + const SkPoint pos[], const SkPaint& paint) +{ + mCanvas->drawPosText(text, byteLength, pos, paint); +} + +void PlatformGraphicsContextSkia::drawMediaButton(const IntRect& rect, RenderSkinMediaButton::MediaButton buttonType, + bool translucent, bool drawBackground, + const IntRect& thumb) +{ + RenderSkinMediaButton::Draw(mCanvas, rect, buttonType, translucent, drawBackground, thumb); +} + } // WebCore diff --git a/Source/WebCore/platform/graphics/android/context/PlatformGraphicsContextSkia.h b/Source/WebCore/platform/graphics/android/context/PlatformGraphicsContextSkia.h index 724e20b..6bf53d7 100644 --- a/Source/WebCore/platform/graphics/android/context/PlatformGraphicsContextSkia.h +++ b/Source/WebCore/platform/graphics/android/context/PlatformGraphicsContextSkia.h @@ -35,11 +35,10 @@ public: PlatformGraphicsContextSkia(SkCanvas* canvas, bool takeCanvasOwnership = false); virtual ~PlatformGraphicsContextSkia(); virtual bool isPaintingDisabled(); - virtual SkCanvas* getCanvas() { return mCanvas; } + SkCanvas* canvas() { return mCanvas; } virtual ContextType type() { return PaintingContext; } virtual SkCanvas* recordingCanvas() { return mCanvas; } - virtual void endRecording(int type = 0) {} // FIXME: This is used by ImageBufferAndroid, which should really be // managing the canvas lifecycle itself @@ -62,19 +61,20 @@ public: // Clipping virtual void addInnerRoundedRectClip(const IntRect& rect, int thickness); virtual void canvasClip(const Path& path); - virtual void clip(const FloatRect& rect); - virtual void clip(const Path& path); - virtual void clipConvexPolygon(size_t numPoints, const FloatPoint*, bool antialias); - virtual void clipOut(const IntRect& r); - virtual void clipOut(const Path& p); - virtual void clipPath(const Path& pathToClip, WindRule clipRule); + virtual bool clip(const FloatRect& rect); + virtual bool clip(const Path& path); + virtual bool clipConvexPolygon(size_t numPoints, const FloatPoint*, bool antialias); + virtual bool clipOut(const IntRect& r); + virtual bool clipOut(const Path& p); + virtual bool clipPath(const Path& pathToClip, WindRule clipRule); + virtual SkIRect getTotalClipBounds() { return mCanvas->getTotalClip().getBounds(); } // Drawing virtual void clearRect(const FloatRect& rect); virtual void drawBitmapPattern(const SkBitmap& bitmap, const SkMatrix& matrix, CompositeOperator compositeOp, const FloatRect& destRect); virtual void drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src, - const SkRect& dst, CompositeOperator op); + const SkRect& dst, CompositeOperator op = CompositeSourceOver); virtual void drawConvexPolygon(size_t numPoints, const FloatPoint* points, bool shouldAntialias); virtual void drawEllipse(const IntRect& rect); @@ -87,7 +87,7 @@ public: virtual void drawLine(const IntPoint& point1, const IntPoint& point2); virtual void drawLineForText(const FloatPoint& pt, float width); virtual void drawLineForTextChecking(const FloatPoint& pt, float width, - GraphicsContext::TextCheckingLineStyle); + GraphicsContext::TextCheckingLineStyle); virtual void drawRect(const IntRect& rect); virtual void fillPath(const Path& pathToFill, WindRule fillRule); virtual void fillRect(const FloatRect& rect); @@ -98,6 +98,11 @@ public: virtual void strokeArc(const IntRect& r, int startAngle, int angleSpan); virtual void strokePath(const Path& pathToStroke); virtual void strokeRect(const FloatRect& rect, float lineWidth); + virtual void drawPosText(const void* text, size_t byteLength, + const SkPoint pos[], const SkPaint& paint); + virtual void drawMediaButton(const IntRect& rect, RenderSkinMediaButton::MediaButton buttonType, + bool translucent = false, bool drawBackground = true, + const IntRect& thumb = IntRect()); private: diff --git a/Source/WebCore/platform/graphics/android/context/RTree.cpp b/Source/WebCore/platform/graphics/android/context/RTree.cpp new file mode 100644 index 0000000..fa048b7 --- /dev/null +++ b/Source/WebCore/platform/graphics/android/context/RTree.cpp @@ -0,0 +1,589 @@ +/* + * Copyright 2012, 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. + */ + +#define LOG_TAG "RTree" +#define LOG_NDEBUG 1 + +#include "config.h" + +#include "RTree.h" + +#include "AndroidLog.h" +#include "LinearAllocator.h" + +namespace RTree { + +#ifdef DEBUG +static unsigned gID = 0; +#endif + +class Element; + +////////////////////////////////////////////////////////////////////// +// utility functions used by ElementList and Node + +static void recomputeBounds(int& minx, int& miny, + int& maxx, int& maxy, + unsigned& nbChildren, + Node**& children, int* area) +{ + // compute the bounds + + if (nbChildren) { + minx = children[0]->m_minX; + miny = children[0]->m_minY; + maxx = children[0]->m_maxX; + maxy = children[0]->m_maxY; + } + + for (unsigned int i = 1; i < nbChildren; i++) + { + minx = std::min(minx, children[i]->m_minX); + miny = std::min(miny, children[i]->m_minY); + maxx = std::max(maxx, children[i]->m_maxX); + maxy = std::max(maxy, children[i]->m_maxY); + } + + if (area) { + int w = maxx - minx; + int h = maxy - miny; + *area = w * h; + } +} + +int computeDeltaArea(Node* node, int& minx, int& miny, + int& maxx, int& maxy) +{ + int newMinX = std::min(minx, node->m_minX); + int newMinY = std::min(miny, node->m_minY); + int newMaxX = std::max(maxx, node->m_maxX); + int newMaxY = std::max(maxy, node->m_maxY); + int w = newMaxX - newMinX; + int h = newMaxY - newMinY; + return w * h; +} + +////////////////////////////////////////////////////////////////////// +// RTree +////////////////////////////////////////////////////////////////////// +// +// This is an implementation of the R-Tree data structure +// "R-Trees - a dynamic index structure for spatial searching", Guttman(84) +// +// The structure works as follow -- elements have bounds, intermediate +// nodes will also maintain bounds (the union of their children' bounds). +// +// Searching is simple -- we just traverse the tree comparing the bounds +// until we find the elements we are interested in. +// +// Each node can have at most M children -- the performances / memory usage +// is strongly impacted by a choice of a good M value (RTree::m_maxChildren). +// +// Inserting an element +// -------------------- +// +// To find the leaf node N where we can insert a new element (RTree::insert(), +// Node::insert()), we need to traverse the tree, picking the branch where +// adding the new element will result in the least growth of its bounds, +// until we reach a leaf node (Node::findNode()). +// +// If the number of children of that leaf node is under M, we simply +// insert it. Otherwise, if we reached maximum capacity for that leaf, +// we split the list of children (Node::split()), creating two lists, +// where each list' elements is as far as each other as possible +// (to decrease the likelyhood of future splits). +// +// We can then assign one of the list to the original leaf node N, and +// we then create a new node NN that we try to attach to N's parent. +// +// If N's parent is also full, we go up in the hierachy and repeat +// (Node::adjustTree()). +// +////////////////////////////////////////////////////////////////////// + +RTree::RTree(int M) +{ + m_maxChildren = M; + m_listA = new ElementList(M); + m_listB = new ElementList(M); + m_allocator = new WebCore::LinearAllocator(sizeof(Node)); + m_root = Node::create(this); +} + +RTree::~RTree() +{ + delete m_listA; + delete m_listB; + deleteNode(m_root); + delete m_allocator; +} + +void RTree::insert(WebCore::IntRect& bounds, WebCore::RecordingData* payload) +{ + Node* e = Node::create(this, bounds.x(), bounds.y(), + bounds.maxX(), bounds.maxY(), payload); + m_root->insert(e); +} + +void RTree::search(WebCore::IntRect& clip, Vector<WebCore::RecordingData*>&list) +{ + m_root->search(clip.x(), clip.y(), clip.maxX(), clip.maxY(), list); +} + +void RTree::remove(WebCore::IntRect& clip) +{ + m_root->remove(clip.x(), clip.y(), clip.maxX(), clip.maxY()); +} + +void RTree::display() +{ +#ifdef DEBUG + m_root->drawTree(); +#endif +} + +void* RTree::allocateNode() +{ + return m_allocator->alloc(sizeof(Node)); +} + +void RTree::deleteNode(Node* n) +{ + if (n) + n->~Node(); +} + +////////////////////////////////////////////////////////////////////// +// ElementList + +ElementList::ElementList(int size) + : m_nbChildren(0) + , m_minX(0) + , m_maxX(0) + , m_minY(0) + , m_maxY(0) + , m_area(0) + , m_didTighten(false) +{ + m_children = new Node*[size]; +} + +ElementList::~ElementList() +{ + delete[] m_children; +} + +void ElementList::add(Node* node) +{ + m_children[m_nbChildren] = node; + m_nbChildren++; + m_didTighten = false; +} + +void ElementList::tighten() +{ + if (m_didTighten) + return; + recomputeBounds(m_minX, m_minY, m_maxX, m_maxY, + m_nbChildren, m_children, &m_area); + m_didTighten = true; +} + +int ElementList::delta(Node* node) +{ + if (!m_didTighten) + tighten(); + return computeDeltaArea(node, m_minX, m_minY, m_maxX, m_maxY); +} + +void ElementList::removeAll() +{ + m_nbChildren = 0; + m_minX = 0; + m_maxX = 0; + m_minY = 0; + m_maxY = 0; + m_area = 0; + m_didTighten = false; +} + +void ElementList::display() { +#ifdef DEBUG + for (unsigned int i = 0; i < m_nbChildren; i++) + m_children[i]->display(0); +#endif +} + +////////////////////////////////////////////////////////////////////// +// Node + +Node::Node(RTree* t, int minx, int miny, int maxx, int maxy, WebCore::RecordingData* payload) + : m_tree(t) + , m_parent(0) + , m_children(0) + , m_nbChildren(0) + , m_payload(payload) + , m_minX(minx) + , m_minY(miny) + , m_maxX(maxx) + , m_maxY(maxy) +#ifdef DEBUG + , m_tid(gID++) +#endif +{ +#ifdef DEBUG + ALOGV("-> New Node %d", m_tid); +#endif +} + +Node::~Node() +{ + for (unsigned i = 0; i < m_nbChildren; i++) + m_tree->deleteNode(m_children[i]); + delete[] m_children; + delete m_payload; +} + +void Node::setParent(Node* node) +{ + m_parent = node; +} + +void Node::insert(Node* node) +{ + Node* N = findNode(node); +#ifdef DEBUG + ALOGV("-> Insert Node %d (%d, %d) in node %d", + node->m_tid, node->m_minX, node->m_minY, N->m_tid); +#endif + N->add(node); +} + +Node* Node::findNode(Node* node) +{ + if (m_nbChildren == 0) + return m_parent ? m_parent : this; + + // pick the child whose bounds will be extended least + + Node* pick = m_children[0]; + int minIncrease = pick->delta(node); + for (unsigned int i = 1; i < m_nbChildren; i++) { + int increase = m_children[i]->delta(node); + if (increase < minIncrease) { + minIncrease = increase; + pick = m_children[i]; + } + } + + return pick->findNode(node); +} + +void Node::tighten() +{ + recomputeBounds(m_minX, m_minY, m_maxX, m_maxY, + m_nbChildren, m_children, 0); +} + +int Node::delta(Node* node) +{ + return computeDeltaArea(node, m_minX, m_minY, m_maxX, m_maxY); +} + +void Node::simpleAdd(Node* node) +{ + node->setParent(this); + if (!m_children) + m_children = new Node*[m_tree->m_maxChildren + 1]; + m_children[m_nbChildren] = node; + m_nbChildren++; +} + +void Node::add(Node* node) +{ + simpleAdd(node); + Node* NN = 0; + if (m_nbChildren > m_tree->m_maxChildren) + NN = split(); + + adjustTree(this, NN); +} + +void Node::remove(Node* node) +{ + int nodeIndex = -1; + for (unsigned int i = 0; i < m_nbChildren; i++) { + if (m_children[i] == node) { + nodeIndex = i; + break; + } + } + if (nodeIndex == -1) + return; + + // compact + for (unsigned int i = nodeIndex; i < m_nbChildren - 1; i++) + m_children[i] = m_children[i + 1]; + m_nbChildren--; +} + +void Node::destroy(int index) +{ + delete m_children[index]; + // compact + for (unsigned int i = index; i < m_nbChildren - 1; i++) + m_children[i] = m_children[i + 1]; + m_nbChildren--; +} + +void Node::removeAll() +{ + m_nbChildren = 0; + m_minX = 0; + m_maxX = 0; + m_minY = 0; + m_maxY = 0; +} + +Node* Node::split() +{ + // First, let's get the seeds + // The idea is to get elements as distant as possible + // as we can, so that the resulting splitted lists + // will be more likely to not overlap. + Node* minElementX = m_children[0]; + Node* maxElementX = m_children[0]; + Node* minElementY = m_children[0]; + Node* maxElementY = m_children[0]; + for (unsigned int i = 1; i < m_nbChildren; i++) { + if (m_children[i]->m_minX < minElementX->m_minX) + minElementX = m_children[i]; + if (m_children[i]->m_minY < minElementY->m_minY) + minElementY = m_children[i]; + if (m_children[i]->m_maxX >= maxElementX->m_maxX) + maxElementX = m_children[i]; + if (m_children[i]->m_maxY >= maxElementY->m_maxY) + maxElementY = m_children[i]; + } + + int dx = maxElementX->m_maxX - minElementX->m_minX; + int dy = maxElementY->m_maxY - minElementY->m_minY; + + // assign the two seeds... + Node* elementA = minElementX; + Node* elementB = maxElementX; + + if (dx < dy) { + elementA = minElementY; + elementB = maxElementY; + } + + // If we get the same element, just get the first and + // last element inserted... + if (elementA == elementB) { + elementA = m_children[0]; + elementB = m_children[m_nbChildren - 1]; + } + +#ifdef DEBUG + ALOGV("split Node %d, dx: %d dy: %d elem A is %d, elem B is %d", + m_tid, dx, dy, elementA->m_tid, elementB->m_tid); +#endif + + // Let's use some temporary lists to do the split + ElementList* listA = m_tree->m_listA; + ElementList* listB = m_tree->m_listB; + listA->removeAll(); + listB->removeAll(); + + listA->add(elementA); + listB->add(elementB); + + remove(elementA); + remove(elementB); + + // For any remaining elements, insert it into the list + // resulting in the smallest growth + for (unsigned int i = 0; i < m_nbChildren; i++) { + Node* node = m_children[i]; + int dA = listA->delta(node); + int dB = listB->delta(node); + + if (dA < dB && listA->m_nbChildren < m_tree->m_maxChildren) + listA->add(node); + else if (dB < dA && listB->m_nbChildren < m_tree->m_maxChildren) + listB->add(node); + else { + ElementList* smallestList = + listA->m_nbChildren > listB->m_nbChildren ? listB : listA; + smallestList->add(node); + } + } + + // Use the list to rebuild the nodes + removeAll(); + for (unsigned int i = 0; i < listA->m_nbChildren; i++) + simpleAdd(listA->m_children[i]); + + Node* NN = Node::create(m_tree); + for (unsigned int i = 0; i < listB->m_nbChildren; i++) + NN->simpleAdd(listB->m_children[i]); + NN->tighten(); + + return NN; +} + +bool Node::isRoot() +{ + return m_tree->m_root == this; +} + +void Node::adjustTree(Node* N, Node* NN) +{ + bool callParent = N->updateBounds(); + + if (N->isRoot() && NN) { + // build new root + Node* root = Node::create(m_tree); +#ifdef DEBUG + ALOGV("-> node %d created as new root", root->m_tid); +#endif + root->simpleAdd(N); + root->simpleAdd(NN); + root->tighten(); + m_tree->m_root = root; + return; + } + + if (N->isRoot()) + return; + + if (N->m_parent) { + if (NN) + N->m_parent->add(NN); + else if (callParent) + adjustTree(N->m_parent, 0); + } +} + +bool Node::updateBounds() +{ + int ominx = m_minX; + int ominy = m_minY; + int omaxx = m_maxX; + int omaxy = m_maxY; + tighten(); + if ((ominx != m_minX) + || (ominy != m_minY) + || (omaxx != m_maxX) + || (omaxy != m_maxY)) + return true; + return false; +} + +#ifdef DEBUG +static int gMaxLevel = 0; +static int gNbNodes = 0; +static int gNbElements = 0; + +void Node::drawTree(int level) +{ + if (level == 0) { + ALOGV("\n*** show tree ***\n"); + gMaxLevel = 0; + gNbNodes = 0; + gNbElements = 0; + } + + display(level); + for (unsigned int i = 0; i < m_nbChildren; i++) + { + m_children[i]->drawTree(level + 1); + } + + if (gMaxLevel < level) + gMaxLevel = level; + + if (!m_nbChildren) + gNbElements++; + else + gNbNodes++; + + if (level == 0) { + ALOGV("********************\n"); + ALOGV("Depth level %d, total bytes: %d, %d nodes, %d bytes (%d bytes/node), %d elements, %d bytes (%d bytes/node)", + gMaxLevel, gNbNodes * sizeof(Node) + gNbElements * sizeof(Element), + gNbNodes, gNbNodes * sizeof(Node), sizeof(Node), + gNbElements, gNbElements * sizeof(Element), sizeof(Element)); + } +} +#endif + +#ifdef DEBUG +void Node::display(int level) +{ + ALOGV("%*sNode %d - %d, %d, %d, %d (%d x %d)", + 2*level, "", m_tid, m_minX, m_minY, m_maxX, m_maxY, m_maxX - m_minX, m_maxY - m_minY); +} +#endif + +bool Node::overlap(int minx, int miny, int maxx, int maxy) +{ + return ! (minx > m_maxX + || maxx < m_minX + || maxy < m_minY + || miny > m_maxY); +} + +void Node::search(int minx, int miny, int maxx, int maxy, Vector<WebCore::RecordingData*>& list) +{ + if (isElement() && overlap(minx, miny, maxx, maxy)) + list.append(this->m_payload); + + for (unsigned int i = 0; i < m_nbChildren; i++) { + if (m_children[i]->overlap(minx, miny, maxx, maxy)) + m_children[i]->search(minx, miny, maxx, maxy, list); + } +} + +bool Node::inside(int minx, int miny, int maxx, int maxy) +{ + return (minx <= m_minX + && maxx >= m_maxX + && miny <= m_minY + && maxy >= m_maxY); +} + +void Node::remove(int minx, int miny, int maxx, int maxy) +{ + for (unsigned int i = 0; i < m_nbChildren; i++) { + if (m_children[i]->inside(minx, miny, maxx, maxy)) + destroy(i); + else if (m_children[i]->overlap(minx, miny, maxx, maxy)) + m_children[i]->remove(minx, miny, maxx, maxy); + } +} + +} // Namespace RTree diff --git a/Source/WebCore/platform/graphics/android/context/RTree.h b/Source/WebCore/platform/graphics/android/context/RTree.h new file mode 100644 index 0000000..366e3d1 --- /dev/null +++ b/Source/WebCore/platform/graphics/android/context/RTree.h @@ -0,0 +1,180 @@ +/* + * Copyright 2012, 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 RTree_h +#define RTree_h + +#include <Vector.h> +#include "IntRect.h" +#include "GraphicsOperation.h" + +namespace WebCore { + +class LinearAllocator; + +class RecordingData { +public: + RecordingData(GraphicsOperation::Operation* ops, size_t orderBy) + : m_orderBy(orderBy) + , m_operation(ops) + {} + ~RecordingData() { + m_operation->~Operation(); + } + + size_t m_orderBy; + GraphicsOperation::Operation* m_operation; +}; + +} // namespace WebCore + +namespace RTree { + +class ElementList; +class Node; + +class RTree { +public: + // M -- max number of children per node + RTree(int M = 10); + ~RTree(); + + void insert(WebCore::IntRect& bounds, WebCore::RecordingData* payload); + // Does an overlap search + void search(WebCore::IntRect& clip, Vector<WebCore::RecordingData*>& list); + // Does an inclusive remove -- all elements fully inside the clip will + // be removed from the tree + void remove(WebCore::IntRect& clip); + void display(); + + void* allocateNode(); + void deleteNode(Node* n); + +private: + + Node* m_root; + unsigned m_maxChildren; + ElementList* m_listA; + ElementList* m_listB; + WebCore::LinearAllocator* m_allocator; + + friend class Node; +}; + +class ElementList { +public: + + ElementList(int size); + ~ElementList(); + void add(Node* n); + void tighten(); + int delta(Node* n); + void removeAll(); + void display(); + + Node** m_children; + unsigned m_nbChildren; + +private: + + int m_minX; + int m_maxX; + int m_minY; + int m_maxY; + int m_area; + bool m_didTighten; +}; + +class Node { +public: + static Node* gRoot; + + static Node* create(RTree* tree) { + return create(tree, 0, 0, 0, 0, 0); + } + + static Node* create(RTree* tree, int minx, int miny, int maxx, int maxy, + WebCore::RecordingData* payload) { + return new (tree->allocateNode()) Node(tree, minx, miny, maxx, maxy, payload); + } + + ~Node(); + + void insert(Node* n); + void search(int minx, int miny, int maxx, int maxy, Vector<WebCore::RecordingData*>& list); + void remove(int minx, int miny, int maxx, int maxy); + + // Intentionally not implemented as Node* is custom allocated, we don't want to use this + void operator delete(void*); + +private: + Node(RTree* tree, int minx, int miny, int maxx, int maxy, WebCore::RecordingData* payload); + + void setParent(Node* n); + Node* findNode(Node* n); + void simpleAdd(Node* n); + void add(Node* n); + void remove(Node* n); + void destroy(int index); + void removeAll(); + Node* split(); + void adjustTree(Node* N, Node* NN); + void tighten(); + bool updateBounds(); + int delta(Node* n); + + bool overlap(int minx, int miny, int maxx, int maxy); + bool inside(int minx, int miny, int maxx, int maxy); + + bool isElement() { return m_payload; } + bool isRoot(); + +private: + + RTree* m_tree; + Node* m_parent; + + Node** m_children; + unsigned m_nbChildren; + + WebCore::RecordingData* m_payload; + +public: + + int m_minX; + int m_minY; + int m_maxX; + int m_maxY; + +#ifdef DEBUG + void drawTree(int level = 0); + void display(int level = 0); + unsigned m_tid; +#endif +}; + +} // namespace RTree + +#endif // RTree_h diff --git a/Source/WebCore/platform/graphics/android/context/RecordingContextCanvasProxy.cpp b/Source/WebCore/platform/graphics/android/context/RecordingContextCanvasProxy.cpp new file mode 100644 index 0000000..838e450 --- /dev/null +++ b/Source/WebCore/platform/graphics/android/context/RecordingContextCanvasProxy.cpp @@ -0,0 +1,68 @@ +/* + * Copyright 2012, 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 "RecordingContextCanvasProxy.h" + +#include "PlatformGraphicsContextRecording.h" + +namespace WebCore { + +// Return value is unused by FontAndroid +int RecordingContextCanvasProxy::save(SaveFlags) +{ + m_pgc->save(); + return -1; +} + +void RecordingContextCanvasProxy::restore() +{ + m_pgc->restore(); +} + +void RecordingContextCanvasProxy::drawPosText(const void* text, + size_t byteLength, + const SkPoint pos[], + const SkPaint& paint) +{ + m_pgc->drawPosText(text, byteLength, pos, paint); +} + +void RecordingContextCanvasProxy::drawBitmapRect(const SkBitmap& bitmap, + const SkIRect* src, + const SkRect& dst, + const SkPaint*) +{ + m_pgc->drawBitmapRect(bitmap, src, dst); +} + +// Return value is unused by FontAndroid +bool RecordingContextCanvasProxy::rotate(SkScalar degrees) +{ + m_pgc->rotate(degrees / (180.0f / 3.14159265f)); + return true; +} + +} // WebCore diff --git a/Source/WebCore/platform/graphics/android/context/RecordingContextCanvasProxy.h b/Source/WebCore/platform/graphics/android/context/RecordingContextCanvasProxy.h new file mode 100644 index 0000000..4daf5e7 --- /dev/null +++ b/Source/WebCore/platform/graphics/android/context/RecordingContextCanvasProxy.h @@ -0,0 +1,102 @@ +/* + * Copyright 2012, 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 RecordingContextCanvasProxy_h +#define RecordingContextCanvasProxy_h + +#include "SkCanvas.h" + +namespace WebCore { + +class PlatformGraphicsContextRecording; + +class RecordingContextCanvasProxy : public SkCanvas { +public: + RecordingContextCanvasProxy(PlatformGraphicsContextRecording* pgc) + : m_pgc(pgc) + {} + + // Used by FontAndroid + + // Return value is unused by FontAndroid + virtual int save(SaveFlags); + virtual void restore(); + virtual void drawPosText(const void* text, size_t byteLength, + const SkPoint pos[], const SkPaint& paint); + virtual bool rotate(SkScalar degrees); + + // Used by EmojiFont + + virtual void drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src, + const SkRect& dst, const SkPaint*); + + // These aren't used by anyone + + virtual int saveLayer(const SkRect* bounds, const SkPaint*, SaveFlags) { /* NOT IMPLEMENTED*/ CRASH(); return -1; } + virtual bool translate(SkScalar dx, SkScalar dy) { /* NOT IMPLEMENTED*/ CRASH(); return -1; } + virtual bool scale(SkScalar sx, SkScalar sy) { /* NOT IMPLEMENTED*/ CRASH(); return -1; } + virtual bool skew(SkScalar sx, SkScalar sy) { /* NOT IMPLEMENTED*/ CRASH(); return -1; } + virtual bool concat(const SkMatrix& matrix) { /* NOT IMPLEMENTED*/ CRASH(); return -1; } + virtual void setMatrix(const SkMatrix& matrix) { /* NOT IMPLEMENTED*/ CRASH(); } + virtual bool clipRect(const SkRect&, SkRegion::Op, bool) { /* NOT IMPLEMENTED*/ CRASH(); return -1; } + virtual bool clipPath(const SkPath&, SkRegion::Op, bool) { /* NOT IMPLEMENTED*/ CRASH(); return -1; } + virtual bool clipRegion(const SkRegion& region, SkRegion::Op op) { /* NOT IMPLEMENTED*/ CRASH(); return -1; } + virtual void clear(SkColor) { /* NOT IMPLEMENTED*/ CRASH(); } + virtual void drawPaint(const SkPaint& paint) { /* NOT IMPLEMENTED*/ CRASH(); } + virtual void drawPoints(PointMode, size_t count, const SkPoint pts[], + const SkPaint&) { /* NOT IMPLEMENTED*/ CRASH(); } + virtual void drawRect(const SkRect& rect, const SkPaint&) { /* NOT IMPLEMENTED*/ CRASH(); } + virtual void drawPath(const SkPath& path, const SkPaint&) { /* NOT IMPLEMENTED*/ CRASH(); } + virtual void drawBitmap(const SkBitmap&, SkScalar left, SkScalar top, + const SkPaint*) { /* NOT IMPLEMENTED*/ CRASH(); } + virtual void drawBitmapMatrix(const SkBitmap&, const SkMatrix&, + const SkPaint*) { /* NOT IMPLEMENTED*/ CRASH(); } + virtual void drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, + const SkRect& dst, const SkPaint*) { /* NOT IMPLEMENTED*/ CRASH(); } + virtual void drawSprite(const SkBitmap&, int left, int top, + const SkPaint*) { /* NOT IMPLEMENTED*/ CRASH(); } + virtual void drawText(const void* text, size_t byteLength, SkScalar x, + SkScalar y, const SkPaint&) { /* NOT IMPLEMENTED*/ CRASH(); } + virtual void drawPosTextH(const void* text, size_t byteLength, + const SkScalar xpos[], SkScalar constY, const SkPaint&) { /* NOT IMPLEMENTED*/ CRASH(); } + virtual void drawTextOnPath(const void* text, size_t byteLength, + const SkPath& path, const SkMatrix* matrix, + const SkPaint&) { /* NOT IMPLEMENTED*/ CRASH(); } + virtual void drawPicture(SkPicture& picture) { /* NOT IMPLEMENTED*/ CRASH(); } + virtual void drawVertices(VertexMode, int vertexCount, + const SkPoint vertices[], const SkPoint texs[], + const SkColor colors[], SkXfermode*, + const uint16_t indices[], int indexCount, + const SkPaint&) { /* NOT IMPLEMENTED*/ CRASH(); } + virtual void drawData(const void*, size_t) { /* NOT IMPLEMENTED*/ CRASH(); } + virtual bool isDrawingToLayer() const { /* NOT IMPLEMENTED*/ CRASH(); return -1; } + +private: + PlatformGraphicsContextRecording* m_pgc; +}; + +} // namespace WebCore + +#endif // RecordingContextCanvasProxy_h diff --git a/Source/WebCore/platform/graphics/android/fonts/FontAndroid.cpp b/Source/WebCore/platform/graphics/android/fonts/FontAndroid.cpp index 7bed5bb..fcb78ed 100644 --- a/Source/WebCore/platform/graphics/android/fonts/FontAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/fonts/FontAndroid.cpp @@ -26,8 +26,10 @@ #include "config.h" +#define LOG_TAG "FontAndroid" + +#include "AndroidLog.h" #include "EmojiFont.h" -#include "GraphicsOperationCollection.h" #include "GraphicsOperation.h" #include "Font.h" #include "FontData.h" @@ -45,6 +47,7 @@ #include "SkTypeface.h" #include "SkUtils.h" #include "TextRun.h" +#include "SkTypeface_android.h" #ifdef SUPPORT_COMPLEX_SCRIPTS #include "HarfbuzzSkia.h" @@ -191,6 +194,12 @@ void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font, // compile-time assert SkASSERT(sizeof(GlyphBufferGlyph) == sizeof(uint16_t)); + if (numGlyphs == 1 && glyphBuffer.glyphAt(from) == 0x3) { + // Webkit likes to draw end text control command for some reason + // Just ignore it + return; + } + SkPaint paint; if (!setupForText(&paint, gc, font)) { return; @@ -220,10 +229,11 @@ void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font, int localCount = 0; for (int i = 0; i < numGlyphs; i++) { if (EmojiFont::IsEmojiGlyph(glyphs[i])) { - if (localCount) + if (localCount) { canvas->drawPosText(&glyphs[localIndex], - localCount * sizeof(uint16_t), - &pos[localIndex], paint); + localCount * sizeof(uint16_t), + &pos[localIndex], paint); + } EmojiFont::Draw(canvas, glyphs[i], x, y, paint); // reset local index/count track for "real" glyphs localCount = 0; @@ -236,10 +246,11 @@ void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font, y += SkFloatToScalar(adv[i].height()); } // draw the last run of glyphs (if any) - if (localCount) + if (localCount) { canvas->drawPosText(&glyphs[localIndex], - localCount * sizeof(uint16_t), - &pos[localIndex], paint); + localCount * sizeof(uint16_t), + &pos[localIndex], paint); + } } else { for (int i = 0; i < numGlyphs; i++) { pos[i].set(x, y); @@ -255,13 +266,12 @@ void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font, rotator.setRotate(90); rotator.mapPoints(pos, numGlyphs); } - - canvas->drawPosText(glyphs, numGlyphs * sizeof(uint16_t), pos, paint); + canvas->drawPosText(glyphs, + numGlyphs * sizeof(uint16_t), pos, paint); if (font->platformData().orientation() == Vertical) canvas->restore(); } - gc->platformContext()->endRecording(); } void Font::drawEmphasisMarksForComplexText(WebCore::GraphicsContext*, WebCore::TextRun const&, WTF::AtomicString const&, WebCore::FloatPoint const&, int, int) const @@ -461,26 +471,8 @@ public: } private: - enum CustomScript { - Bengali, - Devanagari, - Hebrew, - HebrewBold, - Kannada, - Malayalam, - Naskh, - Tamil, - TamilBold, - Telugu, - Thai, - NUM_SCRIPTS - }; - - static const char* paths[NUM_SCRIPTS]; - void setupFontForScriptRun(); - const FontPlatformData* setupComplexFont(CustomScript script, - const FontPlatformData& platformData); + const FontPlatformData* setupComplexFont(HB_Script script, const FontPlatformData& platformData); HB_FontRec* allocHarfbuzzFont(); void deleteGlyphArrays(); void createGlyphArrays(int); @@ -522,22 +514,6 @@ private: unsigned m_letterSpacing; // pixels to be added after each glyph. }; - -// Indexed using enum CustomScript -const char* TextRunWalker::paths[] = { - "/system/fonts/Lohit-Bengali.ttf", - "/system/fonts/DroidSansDevanagari-Regular.ttf", - "/system/fonts/DroidSansHebrew-Regular.ttf", - "/system/fonts/DroidSansHebrew-Bold.ttf", - "/system/fonts/Lohit-Kannada.ttf", - "/system/fonts/AnjaliNewLipi-light.ttf", - "/system/fonts/DroidNaskh-Regular.ttf", - "/system/fonts/DroidSansTamil-Regular.ttf", - "/system/fonts/DroidSansTamil-Bold.ttf", - "/system/fonts/Lohit-Telugu.ttf", - "/system/fonts/DroidSansThai.ttf" -}; - TextRunWalker::TextRunWalker(const TextRun& run, int startingX, int startingY, const Font* font) : m_font(font) , m_startingX(startingX) @@ -692,8 +668,7 @@ void TextRunWalker::setWordAndLetterSpacing(int wordSpacingAdjustment, } const FontPlatformData* TextRunWalker::setupComplexFont( - CustomScript script, - const FontPlatformData& platformData) + HB_Script script, const FontPlatformData& platformData) { static FallbackHash fallbackPlatformData; @@ -703,15 +678,19 @@ const FontPlatformData* TextRunWalker::setupComplexFont( // italic, then bold italic. additional fake style bits can be added. int scriptStyleIndex = script; if (platformData.isFakeBold()) - scriptStyleIndex += NUM_SCRIPTS; + scriptStyleIndex += HB_ScriptCount; if (platformData.isFakeItalic()) - scriptStyleIndex += NUM_SCRIPTS << 1; + scriptStyleIndex += HB_ScriptCount << 1; FallbackFontKey key(scriptStyleIndex, platformData.size()); FontPlatformData* newPlatformData = 0; if (!fallbackPlatformData.contains(key)) { - SkTypeface* typeface = SkTypeface::CreateFromFile(paths[script]); + SkTypeface::Style currentStyle = SkTypeface::kNormal; + if (platformData.typeface()) + currentStyle = platformData.typeface()->style(); + SkTypeface* typeface = SkCreateTypefaceForScript(script, currentStyle, + SkPaint::kElegant_Variant); newPlatformData = new FontPlatformData(platformData, typeface); SkSafeUnref(typeface); fallbackPlatformData.set(key, newPlatformData); @@ -729,61 +708,8 @@ void TextRunWalker::setupFontForScriptRun() const FontData* fontData = m_font->glyphDataForCharacter(m_run[0], false).fontData; const FontPlatformData& platformData = fontData->fontDataForCharacter(' ')->platformData(); - const FontPlatformData* complexPlatformData = &platformData; - - switch (m_item.item.script) { - case HB_Script_Bengali: - complexPlatformData = setupComplexFont(Bengali, platformData); - break; - case HB_Script_Devanagari: - complexPlatformData = setupComplexFont(Devanagari, platformData); - break; - case HB_Script_Hebrew: - switch (platformData.typeface()->style()) { - case SkTypeface::kBold: - case SkTypeface::kBoldItalic: - complexPlatformData = setupComplexFont(HebrewBold, platformData); - break; - case SkTypeface::kNormal: - case SkTypeface::kItalic: - default: - complexPlatformData = setupComplexFont(Hebrew, platformData); - break; - } - break; - case HB_Script_Kannada: - complexPlatformData = setupComplexFont(Kannada, platformData); - break; - case HB_Script_Malayalam: - complexPlatformData = setupComplexFont(Malayalam, platformData); - break; - case HB_Script_Arabic: - complexPlatformData = setupComplexFont(Naskh, platformData); - break; - case HB_Script_Tamil: - switch (platformData.typeface()->style()) { - case SkTypeface::kBold: - case SkTypeface::kBoldItalic: - complexPlatformData = setupComplexFont(TamilBold, platformData); - break; - case SkTypeface::kNormal: - case SkTypeface::kItalic: - default: - complexPlatformData = setupComplexFont(Tamil, platformData); - break; - } - break; - case HB_Script_Telugu: - complexPlatformData = setupComplexFont(Telugu, platformData); - break; - case HB_Script_Thai: - complexPlatformData = setupComplexFont(Thai, platformData); - break; - default: - // HB_Script_Common; includes Ethiopic - complexPlatformData = &platformData; - break; - } + const FontPlatformData* complexPlatformData = setupComplexFont(m_item.item.script, platformData); + m_item.face = complexPlatformData->harfbuzzFace(); m_item.font->userData = const_cast<FontPlatformData*>(complexPlatformData); @@ -1113,18 +1039,17 @@ void Font::drawComplexText(GraphicsContext* gc, TextRun const& run, if (fill) { walker.fontPlatformDataForScriptRun()->setupPaint(&fillPaint); adjustTextRenderMode(&fillPaint, haveMultipleLayers); - canvas->drawPosText(walker.glyphs(), walker.length() << 1, - walker.positions(), fillPaint); + canvas->drawPosText(walker.glyphs(), + walker.length() << 1, walker.positions(), fillPaint); } if (stroke) { walker.fontPlatformDataForScriptRun()->setupPaint(&strokePaint); adjustTextRenderMode(&strokePaint, haveMultipleLayers); - canvas->drawPosText(walker.glyphs(), walker.length() << 1, - walker.positions(), strokePaint); + canvas->drawPosText(walker.glyphs(), + walker.length() << 1, walker.positions(), strokePaint); } } - gc->platformContext()->endRecording(); } float Font::floatWidthForComplexText(const TextRun& run, diff --git a/Source/WebCore/platform/graphics/android/layers/CanvasTexture.cpp b/Source/WebCore/platform/graphics/android/layers/CanvasTexture.cpp index e4b2bc6..aacb0bc 100644 --- a/Source/WebCore/platform/graphics/android/layers/CanvasTexture.cpp +++ b/Source/WebCore/platform/graphics/android/layers/CanvasTexture.cpp @@ -31,7 +31,6 @@ #if USE(ACCELERATED_COMPOSITING) -#include "android_graphics.h" #include "AndroidLog.h" #include "GLUtils.h" #include "Image.h" @@ -134,10 +133,10 @@ bool CanvasTexture::uploadImageBuffer(ImageBuffer* imageBuffer) // Size mismatch, early abort (will fall back to software) if (imageBuffer->size() != m_size) return false; - GraphicsContext* gc = imageBuffer ? imageBuffer->context() : 0; - if (!gc) + SkCanvas* canvas = imageBufferCanvas(imageBuffer); + if (!canvas) return false; - const SkBitmap& bitmap = android_gc2canvas(gc)->getDevice()->accessBitmap(false); + const SkBitmap& bitmap = canvas->getDevice()->accessBitmap(false); if (!GLUtils::updateSharedSurfaceTextureWithBitmap(anw, bitmap)) return false; m_hasValidTexture = true; diff --git a/Source/WebCore/platform/graphics/android/layers/DumpLayer.cpp b/Source/WebCore/platform/graphics/android/layers/DumpLayer.cpp index 5551965..d827c44 100644 --- a/Source/WebCore/platform/graphics/android/layers/DumpLayer.cpp +++ b/Source/WebCore/platform/graphics/android/layers/DumpLayer.cpp @@ -3,79 +3,87 @@ #if USE(ACCELERATED_COMPOSITING) +#define WRITE_VAL(format, ...) (snprintf(m_valueBuffer, BUF_SIZE, format, __VA_ARGS__), writeEntry(label, m_valueBuffer)) + namespace WebCore { -void lwrite(FILE* file, const char* str) +void LayerDumper::writeIntVal(const char* label, int value) { - fwrite(str, sizeof(char), strlen(str), file); + WRITE_VAL("%d", value); } -void writeIndent(FILE* file, int indentLevel) +void LayerDumper::writeHexVal(const char* label, int value) { - if (indentLevel) - fprintf(file, "%*s", indentLevel*2, " "); + WRITE_VAL("%x", value); } -void writeln(FILE* file, int indentLevel, const char* str) +void LayerDumper::writeFloatVal(const char* label, float value) { - writeIndent(file, indentLevel); - lwrite(file, str); - lwrite(file, "\n"); + WRITE_VAL("%.3f", value); } -void writeIntVal(FILE* file, int indentLevel, const char* str, int value) +void LayerDumper::writePoint(const char* label, SkPoint point) { - writeIndent(file, indentLevel); - fprintf(file, "%s = %d;\n", str, value); + WRITE_VAL("{ x = %.3f; y = %.3f; }", point.fX, point.fY); } -void writeHexVal(FILE* file, int indentLevel, const char* str, int value) +void LayerDumper::writeIntPoint(const char* label, IntPoint point) { - writeIndent(file, indentLevel); - fprintf(file, "%s = %x;\n", str, value); + WRITE_VAL("{ x = %d; y = %d; }", point.x(), point.y()); } -void writeFloatVal(FILE* file, int indentLevel, const char* str, float value) +void LayerDumper::writeSize(const char* label, SkSize size) { - writeIndent(file, indentLevel); - fprintf(file, "%s = %.3f;\n", str, value); + WRITE_VAL("{ w = %.3f; h = %.3f; }", size.width(), size.height()); } -void writePoint(FILE* file, int indentLevel, const char* str, SkPoint point) +void LayerDumper::writeRect(const char* label, SkRect rect) { - writeIndent(file, indentLevel); - fprintf(file, "%s = { x = %.3f; y = %.3f; };\n", str, point.fX, point.fY); + WRITE_VAL("{ x = %.3f; y = %.3f; w = %.3f; h = %.3f; }", + rect.fLeft, rect.fTop, rect.width(), rect.height()); } -void writeIntPoint(FILE* file, int indentLevel, const char* str, IntPoint point) +void LayerDumper::writeMatrix(const char* label, const TransformationMatrix& matrix) { - writeIndent(file, indentLevel); - fprintf(file, "%s = { x = %d; y = %d; };\n", str, point.x(), point.y()); + WRITE_VAL("{ (%.2f,%.2f,%.2f,%.2f),(%.2f,%.2f,%.2f,%.2f)," + "(%.2f,%.2f,%.2f,%.2f),(%.2f,%.2f,%.2f,%.2f) }", + matrix.m11(), matrix.m12(), matrix.m13(), matrix.m14(), + matrix.m21(), matrix.m22(), matrix.m23(), matrix.m24(), + matrix.m31(), matrix.m32(), matrix.m33(), matrix.m34(), + matrix.m41(), matrix.m42(), matrix.m43(), matrix.m44()); } -void writeSize(FILE* file, int indentLevel, const char* str, SkSize size) +void LayerDumper::writeLength(const char* label, SkLength value) { - writeIndent(file, indentLevel); - fprintf(file, "%s = { w = %.3f; h = %.3f; };\n", str, size.width(), size.height()); + if (value.defined()) + WRITE_VAL("{ type = %d; value = %.2f; }", value.type, value.value); + else + writeEntry(label, "<undefined>"); } -void writeRect(FILE* file, int indentLevel, const char* str, SkRect rect) +void FileLayerDumper::beginLayer(const char* className, const LayerAndroid* layerPtr) { - writeIndent(file, indentLevel); - fprintf(file, "%s = { x = %.3f; y = %.3f; w = %.3f; h = %.3f; };\n", - str, rect.fLeft, rect.fTop, rect.width(), rect.height()); + LayerDumper::beginLayer(className, layerPtr); + writeLine("{"); + writeHexVal("layer", (int)layerPtr); } -void writeMatrix(FILE* file, int indentLevel, const char* str, const TransformationMatrix& matrix) +void FileLayerDumper::endLayer() { - writeIndent(file, indentLevel); - fprintf(file, "%s = { (%.2f,%.2f,%.2f,%.2f),(%.2f,%.2f,%.2f,%.2f)," - "(%.2f,%.2f,%.2f,%.2f),(%.2f,%.2f,%.2f,%.2f) };\n", - str, - matrix.m11(), matrix.m12(), matrix.m13(), matrix.m14(), - matrix.m21(), matrix.m22(), matrix.m23(), matrix.m24(), - matrix.m31(), matrix.m32(), matrix.m33(), matrix.m34(), - matrix.m41(), matrix.m42(), matrix.m43(), matrix.m44()); + writeLine("}"); + LayerDumper::endLayer(); +} + +void FileLayerDumper::writeEntry(const char* label, const char* value) +{ + fprintf(m_file, "%*s%s = %s\n", (m_indentLevel + 1) * 2, " ", label, value); +} + +void FileLayerDumper::writeLine(const char* str) +{ + if (m_indentLevel) + fprintf(m_file, "%*s", m_indentLevel * 2, " "); + fprintf(m_file, "%s\n", str); } } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/layers/DumpLayer.h b/Source/WebCore/platform/graphics/android/layers/DumpLayer.h index 5b30952..9fd3365 100644 --- a/Source/WebCore/platform/graphics/android/layers/DumpLayer.h +++ b/Source/WebCore/platform/graphics/android/layers/DumpLayer.h @@ -17,7 +17,9 @@ #ifndef DumpLayer_h #define DumpLayer_h +#include "FixedPositioning.h" #include "IntPoint.h" +#include "LayerAndroid.h" #include "SkPoint.h" #include "SkRect.h" #include "SkSize.h" @@ -50,17 +52,59 @@ namespace WebCore { -void lwrite(FILE* file, const char* str); -void writeIndent(FILE* file, int indentLevel); -void writeln(FILE* file, int indentLevel, const char* str); -void writeIntVal(FILE* file, int indentLevel, const char* str, int value); -void writeHexVal(FILE* file, int indentLevel, const char* str, int value); -void writeFloatVal(FILE* file, int indentLevel, const char* str, float value); -void writePoint(FILE* file, int indentLevel, const char* str, SkPoint point); -void writeIntPoint(FILE* file, int indentLevel, const char* str, IntPoint point); -void writeSize(FILE* file, int indentLevel, const char* str, SkSize size); -void writeRect(FILE* file, int indentLevel, const char* str, SkRect rect); -void writeMatrix(FILE* file, int indentLevel, const char* str, const TransformationMatrix& matrix); +class LayerDumper { +public: + LayerDumper(int initialIndentLevel = 0) + : m_indentLevel(initialIndentLevel) + {} + virtual ~LayerDumper() {} + + virtual void beginLayer(const char* className, const LayerAndroid* layerPtr) {} + + virtual void endLayer() {} + + virtual void beginChildren(int childCount) { + m_indentLevel++; + } + virtual void endChildren() { + m_indentLevel--; + } + + void writeIntVal(const char* label, int value); + void writeHexVal(const char* label, int value); + void writeFloatVal(const char* label, float value); + void writePoint(const char* label, SkPoint value); + void writeIntPoint(const char* label, IntPoint value); + void writeSize(const char* label, SkSize value); + void writeRect(const char* label, SkRect value); + void writeMatrix(const char* label, const TransformationMatrix& value); + void writeLength(const char* label, SkLength value); + +protected: + virtual void writeEntry(const char* label, const char* value) = 0; + + int m_indentLevel; + +private: + static const int BUF_SIZE = 4096; + char m_valueBuffer[BUF_SIZE]; +}; + +class FileLayerDumper : public LayerDumper { +public: + FileLayerDumper(FILE* file) + : m_file(file) + {} + + virtual void beginLayer(const char* className, const LayerAndroid* layerPtr); + virtual void endLayer(); +protected: + virtual void writeEntry(const char* label, const char* value); + +private: + void writeLine(const char* str); + FILE* m_file; +}; } diff --git a/Source/WebCore/platform/graphics/android/layers/FixedPositioning.cpp b/Source/WebCore/platform/graphics/android/layers/FixedPositioning.cpp index 82afe8f..aa204f8 100644 --- a/Source/WebCore/platform/graphics/android/layers/FixedPositioning.cpp +++ b/Source/WebCore/platform/graphics/android/layers/FixedPositioning.cpp @@ -86,25 +86,17 @@ void FixedPositioning::contentDraw(SkCanvas* canvas, Layer::PaintStyle style) } } -void writeLength(FILE* file, int indentLevel, const char* str, SkLength length) +void FixedPositioning::dumpLayer(LayerDumper* dumper) const { - if (!length.defined()) - return; - writeIndent(file, indentLevel); - fprintf(file, "%s = { type = %d; value = %.2f; };\n", str, length.type, length.value); -} - -void FixedPositioning::dumpLayer(FILE* file, int indentLevel) const -{ - writeLength(file, indentLevel + 1, "fixedLeft", m_fixedLeft); - writeLength(file, indentLevel + 1, "fixedTop", m_fixedTop); - writeLength(file, indentLevel + 1, "fixedRight", m_fixedRight); - writeLength(file, indentLevel + 1, "fixedBottom", m_fixedBottom); - writeLength(file, indentLevel + 1, "fixedMarginLeft", m_fixedMarginLeft); - writeLength(file, indentLevel + 1, "fixedMarginTop", m_fixedMarginTop); - writeLength(file, indentLevel + 1, "fixedMarginRight", m_fixedMarginRight); - writeLength(file, indentLevel + 1, "fixedMarginBottom", m_fixedMarginBottom); - writeRect(file, indentLevel + 1, "fixedRect", m_fixedRect); + dumper->writeLength("fixedLeft", m_fixedLeft); + dumper->writeLength("fixedTop", m_fixedTop); + dumper->writeLength("fixedRight", m_fixedRight); + dumper->writeLength("fixedBottom", m_fixedBottom); + dumper->writeLength("fixedMarginLeft", m_fixedMarginLeft); + dumper->writeLength("fixedMarginTop", m_fixedMarginTop); + dumper->writeLength("fixedMarginRight", m_fixedMarginRight); + dumper->writeLength("fixedMarginBottom", m_fixedMarginBottom); + dumper->writeRect("fixedRect", m_fixedRect); } BackgroundImagePositioning::BackgroundImagePositioning(LayerAndroid* layer, const BackgroundImagePositioning& position) diff --git a/Source/WebCore/platform/graphics/android/layers/FixedPositioning.h b/Source/WebCore/platform/graphics/android/layers/FixedPositioning.h index e273a25..ac838c8 100644 --- a/Source/WebCore/platform/graphics/android/layers/FixedPositioning.h +++ b/Source/WebCore/platform/graphics/android/layers/FixedPositioning.h @@ -130,7 +130,7 @@ public: void contentDraw(SkCanvas* canvas, Layer::PaintStyle style); - void dumpLayer(FILE*, int indentLevel) const; + void dumpLayer(LayerDumper*) const; // ViewStateSerializer friends friend void android::serializeLayer(LayerAndroid* layer, SkWStream* stream); diff --git a/Source/WebCore/platform/graphics/android/layers/IFrameLayerAndroid.cpp b/Source/WebCore/platform/graphics/android/layers/IFrameLayerAndroid.cpp index 3532542..4481f55 100644 --- a/Source/WebCore/platform/graphics/android/layers/IFrameLayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/layers/IFrameLayerAndroid.cpp @@ -29,10 +29,10 @@ IFrameLayerAndroid* IFrameLayerAndroid::updatePosition(SkRect viewport, return this; } -void IFrameLayerAndroid::dumpLayer(FILE* file, int indentLevel) const +void IFrameLayerAndroid::dumpLayer(LayerDumper* dumper) const { - writeIntVal(file, indentLevel + 1, "m_isIframe", true); - writeIntPoint(file, indentLevel + 1, "m_iframeOffset", m_iframeOffset); + LayerAndroid::dumpLayer(dumper); + dumper->writeIntPoint("m_iframeOffset", m_iframeOffset); } } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/layers/IFrameLayerAndroid.h b/Source/WebCore/platform/graphics/android/layers/IFrameLayerAndroid.h index f2fbf49..08e7212 100644 --- a/Source/WebCore/platform/graphics/android/layers/IFrameLayerAndroid.h +++ b/Source/WebCore/platform/graphics/android/layers/IFrameLayerAndroid.h @@ -53,7 +53,7 @@ public: virtual IFrameLayerAndroid* updatePosition(SkRect viewport, IFrameLayerAndroid* parentIframeLayer); - virtual void dumpLayer(FILE*, int indentLevel) const; + virtual void dumpLayer(LayerDumper*) const; const IntPoint& iframeOffset() const { return m_iframeOffset; } diff --git a/Source/WebCore/platform/graphics/android/layers/LayerAndroid.cpp b/Source/WebCore/platform/graphics/android/layers/LayerAndroid.cpp index 228a30e..438d96c 100644 --- a/Source/WebCore/platform/graphics/android/layers/LayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/layers/LayerAndroid.cpp @@ -601,7 +601,7 @@ void LayerAndroid::showLayer(int indent) m_clippingRect.width(), m_clippingRect.height()); ALOGD("%s s:%x %s %s (%d) [%d:%x - 0x%x] - %s %s - area (%d, %d, %d, %d) - visible (%d, %d, %d, %d) " "clip (%d, %d, %d, %d) %s %s m_content(%x), pic w: %d h: %d originalLayer: %x %d", - spaces, m_surface, m_haveClip ? "CLIP LAYER" : "", subclassName().ascii().data(), + spaces, m_surface, m_haveClip ? "CLIP LAYER" : "", subclassName(), subclassType(), uniqueId(), this, m_owningLayer, needsTexture() ? "needsTexture" : "", m_imageCRC ? "hasImage" : "", @@ -954,60 +954,42 @@ void LayerAndroid::setFixedPosition(FixedPositioning* position) { m_fixedPosition = position; } -void LayerAndroid::dumpLayer(FILE* file, int indentLevel) const +void LayerAndroid::dumpLayer(LayerDumper* dumper) const { - writeHexVal(file, indentLevel + 1, "layer", (int)this); - writeIntVal(file, indentLevel + 1, "layerId", m_uniqueId); - writeIntVal(file, indentLevel + 1, "haveClip", m_haveClip); - writeIntVal(file, indentLevel + 1, "isFixed", isPositionFixed()); + dumper->writeIntVal("layerId", m_uniqueId); + dumper->writeIntVal("haveClip", m_haveClip); + dumper->writeIntVal("isFixed", isPositionFixed()); - writeFloatVal(file, indentLevel + 1, "opacity", getOpacity()); - writeSize(file, indentLevel + 1, "size", getSize()); - writePoint(file, indentLevel + 1, "position", getPosition()); - writePoint(file, indentLevel + 1, "anchor", getAnchorPoint()); + dumper->writeFloatVal("opacity", getOpacity()); + dumper->writeSize("size", getSize()); + dumper->writePoint("position", getPosition()); + dumper->writePoint("anchor", getAnchorPoint()); - writeMatrix(file, indentLevel + 1, "drawMatrix", m_drawTransform); - writeMatrix(file, indentLevel + 1, "transformMatrix", m_transform); - writeRect(file, indentLevel + 1, "clippingRect", SkRect(m_clippingRect)); + dumper->writeMatrix("drawMatrix", m_drawTransform); + dumper->writeMatrix("transformMatrix", m_transform); + dumper->writeRect("clippingRect", SkRect(m_clippingRect)); if (m_content) { - writeIntVal(file, indentLevel + 1, "m_content.width", m_content->width()); - writeIntVal(file, indentLevel + 1, "m_content.height", m_content->height()); + dumper->writeIntVal("m_content.width", m_content->width()); + dumper->writeIntVal("m_content.height", m_content->height()); } if (m_fixedPosition) - return m_fixedPosition->dumpLayer(file, indentLevel); + m_fixedPosition->dumpLayer(dumper); } -void LayerAndroid::dumpLayers(FILE* file, int indentLevel) const +void LayerAndroid::dumpLayers(LayerDumper* dumper) const { - writeln(file, indentLevel, "{"); - - dumpLayer(file, indentLevel); + dumper->beginLayer(subclassName(), this); + dumpLayer(dumper); + dumper->beginChildren(countChildren()); if (countChildren()) { - writeln(file, indentLevel + 1, "children = ["); - for (int i = 0; i < countChildren(); i++) { - if (i > 0) - writeln(file, indentLevel + 1, ", "); - getChild(i)->dumpLayers(file, indentLevel + 1); - } - writeln(file, indentLevel + 1, "];"); + for (int i = 0; i < countChildren(); i++) + getChild(i)->dumpLayers(dumper); } - writeln(file, indentLevel, "}"); -} - -void LayerAndroid::dumpToLog() const -{ - FILE* file = fopen("/data/data/com.android.browser/layertmp", "w"); - dumpLayers(file, 0); - fclose(file); - file = fopen("/data/data/com.android.browser/layertmp", "r"); - char buffer[512]; - bzero(buffer, sizeof(buffer)); - while (fgets(buffer, sizeof(buffer), file)) - SkDebugf("%s", buffer); - fclose(file); + dumper->endChildren(); + dumper->endLayer(); } LayerAndroid* LayerAndroid::findById(int match) diff --git a/Source/WebCore/platform/graphics/android/layers/LayerAndroid.h b/Source/WebCore/platform/graphics/android/layers/LayerAndroid.h index 41f6420..b28daef 100644 --- a/Source/WebCore/platform/graphics/android/layers/LayerAndroid.h +++ b/Source/WebCore/platform/graphics/android/layers/LayerAndroid.h @@ -73,6 +73,7 @@ class IFrameLayerAndroid; class LayerMergeState; class RenderLayer; class PaintedSurface; +class LayerDumper; class TexturesResult { public: @@ -100,7 +101,7 @@ public: CanvasLayer, BaseLayer } SubclassType; typedef enum { InvalidateNone = 0, InvalidateLayers } InvalidateFlags; - String subclassName() + const char* subclassName() const { switch (subclassType()) { case LayerAndroid::StandardLayer: @@ -195,9 +196,7 @@ public: bool hasAnimations() const; void addDirtyArea(); - virtual void dumpLayer(FILE*, int indentLevel) const; - void dumpLayers(FILE*, int indentLevel) const; - void dumpToLog() const; + void dumpLayers(LayerDumper*) const; virtual IFrameLayerAndroid* updatePosition(SkRect viewport, IFrameLayerAndroid* parentIframeLayer); @@ -292,6 +291,7 @@ public: } protected: + virtual void dumpLayer(LayerDumper*) const; /** Call this with the current viewport (scrolling, zoom) to update the position of the fixed layers. diff --git a/Source/WebCore/platform/graphics/android/layers/LayerContent.h b/Source/WebCore/platform/graphics/android/layers/LayerContent.h index 10b6507..a18e4c8 100644 --- a/Source/WebCore/platform/graphics/android/layers/LayerContent.h +++ b/Source/WebCore/platform/graphics/android/layers/LayerContent.h @@ -42,7 +42,7 @@ class LayerContent : public SkRefCnt { public: virtual int width() = 0; virtual int height() = 0; - virtual bool isEmpty() { return !width() || !height(); } + bool isEmpty() { return !width() || !height(); } virtual void setCheckForOptimisations(bool check) = 0; virtual void checkForOptimisations() = 0; virtual bool hasText() = 0; diff --git a/Source/WebCore/platform/graphics/android/layers/MediaPlayerPrivateAndroid.h b/Source/WebCore/platform/graphics/android/layers/MediaPlayerPrivateAndroid.h index 17fd4d8..3b4f630 100644 --- a/Source/WebCore/platform/graphics/android/layers/MediaPlayerPrivateAndroid.h +++ b/Source/WebCore/platform/graphics/android/layers/MediaPlayerPrivateAndroid.h @@ -104,8 +104,8 @@ public: { return m_videoLayer; } - void onStopFullscreen(); - + void onStopFullscreen(bool stillPlaying); + virtual void enterFullscreenMode() { } protected: // Android-specific methods and fields. static MediaPlayerPrivateInterface* create(MediaPlayer* player); diff --git a/Source/WebCore/platform/graphics/android/layers/PictureLayerContent.cpp b/Source/WebCore/platform/graphics/android/layers/PictureLayerContent.cpp index 4398146..e40c9b6 100644 --- a/Source/WebCore/platform/graphics/android/layers/PictureLayerContent.cpp +++ b/Source/WebCore/platform/graphics/android/layers/PictureLayerContent.cpp @@ -1,6 +1,10 @@ +#define LOG_TAG "PictureLayerContent" +#define LOG_NDEBUG 1 + #include "config.h" #include "PictureLayerContent.h" +#include "AndroidLog.h" #include "InspectorCanvas.h" #include "SkPicture.h" @@ -41,16 +45,6 @@ int PictureLayerContent::height() return m_picture->height(); } -bool PictureLayerContent::isEmpty() -{ - if (!m_picture) - return true; - if (m_picture->width() == 0 - || m_picture->height() == 0) - return true; - return false; -} - void PictureLayerContent::checkForOptimisations() { if (!m_checkedContent) @@ -90,6 +84,7 @@ void PictureLayerContent::draw(SkCanvas* canvas) if (!m_picture) return; + TRACE_METHOD(); android::Mutex::Autolock lock(m_drawLock); SkRect r = SkRect::MakeWH(width(), height()); canvas->clipRect(r); diff --git a/Source/WebCore/platform/graphics/android/layers/PictureLayerContent.h b/Source/WebCore/platform/graphics/android/layers/PictureLayerContent.h index 1567f44..cf633cb 100644 --- a/Source/WebCore/platform/graphics/android/layers/PictureLayerContent.h +++ b/Source/WebCore/platform/graphics/android/layers/PictureLayerContent.h @@ -38,7 +38,6 @@ public: virtual int width(); virtual int height(); - virtual bool isEmpty(); virtual void setCheckForOptimisations(bool check) { m_checkedContent = !check; } virtual void checkForOptimisations(); virtual bool hasText(); diff --git a/Source/WebCore/platform/graphics/android/layers/PicturePileLayerContent.cpp b/Source/WebCore/platform/graphics/android/layers/PicturePileLayerContent.cpp index b648e72..1167bda 100644 --- a/Source/WebCore/platform/graphics/android/layers/PicturePileLayerContent.cpp +++ b/Source/WebCore/platform/graphics/android/layers/PicturePileLayerContent.cpp @@ -1,6 +1,10 @@ +#define LOG_TAG "PicturePileLayerContent" +#define LOG_NDEBUG 1 + #include "config.h" #include "PicturePileLayerContent.h" +#include "AndroidLog.h" #include "SkCanvas.h" #include "SkPicture.h" @@ -8,13 +12,19 @@ namespace WebCore { PicturePileLayerContent::PicturePileLayerContent(const PicturePile& picturePile) : m_picturePile(picturePile) + , m_hasText(picturePile.hasText()) + , m_hasContent(!picturePile.isEmpty()) { } void PicturePileLayerContent::draw(SkCanvas* canvas) { + TRACE_METHOD(); android::Mutex::Autolock lock(m_drawLock); m_picturePile.draw(canvas); + + if (CC_UNLIKELY(!m_hasContent)) + ALOGW("Warning: painting PicturePile without content!"); } void PicturePileLayerContent::serialize(SkWStream* stream) diff --git a/Source/WebCore/platform/graphics/android/layers/PicturePileLayerContent.h b/Source/WebCore/platform/graphics/android/layers/PicturePileLayerContent.h index 4fc123e..9f3a263 100644 --- a/Source/WebCore/platform/graphics/android/layers/PicturePileLayerContent.h +++ b/Source/WebCore/platform/graphics/android/layers/PicturePileLayerContent.h @@ -35,18 +35,23 @@ class PicturePileLayerContent : public LayerContent { public: PicturePileLayerContent(const PicturePile& picturePile); - virtual int width() { return m_picturePile.size().width(); } - virtual int height() { return m_picturePile.size().height(); } + // return 0 when no content, so don't have to paint + virtual int width() { return m_hasContent ? m_picturePile.size().width() : 0; } + virtual int height() { return m_hasContent ? m_picturePile.size().height() : 0; } + virtual void setCheckForOptimisations(bool check) {} - virtual void checkForOptimisations() {} - virtual bool hasText() { return true; } + virtual void checkForOptimisations() {} // already performed, stored in m_hasText/m_hasContent + virtual bool hasText() { return m_hasText; } virtual void draw(SkCanvas* canvas); virtual void serialize(SkWStream* stream); virtual PrerenderedInval* prerenderForRect(const IntRect& dirty); virtual void clearPrerenders(); + PicturePile* picturePile() { return &m_picturePile; } private: PicturePile m_picturePile; + bool m_hasText; + bool m_hasContent; }; } // WebCore diff --git a/Source/WebCore/platform/graphics/android/layers/VideoLayerAndroid.h b/Source/WebCore/platform/graphics/android/layers/VideoLayerAndroid.h index 5ebf615..07c241f 100644 --- a/Source/WebCore/platform/graphics/android/layers/VideoLayerAndroid.h +++ b/Source/WebCore/platform/graphics/android/layers/VideoLayerAndroid.h @@ -44,7 +44,7 @@ namespace WebCore { // Otherwise will draw a static image. // NOTE: These values are matching the ones in HTML5VideoView.java // Please keep them in sync when changed here. -typedef enum {INITIALIZED, PREPARING, PREPARED, PLAYING, RELEASED} PlayerState; +typedef enum {INITIALIZED, PREPARING, PREPARED, PLAYING, RESETTED, RELEASED} PlayerState; class VideoLayerAndroid : public LayerAndroid { diff --git a/Source/WebCore/platform/graphics/android/layers/VideoLayerManager.cpp b/Source/WebCore/platform/graphics/android/layers/VideoLayerManager.cpp index a7b3184..1f28cdf 100644 --- a/Source/WebCore/platform/graphics/android/layers/VideoLayerManager.cpp +++ b/Source/WebCore/platform/graphics/android/layers/VideoLayerManager.cpp @@ -73,7 +73,7 @@ int VideoLayerManager::getButtonSize() return VIDEO_BUTTON_SIZE; } -GLuint VideoLayerManager::createTextureFromImage(int buttonType) +GLuint VideoLayerManager::createTextureFromImage(RenderSkinMediaButton::MediaButton buttonType) { SkRect rect = SkRect(m_buttonRect); SkBitmap bitmap; @@ -83,8 +83,7 @@ GLuint VideoLayerManager::createTextureFromImage(int buttonType) SkCanvas canvas(bitmap); canvas.drawARGB(0, 0, 0, 0, SkXfermode::kClear_Mode); - RenderSkinMediaButton::Draw(&canvas, m_buttonRect, buttonType, true, 0, - false); + RenderSkinMediaButton::Draw(&canvas, m_buttonRect, buttonType, true, false); GLuint texture; glGenTextures(1, &texture); diff --git a/Source/WebCore/platform/graphics/android/layers/VideoLayerManager.h b/Source/WebCore/platform/graphics/android/layers/VideoLayerManager.h index adce0f4..346afe4 100644 --- a/Source/WebCore/platform/graphics/android/layers/VideoLayerManager.h +++ b/Source/WebCore/platform/graphics/android/layers/VideoLayerManager.h @@ -28,6 +28,7 @@ #include "GLUtils.h" #include "IntRect.h" +#include "RenderSkinMediaButton.h" #include <wtf/HashMap.h> #include <wtf/Vector.h> #include <utils/threads.h> @@ -122,7 +123,7 @@ private: Vector<GLuint> m_retiredTextures; android::Mutex m_retiredTexturesLock; - GLuint createTextureFromImage(int buttonType); + GLuint createTextureFromImage(RenderSkinMediaButton::MediaButton buttonType); // Texture for showing the static image will be created at native side. bool m_createdTexture; diff --git a/Source/WebCore/platform/graphics/android/rendering/BaseRenderer.cpp b/Source/WebCore/platform/graphics/android/rendering/BaseRenderer.cpp index 6f679da..0ab72b7 100644 --- a/Source/WebCore/platform/graphics/android/rendering/BaseRenderer.cpp +++ b/Source/WebCore/platform/graphics/android/rendering/BaseRenderer.cpp @@ -34,6 +34,7 @@ #include "AndroidLog.h" #include "GaneshRenderer.h" #include "GLUtils.h" +#include "InstrumentedPlatformCanvas.h" #include "RasterRenderer.h" #include "SkBitmap.h" #include "SkBitmapRef.h" @@ -94,7 +95,10 @@ void BaseRenderer::renderTiledContent(TileRenderInfo& renderInfo) const bool visualIndicator = TilesManager::instance()->getShowVisualIndicator(); const SkSize& tileSize = renderInfo.tileSize; - SkCanvas canvas; + Color *background = renderInfo.tilePainter->background(); + InstrumentedPlatformCanvas canvas(TilesManager::instance()->tileWidth(), + TilesManager::instance()->tileHeight(), + background ? *background : Color::transparent); setupCanvas(renderInfo, &canvas); if (!canvas.getDevice()) { @@ -112,10 +116,8 @@ void BaseRenderer::renderTiledContent(TileRenderInfo& renderInfo) canvas.translate(-renderInfo.x * tileSize.width(), -renderInfo.y * tileSize.height()); canvas.scale(renderInfo.scale, renderInfo.scale); renderInfo.tilePainter->paint(&canvas); - if (renderInfo.baseTile && renderInfo.baseTile->backTexture()) - checkForPureColor(renderInfo, &canvas); - else - renderInfo.isPureColor = false; + + checkForPureColor(renderInfo, canvas); if (visualIndicator) { double after = currentTimeMS(); @@ -144,6 +146,13 @@ void BaseRenderer::renderTiledContent(TileRenderInfo& renderInfo) renderingComplete(renderInfo, &canvas); } +void BaseRenderer::checkForPureColor(TileRenderInfo& renderInfo, InstrumentedPlatformCanvas& canvas) +{ + renderInfo.isPureColor = canvas.isSolidColor(); + renderInfo.pureColor = canvas.solidColor(); + deviceCheckForPureColor(renderInfo, &canvas); +} + } // namespace WebCore #endif // USE(ACCELERATED_COMPOSITING) diff --git a/Source/WebCore/platform/graphics/android/rendering/BaseRenderer.h b/Source/WebCore/platform/graphics/android/rendering/BaseRenderer.h index b25a50e..dc8831a 100644 --- a/Source/WebCore/platform/graphics/android/rendering/BaseRenderer.h +++ b/Source/WebCore/platform/graphics/android/rendering/BaseRenderer.h @@ -37,6 +37,7 @@ class SkDevice; namespace WebCore { +class InstrumentedPlatformCanvas; class TextureInfo; class TilePainter; class Tile; @@ -87,7 +88,10 @@ protected: virtual void setupCanvas(const TileRenderInfo& renderInfo, SkCanvas* canvas) = 0; virtual void renderingComplete(const TileRenderInfo& renderInfo, SkCanvas* canvas) = 0; - virtual void checkForPureColor(TileRenderInfo& renderInfo, SkCanvas* canvas) = 0; + void checkForPureColor(TileRenderInfo& renderInfo, InstrumentedPlatformCanvas& canvas); + + // performs additional pure color check, renderInfo.isPureColor may already be set to true + virtual void deviceCheckForPureColor(TileRenderInfo& renderInfo, SkCanvas* canvas) = 0; void drawTileInfo(SkCanvas* canvas, const TileRenderInfo& renderInfo, int updateCount, double renderDuration); diff --git a/Source/WebCore/platform/graphics/android/rendering/GLExtras.cpp b/Source/WebCore/platform/graphics/android/rendering/GLExtras.cpp index 2c114d6..175c552 100644 --- a/Source/WebCore/platform/graphics/android/rendering/GLExtras.cpp +++ b/Source/WebCore/platform/graphics/android/rendering/GLExtras.cpp @@ -35,7 +35,6 @@ #include "IntRect.h" #include "SkPath.h" #include "TilesManager.h" -#include "android_graphics.h" // Touch ring border width. This is doubled if the ring is not pressed #define RING_BORDER_WIDTH 1 diff --git a/Source/WebCore/platform/graphics/android/rendering/GLUtils.cpp b/Source/WebCore/platform/graphics/android/rendering/GLUtils.cpp index 4a0b77b..1a54cb7 100644 --- a/Source/WebCore/platform/graphics/android/rendering/GLUtils.cpp +++ b/Source/WebCore/platform/graphics/android/rendering/GLUtils.cpp @@ -384,6 +384,7 @@ bool GLUtils::isPureColorBitmap(const SkBitmap& bitmap, Color& pureColor) // If the bitmap is the pure color, skip the transfer step, and update the Tile Info. // This check is taking < 1ms if we do full bitmap check per tile. // TODO: use the SkPicture to determine whether or not a tile is single color. + TRACE_METHOD(); pureColor = Color(Color::transparent); bitmap.lockPixels(); bool sameColor = true; @@ -445,7 +446,7 @@ bool GLUtils::skipTransferForPureColor(const TileRenderInfo* renderInfo, } void GLUtils::paintTextureWithBitmap(const TileRenderInfo* renderInfo, - const SkBitmap& bitmap) + SkBitmap& bitmap) { if (!renderInfo) return; @@ -471,7 +472,7 @@ void GLUtils::paintTextureWithBitmap(const TileRenderInfo* renderInfo, } } -void GLUtils::updateQueueWithBitmap(const TileRenderInfo* renderInfo, const SkBitmap& bitmap) +void GLUtils::updateQueueWithBitmap(const TileRenderInfo* renderInfo, SkBitmap& bitmap) { if (!renderInfo || !renderInfo->textureInfo @@ -483,6 +484,7 @@ void GLUtils::updateQueueWithBitmap(const TileRenderInfo* renderInfo, const SkBi bool GLUtils::updateSharedSurfaceTextureWithBitmap(ANativeWindow* anw, const SkBitmap& bitmap) { + TRACE_METHOD(); SkAutoLockPixels alp(bitmap); if (!bitmap.getPixels()) return false; diff --git a/Source/WebCore/platform/graphics/android/rendering/GLUtils.h b/Source/WebCore/platform/graphics/android/rendering/GLUtils.h index c2dec7d..3b093d1 100644 --- a/Source/WebCore/platform/graphics/android/rendering/GLUtils.h +++ b/Source/WebCore/platform/graphics/android/rendering/GLUtils.h @@ -80,8 +80,8 @@ public: static void createEGLImageFromTexture(GLuint texture, EGLImageKHR* image); static void createTextureFromEGLImage(GLuint texture, EGLImageKHR image, GLint filter = GL_LINEAR); - static void paintTextureWithBitmap(const TileRenderInfo* renderInfo, const SkBitmap& bitmap); - static void updateQueueWithBitmap(const TileRenderInfo* , const SkBitmap& bitmap); + static void paintTextureWithBitmap(const TileRenderInfo* renderInfo, SkBitmap& bitmap); + static void updateQueueWithBitmap(const TileRenderInfo* , SkBitmap& bitmap); static bool updateSharedSurfaceTextureWithBitmap(ANativeWindow* anw, const SkBitmap& bitmap); static void convertToTransformationMatrix(const float* matrix, TransformationMatrix& transformMatrix); diff --git a/Source/WebCore/platform/graphics/android/rendering/GaneshRenderer.cpp b/Source/WebCore/platform/graphics/android/rendering/GaneshRenderer.cpp index d779af4..8b5e30a 100644 --- a/Source/WebCore/platform/graphics/android/rendering/GaneshRenderer.cpp +++ b/Source/WebCore/platform/graphics/android/rendering/GaneshRenderer.cpp @@ -94,7 +94,8 @@ void GaneshRenderer::renderingComplete(const TileRenderInfo& renderInfo, SkCanva // tile's ANativeWindow (i.e. SurfaceTexture) buffer TransferQueue* tileQueue = TilesManager::instance()->transferQueue(); eglSwapBuffers(eglGetCurrentDisplay(), tileQueue->m_eglSurface); - tileQueue->addItemInTransferQueue(&renderInfo, GpuUpload, 0); + SkBitmap dummyBitmap; + tileQueue->addItemInTransferQueue(&renderInfo, GpuUpload, dummyBitmap); tileQueue->unlockQueue(); } diff --git a/Source/WebCore/platform/graphics/android/rendering/GaneshRenderer.h b/Source/WebCore/platform/graphics/android/rendering/GaneshRenderer.h index cdd9f3e..77982e8 100644 --- a/Source/WebCore/platform/graphics/android/rendering/GaneshRenderer.h +++ b/Source/WebCore/platform/graphics/android/rendering/GaneshRenderer.h @@ -48,9 +48,7 @@ protected: virtual void setupCanvas(const TileRenderInfo& renderInfo, SkCanvas* canvas); virtual void renderingComplete(const TileRenderInfo& renderInfo, SkCanvas* canvas); - virtual void checkForPureColor(TileRenderInfo& renderInfo, SkCanvas* canvas) { - renderInfo.isPureColor = false; - } + virtual void deviceCheckForPureColor(TileRenderInfo& renderInfo, SkCanvas* canvas) {} }; diff --git a/Source/WebCore/platform/graphics/android/rendering/InstrumentedPlatformCanvas.h b/Source/WebCore/platform/graphics/android/rendering/InstrumentedPlatformCanvas.h new file mode 100644 index 0000000..508795a --- /dev/null +++ b/Source/WebCore/platform/graphics/android/rendering/InstrumentedPlatformCanvas.h @@ -0,0 +1,305 @@ +/* + * Copyright (C) 2011 Research In Motion Limited. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef InstrumentedPlatformCanvas_h +#define InstrumentedPlatformCanvas_h + +#include "SkCanvas.h" + +#define DEBUG_SKIA_DRAWING 0 +#if DEBUG_SKIA_DRAWING +#define WRAPCANVAS_LOG_ENTRY(...) do { \ + fprintf(stderr, "%s ", __FUNCTION__); \ + fprintf(stderr, __VA_ARGS__); \ + fprintf(stderr, "\n"); \ +} while (0) +#else +#define WRAPCANVAS_LOG_ENTRY(...) ((void)0) +#endif + +namespace WebCore { + +class InstrumentedPlatformCanvas : public SkCanvas { +public: + InstrumentedPlatformCanvas(int width, int height, Color initialColor) + : m_size(width, height) + , m_isSolidColor(true) + , m_solidColor(initialColor) + { + } + + virtual ~InstrumentedPlatformCanvas() { } + + bool isSolidColor() const { return m_isSolidColor; } + Color solidColor() const { return m_solidColor; } + + // overrides from SkCanvas + virtual int save(SaveFlags flags = kMatrixClip_SaveFlag) + { + WRAPCANVAS_LOG_ENTRY(""); + return SkCanvas::save(flags); + } + + virtual int saveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags) + { + WRAPCANVAS_LOG_ENTRY(""); + m_isSolidColor = false; + return SkCanvas::saveLayer(bounds, paint, flags); + } + + virtual void restore() + { + WRAPCANVAS_LOG_ENTRY(""); + SkCanvas::restore(); + } + + virtual bool translate(SkScalar dx, SkScalar dy) + { + WRAPCANVAS_LOG_ENTRY(""); + return SkCanvas::translate(dx, dy); + } + + virtual bool scale(SkScalar sx, SkScalar sy) + { + WRAPCANVAS_LOG_ENTRY(""); + return SkCanvas::scale(sx, sy); + } + + virtual bool rotate(SkScalar degrees) + { + WRAPCANVAS_LOG_ENTRY(""); + return SkCanvas::rotate(degrees); + } + + virtual bool skew(SkScalar sx, SkScalar sy) + { + WRAPCANVAS_LOG_ENTRY(""); + return SkCanvas::skew(sx, sy); + } + + virtual bool concat(const SkMatrix& matrix) + { + WRAPCANVAS_LOG_ENTRY(""); + return SkCanvas::concat(matrix); + } + + virtual void setMatrix(const SkMatrix& matrix) + { + WRAPCANVAS_LOG_ENTRY(""); + SkCanvas::setMatrix(matrix); + } + + virtual bool clipRect(const SkRect& rect, SkRegion::Op op) + { + WRAPCANVAS_LOG_ENTRY(""); + return SkCanvas::clipRect(rect, op); + } + + virtual bool clipPath(const SkPath& path, SkRegion::Op op) + { + WRAPCANVAS_LOG_ENTRY(""); + m_isSolidColor = false; + return SkCanvas::clipPath(path, op); + } + + virtual bool clipRegion(const SkRegion& region, SkRegion::Op op) + { + WRAPCANVAS_LOG_ENTRY(""); + m_isSolidColor = false; + return SkCanvas::clipRegion(region, op); + } + + virtual void clear(SkColor color) + { + WRAPCANVAS_LOG_ENTRY(""); + m_isSolidColor = true; + m_solidColor = Color(color); + SkCanvas::clear(color); + } + + virtual void drawPaint(const SkPaint& paint) + { + WRAPCANVAS_LOG_ENTRY(""); + m_isSolidColor = false; + SkCanvas::drawPaint(paint); + } + + virtual void drawPoints(PointMode mode, size_t count, const SkPoint pts[], + const SkPaint& paint) + { + WRAPCANVAS_LOG_ENTRY(""); + m_isSolidColor = false; + SkCanvas::drawPoints(mode, count, pts, paint); + } + + virtual void drawRect(const SkRect& rect, const SkPaint& paint) + { +#if DEBUG_SKIA_DRAWING + IntRect rectToDraw(rect); + WRAPCANVAS_LOG_ENTRY("rect = (x=%d,y=%d,width=%d,height=%d)", INT_RECT_ARGS(rectToDraw); +#endif + IntRect canvasRect(IntPoint(), m_size); + if (m_isSolidColor + && getTotalMatrix().rectStaysRect() + && getTotalClip().contains(canvasRect)) { + const SkMatrix& matrix = getTotalMatrix(); + SkRect mapped; + matrix.mapRect(&mapped, rect); + if (mapped.contains(canvasRect)) { + Color color = solidColor(paint); + m_isSolidColor = color.isValid(); + m_solidColor = color; + } else + m_isSolidColor = false; + } else + m_isSolidColor = false; + SkCanvas::drawRect(rect, paint); + } + + virtual void drawPath(const SkPath& path, const SkPaint& paint) + { + WRAPCANVAS_LOG_ENTRY(""); + m_isSolidColor = false; + SkCanvas::drawPath(path, paint); + } + + virtual void drawBitmap(const SkBitmap& bitmap, SkScalar left, + SkScalar top, const SkPaint* paint) + { + WRAPCANVAS_LOG_ENTRY(""); + m_isSolidColor = false; + SkCanvas::drawBitmap(bitmap, left, top, paint); + } + + virtual void drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src, + const SkRect& dst, const SkPaint* paint) + { + WRAPCANVAS_LOG_ENTRY(""); + m_isSolidColor = false; + SkCanvas::drawBitmapRect(bitmap, src, dst, paint); + } + + virtual void drawBitmapMatrix(const SkBitmap& bitmap, + const SkMatrix& matrix, const SkPaint* paint) + { + WRAPCANVAS_LOG_ENTRY(""); + m_isSolidColor = false; + SkCanvas::drawBitmapMatrix(bitmap, matrix, paint); + } + + virtual void drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, + const SkRect& dst, const SkPaint* paint = 0) + { + WRAPCANVAS_LOG_ENTRY(""); + m_isSolidColor = false; + SkCanvas::drawBitmapNine(bitmap, center, dst, paint); + } + + virtual void drawSprite(const SkBitmap& bitmap, int left, int top, + const SkPaint* paint) + { + WRAPCANVAS_LOG_ENTRY(""); + m_isSolidColor = false; + SkCanvas::drawSprite(bitmap, left, top, paint); + } + + virtual void drawText(const void* text, size_t byteLength, SkScalar x, + SkScalar y, const SkPaint& paint) + { + WRAPCANVAS_LOG_ENTRY(""); + m_isSolidColor = false; + SkCanvas::drawText(text, byteLength, x, y, paint); + } + + virtual void drawPosText(const void* text, size_t byteLength, + const SkPoint pos[], const SkPaint& paint) + { + WRAPCANVAS_LOG_ENTRY(""); + m_isSolidColor = false; + SkCanvas::drawPosText(text, byteLength, pos, paint); + } + + virtual void drawPosTextH(const void* text, size_t byteLength, + const SkScalar xpos[], SkScalar constY, const SkPaint& paint) + { + WRAPCANVAS_LOG_ENTRY(""); + m_isSolidColor = false; + SkCanvas::drawPosTextH(text, byteLength, xpos, constY, paint); + } + + virtual void drawTextOnPath(const void* text, size_t byteLength, + const SkPath& path, const SkMatrix* matrix, const SkPaint& paint) + { + WRAPCANVAS_LOG_ENTRY(""); + m_isSolidColor = false; + SkCanvas::drawTextOnPath(text, byteLength, path, matrix, paint); + } + + virtual void drawPicture(SkPicture& picture) + { + WRAPCANVAS_LOG_ENTRY(""); + m_isSolidColor = false; + SkCanvas::drawPicture(picture); + } + + virtual void drawVertices(VertexMode mode, int vertexCount, + const SkPoint vertices[], const SkPoint texs[], + const SkColor colors[], SkXfermode* xfermode, + const uint16_t indices[], int indexCount, const SkPaint& paint) + { + WRAPCANVAS_LOG_ENTRY(""); + m_isSolidColor = false; + SkCanvas::drawVertices(mode, vertexCount, vertices, texs, + colors, xfermode, indices, indexCount, paint); + } + + virtual void drawData(const void* data, size_t size) + { + WRAPCANVAS_LOG_ENTRY(""); + m_isSolidColor = false; + SkCanvas::drawData(data, size); + } + +private: + Color solidColor(const SkPaint& paint) + { + if (paint.getStyle() != SkPaint::kFill_Style) + return Color(); + if (paint.getLooper() || paint.getShader()) + return Color(); + + SkXfermode::Mode mode; + SkXfermode::AsMode(paint.getXfermode(), &mode); + if (mode == SkXfermode::kClear_Mode) + return Color(0, 0, 0, 0); + + if ((mode == SkXfermode::kSrcOver_Mode && paint.getAlpha() == 255) + || mode == SkXfermode::kSrc_Mode) + return Color(paint.getColor()); + return Color(); + } + + IntSize m_size; + bool m_isSolidColor; + Color m_solidColor; + SkPaint m_solidPaint; +}; + +} // namespace WebCore + +#endif // InstrumentedPlatformCanvas_h diff --git a/Source/WebCore/platform/graphics/android/rendering/PaintTileOperation.cpp b/Source/WebCore/platform/graphics/android/rendering/PaintTileOperation.cpp index 3fcbdb2..c1b91a3 100644 --- a/Source/WebCore/platform/graphics/android/rendering/PaintTileOperation.cpp +++ b/Source/WebCore/platform/graphics/android/rendering/PaintTileOperation.cpp @@ -79,12 +79,12 @@ bool PaintTileOperation::operator==(const QueuedOperation* operation) return op->m_tile == m_tile; } -void PaintTileOperation::run() +void PaintTileOperation::run(BaseRenderer* renderer) { TRACE_METHOD(); if (m_tile) { - m_tile->paintBitmap(m_painter); + m_tile->paintBitmap(m_painter, renderer); m_tile->setRepaintPending(false); m_tile = 0; } diff --git a/Source/WebCore/platform/graphics/android/rendering/PaintTileOperation.h b/Source/WebCore/platform/graphics/android/rendering/PaintTileOperation.h index c82cdcd..ecd3ce9 100644 --- a/Source/WebCore/platform/graphics/android/rendering/PaintTileOperation.h +++ b/Source/WebCore/platform/graphics/android/rendering/PaintTileOperation.h @@ -42,7 +42,7 @@ public: GLWebViewState* state, bool isLowResPrefetch); virtual ~PaintTileOperation(); virtual bool operator==(const QueuedOperation* operation); - virtual void run(); + virtual void run(BaseRenderer* renderer); virtual void* uniquePtr() { return m_tile; } // returns a rendering priority for m_tile, lower values are processed faster virtual int priority(); diff --git a/Source/WebCore/platform/graphics/android/rendering/QueuedOperation.h b/Source/WebCore/platform/graphics/android/rendering/QueuedOperation.h index 7625528..fe6f8a3 100644 --- a/Source/WebCore/platform/graphics/android/rendering/QueuedOperation.h +++ b/Source/WebCore/platform/graphics/android/rendering/QueuedOperation.h @@ -28,10 +28,12 @@ namespace WebCore { +class BaseRenderer; + class QueuedOperation { public: virtual ~QueuedOperation() {} - virtual void run() = 0; + virtual void run(BaseRenderer* renderer) = 0; virtual bool operator==(const QueuedOperation* operation) = 0; virtual void* uniquePtr() = 0; virtual int priority() = 0; diff --git a/Source/WebCore/platform/graphics/android/rendering/RasterRenderer.cpp b/Source/WebCore/platform/graphics/android/rendering/RasterRenderer.cpp index 47e5c17..fd26380 100644 --- a/Source/WebCore/platform/graphics/android/rendering/RasterRenderer.cpp +++ b/Source/WebCore/platform/graphics/android/rendering/RasterRenderer.cpp @@ -42,20 +42,17 @@ namespace WebCore { -SkBitmap* RasterRenderer::g_bitmap = 0; - -RasterRenderer::RasterRenderer() : BaseRenderer(BaseRenderer::Raster) +RasterRenderer::RasterRenderer() + : BaseRenderer(BaseRenderer::Raster) + , m_bitmapIsPureColor(false) { + m_bitmap.setConfig(SkBitmap::kARGB_8888_Config, + TilesManager::instance()->tileWidth(), + TilesManager::instance()->tileHeight()); + m_bitmap.allocPixels(); #ifdef DEBUG_COUNT ClassTracker::instance()->increment("RasterRenderer"); #endif - if (!g_bitmap) { - g_bitmap = new SkBitmap(); - g_bitmap->setConfig(SkBitmap::kARGB_8888_Config, - TilesManager::instance()->tileWidth(), - TilesManager::instance()->tileHeight()); - g_bitmap->allocPixels(); - } } RasterRenderer::~RasterRenderer() @@ -67,9 +64,14 @@ RasterRenderer::~RasterRenderer() void RasterRenderer::setupCanvas(const TileRenderInfo& renderInfo, SkCanvas* canvas) { + TRACE_METHOD(); + if (renderInfo.baseTile->isLayerTile()) { - g_bitmap->setIsOpaque(false); - g_bitmap->eraseARGB(0, 0, 0, 0); + m_bitmap.setIsOpaque(false); + + // clear bitmap if necessary + if (!m_bitmapIsPureColor || m_bitmapPureColor != Color::transparent) + m_bitmap.eraseARGB(0, 0, 0, 0); } else { Color defaultBackground = Color::white; Color* background = renderInfo.tilePainter->background(); @@ -78,12 +80,15 @@ void RasterRenderer::setupCanvas(const TileRenderInfo& renderInfo, SkCanvas* can background = &defaultBackground; } ALOGV("setupCanvas use background on Base Layer %x", background->rgb()); - g_bitmap->setIsOpaque(!background->hasAlpha()); - g_bitmap->eraseARGB(background->alpha(), background->red(), - background->green(), background->blue()); + m_bitmap.setIsOpaque(!background->hasAlpha()); + + // fill background color if necessary + if (!m_bitmapIsPureColor || m_bitmapPureColor != *background) + m_bitmap.eraseARGB(background->alpha(), background->red(), + background->green(), background->blue()); } - SkDevice* device = new SkDevice(*g_bitmap); + SkDevice* device = new SkDevice(m_bitmap); canvas->setDevice(device); @@ -92,14 +97,20 @@ void RasterRenderer::setupCanvas(const TileRenderInfo& renderInfo, SkCanvas* can void RasterRenderer::renderingComplete(const TileRenderInfo& renderInfo, SkCanvas* canvas) { - const SkBitmap& bitmap = canvas->getDevice()->accessBitmap(false); - GLUtils::paintTextureWithBitmap(&renderInfo, bitmap); + // We may swap the content of m_bitmap with the bitmap in the transfer queue. + GLUtils::paintTextureWithBitmap(&renderInfo, m_bitmap); } -void RasterRenderer::checkForPureColor(TileRenderInfo& renderInfo, SkCanvas* canvas) +void RasterRenderer::deviceCheckForPureColor(TileRenderInfo& renderInfo, SkCanvas* canvas) { - const SkBitmap& bitmap = canvas->getDevice()->accessBitmap(false); - renderInfo.isPureColor = GLUtils::isPureColorBitmap(bitmap, renderInfo.pureColor); + if (!renderInfo.isPureColor) { + // base renderer may have already determined isPureColor, so only do the + // brute force check if needed + renderInfo.isPureColor = GLUtils::isPureColorBitmap(m_bitmap, renderInfo.pureColor); + } + + m_bitmapIsPureColor = renderInfo.isPureColor; + m_bitmapPureColor = renderInfo.pureColor; } } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/rendering/RasterRenderer.h b/Source/WebCore/platform/graphics/android/rendering/RasterRenderer.h index 39e00f2..791c6b6 100644 --- a/Source/WebCore/platform/graphics/android/rendering/RasterRenderer.h +++ b/Source/WebCore/platform/graphics/android/rendering/RasterRenderer.h @@ -46,14 +46,14 @@ public: ~RasterRenderer(); protected: - virtual void setupCanvas(const TileRenderInfo& renderInfo, SkCanvas* canvas); virtual void renderingComplete(const TileRenderInfo& renderInfo, SkCanvas* canvas); - virtual void checkForPureColor(TileRenderInfo& renderInfo, SkCanvas* canvas); + virtual void deviceCheckForPureColor(TileRenderInfo& renderInfo, SkCanvas* canvas); private: - static SkBitmap* g_bitmap; - + SkBitmap m_bitmap; + bool m_bitmapIsPureColor; + Color m_bitmapPureColor; }; } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/rendering/ShaderProgram.cpp b/Source/WebCore/platform/graphics/android/rendering/ShaderProgram.cpp index d7266a3..b59b6e2 100644 --- a/Source/WebCore/platform/graphics/android/rendering/ShaderProgram.cpp +++ b/Source/WebCore/platform/graphics/android/rendering/ShaderProgram.cpp @@ -257,6 +257,16 @@ GLint ShaderProgram::createProgram(const char* pVertexSource, const char* pFragm return program; } +void ShaderProgram::initProgram(ShaderType type) +{ + // initialize shader's static texSampler and position values + glUseProgram(m_handleArray[type].programHandle); + + if (m_handleArray[type].texSamplerHandle != -1) + glUniform1i(m_handleArray[type].texSamplerHandle, 0); + glEnableVertexAttribArray(m_handleArray[type].positionHandle); +} + ShaderProgram::ShaderProgram() : m_blendingEnabled(false) , m_contrast(1) @@ -321,6 +331,7 @@ void ShaderProgram::initGLResources() GLint pureColorValue = glGetUniformLocation(pureColorProgram, "inputColor"); m_handleArray[PureColor].init(-1, -1, pureColorPosition, pureColorProgram, pureColorProjMtx, pureColorValue, -1, -1, -1, -1); + initProgram(PureColor); GLint tex2DAlpha = glGetUniformLocation(tex2DProgram, "alpha"); GLint tex2DPosition = glGetAttribLocation(tex2DProgram, "vPosition"); @@ -329,6 +340,7 @@ void ShaderProgram::initGLResources() GLint tex2DFillPortion = glGetUniformLocation(tex2DProgram, "fillPortion"); m_handleArray[Tex2D].init(tex2DAlpha, -1, tex2DPosition, tex2DProgram, tex2DProjMtx, -1, tex2DTexSampler, -1, tex2DFillPortion, -1); + initProgram(Tex2D); GLint tex2DInvAlpha = glGetUniformLocation(tex2DInvProgram, "alpha"); GLint tex2DInvContrast = glGetUniformLocation(tex2DInvProgram, "contrast"); @@ -340,6 +352,7 @@ void ShaderProgram::initGLResources() tex2DInvPosition, tex2DInvProgram, tex2DInvProjMtx, -1, tex2DInvTexSampler, -1, tex2DInvFillPortion, -1); + initProgram(Tex2DInv); GLint repeatTexAlpha = glGetUniformLocation(repeatTexProgram, "alpha"); GLint repeatTexPosition = glGetAttribLocation(repeatTexProgram, "vPosition"); @@ -351,6 +364,7 @@ void ShaderProgram::initGLResources() repeatTexProgram,repeatTexProjMtx, -1, repeatTexTexSampler, -1, repeatTexFillPortion, repeatTexScale); + initProgram(RepeatTex); GLint repeatTexInvAlpha = glGetUniformLocation(repeatTexInvProgram, "alpha"); GLint repeatTexInvContrast = glGetUniformLocation(tex2DInvProgram, "contrast"); @@ -364,6 +378,7 @@ void ShaderProgram::initGLResources() repeatTexInvProjMtx, -1, repeatTexInvTexSampler, -1, repeatTexInvFillPortion, repeatTexInvScale); + initProgram(RepeatTexInv); GLint texOESAlpha = glGetUniformLocation(texOESProgram, "alpha"); GLint texOESPosition = glGetAttribLocation(texOESProgram, "vPosition"); @@ -372,6 +387,7 @@ void ShaderProgram::initGLResources() GLint texOESFillPortion = glGetUniformLocation(texOESProgram, "fillPortion"); m_handleArray[TexOES].init(texOESAlpha, -1, texOESPosition, texOESProgram, texOESProjMtx, -1, texOESTexSampler, -1, texOESFillPortion, -1); + initProgram(TexOES); GLint texOESInvAlpha = glGetUniformLocation(texOESInvProgram, "alpha"); GLint texOESInvContrast = glGetUniformLocation(texOESInvProgram, "contrast"); @@ -383,6 +399,7 @@ void ShaderProgram::initGLResources() texOESInvPosition, texOESInvProgram, texOESInvProjMtx, -1, texOESInvTexSampler, -1, texOESInvFillPortion, -1); + initProgram(TexOESInv); GLint videoPosition = glGetAttribLocation(videoProgram, "vPosition"); GLint videoProjMtx = glGetUniformLocation(videoProgram, "projectionMatrix"); @@ -391,6 +408,7 @@ void ShaderProgram::initGLResources() m_handleArray[Video].init(-1, -1, videoPosition, videoProgram, videoProjMtx, -1, videoTexSampler, videoTexMtx, -1, -1); + initProgram(Video); const GLfloat coord[] = { 0.0f, 0.0f, // C @@ -539,6 +557,16 @@ void ShaderProgram::setupDrawing(const IntRect& invScreenRect, // Set up m_clipProjectionMatrix, m_currentScale and m_webViewMatrix before // calling this function. setupSurfaceProjectionMatrix(); + + //// initialize frame-constant values //// + glActiveTexture(GL_TEXTURE0); + glBindBuffer(GL_ARRAY_BUFFER, m_textureBuffer[0]); + + //// initialize GL cache //// + m_cachedProgramType = UndefinedShader; + m_cachedOpacity = -1; + m_cachedFillPortion = FloatRect(); + m_cachedPureColor = Color(); } // Calculate the right color value sent into the shader considering the (0,1) @@ -695,23 +723,34 @@ void ShaderProgram::drawQuadInternal(ShaderType type, const GLfloat* matrix, const Color& pureColor, const FloatRect& fillPortion, const FloatSize& repeatScale) { - glUseProgram(m_handleArray[type].programHandle); + if (m_cachedProgramType != type) { + glUseProgram(m_handleArray[type].programHandle); + glVertexAttribPointer(m_handleArray[type].positionHandle, + 2, GL_FLOAT, GL_FALSE, 0, 0); + m_cachedProgramType = type; + m_cachedOpacity = -1; // reset cache for variable shared by multiple programs + } glUniformMatrix4fv(m_handleArray[type].projMtxHandle, 1, GL_FALSE, matrix); if (type != PureColor) { - glActiveTexture(GL_TEXTURE0); - glUniform1i(m_handleArray[type].texSamplerHandle, 0); glBindTexture(textureTarget, textureId); glTexParameteri(textureTarget, GL_TEXTURE_MIN_FILTER, filter); glTexParameteri(textureTarget, GL_TEXTURE_MAG_FILTER, filter); - glUniform1f(m_handleArray[type].alphaHandle, opacity); + + if (m_cachedOpacity != opacity) { + glUniform1f(m_handleArray[type].alphaHandle, opacity); + m_cachedOpacity = opacity; + } GLint contrastHandle = m_handleArray[type].contrastHandle; if (contrastHandle != -1) glUniform1f(contrastHandle, m_contrast); - glUniform4f(m_handleArray[type].fillPortionHandle, fillPortion.x(), fillPortion.y(), - fillPortion.width(), fillPortion.height()); + if (m_cachedFillPortion != fillPortion) { + glUniform4f(m_handleArray[type].fillPortionHandle, fillPortion.x(), fillPortion.y(), + fillPortion.width(), fillPortion.height()); + m_cachedFillPortion = fillPortion; + } // Only when we have repeat scale, this handle can be >= 0; if (m_handleArray[type].scaleHandle != -1) { @@ -719,16 +758,14 @@ void ShaderProgram::drawQuadInternal(ShaderType type, const GLfloat* matrix, repeatScale.width(), repeatScale.height()); } } else { - glUniform4f(m_handleArray[type].pureColorHandle, - pureColor.red() / 255.0, pureColor.green() / 255.0, - pureColor.blue() / 255.0, pureColor.alpha() / 255.0); + if (m_cachedPureColor != pureColor) { + glUniform4f(m_handleArray[type].pureColorHandle, + pureColor.red() / 255.0, pureColor.green() / 255.0, + pureColor.blue() / 255.0, pureColor.alpha() / 255.0); + m_cachedPureColor = pureColor; + } } - GLint positionHandle = m_handleArray[type].positionHandle; - glBindBuffer(GL_ARRAY_BUFFER, m_textureBuffer[0]); - glEnableVertexAttribArray(positionHandle); - glVertexAttribPointer(positionHandle, 2, GL_FLOAT, GL_FALSE, 0, 0); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } @@ -819,7 +856,13 @@ void ShaderProgram::drawVideoLayerQuad(const TransformationMatrix& drawMatrix, int textureId) { // switch to our custom yuv video rendering program - glUseProgram(m_handleArray[Video].programHandle); + if (m_cachedProgramType != Video) { + glUseProgram(m_handleArray[Video].programHandle); + glVertexAttribPointer(m_handleArray[Video].positionHandle, + 2, GL_FLOAT, GL_FALSE, 0, 0); + m_cachedProgramType = Video; + } + // TODO: Merge drawVideoLayerQuad into drawQuad. TransformationMatrix modifiedDrawMatrix; modifiedDrawMatrix.scale3d(m_currentScale, m_currentScale, 1); @@ -835,15 +878,8 @@ void ShaderProgram::drawVideoLayerQuad(const TransformationMatrix& drawMatrix, projectionMatrix); glUniformMatrix4fv(m_handleArray[Video].videoMtxHandle, 1, GL_FALSE, textureMatrix); - glActiveTexture(GL_TEXTURE0); - glUniform1i(m_handleArray[Video].texSamplerHandle, 0); glBindTexture(GL_TEXTURE_EXTERNAL_OES, textureId); - GLint videoPosition = m_handleArray[Video].positionHandle; - glBindBuffer(GL_ARRAY_BUFFER, m_textureBuffer[0]); - glEnableVertexAttribArray(videoPosition); - glVertexAttribPointer(videoPosition, 2, GL_FLOAT, GL_FALSE, 0, 0); - setBlendingState(false); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } diff --git a/Source/WebCore/platform/graphics/android/rendering/ShaderProgram.h b/Source/WebCore/platform/graphics/android/rendering/ShaderProgram.h index 27eb737..9c5dc17 100644 --- a/Source/WebCore/platform/graphics/android/rendering/ShaderProgram.h +++ b/Source/WebCore/platform/graphics/android/rendering/ShaderProgram.h @@ -168,6 +168,7 @@ public: private: GLuint loadShader(GLenum shaderType, const char* pSource); GLint createProgram(const char* vertexSource, const char* fragmentSource); + void initProgram(ShaderType type); GLfloat* getTileProjectionMatrix(const DrawQuadData* data); void setBlendingState(bool enableBlending); void drawQuadInternal(ShaderType type, const GLfloat* matrix, int textureId, @@ -231,6 +232,11 @@ private: GLfloat m_tileProjMatrix[16]; Vector<ShaderResource> m_resources; + + ShaderType m_cachedProgramType; + GLfloat m_cachedOpacity; + FloatRect m_cachedFillPortion; + Color m_cachedPureColor; }; } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/rendering/Surface.cpp b/Source/WebCore/platform/graphics/android/rendering/Surface.cpp index 1898910..96a4a16 100644 --- a/Source/WebCore/platform/graphics/android/rendering/Surface.cpp +++ b/Source/WebCore/platform/graphics/android/rendering/Surface.cpp @@ -218,7 +218,7 @@ void Surface::prepareGL(bool layerTilesDisabled, bool updateWithBlit) ALOGV("prepareGL on Surf %p with SurfBack %p, %d layers, first layer %s (%d) " "prepareArea(%d, %d - %d x %d) fullArea(%d, %d - %d x %d)", this, m_surfaceBacking, m_layers.size(), - getFirstLayer()->subclassName().ascii().data(), + getFirstLayer()->subclassName(), getFirstLayer()->uniqueId(), prepareArea.x(), prepareArea.y(), prepareArea.width(), prepareArea.height(), fullArea.x(), fullArea.y(), fullArea.width(), fullArea.height()); @@ -253,7 +253,7 @@ bool Surface::drawGL(bool layerTilesDisabled) bool askRedraw = false; if (m_surfaceBacking && !tilesDisabled) { ALOGV("drawGL on Surf %p with SurfBack %p, first layer %s (%d)", this, m_surfaceBacking, - getFirstLayer()->subclassName().ascii().data(), getFirstLayer()->uniqueId()); + getFirstLayer()->subclassName(), getFirstLayer()->uniqueId()); bool force3dContentVisible = true; IntRect drawArea = visibleContentArea(force3dContentVisible); diff --git a/Source/WebCore/platform/graphics/android/rendering/SurfaceBacking.cpp b/Source/WebCore/platform/graphics/android/rendering/SurfaceBacking.cpp index d7f6535..5b11df6 100644 --- a/Source/WebCore/platform/graphics/android/rendering/SurfaceBacking.cpp +++ b/Source/WebCore/platform/graphics/android/rendering/SurfaceBacking.cpp @@ -40,13 +40,15 @@ namespace WebCore { SurfaceBacking::SurfaceBacking(bool isBaseSurface) + : m_frontTileGrid(new TileGrid(isBaseSurface)) + , m_backTileGrid(new TileGrid(isBaseSurface)) + , m_lowResTileGrid(new TileGrid(isBaseSurface)) + , m_scale(-1) + , m_futureScale(-1) + , m_zooming(false) + , m_hasAllowedZoom(false) + { - m_frontTileGrid = new TileGrid(isBaseSurface); - m_backTileGrid = new TileGrid(isBaseSurface); - m_lowResTileGrid = new TileGrid(isBaseSurface); - m_scale = -1; - m_futureScale = -1; - m_zooming = false; #ifdef DEBUG_COUNT ClassTracker::instance()->increment("SurfaceBacking"); #endif @@ -67,9 +69,16 @@ void SurfaceBacking::prepareGL(GLWebViewState* state, bool allowZoom, TilePainter* painter, bool aggressiveRendering, bool updateWithBlit) { + // If the surface backing has ever zoomed beyond 1.0 scale, it's always + // allowed to (so repaints aren't necessary when allowZoom toggles). If not, + // and allowZoom is false, don't allow scale greater than 1.0 + m_hasAllowedZoom |= allowZoom; float scale = state->scale(); - if (scale > 1 && !allowZoom) + bool scaleOverridden = false; + if (scale > 1 && !m_hasAllowedZoom) { scale = 1; + scaleOverridden = true; + } if (m_scale == -1) { m_scale = scale; @@ -78,7 +87,10 @@ void SurfaceBacking::prepareGL(GLWebViewState* state, bool allowZoom, if (m_futureScale != scale) { m_futureScale = scale; - m_zoomUpdateTime = WTF::currentTime() + SurfaceBacking::s_zoomUpdateDelay; + if (scaleOverridden) + m_zoomUpdateTime = 0; // start rendering immediately + else + m_zoomUpdateTime = WTF::currentTime() + SurfaceBacking::s_zoomUpdateDelay; m_zooming = true; // release back TileGrid's TileTextures, so they can be reused immediately diff --git a/Source/WebCore/platform/graphics/android/rendering/SurfaceBacking.h b/Source/WebCore/platform/graphics/android/rendering/SurfaceBacking.h index 5709f2a..80c6545 100644 --- a/Source/WebCore/platform/graphics/android/rendering/SurfaceBacking.h +++ b/Source/WebCore/platform/graphics/android/rendering/SurfaceBacking.h @@ -85,7 +85,7 @@ private: void swapTileGrids(); // Delay before we schedule a new tile at the new scale factor - static const double s_zoomUpdateDelay = 0.2; // 200 ms + static const double s_zoomUpdateDelay = 0.1; // 100 ms TileGrid* m_frontTileGrid; TileGrid* m_backTileGrid; @@ -95,6 +95,7 @@ private: float m_futureScale; double m_zoomUpdateTime; bool m_zooming; + bool m_hasAllowedZoom; }; } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/rendering/SurfaceCollectionManager.cpp b/Source/WebCore/platform/graphics/android/rendering/SurfaceCollectionManager.cpp index 174720f..1270498 100644 --- a/Source/WebCore/platform/graphics/android/rendering/SurfaceCollectionManager.cpp +++ b/Source/WebCore/platform/graphics/android/rendering/SurfaceCollectionManager.cpp @@ -38,6 +38,10 @@ namespace WebCore { using namespace android::uirenderer; +// Tag used to display current number of SurfaceCollections. +// Note: this will only work if one webview is actively drawing at a time. +static const char* COLLECTION_COUNT_TAG = "CollectionCount"; + SurfaceCollectionManager::SurfaceCollectionManager() : m_drawingCollection(0) , m_paintingCollection(0) @@ -87,6 +91,12 @@ void SurfaceCollectionManager::swap() m_paintingCollection = m_queuedCollection; m_queuedCollection = 0; + if (ATRACE_ENABLED()) { + ATRACE_INT(COLLECTION_COUNT_TAG, + (m_drawingCollection ? 1 : 0) + + (m_paintingCollection ? 1 : 0)); + } + ALOGV("SWAPPING COMPLETE, D %p, P %p, Q %p", m_drawingCollection, m_paintingCollection, m_queuedCollection); } @@ -106,6 +116,8 @@ void SurfaceCollectionManager::clearCollections() m_paintingCollection = 0; SkSafeUnref(m_queuedCollection); m_queuedCollection = 0; + + ATRACE_INT(COLLECTION_COUNT_TAG, 0); } void SurfaceCollectionManager::updatePaintingCollection(SurfaceCollection* newCollection) @@ -126,8 +138,10 @@ bool SurfaceCollectionManager::updateWithSurfaceCollection(SurfaceCollection* ne if (!newCollection || brandNew) { clearCollections(); - if (brandNew) + if (brandNew) { updatePaintingCollection(newCollection); + ATRACE_INT(COLLECTION_COUNT_TAG, 1); + } return false; } @@ -157,6 +171,13 @@ bool SurfaceCollectionManager::updateWithSurfaceCollection(SurfaceCollection* ne // don't have painting collection, paint this one! updatePaintingCollection(newCollection); } + + if (ATRACE_ENABLED()) { + ATRACE_INT(COLLECTION_COUNT_TAG, + (m_drawingCollection ? 1 : 0) + + (m_paintingCollection ? 1 : 0) + + (m_queuedCollection ? 1 : 0)); + } return m_drawingCollection && TilesManager::instance()->useDoubleBuffering(); } @@ -225,12 +246,12 @@ int SurfaceCollectionManager::drawGL(double currentTime, IntRect& viewRect, int returnFlags = 0; bool didCollectionSwap = false; + bool tryFastBlit = !m_fastSwapMode; if (m_paintingCollection) { ALOGV("preparing painting collection %p", m_paintingCollection); m_paintingCollection->evaluateAnimations(currentTime); - bool tryFastBlit = !m_fastSwapMode; m_paintingCollection->prepareGL(visibleContentRect, tryFastBlit); m_paintingCollection->computeTexturesAmount(texturesResultPtr); @@ -261,6 +282,9 @@ int SurfaceCollectionManager::drawGL(double currentTime, IntRect& viewRect, && m_drawingCollection->isReady())) { // either a swap just occurred, or there is no more work to be done: do a full draw m_drawingCollection->swapTiles(); + + if (didCollectionSwap && m_paintingCollection) + m_paintingCollection->prepareGL(visibleContentRect, tryFastBlit); returnFlags |= DrawGlInfo::kStatusDraw; } else { // current collection not ready - invoke functor in process mode @@ -286,6 +310,9 @@ int SurfaceCollectionManager::drawGL(double currentTime, IntRect& viewRect, if (didCollectionSwap || m_fastSwapMode || (drawingReady && !m_paintingCollection)) m_drawingCollection->swapTiles(); + if (didCollectionSwap && m_paintingCollection) + m_paintingCollection->prepareGL(visibleContentRect, tryFastBlit); + if (drawingReady) { // exit fast swap mode, as content is up to date m_fastSwapMode = false; diff --git a/Source/WebCore/platform/graphics/android/rendering/TexturesGenerator.cpp b/Source/WebCore/platform/graphics/android/rendering/TexturesGenerator.cpp index cc94c9c..74e663a 100644 --- a/Source/WebCore/platform/graphics/android/rendering/TexturesGenerator.cpp +++ b/Source/WebCore/platform/graphics/android/rendering/TexturesGenerator.cpp @@ -32,6 +32,7 @@ #if USE(ACCELERATED_COMPOSITING) #include "AndroidLog.h" +#include "BaseRenderer.h" #include "GLUtils.h" #include "PaintTileOperation.h" #include "TilesManager.h" @@ -39,6 +40,19 @@ namespace WebCore { +TexturesGenerator::TexturesGenerator(TilesManager* instance) + : Thread(false) + , m_tilesManager(instance) + , m_deferredMode(false) + , m_renderer(0) +{ +} + +TexturesGenerator::~TexturesGenerator() +{ + delete m_renderer; +} + bool TexturesGenerator::tryUpdateOperationWithPainter(Tile* tile, TilePainter* painter) { android::Mutex::Autolock lock(mRequestedOperationsLock); @@ -83,12 +97,11 @@ void TexturesGenerator::removeOperationsForFilter(OperationFilter* filter) i++; } } - delete filter; } status_t TexturesGenerator::readyToRun() { - ALOGV("Thread ready to run"); + m_renderer = BaseRenderer::createRenderer(); return NO_ERROR; } @@ -165,7 +178,9 @@ bool TexturesGenerator::threadLoop() if (currentOperation) { ALOGV("threadLoop, painting the request with priority %d", currentOperation->priority()); - currentOperation->run(); + // swap out the renderer if necessary + BaseRenderer::swapRendererIfNeeded(m_renderer); + currentOperation->run(m_renderer); } mRequestedOperationsLock.lock(); diff --git a/Source/WebCore/platform/graphics/android/rendering/TexturesGenerator.h b/Source/WebCore/platform/graphics/android/rendering/TexturesGenerator.h index 290ad08..e487edb 100644 --- a/Source/WebCore/platform/graphics/android/rendering/TexturesGenerator.h +++ b/Source/WebCore/platform/graphics/android/rendering/TexturesGenerator.h @@ -29,7 +29,7 @@ #if USE(ACCELERATED_COMPOSITING) #include "QueuedOperation.h" -#include "TilePainter.h" +#include "TransferQueue.h" #include <wtf/HashMap.h> #include <wtf/Vector.h> @@ -43,10 +43,9 @@ class TilesManager; class TexturesGenerator : public Thread { public: - TexturesGenerator(TilesManager* instance) : Thread(false) - , m_tilesManager(instance) - , m_deferredMode(false) { } - virtual ~TexturesGenerator() { } + TexturesGenerator(TilesManager* instance); + virtual ~TexturesGenerator(); + virtual status_t readyToRun(); bool tryUpdateOperationWithPainter(Tile* tile, TilePainter* painter); @@ -69,6 +68,7 @@ private: TilesManager* m_tilesManager; bool m_deferredMode; + BaseRenderer* m_renderer; // defer painting for one second if best in queue has priority // QueuedOperation::gDeferPriorityCutoff or higher diff --git a/Source/WebCore/platform/graphics/android/rendering/Tile.cpp b/Source/WebCore/platform/graphics/android/rendering/Tile.cpp index 96b189a..76be981 100644 --- a/Source/WebCore/platform/graphics/android/rendering/Tile.cpp +++ b/Source/WebCore/platform/graphics/android/rendering/Tile.cpp @@ -33,7 +33,7 @@ #include "AndroidLog.h" #include "GLUtils.h" -#include "RasterRenderer.h" +#include "BaseRenderer.h" #include "TextureInfo.h" #include "TileTexture.h" #include "TilesManager.h" @@ -64,7 +64,6 @@ Tile::Tile(bool isLayerTile) #ifdef DEBUG_COUNT ClassTracker::instance()->increment("Tile"); #endif - m_renderer = BaseRenderer::createRenderer(); } Tile::~Tile() @@ -74,8 +73,6 @@ Tile::~Tile() if (m_frontTexture) m_frontTexture->release(this); - delete m_renderer; - #ifdef DEBUG_COUNT ClassTracker::instance()->decrement("Tile"); #endif @@ -297,7 +294,7 @@ bool Tile::isTileVisible(const IntRect& viewTileBounds) } // This is called from the texture generation thread -void Tile::paintBitmap(TilePainter* painter) +void Tile::paintBitmap(TilePainter* painter, BaseRenderer* renderer) { // We acquire the values below atomically. This ensures that we are reading // values correctly across cores. Further, once we have these values they @@ -328,8 +325,6 @@ void Tile::paintBitmap(TilePainter* painter) return; } - // swap out the renderer if necessary - BaseRenderer::swapRendererIfNeeded(m_renderer); // setup the common renderInfo fields; TileRenderInfo renderInfo; renderInfo.x = x; @@ -343,7 +338,7 @@ void Tile::paintBitmap(TilePainter* painter) const float tileWidth = renderInfo.tileSize.width(); const float tileHeight = renderInfo.tileSize.height(); - m_renderer->renderTiledContent(renderInfo); + renderer->renderTiledContent(renderInfo); m_atomicSync.lock(); diff --git a/Source/WebCore/platform/graphics/android/rendering/Tile.h b/Source/WebCore/platform/graphics/android/rendering/Tile.h index b045f1f..f467bb0 100644 --- a/Source/WebCore/platform/graphics/android/rendering/Tile.h +++ b/Source/WebCore/platform/graphics/android/rendering/Tile.h @@ -28,7 +28,6 @@ #if USE(ACCELERATED_COMPOSITING) -#include "BaseRenderer.h" #include "FloatPoint.h" #include "SkRect.h" #include "SkRegion.h" @@ -39,9 +38,10 @@ namespace WebCore { +class BaseRenderer; +class GLWebViewState; class TextureInfo; class TileTexture; -class GLWebViewState; /** * An individual tile that is used to construct part of a webpage's BaseLayer of @@ -107,7 +107,7 @@ public: const FloatRect& fillPortion); // the only thread-safe function called by the background thread - void paintBitmap(TilePainter* painter); + void paintBitmap(TilePainter* painter, BaseRenderer* renderer); bool intersectWithRect(int x, int y, int tileWidth, int tileHeight, float scale, const SkRect& dirtyRect, @@ -171,8 +171,6 @@ private: // across all threads and cores. android::Mutex m_atomicSync; - BaseRenderer* m_renderer; - bool m_isLayerTile; // the most recent GL draw before this tile was prepared. used for diff --git a/Source/WebCore/platform/graphics/android/rendering/TilesManager.cpp b/Source/WebCore/platform/graphics/android/rendering/TilesManager.cpp index 0b4ba7b..e584b81 100644 --- a/Source/WebCore/platform/graphics/android/rendering/TilesManager.cpp +++ b/Source/WebCore/platform/graphics/android/rendering/TilesManager.cpp @@ -65,6 +65,10 @@ #define LAYER_TEXTURES_DESTROY_TIMEOUT 60 // If we do not need layers for 60 seconds, free the textures +// Eventually this should be dynamically be determined, and smart scheduling +// between the generators should be implemented +#define NUM_TEXTURES_GENERATORS 1 + namespace WebCore { int TilesManager::getMaxTextureAllocation() @@ -105,10 +109,21 @@ TilesManager::TilesManager() m_availableTextures.reserveCapacity(MAX_TEXTURE_ALLOCATION); m_tilesTextures.reserveCapacity(MAX_TEXTURE_ALLOCATION); m_availableTilesTextures.reserveCapacity(MAX_TEXTURE_ALLOCATION); - m_pixmapsGenerationThread = new TexturesGenerator(this); - m_pixmapsGenerationThread->run("TexturesGenerator"); + + m_textureGenerators = new sp<TexturesGenerator>[NUM_TEXTURES_GENERATORS]; + for (int i = 0; i < NUM_TEXTURES_GENERATORS; i++) { + m_textureGenerators[i] = new TexturesGenerator(this); + ALOGD("Starting TG #%d, %p", i, m_textureGenerators[i].get()); + m_textureGenerators[i]->run("TexturesGenerator"); + } } +TilesManager::~TilesManager() +{ + delete[] m_textureGenerators; +} + + void TilesManager::allocateTextures() { int nbTexturesToAllocate = m_currentTextureCount - m_textures.size(); @@ -488,6 +503,29 @@ void TilesManager::updateTilesIfContextVerified() return; } +void TilesManager::removeOperationsForFilter(OperationFilter* filter) +{ + for (int i = 0; i < NUM_TEXTURES_GENERATORS; i++) + m_textureGenerators[i]->removeOperationsForFilter(filter); + delete filter; +} + +bool TilesManager::tryUpdateOperationWithPainter(Tile* tile, TilePainter* painter) +{ + for (int i = 0; i < NUM_TEXTURES_GENERATORS; i++) { + if (m_textureGenerators[i]->tryUpdateOperationWithPainter(tile, painter)) + return true; + } + return false; +} + +void TilesManager::scheduleOperation(QueuedOperation* operation) +{ + // TODO: painter awareness, store prefer awareness, store preferred thread into painter + m_scheduleThread = (m_scheduleThread + 1) % NUM_TEXTURES_GENERATORS; + m_textureGenerators[m_scheduleThread]->scheduleOperation(operation); +} + int TilesManager::tileWidth() { return TILE_WIDTH; diff --git a/Source/WebCore/platform/graphics/android/rendering/TilesManager.h b/Source/WebCore/platform/graphics/android/rendering/TilesManager.h index f0d2eac..0781ef6 100644 --- a/Source/WebCore/platform/graphics/android/rendering/TilesManager.h +++ b/Source/WebCore/platform/graphics/android/rendering/TilesManager.h @@ -53,23 +53,9 @@ public: return gInstance != 0; } - void removeOperationsForFilter(OperationFilter* filter) - { - m_pixmapsGenerationThread->removeOperationsForFilter(filter); - } - - bool tryUpdateOperationWithPainter(Tile* tile, TilePainter* painter) - { - return m_pixmapsGenerationThread->tryUpdateOperationWithPainter(tile, painter); - } - - void scheduleOperation(QueuedOperation* operation) - { - m_pixmapsGenerationThread->scheduleOperation(operation); - } - ShaderProgram* shader() { return &m_shader; } TransferQueue* transferQueue(); + VideoLayerManager* videoLayerManager() { return &m_videoLayerManager; } void updateTilesIfContextVerified(); @@ -165,8 +151,15 @@ public: return m_drawGLCount; } + // operations on/for texture generator threads + void removeOperationsForFilter(OperationFilter* filter); + bool tryUpdateOperationWithPainter(Tile* tile, TilePainter* painter); + void scheduleOperation(QueuedOperation* operation); + private: TilesManager(); + ~TilesManager(); + int m_scheduleThread; void discardTexturesVector(unsigned long long sparedDrawCount, WTF::Vector<TileTexture*>& textures, @@ -198,7 +191,7 @@ private: unsigned int m_contentUpdates; // nr of successful tiled paints unsigned int m_webkitContentUpdates; // nr of paints from webkit - sp<TexturesGenerator> m_pixmapsGenerationThread; + sp<TexturesGenerator>* m_textureGenerators; android::Mutex m_texturesLock; diff --git a/Source/WebCore/platform/graphics/android/rendering/TransferQueue.cpp b/Source/WebCore/platform/graphics/android/rendering/TransferQueue.cpp index f37afa4..b15fa6d 100644 --- a/Source/WebCore/platform/graphics/android/rendering/TransferQueue.cpp +++ b/Source/WebCore/platform/graphics/android/rendering/TransferQueue.cpp @@ -32,6 +32,7 @@ #if USE(ACCELERATED_COMPOSITING) #include "AndroidLog.h" +#include "BaseRenderer.h" #include "DrawQuadData.h" #include "GLUtils.h" #include "Tile.h" @@ -389,8 +390,9 @@ void TransferQueue::updateDirtyTiles() } void TransferQueue::updateQueueWithBitmap(const TileRenderInfo* renderInfo, - const SkBitmap& bitmap) + SkBitmap& bitmap) { + TRACE_METHOD(); if (!tryUpdateQueueWithBitmap(renderInfo, bitmap)) { // failed placing bitmap in queue, discard tile's texture so it will be // re-enqueued (and repainted) @@ -401,7 +403,7 @@ void TransferQueue::updateQueueWithBitmap(const TileRenderInfo* renderInfo, } bool TransferQueue::tryUpdateQueueWithBitmap(const TileRenderInfo* renderInfo, - const SkBitmap& bitmap) + SkBitmap& bitmap) { // This lock need to cover the full update since it is possible that queue // will be cleaned up in the middle of this update without the lock. @@ -427,7 +429,7 @@ bool TransferQueue::tryUpdateQueueWithBitmap(const TileRenderInfo* renderInfo, } // b) After update the Surface Texture, now udpate the transfer queue info. - addItemInTransferQueue(renderInfo, currentUploadType, &bitmap); + addItemInTransferQueue(renderInfo, currentUploadType, bitmap); ALOGV("Bitmap updated x, y %d %d, baseTile %p", renderInfo->x, renderInfo->y, renderInfo->baseTile); @@ -473,7 +475,7 @@ void TransferQueue::addItemCommon(const TileRenderInfo* renderInfo, // Currently only called by GLUtils::updateSharedSurfaceTextureWithBitmap. void TransferQueue::addItemInTransferQueue(const TileRenderInfo* renderInfo, TextureUploadType type, - const SkBitmap* bitmap) + SkBitmap& bitmap) { m_transferQueueIndex = (m_transferQueueIndex + 1) % m_transferQueueSize; @@ -485,15 +487,18 @@ void TransferQueue::addItemInTransferQueue(const TileRenderInfo* renderInfo, TileTransferData* data = &m_transferQueue[index]; addItemCommon(renderInfo, type, data); - if (type == CpuUpload && bitmap) { + if (type == CpuUpload) { // Lazily create the bitmap if (!m_transferQueue[index].bitmap) { m_transferQueue[index].bitmap = new SkBitmap(); - int w = bitmap->width(); - int h = bitmap->height(); - m_transferQueue[index].bitmap->setConfig(bitmap->config(), w, h); + int w = bitmap.width(); + int h = bitmap.height(); + m_transferQueue[index].bitmap->setConfig(bitmap.config(), w, h); + m_transferQueue[index].bitmap->allocPixels(); } - bitmap->copyTo(m_transferQueue[index].bitmap, bitmap->config()); + SkBitmap temp = (*m_transferQueue[index].bitmap); + (*m_transferQueue[index].bitmap) = bitmap; + bitmap = temp; } m_emptyItemCount--; diff --git a/Source/WebCore/platform/graphics/android/rendering/TransferQueue.h b/Source/WebCore/platform/graphics/android/rendering/TransferQueue.h index c0835d7..55011b0 100644 --- a/Source/WebCore/platform/graphics/android/rendering/TransferQueue.h +++ b/Source/WebCore/platform/graphics/android/rendering/TransferQueue.h @@ -115,11 +115,11 @@ public: // insert the bitmap into the queue, mark the tile dirty if failing void updateQueueWithBitmap(const TileRenderInfo* renderInfo, - const SkBitmap& bitmap); + SkBitmap& bitmap); void addItemInTransferQueue(const TileRenderInfo* info, TextureUploadType type, - const SkBitmap* bitmap); + SkBitmap& bitmap); // Check if the item @ index is ready for update. // The lock will be done when returning true. bool readyForUpdate(); @@ -145,7 +145,7 @@ public: private: // return true if successfully inserted into queue bool tryUpdateQueueWithBitmap(const TileRenderInfo* renderInfo, - const SkBitmap& bitmap); + SkBitmap& bitmap); bool getHasGLContext(); void setHasGLContext(bool hasContext); void emptyAndAbandonQueue(); diff --git a/Source/WebCore/platform/graphics/android/utils/LinearAllocator.cpp b/Source/WebCore/platform/graphics/android/utils/LinearAllocator.cpp new file mode 100644 index 0000000..1899557 --- /dev/null +++ b/Source/WebCore/platform/graphics/android/utils/LinearAllocator.cpp @@ -0,0 +1,180 @@ +/* + * Copyright 2012, 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. + */ + +#define LOG_TAG "LinearAllocator" +#define LOG_NDEBUG 1 + +#include "config.h" +#include "LinearAllocator.h" + +#include "AndroidLog.h" + +namespace WebCore { + +// The ideal size of a page allocation +#define TARGET_PAGE_SIZE 16384 // 16kb + +// our pool needs to big enough to hold at least this many items +#define MIN_OBJECT_COUNT 4 + +#if LOG_NDEBUG +#define ADD_ALLOCATION(size) +#define RM_ALLOCATION(size) +#else +#include <utils/Thread.h> +static size_t s_totalAllocations = 0; +static double s_lastLogged = 0; +static android::Mutex s_mutex; + +static void _logUsageLocked() { + double now = currentTimeMS(); + if (now - s_lastLogged > 5) { + s_lastLogged = now; + ALOGV("Total memory usage: %d kb", s_totalAllocations / 1024); + } +} + +static void _addAllocation(size_t size) { + android::AutoMutex lock(s_mutex); + s_totalAllocations += size; + _logUsageLocked(); +} + +#define ADD_ALLOCATION(size) _addAllocation(size); +#define RM_ALLOCATION(size) _addAllocation(-size); +#endif + +class LinearAllocator::Page { +public: + Page* next() { return m_nextPage; } + void setNext(Page* next) { m_nextPage = next; } + + Page() + : m_nextPage(0) + {} + + void* start() + { + return (void*) (((unsigned)this) + sizeof(LinearAllocator::Page)); + } + + void* end(int pageSize) + { + return (void*) (((unsigned)start()) + pageSize); + } + +private: + Page(const Page& other) {} + Page* m_nextPage; +}; + +LinearAllocator::LinearAllocator(size_t averageAllocSize) + : m_next(0) + , m_currentPage(0) + , m_pages(0) +{ + if (averageAllocSize) { + int usable_page_size = TARGET_PAGE_SIZE - sizeof(LinearAllocator::Page); + int pcount = usable_page_size / averageAllocSize; + if (pcount < MIN_OBJECT_COUNT) + pcount = MIN_OBJECT_COUNT; + m_pageSize = pcount * averageAllocSize + sizeof(LinearAllocator::Page); + } else + m_pageSize = TARGET_PAGE_SIZE; + m_maxAllocSize = (m_pageSize - sizeof(LinearAllocator::Page)); +} + +LinearAllocator::~LinearAllocator(void) +{ + Page* p = m_pages; + while (p) { + Page* next = p->next(); + delete p; + RM_ALLOCATION(m_pageSize); + p = next; + } +} + +void* LinearAllocator::start(Page* p) +{ + return ((char*)p) + sizeof(Page); +} + +void* LinearAllocator::end(Page* p) +{ + return ((char*)p) + m_pageSize; +} + +void LinearAllocator::ensureNext(size_t size) +{ + if (m_next && ((char*)m_next + size) <= end(m_currentPage)) + return; + Page* p = newPage(); + if (m_currentPage) + m_currentPage->setNext(p); + m_currentPage = p; + if (!m_pages) + m_pages = m_currentPage; + m_next = start(m_currentPage); +} + +unsigned LinearAllocator::memusage() +{ + unsigned memusage = 0; + Page* p = m_pages; + while (p) { + memusage += m_pageSize; + p = p->next(); + } + return memusage; +} + +void* LinearAllocator::alloc(size_t size) +{ + if (size > m_maxAllocSize) { + ALOGE("Allocation too large! (%d exceeds max size %d)", size, m_maxAllocSize); + return 0; + } + ensureNext(size); + void* ptr = m_next; + m_next = ((char*)m_next) + size; + return ptr; +} + +void LinearAllocator::rewindTo(void* ptr) +{ + // Don't bother rewinding across pages + if (ptr >= start(m_currentPage) && ptr < end(m_currentPage)) + m_next = ptr; +} + +LinearAllocator::Page* LinearAllocator::newPage() +{ + ADD_ALLOCATION(m_pageSize); + void* buf = malloc(m_pageSize); + return new (buf) Page(); +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/context/GraphicsOperationCollection.h b/Source/WebCore/platform/graphics/android/utils/LinearAllocator.h index 9d7b530..1f3265c 100644 --- a/Source/WebCore/platform/graphics/android/context/GraphicsOperationCollection.h +++ b/Source/WebCore/platform/graphics/android/utils/LinearAllocator.h @@ -23,50 +23,39 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef GraphicsOperationCollection_h -#define GraphicsOperationCollection_h - -#if USE(ACCELERATED_COMPOSITING) - -#include "Color.h" -#include "GraphicsOperation.h" -#include "IntRect.h" -#include "SkRefCnt.h" +#ifndef LinearAllocator_h +#define LinearAllocator_h namespace WebCore { -class PlatformGraphicsContext; - -class GraphicsOperationCollection : public SkRefCnt { +class LinearAllocator +{ public: - GraphicsOperationCollection(const IntRect& drawArea); - ~GraphicsOperationCollection(); + LinearAllocator(size_t averageAllocSize = 0); + ~LinearAllocator(); - void apply(PlatformGraphicsContext* context); - void append(GraphicsOperation::Operation* operation); - - bool isEmpty(); + void* alloc(size_t size); + void rewindTo(void*); private: - IntRect m_drawArea; - Vector<GraphicsOperation::Operation*> m_operations; -}; + LinearAllocator(const LinearAllocator& other); -class AutoGraphicsOperationCollection { -public: - AutoGraphicsOperationCollection(const IntRect& area); - ~AutoGraphicsOperationCollection(); - GraphicsContext* context() { return m_graphicsContext; } - GraphicsOperationCollection* picture() { return m_graphicsOperationCollection; } + class Page; -private: - GraphicsOperationCollection* m_graphicsOperationCollection; - PlatformGraphicsContext* m_platformGraphicsContext; - GraphicsContext* m_graphicsContext; -}; + Page* newPage(); + void ensureNext(size_t size); + void* start(Page *p); + void* end(Page* p); -} + unsigned memusage(); + + size_t m_pageSize; + size_t m_maxAllocSize; + void* m_next; + Page* m_currentPage; + Page* m_pages; +}; -#endif // USE(ACCELERATED_COMPOSITING) +} // namespace WebCore -#endif // GraphicsOperationCollection_h +#endif // LinearAllocator_h diff --git a/Source/WebCore/platform/mock/GeolocationServiceMock.cpp b/Source/WebCore/platform/mock/GeolocationServiceMock.cpp index c3ba7b4..b254cb8 100644 --- a/Source/WebCore/platform/mock/GeolocationServiceMock.cpp +++ b/Source/WebCore/platform/mock/GeolocationServiceMock.cpp @@ -80,12 +80,7 @@ void GeolocationServiceMock::setError(PassRefPtr<PositionError> error) makeGeolocationCallbackFromAllInstances(); } -#if PLATFORM(ANDROID) -// TODO: Upstream to webkit.org. See https://bugs.webkit.org/show_bug.cgi?id=34082 -bool GeolocationServiceMock::startUpdating(PositionOptions*, bool /* suspend */) -#else bool GeolocationServiceMock::startUpdating(PositionOptions*) -#endif { m_isActive = true; m_timer.startOneShot(0); diff --git a/Source/WebCore/platform/mock/GeolocationServiceMock.h b/Source/WebCore/platform/mock/GeolocationServiceMock.h index 1b4db93..7d02797 100755 --- a/Source/WebCore/platform/mock/GeolocationServiceMock.h +++ b/Source/WebCore/platform/mock/GeolocationServiceMock.h @@ -46,12 +46,7 @@ class GeolocationServiceMock : public GeolocationService { GeolocationServiceMock(GeolocationServiceClient*); virtual ~GeolocationServiceMock(); -#if PLATFORM(ANDROID) - // TODO: Upstream to webkit.org. See https://bugs.webkit.org/show_bug.cgi?id=34082 - virtual bool startUpdating(PositionOptions*, bool suspend); -#else virtual bool startUpdating(PositionOptions*); -#endif virtual void stopUpdating(); static void setPosition(PassRefPtr<Geoposition> position); diff --git a/Source/WebCore/plugins/android/PluginViewAndroid.cpp b/Source/WebCore/plugins/android/PluginViewAndroid.cpp index fdf6e03..24a14aa 100644 --- a/Source/WebCore/plugins/android/PluginViewAndroid.cpp +++ b/Source/WebCore/plugins/android/PluginViewAndroid.cpp @@ -55,7 +55,6 @@ #include "Touch.h" #include "TouchEvent.h" #include "TouchList.h" -#include "android_graphics.h" #include "SkCanvas.h" #include "npruntime_impl.h" // #include "runtime_root.h" @@ -405,7 +404,7 @@ bool PluginView::platformGetValueStatic(NPNVariable variable, void* value, NPErr // our interface query is valid with no NPP instance *result = NPERR_GENERIC_ERROR; - switch (variable) { + switch ((int)variable) { case NPNVisOfflineBool: { if (value != NULL) { bool* retValue = static_cast<bool*>(value); @@ -422,7 +421,7 @@ bool PluginView::platformGetValueStatic(NPNVariable variable, void* value, NPErr return true; } default: - ; // do nothing + break; // do nothing } (void)anp_getInterface(variable, value, result); @@ -490,7 +489,7 @@ void PluginView::setNPWindowIfNeeded() bool PluginView::platformGetValue(NPNVariable variable, void* value, NPError* result) { - switch (variable) { + switch ((int)variable) { case NPNVWindowNPObject: { NPObject* windowScriptObject = m_parentFrame->script()->windowScriptNPObject(); @@ -581,7 +580,7 @@ NPError PluginView::platformSetValue(NPPVariable variable, void* value) { NPError error = NPERR_GENERIC_ERROR; - switch (variable) { + switch ((int)variable) { case kRequestDrawingModel_ANPSetValue: { ANPDrawingModel model = reinterpret_cast<ANPDrawingModel>(value); if (m_window->setDrawingModel(model)) @@ -690,15 +689,12 @@ void PluginView::paint(GraphicsContext* context, const IntRect& rect) notification of its global position change. */ updatePluginWidget(); - SkCanvas* canvas = context->platformContext()->getCanvas(); - if (!canvas) - return; - m_window->setSurfaceClip(canvas->getTotalClip().getBounds()); + m_window->setSurfaceClip(context->platformContext()->getTotalClipBounds()); } else { m_window->inval(rect, false); context->save(); context->translate(frame.x(), frame.y()); - m_window->draw(android_gc2canvas(context)); + m_window->draw(context->platformContext()); context->restore(); } diff --git a/Source/WebKit/Android.mk b/Source/WebKit/Android.mk index c3e9798..07634b6 100644 --- a/Source/WebKit/Android.mk +++ b/Source/WebKit/Android.mk @@ -27,6 +27,9 @@ LOCAL_SRC_FILES := \ android/WebCoreSupport/EditorClientAndroid.cpp \ android/WebCoreSupport/FrameLoaderClientAndroid.cpp \ android/WebCoreSupport/FrameNetworkingContextAndroid.cpp \ + android/WebCoreSupport/GeolocationClientAndroid.cpp \ + android/WebCoreSupport/GeolocationClientImpl.cpp \ + android/WebCoreSupport/GeolocationManager.cpp \ android/WebCoreSupport/GeolocationPermissions.cpp \ android/WebCoreSupport/MediaPlayerPrivateAndroid.cpp \ android/WebCoreSupport/MemoryUsage.cpp \ @@ -61,6 +64,7 @@ LOCAL_SRC_FILES += \ android/jni/DeviceMotionClientImpl.cpp \ android/jni/DeviceOrientationClientImpl.cpp \ android/jni/GeolocationPermissionsBridge.cpp \ + android/jni/GeolocationServiceBridge.cpp \ android/jni/JavaBridge.cpp \ android/jni/JavaSharedClient.cpp \ android/jni/MIMETypeRegistry.cpp \ diff --git a/Source/WebKit/android/AndroidLog.h b/Source/WebKit/android/AndroidLog.h index f034d35..6b6c1a0 100644 --- a/Source/WebKit/android/AndroidLog.h +++ b/Source/WebKit/android/AndroidLog.h @@ -30,6 +30,8 @@ #define LOG_TAG __FILE__ #endif +#define ATRACE_TAG ATRACE_TAG_WEBVIEW + #include <cutils/log.h> #include <utils/Trace.h> #include <wtf/CurrentTime.h> @@ -58,7 +60,7 @@ extern FILE* gRenderTreeFile; #define INT_RECT_FORMAT "[x=%d,y=%d,w=%d,h=%d]" #define INT_RECT_ARGS(ir) ir.x(), ir.y(), ir.width(), ir.height() -#define TRACE_METHOD() android::ScopedTrace __st(ATRACE_TAG_WEBVIEW, __func__); +#define TRACE_METHOD() android::ScopedTrace __st(ATRACE_TAG, __func__); #define TIME_METHOD() MethodTimer __method_timer(__func__) class MethodTimer { diff --git a/Source/WebKit/android/RenderSkinMediaButton.cpp b/Source/WebKit/android/RenderSkinMediaButton.cpp index b3aa57d..a2f19c3 100644 --- a/Source/WebKit/android/RenderSkinMediaButton.cpp +++ b/Source/WebKit/android/RenderSkinMediaButton.cpp @@ -26,12 +26,13 @@ #define LOG_TAG "WebCore" #include "config.h" -#include "android_graphics.h" +#include "RenderSkinMediaButton.h" + #include "Document.h" #include "IntRect.h" #include "Node.h" #include "RenderObject.h" -#include "RenderSkinMediaButton.h" +#include "RenderSkinAndroid.h" #include "RenderSlider.h" #include "SkCanvas.h" #include "SkNinePatch.h" @@ -88,8 +89,9 @@ void RenderSkinMediaButton::Decode() } } -void RenderSkinMediaButton::Draw(SkCanvas* canvas, const IntRect& r, int buttonType, - bool translucent, RenderObject* o, bool drawBackground) +void RenderSkinMediaButton::Draw(SkCanvas* canvas, const IntRect& r, + MediaButton buttonType, bool translucent, + bool drawBackground, const IntRect& thumb) { if (!gDecoded) { Decode(); @@ -179,9 +181,7 @@ void RenderSkinMediaButton::Draw(SkCanvas* canvas, const IntRect& r, int buttonT SkScalar quarterHeight = SkScalarHalf(SkScalarHalf(bounds.height())); bounds.fTop += quarterHeight + SkScalarHalf(3); bounds.fBottom += -quarterHeight + SK_ScalarHalf; - if (o && o->isSlider()) { - RenderSlider* slider = toRenderSlider(o); - IntRect thumb = slider->thumbRect(); + if (!thumb.isEmpty()) { // Inset the track by half the width of the thumb, so the track // does not appear to go beyond the space where the thumb can // be. diff --git a/Source/WebKit/android/RenderSkinMediaButton.h b/Source/WebKit/android/RenderSkinMediaButton.h index 484b90c..98c9e04 100644 --- a/Source/WebKit/android/RenderSkinMediaButton.h +++ b/Source/WebKit/android/RenderSkinMediaButton.h @@ -26,27 +26,43 @@ #ifndef RenderSkinMediaButton_h #define RenderSkinMediaButton_h -#include "RenderSkinAndroid.h" +#include "IntRect.h" class SkCanvas; namespace WebCore { -class IntRect; -class RenderObject; class RenderSkinMediaButton { public: static void Decode(); + /** - * 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. + * Button types */ - static void Draw(SkCanvas* , const IntRect& , int buttonType, bool translucent = false, - RenderObject* o = 0, bool drawBackground = true); + typedef enum + { + PAUSE, + PLAY, + MUTE, + REWIND, + FORWARD, + FULLSCREEN, + SPINNER_OUTER, + SPINNER_INNER, + VIDEO, + BACKGROUND_SLIDER, + SLIDER_TRACK, + SLIDER_THUMB + } MediaButton; + /** - * Button types + * 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. */ - enum { PAUSE, PLAY, MUTE, REWIND, FORWARD, FULLSCREEN, SPINNER_OUTER, SPINNER_INNER , VIDEO, BACKGROUND_SLIDER, SLIDER_TRACK, SLIDER_THUMB }; + static void Draw(SkCanvas* canvas, const IntRect& rect, MediaButton buttonType, + bool translucent = false, bool drawBackground = true, + const IntRect& thumb = IntRect()); + /** * Slider dimensions */ diff --git a/Source/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp b/Source/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp index 907dc3c..9094732 100644 --- a/Source/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp +++ b/Source/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp @@ -512,39 +512,6 @@ void ChromeClientAndroid::populateVisitedLinks() android::WebViewCore::getWebViewCore(view)->populateVisitedLinks(&page->group()); } -void ChromeClientAndroid::requestGeolocationPermissionForFrame(Frame* frame, Geolocation* geolocation) -{ - ASSERT(geolocation); - if (!m_geolocationPermissions) { - m_geolocationPermissions = new GeolocationPermissions(android::WebViewCore::getWebViewCore(frame->view()), - m_webFrame->page()->mainFrame()); - } - m_geolocationPermissions->queryPermissionState(frame); -} - -void ChromeClientAndroid::cancelGeolocationPermissionRequestForFrame(Frame* frame, WebCore::Geolocation*) -{ - if (m_geolocationPermissions) - m_geolocationPermissions->cancelPermissionStateQuery(frame); -} - -void ChromeClientAndroid::provideGeolocationPermissions(const String &origin, bool allow, bool remember) -{ - ASSERT(m_geolocationPermissions); - m_geolocationPermissions->providePermissionState(origin, allow, remember); -} - -void ChromeClientAndroid::storeGeolocationPermissions() -{ - GeolocationPermissions::maybeStorePermanentPermissions(); -} - -void ChromeClientAndroid::onMainFrameLoadStarted() -{ - if (m_geolocationPermissions.get()) - m_geolocationPermissions->resetTemporaryPermissionStates(); -} - void ChromeClientAndroid::runOpenPanel(Frame* frame, PassRefPtr<FileChooser> chooser) { @@ -605,16 +572,6 @@ void ChromeClientAndroid::reachedApplicationCacheOriginQuota(SecurityOrigin*) notImplemented(); } -#if ENABLE(ANDROID_INSTALLABLE_WEB_APPS) -void ChromeClientAndroid::webAppCanBeInstalled() -{ - FrameView* frameView = m_webFrame->page()->mainFrame()->view(); - android::WebViewCore* core = android::WebViewCore::getWebViewCore(frameView); - if (core) - core->notifyWebAppCanBeInstalled(); -} -#endif - #if ENABLE(VIDEO) bool ChromeClientAndroid::supportsFullscreenForNode(const Node* node) { @@ -627,16 +584,23 @@ void ChromeClientAndroid::enterFullscreenForNode(Node* node) return; HTMLMediaElement* videoElement = static_cast<HTMLMediaElement*>(node); - String url = videoElement->currentSrc(); - LayerAndroid* layer = videoElement->platformLayer(); - if (!layer) - return; FrameView* frameView = m_webFrame->page()->mainFrame()->view(); android::WebViewCore* core = android::WebViewCore::getWebViewCore(frameView); - m_webFrame->page()->mainFrame()->document()->webkitWillEnterFullScreenForElement(videoElement); if (core) - core->enterFullscreenForVideoLayer(layer->uniqueId(), url); + core->enterFullscreenForVideoLayer(); + + MediaPlayer* player = videoElement->player(); + if (player) { + // We need to use the same document object as the + // MediaPlayerPrivateAndroid::onStopFullscreen(). + Document* doc = player->mediaPlayerClient()->mediaPlayerOwningDocument(); + if (doc) + doc->webkitWillEnterFullScreenForElement(videoElement); + // Now the player is responsible to trigger to the java side for + // entering full screen mode. + player->enterFullscreenMode(); + } } void ChromeClientAndroid::exitFullscreenForNode(Node* node) diff --git a/Source/WebKit/android/WebCoreSupport/ChromeClientAndroid.h b/Source/WebKit/android/WebCoreSupport/ChromeClientAndroid.h index 36576e6..4d27605 100644 --- a/Source/WebKit/android/WebCoreSupport/ChromeClientAndroid.h +++ b/Source/WebKit/android/WebCoreSupport/ChromeClientAndroid.h @@ -28,7 +28,6 @@ #include "ChromeClient.h" -#include "GeolocationPermissions.h" #include "PopupMenu.h" #include "SearchPopupMenu.h" #include "Timer.h" @@ -47,13 +46,13 @@ namespace android { class ChromeClientAndroid : public ChromeClient { public: - ChromeClientAndroid() : m_webFrame(0), m_geolocationPermissions(0) + ChromeClientAndroid() : m_webFrame(0) #if USE(ACCELERATED_COMPOSITING) - , m_rootGraphicsLayer(0) - , m_needsLayerSync(false) + , m_rootGraphicsLayer(0) + , m_needsLayerSync(false) #endif - , m_triedToReclaimDBQuota(false) - { } + , m_triedToReclaimDBQuota(false) + { } virtual void chromeDestroyed(); virtual void setWindowRect(const FloatRect&); @@ -147,12 +146,9 @@ namespace android { #endif // Methods used to request and provide Geolocation permissions. - virtual void requestGeolocationPermissionForFrame(Frame*, Geolocation*); - virtual void cancelGeolocationPermissionRequestForFrame(WebCore::Frame*, WebCore::Geolocation*); - // Android-specific - void provideGeolocationPermissions(const String &origin, bool allow, bool remember); - void storeGeolocationPermissions(); - void onMainFrameLoadStarted(); + // Not used with client-based Geolocation + virtual void requestGeolocationPermissionForFrame(Frame*, Geolocation*) { ASSERT_NOT_REACHED(); } + virtual void cancelGeolocationPermissionRequestForFrame(WebCore::Frame*, WebCore::Geolocation*) { ASSERT_NOT_REACHED(); } virtual void runOpenPanel(Frame*, PassRefPtr<FileChooser>); virtual void setCursor(const Cursor&); @@ -184,10 +180,6 @@ namespace android { virtual void showContextMenu(); #endif -#if ENABLE(ANDROID_INSTALLABLE_WEB_APPS) - virtual void webAppCanBeInstalled(); -#endif - #if ENABLE(FULLSCREEN_API) virtual void exitFullScreenForElement(Element*); #endif @@ -202,8 +194,6 @@ namespace android { private: android::WebFrame* m_webFrame; - // The Geolocation permissions manager. - OwnPtr<GeolocationPermissions> m_geolocationPermissions; #if USE(ACCELERATED_COMPOSITING) WebCore::GraphicsLayer* m_rootGraphicsLayer; bool m_needsLayerSync; diff --git a/Source/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp b/Source/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp index ac5cd9d..f62b2d1 100644 --- a/Source/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp +++ b/Source/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp @@ -76,7 +76,6 @@ #include "WebViewClientError.h" #include "WebViewCore.h" #include "autofill/WebAutofill.h" -#include "android_graphics.h" #include <androidfw/AssetManager.h> #include <wtf/text/CString.h> diff --git a/Source/WebKit/android/WebCoreSupport/GeolocationClientAndroid.cpp b/Source/WebKit/android/WebCoreSupport/GeolocationClientAndroid.cpp new file mode 100644 index 0000000..7c5b207 --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/GeolocationClientAndroid.cpp @@ -0,0 +1,96 @@ +/* + * Copyright 2012, 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 "GeolocationClientAndroid.h" + +#include "WebViewCore.h" + +#include <Frame.h> +#include <Page.h> + +using WebCore::Geolocation; +using WebCore::GeolocationClient; +using WebCore::GeolocationController; +using WebCore::GeolocationPosition; + +namespace android { + +GeolocationClientAndroid::GeolocationClientAndroid() : m_webViewCore(0) +{ +} + +GeolocationClientAndroid::~GeolocationClientAndroid() +{ +} + +void GeolocationClientAndroid::geolocationDestroyed() +{ + delete this; +} + +void GeolocationClientAndroid::startUpdating() +{ + client()->startUpdating(); +} + +void GeolocationClientAndroid::stopUpdating() +{ + client()->stopUpdating(); +} + +void GeolocationClientAndroid::setEnableHighAccuracy(bool enableHighAccuracy) +{ + client()->setEnableHighAccuracy(enableHighAccuracy); +} + +GeolocationPosition* GeolocationClientAndroid::lastPosition() +{ + return client()->lastPosition(); +} + +void GeolocationClientAndroid::requestPermission(Geolocation* geolocation) +{ + client()->requestPermission(geolocation); +} + +void GeolocationClientAndroid::cancelPermissionRequest(Geolocation* geolocation) +{ + client()->cancelPermissionRequest(geolocation); +} + +void GeolocationClientAndroid::setWebViewCore(WebViewCore* webViewCore) +{ + ASSERT(!m_webViewCore); + m_webViewCore = webViewCore; + ASSERT(m_webViewCore); +} + +GeolocationClient* GeolocationClientAndroid::client() const +{ + return m_webViewCore->geolocationManager()->client(); +} + +} // namespace android diff --git a/Source/WebKit/android/WebCoreSupport/GeolocationClientAndroid.h b/Source/WebKit/android/WebCoreSupport/GeolocationClientAndroid.h new file mode 100644 index 0000000..22405e1 --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/GeolocationClientAndroid.h @@ -0,0 +1,61 @@ +/* + * Copyright 2012, 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 GeolocationClientAndroid_h +#define GeolocationClientAndroid_h + +#include <GeolocationClient.h> + +namespace android { + +class WebViewCore; + +// The Android implementation of GeolocationClient. Acts as a proxy to +// the real or mock impl, which is owned by the GeolocationManager. +class GeolocationClientAndroid : public WebCore::GeolocationClient { +public: + GeolocationClientAndroid(); + virtual ~GeolocationClientAndroid(); + + // GeolocationClient + virtual void geolocationDestroyed(); + virtual void startUpdating(); + virtual void stopUpdating(); + virtual void setEnableHighAccuracy(bool); + virtual WebCore::GeolocationPosition* lastPosition(); + virtual void requestPermission(WebCore::Geolocation*); + virtual void cancelPermissionRequest(WebCore::Geolocation*); + + void setWebViewCore(WebViewCore*); + +private: + WebCore::GeolocationClient* client() const; + + WebViewCore* m_webViewCore; +}; + +} // namespace android + +#endif // GeolocationClientAndroid_h diff --git a/Source/WebKit/android/WebCoreSupport/GeolocationClientImpl.cpp b/Source/WebKit/android/WebCoreSupport/GeolocationClientImpl.cpp new file mode 100644 index 0000000..6291b7d --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/GeolocationClientImpl.cpp @@ -0,0 +1,223 @@ +/* + * Copyright 2012, 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 "GeolocationClientImpl.h" + +#include <Frame.h> +#include <Page.h> +#include <GeolocationController.h> +#include <GeolocationError.h> +#include <GeolocationPosition.h> +#include <WebViewCore.h> +#if PLATFORM(ANDROID) +// Required for sim-eng build +#include <math.h> +#endif +#include <wtf/CurrentTime.h> + +using WebCore::Geolocation; +using WebCore::GeolocationError; +using WebCore::GeolocationPosition; +using WebCore::Timer; + +using namespace std; + +namespace { + +bool isPositionMovement(GeolocationPosition* position1, GeolocationPosition* position2) +{ + // For the small distances in which we are likely concerned, it's reasonable + // to approximate the distance between the two positions as the sum of the + // differences in latitude and longitude. + double delta = fabs(position1->latitude() - position2->latitude()) + fabs(position1->longitude() - position2->longitude()); + // Approximate conversion from degrees of arc to metres. + delta *= 60 * 1852; + // The threshold is when the distance between the two positions exceeds the + // worse (larger) of the two accuracies. + int maxAccuracy = max(position1->accuracy(), position2->accuracy()); + return delta > maxAccuracy; +} + +bool isPositionMoreAccurate(GeolocationPosition* position1, GeolocationPosition* position2) +{ + return position2->accuracy() < position1->accuracy(); +} + +bool isPositionMoreTimely(GeolocationPosition* position1) +{ + double currentTime = WTF::currentTime(); + double maximumAge = 10 * 60; // 10 minutes + return currentTime - position1->timestamp() > maximumAge; +} + +} // anonymous namespace + +namespace android { + +GeolocationClientImpl::GeolocationClientImpl(WebViewCore* webViewCore) + : m_webViewCore(webViewCore) + , m_timer(this, &GeolocationClientImpl::timerFired) + , m_isSuspended(false) + , m_useGps(false) +{ +} + +GeolocationClientImpl::~GeolocationClientImpl() +{ +} + +void GeolocationClientImpl::geolocationDestroyed() +{ + // Lifetime is managed by GeolocationManager. +} + +void GeolocationClientImpl::startUpdating() +{ + // This method is called every time a new watch or one-shot position request + // is started. If we already have a position or an error, call back + // immediately. + if (m_lastPosition || m_lastError) { + m_timer.startOneShot(0); + } + + // Lazilly create the Java object. + bool haveJavaBridge = m_javaBridge; + if (!haveJavaBridge) + m_javaBridge.set(new GeolocationServiceBridge(this, m_webViewCore)); + ASSERT(m_javaBridge); + + // Set whether to use GPS before we start the implementation. + m_javaBridge->setEnableGps(m_useGps); + + // If we're suspended, don't start the service. It will be started when we + // get the call to resume(). + if (!haveJavaBridge && !m_isSuspended) + m_javaBridge->start(); +} + +void GeolocationClientImpl::stopUpdating() +{ + // TODO: It would be good to re-use the Java bridge object. + m_javaBridge.clear(); + m_useGps = false; + // Reset last position and error to make sure that we always try to get a + // new position from the client when a request is first made. + m_lastPosition = 0; + m_lastError = 0; + + if (m_timer.isActive()) + m_timer.stop(); +} + +void GeolocationClientImpl::setEnableHighAccuracy(bool enableHighAccuracy) +{ + // On Android, high power == GPS. + m_useGps = enableHighAccuracy; + if (m_javaBridge) + m_javaBridge->setEnableGps(m_useGps); +} + +GeolocationPosition* GeolocationClientImpl::lastPosition() +{ + return m_lastPosition.get(); +} + +void GeolocationClientImpl::requestPermission(Geolocation* geolocation) +{ + permissions()->queryPermissionState(geolocation->frame()); +} + +void GeolocationClientImpl::cancelPermissionRequest(Geolocation* geolocation) +{ + permissions()->cancelPermissionStateQuery(geolocation->frame()); +} + +// Note that there is no guarantee that subsequent calls to this method offer a +// more accurate or updated position. +void GeolocationClientImpl::newPositionAvailable(PassRefPtr<GeolocationPosition> position) +{ + ASSERT(position); + if (!m_lastPosition + || isPositionMovement(m_lastPosition.get(), position.get()) + || isPositionMoreAccurate(m_lastPosition.get(), position.get()) + || isPositionMoreTimely(m_lastPosition.get())) { + m_lastPosition = position; + // Remove the last error. + m_lastError = 0; + m_webViewCore->mainFrame()->page()->geolocationController()->positionChanged(m_lastPosition.get()); + } +} + +void GeolocationClientImpl::newErrorAvailable(PassRefPtr<WebCore::GeolocationError> error) +{ + ASSERT(error); + // We leave the last position + m_lastError = error; + m_webViewCore->mainFrame()->page()->geolocationController()->errorOccurred(m_lastError.get()); +} + +void GeolocationClientImpl::suspend() +{ + m_isSuspended = true; + if (m_javaBridge) + m_javaBridge->stop(); +} + +void GeolocationClientImpl::resume() +{ + m_isSuspended = false; + if (m_javaBridge) + m_javaBridge->start(); +} + +void GeolocationClientImpl::resetTemporaryPermissionStates() +{ + permissions()->resetTemporaryPermissionStates(); +} + +void GeolocationClientImpl::providePermissionState(String origin, bool allow, bool remember) +{ + permissions()->providePermissionState(origin, allow, remember); +} + +GeolocationPermissions* GeolocationClientImpl::permissions() const +{ + if (!m_permissions) + m_permissions = new GeolocationPermissions(m_webViewCore); + return m_permissions.get(); +} + +void GeolocationClientImpl::timerFired(Timer<GeolocationClientImpl>* timer) +{ + ASSERT(&m_timer == timer); + ASSERT(m_lastPosition || m_lastError); + if (m_lastPosition) + m_webViewCore->mainFrame()->page()->geolocationController()->positionChanged(m_lastPosition.get()); + else + m_webViewCore->mainFrame()->page()->geolocationController()->errorOccurred(m_lastError.get()); +} + +} // namespace android diff --git a/Source/WebKit/android/WebCoreSupport/GeolocationClientImpl.h b/Source/WebKit/android/WebCoreSupport/GeolocationClientImpl.h new file mode 100644 index 0000000..26e6c0c --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/GeolocationClientImpl.h @@ -0,0 +1,86 @@ +/* + * Copyright 2012, 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 GeolocationClientImpl_h +#define GeolocationClientImpl_h + +#include "GeolocationServiceBridge.h" +#include "GeolocationClient.h" +#include "GeolocationPermissions.h" + +#include <Timer.h> +#include <wtf/OwnPtr.h> +#include <wtf/RefPtr.h> + +namespace WebCore { +class Geolocation; +class GeolocationController; +} + +namespace android { + +class WebViewCore; + +// The real implementation of GeolocationClient. +class GeolocationClientImpl : public WebCore::GeolocationClient, public GeolocationServiceBridge::Listener { +public: + GeolocationClientImpl(WebViewCore*); + virtual ~GeolocationClientImpl(); + + // WebCore::GeolocationClient + virtual void geolocationDestroyed(); + virtual void startUpdating(); + virtual void stopUpdating(); + virtual void setEnableHighAccuracy(bool); + virtual WebCore::GeolocationPosition* lastPosition(); + virtual void requestPermission(WebCore::Geolocation*); + virtual void cancelPermissionRequest(WebCore::Geolocation*); + + // GeolocationServiceBridge::Listener + virtual void newPositionAvailable(PassRefPtr<WebCore::GeolocationPosition>); + virtual void newErrorAvailable(PassRefPtr<WebCore::GeolocationError>); + + void suspend(); + void resume(); + void resetTemporaryPermissionStates(); + void providePermissionState(String origin, bool allow, bool remember); + +private: + GeolocationPermissions* permissions() const; + void timerFired(WebCore::Timer<GeolocationClientImpl>*); + + WebViewCore* m_webViewCore; + RefPtr<WebCore::GeolocationPosition> m_lastPosition; + RefPtr<WebCore::GeolocationError> m_lastError; + OwnPtr<GeolocationServiceBridge> m_javaBridge; + mutable OwnPtr<GeolocationPermissions> m_permissions; + WebCore::Timer<GeolocationClientImpl> m_timer; + bool m_isSuspended; + bool m_useGps; +}; + +} // namespace android + +#endif // GeolocationClientImpl_h diff --git a/Source/WebKit/android/WebCoreSupport/GeolocationManager.cpp b/Source/WebKit/android/WebCoreSupport/GeolocationManager.cpp new file mode 100644 index 0000000..cbf399d --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/GeolocationManager.cpp @@ -0,0 +1,125 @@ +/* + * Copyright 2012, 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 "GeolocationManager.h" + +#include "GeolocationClientImpl.h" +#include "WebViewCore.h" + +#include <Frame.h> +#include <GeolocationError.h> +#include <GeolocationPosition.h> +#include <JNIHelp.h> +#include <Page.h> + +using WebCore::GeolocationClient; +using WebCore::GeolocationClientMock; + +namespace android { + +GeolocationManager::GeolocationManager(WebViewCore* webViewCore) + : m_useMock(false) + , m_webViewCore(webViewCore) +{ +} + +GeolocationClient* GeolocationManager::client() const +{ + if (m_useMock) + return mockClient(); + return realClient(); +} + +void GeolocationManager::suspendRealClient() +{ + // Don't create the real client if it's not present. + if (m_realClient) + m_realClient->suspend(); +} + +void GeolocationManager::resumeRealClient() +{ + // Don't create the real client if it's not present. + if (m_realClient) + m_realClient->resume(); +} + +void GeolocationManager::resetRealClientTemporaryPermissionStates() +{ + // Don't create the real client if it's not present. + if (m_realClient) + m_realClient->resetTemporaryPermissionStates(); +} + +void GeolocationManager::provideRealClientPermissionState(WTF::String origin, bool allow, bool remember) +{ + // Don't create the real client if it's not present. + if (m_realClient) + m_realClient->providePermissionState(origin, allow, remember); +} + +void GeolocationManager::setUseMock() +{ + m_useMock = true; + m_mockClient.clear(); +} + +void GeolocationManager::setMockPosition(PassRefPtr<WebCore::GeolocationPosition> position) +{ + ASSERT(m_useMock); + mockClient()->setPosition(position); +} + +void GeolocationManager::setMockError(PassRefPtr<WebCore::GeolocationError> error) +{ + ASSERT(m_useMock); + mockClient()->setError(error); +} + +void GeolocationManager::setMockPermission(bool allowed) +{ + ASSERT(m_useMock); + mockClient()->setPermission(allowed); +} + +GeolocationClientImpl* GeolocationManager::realClient() const +{ + if (!m_realClient) + m_realClient.set(new GeolocationClientImpl(m_webViewCore)); + return m_realClient.get(); +} + +GeolocationClientMock* GeolocationManager::mockClient() const +{ + ASSERT(m_useMock); + if (!m_mockClient) { + m_mockClient.set(new GeolocationClientMock); + m_mockClient->setController(m_webViewCore->mainFrame()->page()->geolocationController()); + } + return m_mockClient.get(); +} + +} // namespace android diff --git a/Source/WebKit/android/WebCoreSupport/GeolocationManager.h b/Source/WebKit/android/WebCoreSupport/GeolocationManager.h new file mode 100644 index 0000000..6459db1 --- /dev/null +++ b/Source/WebKit/android/WebCoreSupport/GeolocationManager.h @@ -0,0 +1,80 @@ +/* + * Copyright 2012, 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 GeolocationManager_h +#define GeolocationManager_h + +#include "GeolocationClientImpl.h" + +#include <GeolocationClientMock.h> +#include <OwnPtr.h> +#include <PassRefPtr.h> + +namespace WebCore { +class GeolocationError; +class GeolocationPosition; +} + +namespace android { + +class GeolocationClientImpl; +class WebViewCore; + +// This class takes care of the fact that the client used for Geolocation +// may be either the real implementation or a mock. It also handles setting the +// data on the mock client. This class is owned by WebViewCore and exists to +// keep cruft out of that class. +class GeolocationManager { +public: + GeolocationManager(WebViewCore*); + + // For use by GeolocationClientAndroid. Gets the current client, either the + // real or mock. + WebCore::GeolocationClient* client() const; + + void suspendRealClient(); + void resumeRealClient(); + void resetRealClientTemporaryPermissionStates(); + void provideRealClientPermissionState(WTF::String origin, bool allow, bool remember); + + // Sets use of the Geolocation mock client. Also resets that client. + void setUseMock(); + void setMockPosition(PassRefPtr<WebCore::GeolocationPosition>); + void setMockError(PassRefPtr<WebCore::GeolocationError>); + void setMockPermission(bool allowed); + +private: + GeolocationClientImpl* realClient() const; + WebCore::GeolocationClientMock* mockClient() const; + + bool m_useMock; + WebViewCore* m_webViewCore; + mutable OwnPtr<GeolocationClientImpl> m_realClient; + mutable OwnPtr<WebCore::GeolocationClientMock> m_mockClient; +}; + +} // namespace android + +#endif // GeolocationManager_h diff --git a/Source/WebKit/android/WebCoreSupport/GeolocationPermissions.cpp b/Source/WebKit/android/WebCoreSupport/GeolocationPermissions.cpp index 36a9b61..fb29bd6 100755 --- a/Source/WebKit/android/WebCoreSupport/GeolocationPermissions.cpp +++ b/Source/WebKit/android/WebCoreSupport/GeolocationPermissions.cpp @@ -26,16 +26,16 @@ #include "config.h" #include "GeolocationPermissions.h" -#include "DOMWindow.h" -#include "Frame.h" -#include "Geolocation.h" -#include "Navigator.h" -#include "SQLiteDatabase.h" -#include "SQLiteFileSystem.h" -#include "SQLiteStatement.h" -#include "SQLiteTransaction.h" #include "WebViewCore.h" +#include <DOMWindow.h> +#include <Frame.h> +#include <Geolocation.h> +#include <Navigator.h> +#include <SQLiteDatabase.h> +#include <SQLiteFileSystem.h> +#include <SQLiteStatement.h> +#include <SQLiteTransaction.h> #include <text/CString.h> using namespace WebCore; @@ -51,9 +51,8 @@ String GeolocationPermissions::s_databasePath; static const char* databaseName = "GeolocationPermissions.db"; -GeolocationPermissions::GeolocationPermissions(WebViewCore* webViewCore, Frame* mainFrame) +GeolocationPermissions::GeolocationPermissions(WebViewCore* webViewCore) : m_webViewCore(webViewCore) - , m_mainFrame(mainFrame) , m_timer(this, &GeolocationPermissions::timerFired) { @@ -266,7 +265,7 @@ void GeolocationPermissions::maybeCallbackFrames(String origin, bool allow) // or have their contents replaced. Even uniqueChildName is not unique when // frames are dynamically deleted and created. Instead, we simply call back // to the Geolocation object in all frames from the correct origin. - for (Frame* frame = m_mainFrame; frame; frame = frame->tree()->traverseNext()) { + for (Frame* frame = m_webViewCore->mainFrame(); frame; frame = frame->tree()->traverseNext()) { if (origin == frame->document()->securityOrigin()->toString()) { // If the page has changed, it may no longer have a Geolocation // object. diff --git a/Source/WebKit/android/WebCoreSupport/GeolocationPermissions.h b/Source/WebKit/android/WebCoreSupport/GeolocationPermissions.h index fb31dfe..8f4b96e 100644 --- a/Source/WebKit/android/WebCoreSupport/GeolocationPermissions.h +++ b/Source/WebKit/android/WebCoreSupport/GeolocationPermissions.h @@ -26,9 +26,8 @@ #ifndef GeolocationPermissions_h #define GeolocationPermissions_h -#include "PlatformString.h" -#include "Timer.h" - +#include <PlatformString.h> +#include <Timer.h> #include <wtf/HashMap.h> #include <wtf/HashSet.h> #include <wtf/RefCounted.h> @@ -63,9 +62,8 @@ namespace android { class GeolocationPermissions : public RefCounted<GeolocationPermissions> { public: // Creates the GeolocationPermissions object to manage permissions for - // the specified main frame (i.e. tab). The WebViewCore is used to - // communicate with the browser to display UI. - GeolocationPermissions(WebViewCore* webViewCore, WebCore::Frame* mainFrame); + // the WebView. + GeolocationPermissions(WebViewCore* webViewCore); virtual ~GeolocationPermissions(); // Queries the permission state for the specified frame. If the @@ -140,7 +138,6 @@ namespace android { const WTF::String& nextOriginInQueue(); WebViewCore* m_webViewCore; - WebCore::Frame* m_mainFrame; // A vector of the origins queued to make a permission request. // The first in the vector is the origin currently making the request. typedef Vector<WTF::String> OriginVector; diff --git a/Source/WebKit/android/WebCoreSupport/MediaPlayerPrivateAndroid.cpp b/Source/WebKit/android/WebCoreSupport/MediaPlayerPrivateAndroid.cpp index 1607b0e..de91766 100644 --- a/Source/WebKit/android/WebCoreSupport/MediaPlayerPrivateAndroid.cpp +++ b/Source/WebKit/android/WebCoreSupport/MediaPlayerPrivateAndroid.cpp @@ -30,6 +30,7 @@ #include "BaseLayerAndroid.h" #include "GraphicsContext.h" +#include "HTMLMediaElement.h" #include "SkiaUtils.h" #include "TilesManager.h" #include "VideoLayerAndroid.h" @@ -55,6 +56,7 @@ static const char* g_ProxyJavaClassAudio = "android/webkit/HTML5Audio"; struct MediaPlayerPrivate::JavaGlue { jobject m_javaProxy; jmethodID m_play; + jmethodID m_enterFullscreenForVideoLayer; jmethodID m_teardown; jmethodID m_seek; jmethodID m_pause; @@ -191,11 +193,19 @@ void MediaPlayerPrivate::onTimeupdate(int position) m_player->timeChanged(); } -void MediaPlayerPrivate::onStopFullscreen() +void MediaPlayerPrivate::onStopFullscreen(bool stillPlaying) { - if (m_player && m_player->mediaPlayerClient() - && m_player->mediaPlayerClient()->mediaPlayerOwningDocument()) { - m_player->mediaPlayerClient()->mediaPlayerOwningDocument()->webkitCancelFullScreen(); + if (m_player && m_player->mediaPlayerClient()) { + Document* doc = m_player->mediaPlayerClient()->mediaPlayerOwningDocument(); + if (doc) { + HTMLMediaElement* element = + static_cast<HTMLMediaElement*>(doc->webkitCurrentFullScreenElement()); + element->exitFullscreen(); + doc->webkitDidExitFullScreenForElement(element); + + if (stillPlaying) + element->play(true); + } } } @@ -234,6 +244,22 @@ public: checkException(env); } + + void enterFullscreenMode() + { + JNIEnv* env = JSC::Bindings::getJNIEnv(); + if (!env || !m_url.length() || !m_glue->m_javaProxy) + return; + + jstring jUrl = wtfStringToJstring(env, m_url); + env->CallVoidMethod(m_glue->m_javaProxy, + m_glue->m_enterFullscreenForVideoLayer, jUrl, + m_videoLayer->uniqueId()); + env->DeleteLocalRef(jUrl); + + checkException(env); + } + bool canLoadPoster() const { return true; } void setPoster(const String& url) { @@ -260,9 +286,6 @@ public: if (!m_poster || (!m_poster->getPixels() && !m_poster->pixelRef())) return; - SkCanvas* canvas = ctxt->platformContext()->getCanvas(); - if (!canvas) - return; // We paint with the following rules in mind: // - only downscale the poster, never upscale // - maintain the natural aspect ratio of the poster @@ -273,7 +296,7 @@ public: int posterX = ((r.width() - posterWidth) / 2) + r.x(); int posterY = ((r.height() - posterHeight) / 2) + r.y(); IntRect targetRect(posterX, posterY, posterWidth, posterHeight); - canvas->drawBitmapRect(*m_poster, 0, targetRect, 0); + ctxt->platformContext()->drawBitmapRect(*m_poster, 0, targetRect); } void onPosterFetched(SkBitmap* poster) @@ -289,6 +312,13 @@ public: m_naturalSize = IntSize(poster->width(), poster->height()); m_player->sizeChanged(); } + // At this time, we know that the proxy has been setup. And it is the + // right time to trigger autoplay through the HTMLMediaElement state + // change. Since we are using the java MediaPlayer, so we have to + // pretend that the MediaPlayer has enough data. + m_readyState = MediaPlayer::HaveEnoughData; + m_player->readyStateChanged(); + } void onPrepared(int duration, int width, int height) @@ -319,9 +349,13 @@ public: return; m_glue = new JavaGlue; - m_glue->m_getInstance = env->GetStaticMethodID(clazz, "getInstance", "(Landroid/webkit/WebViewCore;I)Landroid/webkit/HTML5VideoViewProxy;"); + m_glue->m_getInstance = + env->GetStaticMethodID(clazz, "getInstance", + "(Landroid/webkit/WebViewCore;I)Landroid/webkit/HTML5VideoViewProxy;"); m_glue->m_loadPoster = env->GetMethodID(clazz, "loadPoster", "(Ljava/lang/String;)V"); m_glue->m_play = env->GetMethodID(clazz, "play", "(Ljava/lang/String;II)V"); + m_glue->m_enterFullscreenForVideoLayer = + env->GetMethodID(clazz, "enterFullscreenForVideoLayer", "(Ljava/lang/String;I)V"); m_glue->m_teardown = env->GetMethodID(clazz, "teardown", "()V"); m_glue->m_seek = env->GetMethodID(clazz, "seek", "(I)V"); @@ -628,12 +662,12 @@ static bool SendSurfaceTexture(JNIEnv* env, jobject obj, jobject surfTex, return true; } -static void OnStopFullscreen(JNIEnv* env, jobject obj, int pointer) +static void OnStopFullscreen(JNIEnv* env, jobject obj, int stillPlaying, int pointer) { if (pointer) { WebCore::MediaPlayerPrivate* player = reinterpret_cast<WebCore::MediaPlayerPrivate*>(pointer); - player->onStopFullscreen(); + player->onStopFullscreen(stillPlaying); } } @@ -645,7 +679,7 @@ static JNINativeMethod g_MediaPlayerMethods[] = { (void*) OnPrepared }, { "nativeOnEnded", "(I)V", (void*) OnEnded }, - { "nativeOnStopFullscreen", "(I)V", + { "nativeOnStopFullscreen", "(II)V", (void*) OnStopFullscreen }, { "nativeOnPaused", "(I)V", (void*) OnPaused }, diff --git a/Source/WebKit/android/WebCoreSupport/MemoryUsage.cpp b/Source/WebKit/android/WebCoreSupport/MemoryUsage.cpp index 592fad3..5b8c33b 100644 --- a/Source/WebKit/android/WebCoreSupport/MemoryUsage.cpp +++ b/Source/WebKit/android/WebCoreSupport/MemoryUsage.cpp @@ -26,50 +26,22 @@ #include "config.h" #include "MemoryUsage.h" -#include <malloc.h> -#include <wtf/CurrentTime.h> - #include <v8.h> -using namespace WTF; - -class MemoryUsageCache { -public: - MemoryUsageCache() - : m_cachedMemoryUsage(0) - , m_cacheTime(0) - { - } +// Workaround an issue where malloc_footprint is in malloc.h +// but is not actually implemented. +// See: http://code.google.com/p/android/issues/detail?id=34897 +extern "C" size_t dlmalloc_footprint(void); - int getCachedMemoryUsage(bool forceFresh); - -private: - unsigned m_cachedMemoryUsage; - double m_cacheTime; - static const int CACHE_VALIDITY_MS = 2000; -}; +using namespace WTF; -int MemoryUsageCache::getCachedMemoryUsage(bool forceFresh) +int MemoryUsage::memoryUsageMb(bool /* forceFresh */) { - if (!forceFresh && currentTimeMS() <= m_cacheTime + CACHE_VALIDITY_MS) - return m_cachedMemoryUsage; - - struct mallinfo minfo = mallinfo(); - m_cachedMemoryUsage = (minfo.hblkhd + minfo.arena) >> 20; - + size_t footprint = dlmalloc_footprint() >> 20; v8::HeapStatistics stat; v8::V8::GetHeapStatistics(&stat); unsigned v8Usage = stat.total_heap_size() >> 20; - m_cachedMemoryUsage += v8Usage; - - m_cacheTime = currentTimeMS(); - return m_cachedMemoryUsage; -} - -int MemoryUsage::memoryUsageMb(bool forceFresh) -{ - static MemoryUsageCache cache; - return cache.getCachedMemoryUsage(forceFresh); + return footprint + v8Usage; } int MemoryUsage::m_lowMemoryUsageMb = 0; diff --git a/Source/WebKit/android/WebCoreSupport/PlatformBridge.cpp b/Source/WebKit/android/WebCoreSupport/PlatformBridge.cpp index 9b8aac8..864b27d 100644 --- a/Source/WebKit/android/WebCoreSupport/PlatformBridge.cpp +++ b/Source/WebKit/android/WebCoreSupport/PlatformBridge.cpp @@ -111,12 +111,6 @@ NPObject* PlatformBridge::pluginScriptableObject(Widget* widget) return pluginView->getNPObject(); } -bool PlatformBridge::isWebViewPaused(const WebCore::FrameView* frameView) -{ - android::WebViewCore* webViewCore = android::WebViewCore::getWebViewCore(frameView); - return webViewCore->isPaused(); -} - bool PlatformBridge::popupsAllowed(NPP) { return false; @@ -170,10 +164,10 @@ void PlatformBridge::updateViewport(FrameView* frameView) webViewCore->updateViewport(); } -void PlatformBridge::updateTextfield(FrameView* frameView, Node* nodePtr, bool changeToPassword, const WTF::String& text) +void PlatformBridge::updateTextfield(FrameView* frameView, Node* nodePtr, const WTF::String& text) { android::WebViewCore* webViewCore = android::WebViewCore::getWebViewCore(frameView); - webViewCore->updateTextfield(nodePtr, changeToPassword, text); + webViewCore->updateTextfield(nodePtr, text); } void PlatformBridge::setScrollPosition(ScrollView* scrollView, int x, int y) { diff --git a/Source/WebCore/platform/android/GeolocationServiceBridge.cpp b/Source/WebKit/android/jni/GeolocationServiceBridge.cpp index 697b63b..056c788 100644 --- a/Source/WebCore/platform/android/GeolocationServiceBridge.cpp +++ b/Source/WebKit/android/jni/GeolocationServiceBridge.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2009, The Android Open Source Project + * Copyright 2012, The Android Open Source Project * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,16 +26,17 @@ #include "config.h" #include "GeolocationServiceBridge.h" -#include "Frame.h" -#include "GeolocationServiceAndroid.h" -#include "Geoposition.h" -#include "PositionError.h" #include "WebViewCore.h" -#include <JNIHelp.h> -namespace WebCore { +#include <GeolocationError.h> +#include <GeolocationPosition.h> +#include <JNIHelp.h> using JSC::Bindings::getJNIEnv; +using WebCore::GeolocationError; +using WebCore::GeolocationPosition; + +namespace android { static const char* javaGeolocationServiceClassName = "android/webkit/GeolocationService"; enum javaGeolocationServiceClassMethods { @@ -71,12 +72,12 @@ enum javaLocationClassMethods { }; static jmethodID javaLocationClassMethodIDs[LocationMethodCount]; -GeolocationServiceBridge::GeolocationServiceBridge(ListenerInterface* listener, Frame* frame) +GeolocationServiceBridge::GeolocationServiceBridge(Listener* listener, WebViewCore* webViewCore) : m_listener(listener) , m_javaGeolocationServiceObject(0) { ASSERT(m_listener); - startJavaImplementation(frame); + startJavaImplementation(webViewCore); } GeolocationServiceBridge::~GeolocationServiceBridge() @@ -115,18 +116,17 @@ void GeolocationServiceBridge::newLocationAvailable(JNIEnv* env, jclass, jlong n ASSERT(nativeObject); ASSERT(location); GeolocationServiceBridge* object = reinterpret_cast<GeolocationServiceBridge*>(nativeObject); - object->m_listener->newPositionAvailable(toGeoposition(env, location)); + object->m_listener->newPositionAvailable(toGeolocationPosition(env, location)); } void GeolocationServiceBridge::newErrorAvailable(JNIEnv* env, jclass, jlong nativeObject, jstring message) { GeolocationServiceBridge* object = reinterpret_cast<GeolocationServiceBridge*>(nativeObject); - RefPtr<PositionError> error = - PositionError::create(PositionError::POSITION_UNAVAILABLE, android::jstringToWtfString(env, message)); + RefPtr<GeolocationError> error = GeolocationError::create(GeolocationError::PositionUnavailable, jstringToWtfString(env, message)); object->m_listener->newErrorAvailable(error.release()); } -PassRefPtr<Geoposition> GeolocationServiceBridge::toGeoposition(JNIEnv *env, const jobject &location) +PassRefPtr<GeolocationPosition> GeolocationServiceBridge::toGeolocationPosition(JNIEnv *env, const jobject &location) { // Altitude is optional and may not be supplied. bool hasAltitude = @@ -155,21 +155,18 @@ PassRefPtr<Geoposition> GeolocationServiceBridge::toGeoposition(JNIEnv *env, con env->CallFloatMethod(location, javaLocationClassMethodIDs[LocationMethodGetSpeed]) : 0.0; - RefPtr<Coordinates> newCoordinates = WebCore::Coordinates::create( + return GeolocationPosition::create( + env->CallLongMethod(location, javaLocationClassMethodIDs[LocationMethodGetTime]) / 1000.0, env->CallDoubleMethod(location, javaLocationClassMethodIDs[LocationMethodGetLatitude]), env->CallDoubleMethod(location, javaLocationClassMethodIDs[LocationMethodGetLongitude]), - hasAltitude, Altitude, Accuracy, + hasAltitude, Altitude, false, 0.0, // AltitudeAccuracy not provided. hasHeading, heading, hasSpeed, speed); - - return WebCore::Geoposition::create( - newCoordinates.release(), - env->CallLongMethod(location, javaLocationClassMethodIDs[LocationMethodGetTime])); } -void GeolocationServiceBridge::startJavaImplementation(Frame* frame) +void GeolocationServiceBridge::startJavaImplementation(WebViewCore* webViewCore) { JNIEnv* env = getJNIEnv(); @@ -188,7 +185,7 @@ void GeolocationServiceBridge::startJavaImplementation(Frame* frame) env->GetMethodID(javaGeolocationServiceClass, "setEnableGps", "(Z)V"); // Create the Java GeolocationService object. - jobject context = android::WebViewCore::getWebViewCore(frame->view())->getContext(); + jobject context = webViewCore->getContext(); if (!context) return; jlong nativeObject = reinterpret_cast<jlong>(this); @@ -237,10 +234,9 @@ void GeolocationServiceBridge::startJavaImplementation(Frame* frame) void GeolocationServiceBridge::stopJavaImplementation() { - // Called by GeolocationServiceAndroid on WebKit thread. if (!m_javaGeolocationServiceObject) return; getJNIEnv()->DeleteGlobalRef(m_javaGeolocationServiceObject); } -} // namespace WebCore +} // namespace android diff --git a/Source/WebCore/platform/android/GeolocationServiceBridge.h b/Source/WebKit/android/jni/GeolocationServiceBridge.h index 3997d65..826ba71 100644 --- a/Source/WebCore/platform/android/GeolocationServiceBridge.h +++ b/Source/WebKit/android/jni/GeolocationServiceBridge.h @@ -1,5 +1,5 @@ /* - * Copyright 2009, The Android Open Source Project + * Copyright 2012, The Android Open Source Project * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,22 +26,31 @@ #ifndef GeolocationServiceBridge_h #define GeolocationServiceBridge_h -#include "JNIUtility.h" +#include <JNIUtility.h> #include <wtf/PassRefPtr.h> namespace WebCore { +class GeolocationError; +class GeolocationPosition; +} -class Frame; -class GeolocationServiceAndroid; -class Geoposition; +namespace android { + +class WebViewCore; // GeolocationServiceBridge is the bridge to the Java implementation. It manages // the lifetime of the Java object. It is an implementation detail of -// GeolocationServiceAndroid. +// GeolocationClientAndroid. class GeolocationServiceBridge { public: - typedef GeolocationServiceAndroid ListenerInterface; - GeolocationServiceBridge(ListenerInterface* listener, Frame* frame); + class Listener { + public: + virtual ~Listener() {} + virtual void newPositionAvailable(PassRefPtr<WebCore::GeolocationPosition>) = 0; + virtual void newErrorAvailable(PassRefPtr<WebCore::GeolocationError>) = 0; + }; + + GeolocationServiceBridge(Listener*, WebViewCore*); ~GeolocationServiceBridge(); bool start(); @@ -51,16 +60,16 @@ public: // Static wrapper functions to hide JNI nastiness. static void newLocationAvailable(JNIEnv *env, jclass, jlong nativeObject, jobject location); static void newErrorAvailable(JNIEnv *env, jclass, jlong nativeObject, jstring message); - static PassRefPtr<Geoposition> toGeoposition(JNIEnv *env, const jobject &location); + static PassRefPtr<WebCore::GeolocationPosition> toGeolocationPosition(JNIEnv *env, const jobject &location); private: - void startJavaImplementation(Frame* frame); + void startJavaImplementation(WebViewCore*); void stopJavaImplementation(); - ListenerInterface* m_listener; + Listener* m_listener; jobject m_javaGeolocationServiceObject; }; -} // namespace WebCore +} // namespace android #endif // GeolocationServiceBridge_h diff --git a/Source/WebKit/android/jni/MockGeolocation.cpp b/Source/WebKit/android/jni/MockGeolocation.cpp index 250953f..d588010 100755 --- a/Source/WebKit/android/jni/MockGeolocation.cpp +++ b/Source/WebKit/android/jni/MockGeolocation.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2009, The Android Open Source Project + * Copyright 2012, The Android Open Source Project * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,19 +23,17 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// The functions in this file are used to configure the mock GeolocationService +// The functions in this file are used to configure the mock Geolocation client // for the LayoutTests. #include "config.h" -#include "Coordinates.h" -#include "GeolocationServiceMock.h" -#include "Geoposition.h" -#include "JavaSharedClient.h" -#include "PositionError.h" -#include "WebCoreJni.h" -#include <JNIHelp.h> -#include <JNIUtility.h> +#include "WebViewCore.h" + +#include <GeolocationError.h> +#include <GeolocationPosition.h> +#include "JNIHelp.h" +#include "ScopedLocalRef.h" #include <wtf/CurrentTime.h> using namespace WebCore; @@ -44,30 +42,46 @@ namespace android { static const char* javaMockGeolocationClass = "android/webkit/MockGeolocation"; -static void setPosition(JNIEnv* env, jobject, double latitude, double longitude, double accuracy) +WebViewCore* getWebViewCore(JNIEnv* env, jobject webViewCore) +{ + ScopedLocalRef<jclass> webViewCoreClass(env, env->FindClass("android/webkit/WebViewCore")); + jfieldID nativeClassField = env->GetFieldID(webViewCoreClass.get(), "mNativeClass", "I"); + return reinterpret_cast<WebViewCore*>(env->GetIntField(webViewCore, nativeClassField)); +} + +static void setUseMock(JNIEnv* env, jobject, jobject webViewCore) +{ + getWebViewCore(env, webViewCore)->geolocationManager()->setUseMock(); +} + +static void setPosition(JNIEnv* env, jobject, jobject webViewCore, double latitude, double longitude, double accuracy) +{ + getWebViewCore(env, webViewCore)->geolocationManager()->setMockPosition(GeolocationPosition::create(WTF::currentTime(), + latitude, + longitude, + accuracy, + false, 0.0, // altitude, + false, 0.0, // altitudeAccuracy, + false, 0.0, // heading + false, 0.0)); // speed +} + +static void setError(JNIEnv* env, jobject, jobject webViewCore, int code, jstring message) { - RefPtr<Coordinates> coordinates = Coordinates::create(latitude, - longitude, - false, 0.0, // altitude, - accuracy, - false, 0.0, // altitudeAccuracy, - false, 0.0, // heading - false, 0.0); // speed - RefPtr<Geoposition> position = Geoposition::create(coordinates.release(), WTF::currentTimeMS()); - GeolocationServiceMock::setPosition(position.release()); + GeolocationError::ErrorCode codeEnum = static_cast<GeolocationError::ErrorCode>(code); + getWebViewCore(env, webViewCore)->geolocationManager()->setMockError(GeolocationError::create(codeEnum, jstringToWtfString(env, message))); } -static void setError(JNIEnv* env, jobject, int code, jstring message) +static void setPermission(JNIEnv* env, jobject, jobject webViewCore, bool allow) { - PositionError::ErrorCode codeEnum = static_cast<PositionError::ErrorCode>(code); - String messageString = jstringToWtfString(env, message); - RefPtr<PositionError> error = PositionError::create(codeEnum, messageString); - GeolocationServiceMock::setError(error.release()); + getWebViewCore(env, webViewCore)->geolocationManager()->setMockPermission(allow); } static JNINativeMethod gMockGeolocationMethods[] = { - { "nativeSetPosition", "(DDD)V", (void*) setPosition }, - { "nativeSetError", "(ILjava/lang/String;)V", (void*) setError } + { "nativeSetUseMock", "(Landroid/webkit/WebViewCore;)V", (void*) setUseMock }, + { "nativeSetPosition", "(Landroid/webkit/WebViewCore;DDD)V", (void*) setPosition }, + { "nativeSetError", "(Landroid/webkit/WebViewCore;ILjava/lang/String;)V", (void*) setError }, + { "nativeSetPermission", "(Landroid/webkit/WebViewCore;Z)V", (void*) setPermission }, }; int registerMockGeolocation(JNIEnv* env) diff --git a/Source/WebKit/android/jni/PicturePile.cpp b/Source/WebKit/android/jni/PicturePile.cpp index ccdfa59..91f3e74 100644 --- a/Source/WebKit/android/jni/PicturePile.cpp +++ b/Source/WebKit/android/jni/PicturePile.cpp @@ -35,11 +35,16 @@ #include "PlatformGraphicsContextSkia.h" #include "SkCanvas.h" #include "SkNWayCanvas.h" -#include "SkPicture.h" #include "SkPixelRef.h" #include "SkRect.h" #include "SkRegion.h" +#if USE_RECORDING_CONTEXT +#include "PlatformGraphicsContextRecording.h" +#else +#include "SkPicture.h" +#endif + #define ENABLE_PRERENDERED_INVALS true #define MAX_OVERLAP_COUNT 2 #define MAX_OVERLAP_AREA .7 @@ -52,11 +57,28 @@ static SkIRect toSkIRect(const IntRect& rect) { static IntRect extractClipBounds(SkCanvas* canvas, const IntSize& size) { SkRect clip; - canvas->getClipBounds(&clip); + if (!canvas->getClipBounds(&clip)) { + ALOGW("Empty clip!"); + return IntRect(); + } clip.intersect(0, 0, size.width(), size.height()); return enclosingIntRect(clip); } +PictureContainer::PictureContainer(const PictureContainer& other) + : picture(other.picture) + , area(other.area) + , dirty(other.dirty) + , prerendered(other.prerendered) +{ + SkSafeRef(picture); +} + +PictureContainer::~PictureContainer() +{ + SkSafeUnref(picture); +} + PicturePile::PicturePile(const PicturePile& other) : m_size(other.m_size) , m_pile(other.m_pile) @@ -64,15 +86,6 @@ PicturePile::PicturePile(const PicturePile& other) { } -PicturePile::PicturePile(SkPicture* picture) -{ - m_size = IntSize(picture->width(), picture->height()); - PictureContainer pc(IntRect(0, 0, m_size.width(), m_size.height())); - pc.picture = picture; - pc.dirty = false; - m_pile.append(pc); -} - void PicturePile::draw(SkCanvas* canvas) { /* Loop down recursively, subtracting the previous clip from the SkRegion, @@ -81,8 +94,9 @@ void PicturePile::draw(SkCanvas* canvas) * the rect bounds of the SkRegion for the clip, so this still can't be * used for translucent surfaces */ - TRACE_METHOD(); IntRect clipBounds = extractClipBounds(canvas, m_size); + if (clipBounds.isEmpty()) + return; SkRegion clipRegion(toSkIRect(clipBounds)); drawWithClipRecursive(canvas, clipRegion, m_pile.size() - 1); } @@ -106,9 +120,8 @@ void PicturePile::drawWithClipRecursive(SkCanvas* canvas, SkRegion& clipRegion, clipRegion.op(intersection, SkRegion::kDifference_Op); drawWithClipRecursive(canvas, clipRegion, index - 1); int saved = canvas->save(); - canvas->clipRect(intersection); - canvas->translate(pc.area.x(), pc.area.y()); - canvas->drawPicture(*pc.picture); + if (canvas->clipRect(intersection)) + drawPicture(canvas, pc); canvas->restoreToCount(saved); } else drawWithClipRecursive(canvas, clipRegion, index - 1); @@ -140,14 +153,30 @@ void PicturePile::setSize(const IntSize& size) { if (m_size == size) return; + IntSize oldSize = m_size; m_size = size; - // TODO: See above about just adding invals for new content - m_pile.clear(); - m_webkitInvals.clear(); - if (!size.isEmpty()) { - IntRect area(0, 0, size.width(), size.height()); - m_webkitInvals.append(area); - m_pile.append(area); + if (size.width() <= oldSize.width() && size.height() <= oldSize.height()) { + // We are shrinking - huzzah, nothing to do! + // TODO: Loop through and throw out Pictures that are now clipped out + } else if (oldSize.width() == size.width()) { + // Only changing vertically + IntRect rect(0, std::min(oldSize.height(), size.height()), + size.width(), std::abs(oldSize.height() - size.height())); + invalidate(rect); + } else if (oldSize.height() == size.height()) { + // Only changing horizontally + IntRect rect(std::min(oldSize.width(), size.width()), 0, + std::abs(oldSize.width() - size.width()), size.height()); + invalidate(rect); + } else { + // Both width & height changed, full inval :( + m_pile.clear(); + m_webkitInvals.clear(); + if (!size.isEmpty()) { + IntRect area(0, 0, size.width(), size.height()); + m_webkitInvals.append(area); + m_pile.append(area); + } } } @@ -163,43 +192,8 @@ void PicturePile::updatePicturesIfNeeded(PicturePainter* painter) void PicturePile::updatePicture(PicturePainter* painter, PictureContainer& pc) { - /* The ref counting here is a bit unusual. What happens is begin/end recording - * will ref/unref the recording canvas. However, 'canvas' might be pointing - * at an SkNWayCanvas instead of the recording canvas, which needs to be - * unref'd. Thus what we do is ref the recording canvas so that we can - * always unref whatever canvas we have at the end. - */ TRACE_METHOD(); - SkPicture* picture = new SkPicture(); - SkCanvas* canvas = picture->beginRecording(pc.area.width(), pc.area.height(), - SkPicture::kUsePathBoundsForClip_RecordingFlag); - SkSafeRef(canvas); - canvas->translate(-pc.area.x(), -pc.area.y()); - IntRect drawArea = pc.area; - if (pc.prerendered.get()) { - SkCanvas* prerender = painter->createPrerenderCanvas(pc.prerendered.get()); - if (!prerender) { - ALOGV("Failed to create prerendered for " INT_RECT_FORMAT, - INT_RECT_ARGS(pc.prerendered->area)); - pc.prerendered.clear(); - } else { - drawArea.unite(pc.prerendered->area); - SkNWayCanvas* nwayCanvas = new SkNWayCanvas(drawArea.width(), drawArea.height()); - nwayCanvas->translate(-drawArea.x(), -drawArea.y()); - nwayCanvas->addCanvas(canvas); - nwayCanvas->addCanvas(prerender); - SkSafeUnref(canvas); - SkSafeUnref(prerender); - canvas = nwayCanvas; - } - } - WebCore::PlatformGraphicsContextSkia pgc(canvas); - WebCore::GraphicsContext gc(&pgc); - ALOGV("painting picture: " INT_RECT_FORMAT, INT_RECT_ARGS(drawArea)); - painter->paintContents(&gc, drawArea); - SkSafeUnref(canvas); - picture->endRecording(); - + Picture* picture = recordPicture(painter, pc); SkSafeUnref(pc.picture); pc.picture = picture; pc.dirty = false; @@ -298,4 +292,97 @@ PrerenderedInval* PicturePile::prerenderedInvalForArea(const IntRect& area) return 0; } +bool PicturePile::hasText() const +{ + for (size_t i = 0; i < m_pile.size(); i++) { + if (m_pile[i].hasText) + return true; + } + return false; +} + +bool PicturePile::isEmpty() const +{ + for (size_t i = 0; i < m_pile.size(); i++) { + if (m_pile[i].picture) + return false; + } + return true; +} + +#if USE_RECORDING_CONTEXT +void PicturePile::drawPicture(SkCanvas* canvas, PictureContainer& pc) +{ + TRACE_METHOD(); + pc.picture->draw(canvas); +} + +Picture* PicturePile::recordPicture(PicturePainter* painter, PictureContainer& pc) +{ + pc.prerendered.clear(); // TODO: Support? Not needed? + + Recording* picture = new Recording(); + WebCore::PlatformGraphicsContextRecording pgc(picture); + WebCore::GraphicsContext gc(&pgc); + painter->paintContents(&gc, pc.area); + pc.hasText = pgc.hasText(); + if (pgc.isEmpty()) { + SkSafeUnref(picture); + picture = 0; + } + + return picture; +} +#else +void PicturePile::drawPicture(SkCanvas* canvas, PictureContainer& pc) +{ + canvas->translate(pc.area.x(), pc.area.y()); + pc.picture->draw(canvas); +} + +Picture* PicturePile::recordPicture(PicturePainter* painter, PictureContainer& pc) +{ + /* The ref counting here is a bit unusual. What happens is begin/end recording + * will ref/unref the recording canvas. However, 'canvas' might be pointing + * at an SkNWayCanvas instead of the recording canvas, which needs to be + * unref'd. Thus what we do is ref the recording canvas so that we can + * always unref whatever canvas we have at the end. + */ + SkPicture* picture = new SkPicture(); + SkCanvas* canvas = picture->beginRecording(pc.area.width(), pc.area.height(), + SkPicture::kUsePathBoundsForClip_RecordingFlag); + SkSafeRef(canvas); + canvas->translate(-pc.area.x(), -pc.area.y()); + IntRect drawArea = pc.area; + if (pc.prerendered.get()) { + SkCanvas* prerender = painter->createPrerenderCanvas(pc.prerendered.get()); + if (!prerender) { + ALOGV("Failed to create prerendered for " INT_RECT_FORMAT, + INT_RECT_ARGS(pc.prerendered->area)); + pc.prerendered.clear(); + } else { + drawArea.unite(pc.prerendered->area); + SkNWayCanvas* nwayCanvas = new SkNWayCanvas(drawArea.width(), drawArea.height()); + nwayCanvas->translate(-drawArea.x(), -drawArea.y()); + nwayCanvas->addCanvas(canvas); + nwayCanvas->addCanvas(prerender); + SkSafeUnref(canvas); + SkSafeUnref(prerender); + canvas = nwayCanvas; + } + } + WebCore::PlatformGraphicsContextSkia pgc(canvas); + WebCore::GraphicsContext gc(&pgc); + ALOGV("painting picture: " INT_RECT_FORMAT, INT_RECT_ARGS(drawArea)); + painter->paintContents(&gc, drawArea); + + // TODO: consider paint-time checking for these with SkPicture painting? + pc.hasText = true; + + SkSafeUnref(canvas); + picture->endRecording(); + return picture; +} +#endif + } // namespace WebCore diff --git a/Source/WebKit/android/jni/PicturePile.h b/Source/WebKit/android/jni/PicturePile.h index b28a792..6e3e46d 100644 --- a/Source/WebKit/android/jni/PicturePile.h +++ b/Source/WebKit/android/jni/PicturePile.h @@ -38,7 +38,17 @@ #include <wtf/ThreadSafeRefCounted.h> #include <wtf/Vector.h> +#define USE_RECORDING_CONTEXT true +#if USE_RECORDING_CONTEXT +namespace WebCore { +class Recording; +} +typedef WebCore::Recording Picture; +#else class SkPicture; +typedef SkPicture Picture; +#endif + class SkCanvas; namespace WebCore { @@ -57,37 +67,27 @@ public: class PictureContainer { public: - SkPicture* picture; + Picture* picture; IntRect area; bool dirty; RefPtr<PrerenderedInval> prerendered; + bool hasText; PictureContainer(const IntRect& area) : picture(0) , area(area) , dirty(true) + , hasText(false) {} - PictureContainer(const PictureContainer& other) - : picture(other.picture) - , area(other.area) - , dirty(other.dirty) - , prerendered(other.prerendered) - { - SkSafeRef(picture); - } - - ~PictureContainer() - { - SkSafeUnref(picture); - } + PictureContainer(const PictureContainer& other); + ~PictureContainer(); }; class PicturePile { public: PicturePile() {} PicturePile(const PicturePile& other); - PicturePile(SkPicture* picture); const IntSize& size() { return m_size; } @@ -104,11 +104,17 @@ public: SkRegion& dirtyRegion() { return m_dirtyRegion; } PrerenderedInval* prerenderedInvalForArea(const IntRect& area); + // UI-side methods used to check content, after construction/updates are complete + bool hasText() const; + bool isEmpty() const; + private: void applyWebkitInvals(); void updatePicture(PicturePainter* painter, PictureContainer& container); + Picture* recordPicture(PicturePainter* painter, PictureContainer& container); void appendToPile(const IntRect& inval, const IntRect& originalInval = IntRect()); void drawWithClipRecursive(SkCanvas* canvas, SkRegion& clipRegion, int index); + void drawPicture(SkCanvas* canvas, PictureContainer& pc); IntSize m_size; Vector<PictureContainer> m_pile; diff --git a/Source/WebKit/android/jni/ViewStateSerializer.cpp b/Source/WebKit/android/jni/ViewStateSerializer.cpp index 02ddca6..8963837 100644 --- a/Source/WebKit/android/jni/ViewStateSerializer.cpp +++ b/Source/WebKit/android/jni/ViewStateSerializer.cpp @@ -30,6 +30,7 @@ #include "BaseLayerAndroid.h" #include "CreateJavaOutputStreamAdaptor.h" +#include "DumpLayer.h" #include "FixedPositioning.h" #include "ImagesManager.h" #include "IFrameContentLayerAndroid.h" @@ -56,6 +57,68 @@ enum LayerTypes { LTFixedLayerAndroid = 3 }; +#define ID "mID" +#define LEFT "layout:mLeft" +#define TOP "layout:mTop" +#define WIDTH "layout:getWidth()" +#define HEIGHT "layout:getHeight()" + +class HierarchyLayerDumper : public LayerDumper { +public: + HierarchyLayerDumper(SkWStream* stream, int level) + : LayerDumper(level) + , m_stream(stream) + {} + + virtual void beginLayer(const char* className, const LayerAndroid* layerPtr) { + LayerDumper::beginLayer(className, layerPtr); + for (int i = 0; i < m_indentLevel; i++) { + m_stream->writeText(" "); + } + m_stream->writeText(className); + m_stream->writeText("@"); + m_stream->writeHexAsText(layerPtr->uniqueId()); + m_stream->writeText(" "); + + writeHexVal(ID, (int) layerPtr); + writeIntVal(LEFT, layerPtr->getPosition().fX); + writeIntVal(TOP, layerPtr->getPosition().fY); + writeIntVal(WIDTH, layerPtr->getWidth()); + writeIntVal(HEIGHT, layerPtr->getHeight()); + } + + virtual void beginChildren(int childCount) { + m_stream->writeText("\n"); + LayerDumper::beginChildren(childCount); + } + +protected: + virtual void writeEntry(const char* label, const char* value) { + m_stream->writeText(label); + m_stream->writeText("="); + int len = strlen(value); + m_stream->writeDecAsText(len); + m_stream->writeText(","); + m_stream->writeText(value); + m_stream->writeText(" "); + } + +private: + SkWStream* m_stream; +}; + +static void nativeDumpLayerHierarchy(JNIEnv* env, jobject, jint jbaseLayer, jint level, + jobject jstream, jbyteArray jstorage) +{ + SkWStream *stream = CreateJavaOutputStreamAdaptor(env, jstream, jstorage); + BaseLayerAndroid* baseLayer = reinterpret_cast<BaseLayerAndroid*>(jbaseLayer); + SkSafeRef(baseLayer); + HierarchyLayerDumper dumper(stream, level); + baseLayer->dumpLayers(&dumper); + SkSafeUnref(baseLayer); + delete stream; +} + static bool nativeSerializeViewState(JNIEnv* env, jobject, jint jbaseLayer, jobject jstream, jbyteArray jstorage) { @@ -478,6 +541,8 @@ LayerAndroid* deserializeLayer(int version, SkStream* stream) * JNI registration */ static JNINativeMethod gSerializerMethods[] = { + { "nativeDumpLayerHierarchy", "(IILjava/io/OutputStream;[B)V", + (void*) nativeDumpLayerHierarchy }, { "nativeSerializeViewState", "(ILjava/io/OutputStream;[B)Z", (void*) nativeSerializeViewState }, { "nativeDeserializeViewState", "(ILjava/io/InputStream;[B)I", diff --git a/Source/WebKit/android/jni/WebCoreFrameBridge.cpp b/Source/WebKit/android/jni/WebCoreFrameBridge.cpp index 4ce3d8e..39ae07e 100644 --- a/Source/WebKit/android/jni/WebCoreFrameBridge.cpp +++ b/Source/WebKit/android/jni/WebCoreFrameBridge.cpp @@ -50,6 +50,7 @@ #include "FrameLoadRequest.h" #include "FrameTree.h" #include "FrameView.h" +#include "GeolocationClientAndroid.h" #include "GraphicsContext.h" #include "HistoryItem.h" #include "HTMLCollection.h" @@ -88,7 +89,6 @@ #include "WebFrameView.h" #include "WebUrlLoaderClient.h" #include "WebViewCore.h" -#include "android_graphics.h" #include "jni.h" #include "wds/DebugServer.h" @@ -497,15 +497,9 @@ WebFrame::loadStarted(WebCore::Frame* frame) if (favicon) env->DeleteLocalRef(favicon); - // Inform the client that the main frame has started a new load. - if (isMainFrame && mPage) { - Chrome* chrome = mPage->chrome(); - if (chrome) { - ChromeClientAndroid* client = static_cast<ChromeClientAndroid*>(chrome->client()); - if (client) - client->onMainFrameLoadStarted(); - } - } + // The main frame has started a new load. + if (isMainFrame && mPage) + WebViewCore::getWebViewCore(mPage->mainFrame()->view())->geolocationManager()->resetRealClientTemporaryPermissionStates(); } void @@ -1099,6 +1093,7 @@ static void CreateFrame(JNIEnv* env, jobject obj, jobject javaview, jobject jAss EditorClientAndroid* editorC = new EditorClientAndroid; DeviceMotionClientAndroid* deviceMotionC = new DeviceMotionClientAndroid; DeviceOrientationClientAndroid* deviceOrientationC = new DeviceOrientationClientAndroid; + GeolocationClientAndroid* geolocationC = new GeolocationClientAndroid; WebCore::Page::PageClients pageClients; pageClients.chromeClient = chromeC; @@ -1108,6 +1103,7 @@ static void CreateFrame(JNIEnv* env, jobject obj, jobject javaview, jobject jAss pageClients.inspectorClient = new InspectorClientAndroid; pageClients.deviceMotionClient = deviceMotionC; pageClients.deviceOrientationClient = deviceOrientationC; + pageClients.geolocationClient = geolocationC; WebCore::Page* page = new WebCore::Page(pageClients); editorC->setPage(page); @@ -1150,6 +1146,7 @@ static void CreateFrame(JNIEnv* env, jobject obj, jobject javaview, jobject jAss frame->page()->focusController()->setFocused(true); deviceMotionC->setWebViewCore(webViewCore); deviceOrientationC->setWebViewCore(webViewCore); + geolocationC->setWebViewCore(webViewCore); // Allow local access to file:/// and substitute data WebCore::SecurityOrigin::setLocalLoadPolicy( diff --git a/Source/WebKit/android/jni/WebFrameView.cpp b/Source/WebKit/android/jni/WebFrameView.cpp index 10e31dc..ed332aa 100644 --- a/Source/WebKit/android/jni/WebFrameView.cpp +++ b/Source/WebKit/android/jni/WebFrameView.cpp @@ -28,7 +28,6 @@ #include <config.h> #include "WebFrameView.h" -#include "android_graphics.h" #include "GraphicsContext.h" #include "Frame.h" #include "FrameTree.h" diff --git a/Source/WebKit/android/jni/WebHistory.cpp b/Source/WebKit/android/jni/WebHistory.cpp index b6972e4..baafa00 100644 --- a/Source/WebKit/android/jni/WebHistory.cpp +++ b/Source/WebKit/android/jni/WebHistory.cpp @@ -60,19 +60,19 @@ static void writeItem(WTF::Vector<char>& vector, WebCore::HistoryItem* item); static void writeChildrenRecursive(WTF::Vector<char>& vector, WebCore::HistoryItem* parent); static bool readItemRecursive(WebCore::HistoryItem* child, const char** pData, int length); -// Field ids for WebHistoryItems -struct WebHistoryItemFields { +// Field ids for WebHistoryClassicItems +struct WebHistoryItemClassicFields { jmethodID mInit; -} gWebHistoryItem; +} gWebHistoryItemClassic; -struct WebBackForwardListFields { +struct WebBackForwardListClassicFields { jmethodID mAddHistoryItem; jmethodID mRemoveHistoryItem; jmethodID mSetCurrentIndex; -} gWebBackForwardList; +} gWebBackForwardListClassic; //-------------------------------------------------------------------------- -// WebBackForwardList native methods. +// WebBackForwardListClassic native methods. //-------------------------------------------------------------------------- static void WebHistoryClose(JNIEnv* env, jobject obj, jint frame) @@ -398,9 +398,9 @@ void WebHistory::AddItem(const AutoJObject& list, WebCore::HistoryItem* item) WebHistoryItem* bridge = new WebHistoryItem(item); bridge->setActive(); item->setBridge(bridge); - // Allocate a blank WebHistoryItem - jclass clazz = env->FindClass("android/webkit/WebHistoryItem"); - jobject newItem = env->NewObject(clazz, gWebHistoryItem.mInit, + // Allocate a blank WebHistoryItemClassic + jclass clazz = env->FindClass("android/webkit/WebHistoryItemClassic"); + jobject newItem = env->NewObject(clazz, gWebHistoryItemClassic.mInit, reinterpret_cast<int>(bridge)); env->DeleteLocalRef(clazz); @@ -409,7 +409,7 @@ void WebHistory::AddItem(const AutoJObject& list, WebCore::HistoryItem* item) bridge->updateHistoryItem(item); // Add it to the list. - env->CallVoidMethod(list.get(), gWebBackForwardList.mAddHistoryItem, newItem); + env->CallVoidMethod(list.get(), gWebBackForwardListClassic.mAddHistoryItem, newItem); // Delete our local reference. env->DeleteLocalRef(newItem); @@ -418,13 +418,13 @@ void WebHistory::AddItem(const AutoJObject& list, WebCore::HistoryItem* item) void WebHistory::RemoveItem(const AutoJObject& list, int index) { if (list.get()) - list.env()->CallVoidMethod(list.get(), gWebBackForwardList.mRemoveHistoryItem, index); + list.env()->CallVoidMethod(list.get(), gWebBackForwardListClassic.mRemoveHistoryItem, index); } void WebHistory::UpdateHistoryIndex(const AutoJObject& list, int newIndex) { if (list.get()) - list.env()->CallVoidMethod(list.get(), gWebBackForwardList.mSetCurrentIndex, newIndex); + list.env()->CallVoidMethod(list.get(), gWebBackForwardListClassic.mSetCurrentIndex, newIndex); } static void writeString(WTF::Vector<char>& vector, const WTF::String& str) @@ -945,14 +945,14 @@ static void unitTest() //--------------------------------------------------------- // JNI registration //--------------------------------------------------------- -static JNINativeMethod gWebBackForwardListMethods[] = { +static JNINativeMethod gWebBackForwardListClassicMethods[] = { { "nativeClose", "(I)V", (void*) WebHistoryClose }, { "restoreIndex", "(II)V", (void*) WebHistoryRestoreIndex } }; -static JNINativeMethod gWebHistoryItemMethods[] = { +static JNINativeMethod gWebHistoryItemClassicMethods[] = { { "inflate", "(I[B)I", (void*) WebHistoryInflate }, { "nativeRef", "(I)V", @@ -978,31 +978,30 @@ int registerWebHistory(JNIEnv* env) #ifdef UNIT_TEST unitTest(); #endif - // Find WebHistoryItem, its constructor, and the update method. - jclass clazz = env->FindClass("android/webkit/WebHistoryItem"); - ALOG_ASSERT(clazz, "Unable to find class android/webkit/WebHistoryItem"); - gWebHistoryItem.mInit = env->GetMethodID(clazz, "<init>", "(I)V"); - ALOG_ASSERT(gWebHistoryItem.mInit, "Could not find WebHistoryItem constructor"); - + // Find WebHistoryItemClassic, its constructor, and the update method. + jclass clazz = env->FindClass("android/webkit/WebHistoryItemClassic"); + ALOG_ASSERT(clazz, "Unable to find class android/webkit/WebHistoryItemClassic"); + gWebHistoryItemClassic.mInit = env->GetMethodID(clazz, "<init>", "(I)V"); + ALOG_ASSERT(gWebHistoryItemClassic.mInit, "Could not find WebHistoryItemClassic constructor"); env->DeleteLocalRef(clazz); - // Find the WebBackForwardList object and method. - clazz = env->FindClass("android/webkit/WebBackForwardList"); - ALOG_ASSERT(clazz, "Unable to find class android/webkit/WebBackForwardList"); - gWebBackForwardList.mAddHistoryItem = env->GetMethodID(clazz, "addHistoryItem", + // Find the WebBackForwardListClassic object and method. + clazz = env->FindClass("android/webkit/WebBackForwardListClassic"); + ALOG_ASSERT(clazz, "Unable to find class android/webkit/WebBackForwardListClassic"); + gWebBackForwardListClassic.mAddHistoryItem = env->GetMethodID(clazz, "addHistoryItem", "(Landroid/webkit/WebHistoryItem;)V"); - ALOG_ASSERT(gWebBackForwardList.mAddHistoryItem, "Could not find method addHistoryItem"); - gWebBackForwardList.mRemoveHistoryItem = env->GetMethodID(clazz, "removeHistoryItem", + ALOG_ASSERT(gWebBackForwardListClassic.mAddHistoryItem, "Could not find method addHistoryItem"); + gWebBackForwardListClassic.mRemoveHistoryItem = env->GetMethodID(clazz, "removeHistoryItem", "(I)V"); - ALOG_ASSERT(gWebBackForwardList.mRemoveHistoryItem, "Could not find method removeHistoryItem"); - gWebBackForwardList.mSetCurrentIndex = env->GetMethodID(clazz, "setCurrentIndex", "(I)V"); - ALOG_ASSERT(gWebBackForwardList.mSetCurrentIndex, "Could not find method setCurrentIndex"); + ALOG_ASSERT(gWebBackForwardListClassic.mRemoveHistoryItem, "Could not find method removeHistoryItem"); + gWebBackForwardListClassic.mSetCurrentIndex = env->GetMethodID(clazz, "setCurrentIndex", "(I)V"); + ALOG_ASSERT(gWebBackForwardListClassic.mSetCurrentIndex, "Could not find method setCurrentIndex"); env->DeleteLocalRef(clazz); - int result = jniRegisterNativeMethods(env, "android/webkit/WebBackForwardList", - gWebBackForwardListMethods, NELEM(gWebBackForwardListMethods)); - return (result < 0) ? result : jniRegisterNativeMethods(env, "android/webkit/WebHistoryItem", - gWebHistoryItemMethods, NELEM(gWebHistoryItemMethods)); + int result = jniRegisterNativeMethods(env, "android/webkit/WebBackForwardListClassic", + gWebBackForwardListClassicMethods, NELEM(gWebBackForwardListClassicMethods)); + return (result < 0) ? result : jniRegisterNativeMethods(env, "android/webkit/WebHistoryItemClassic", + gWebHistoryItemClassicMethods, NELEM(gWebHistoryItemClassicMethods)); } } /* namespace android */ diff --git a/Source/WebKit/android/jni/WebSettings.cpp b/Source/WebKit/android/jni/WebSettings.cpp index 467da3d..1bd3e36 100644 --- a/Source/WebKit/android/jni/WebSettings.cpp +++ b/Source/WebKit/android/jni/WebSettings.cpp @@ -151,6 +151,7 @@ struct FieldIds { #endif mOverrideCacheMode = env->GetFieldID(clazz, "mOverrideCacheMode", "I"); mPasswordEchoEnabled = env->GetFieldID(clazz, "mPasswordEchoEnabled", "Z"); + mMediaPlaybackRequiresUserGesture = env->GetFieldID(clazz, "mMediaPlaybackRequiresUserGesture", "Z"); ALOG_ASSERT(mLayoutAlgorithm, "Could not find field mLayoutAlgorithm"); ALOG_ASSERT(mTextSize, "Could not find field mTextSize"); @@ -195,6 +196,7 @@ struct FieldIds { ALOG_ASSERT(mUseDoubleTree, "Could not find field mUseDoubleTree"); ALOG_ASSERT(mPageCacheCapacity, "Could not find field mPageCacheCapacity"); ALOG_ASSERT(mPasswordEchoEnabled, "Could not find field mPasswordEchoEnabled"); + ALOG_ASSERT(mMediaPlaybackRequiresUserGesture, "Could not find field mMediaPlaybackRequiresUserGesture"); jclass enumClass = env->FindClass("java/lang/Enum"); ALOG_ASSERT(enumClass, "Could not find Enum class!"); @@ -281,6 +283,7 @@ struct FieldIds { #endif jfieldID mOverrideCacheMode; jfieldID mPasswordEchoEnabled; + jfieldID mMediaPlaybackRequiresUserGesture; }; static struct FieldIds* gFieldIds; @@ -616,6 +619,9 @@ public: bool echoPassword = env->GetBooleanField(obj, gFieldIds->mPasswordEchoEnabled); s->setPasswordEchoEnabled(echoPassword); + + flag = env->GetBooleanField(obj, gFieldIds->mMediaPlaybackRequiresUserGesture); + s->setMediaPlaybackRequiresUserGesture(flag); } }; diff --git a/Source/WebKit/android/jni/WebStorage.cpp b/Source/WebKit/android/jni/WebStorage.cpp index 66a3517..0cfe414 100644 --- a/Source/WebKit/android/jni/WebStorage.cpp +++ b/Source/WebKit/android/jni/WebStorage.cpp @@ -130,14 +130,10 @@ static void DeleteOrigin(JNIEnv* env, jobject obj, jstring origin) static void DeleteAllData(JNIEnv* env, jobject obj) { + // delete WebSQL database WebCore::DatabaseTracker::tracker().deleteAllDatabases(); - - Vector<WebCore::KURL> manifestUrls; - if (!WebCore::cacheStorage().manifestURLs(&manifestUrls)) - return; - int size = manifestUrls.size(); - for (int i = 0; i < size; ++i) - WebCore::cacheStorage().deleteCacheGroup(manifestUrls[i]); + // delete AppCache + WebCore::cacheStorage().deleteAllEntries(); // FIXME: this is a workaround for eliminating any DOM Storage data (both // session and local storage) as there is no functionality inside WebKit at the diff --git a/Source/WebKit/android/jni/WebViewCore.cpp b/Source/WebKit/android/jni/WebViewCore.cpp index f17e573..3324bfd 100644 --- a/Source/WebKit/android/jni/WebViewCore.cpp +++ b/Source/WebKit/android/jni/WebViewCore.cpp @@ -30,6 +30,7 @@ #include "AccessibilityObject.h" #include "AndroidHitTestResult.h" +#include "ApplicationCacheStorage.h" #include "Attribute.h" #include "content/address_detector.h" #include "Chrome.h" @@ -62,7 +63,6 @@ #include "Geolocation.h" #include "GraphicsContext.h" #include "GraphicsJNI.h" -#include "GraphicsOperationCollection.h" #include "HTMLAnchorElement.h" #include "HTMLAreaElement.h" #include "HTMLElement.h" @@ -131,7 +131,6 @@ #include "WebCoreJni.h" #include "WebFrameView.h" #include "WindowsKeyboardCodes.h" -#include "android_graphics.h" #include "autofill/WebAutofill.h" #include "htmlediting.h" #include "markup.h" @@ -367,8 +366,6 @@ struct WebViewCore::JavaGlue { jmethodID m_showRect; jmethodID m_centerFitRect; jmethodID m_setScrollbarModes; - jmethodID m_setInstallableWebApp; - jmethodID m_enterFullscreenForVideoLayer; jmethodID m_exitFullscreenVideo; jmethodID m_setWebTextViewAutoFillable; jmethodID m_selectAt; @@ -401,7 +398,7 @@ struct WebViewCore::TextFieldInitDataGlue { jfieldID m_maxLength; jfieldID m_contentBounds; jfieldID m_nodeLayerId; - jfieldID m_contentRect; + jfieldID m_clientRect; }; /* @@ -423,7 +420,6 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m , m_mainFrame(mainframe) , m_popupReply(0) , m_blockTextfieldUpdates(false) - , m_focusBoundsChanged(false) , m_skipContentDraw(false) , m_textGeneration(0) , m_maxXScroll(320/4) @@ -436,7 +432,6 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m , m_textWrapWidth(320) , m_scale(1.0f) , m_groupForVisitedLinks(0) - , m_isPaused(false) , m_cacheMode(0) , m_fullscreenVideoMode(false) , m_matchCount(0) @@ -446,6 +441,7 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m , m_screenOnCounter(0) , m_currentNodeDomNavigationAxis(0) , m_deviceMotionAndOrientationManager(this) + , m_geolocationManager(this) #if ENABLE(TOUCH_EVENTS) , m_forwardingTouchEvents(false) #endif @@ -471,7 +467,7 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m m_javaGlue->m_updateViewport = GetJMethod(env, clazz, "updateViewport", "()V"); m_javaGlue->m_sendNotifyProgressFinished = GetJMethod(env, clazz, "sendNotifyProgressFinished", "()V"); m_javaGlue->m_sendViewInvalidate = GetJMethod(env, clazz, "sendViewInvalidate", "(IIII)V"); - m_javaGlue->m_updateTextfield = GetJMethod(env, clazz, "updateTextfield", "(IZLjava/lang/String;I)V"); + m_javaGlue->m_updateTextfield = GetJMethod(env, clazz, "updateTextfield", "(ILjava/lang/String;I)V"); m_javaGlue->m_updateTextSelection = GetJMethod(env, clazz, "updateTextSelection", "(IIIII)V"); m_javaGlue->m_updateTextSizeAndScroll = GetJMethod(env, clazz, "updateTextSizeAndScroll", "(IIIII)V"); m_javaGlue->m_clearTextEntry = GetJMethod(env, clazz, "clearTextEntry", "()V"); @@ -479,7 +475,7 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m m_javaGlue->m_needTouchEvents = GetJMethod(env, clazz, "needTouchEvents", "(Z)V"); m_javaGlue->m_requestKeyboard = GetJMethod(env, clazz, "requestKeyboard", "(Z)V"); m_javaGlue->m_exceededDatabaseQuota = GetJMethod(env, clazz, "exceededDatabaseQuota", "(Ljava/lang/String;Ljava/lang/String;JJ)V"); - m_javaGlue->m_reachedMaxAppCacheSize = GetJMethod(env, clazz, "reachedMaxAppCacheSize", "(J)V"); + m_javaGlue->m_reachedMaxAppCacheSize = GetJMethod(env, clazz, "reachedMaxAppCacheSize", "(JJ)V"); m_javaGlue->m_populateVisitedLinks = GetJMethod(env, clazz, "populateVisitedLinks", "()V"); m_javaGlue->m_geolocationPermissionsShowPrompt = GetJMethod(env, clazz, "geolocationPermissionsShowPrompt", "(Ljava/lang/String;)V"); m_javaGlue->m_geolocationPermissionsHidePrompt = GetJMethod(env, clazz, "geolocationPermissionsHidePrompt", "()V"); @@ -499,9 +495,7 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m m_javaGlue->m_showRect = GetJMethod(env, clazz, "showRect", "(IIIIIIFFFF)V"); m_javaGlue->m_centerFitRect = GetJMethod(env, clazz, "centerFitRect", "(IIII)V"); m_javaGlue->m_setScrollbarModes = GetJMethod(env, clazz, "setScrollbarModes", "(II)V"); - m_javaGlue->m_setInstallableWebApp = GetJMethod(env, clazz, "setInstallableWebApp", "()V"); #if ENABLE(VIDEO) - m_javaGlue->m_enterFullscreenForVideoLayer = GetJMethod(env, clazz, "enterFullscreenForVideoLayer", "(ILjava/lang/String;)V"); m_javaGlue->m_exitFullscreenVideo = GetJMethod(env, clazz, "exitFullscreenVideo", "()V"); #endif m_javaGlue->m_setWebTextViewAutoFillable = GetJMethod(env, clazz, "setWebTextViewAutoFillable", "(ILjava/lang/String;)V"); @@ -526,7 +520,7 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m m_textFieldInitDataGlue->m_maxLength = env->GetFieldID(tfidClazz, "mMaxLength", "I"); m_textFieldInitDataGlue->m_contentBounds = env->GetFieldID(tfidClazz, "mContentBounds", "Landroid/graphics/Rect;"); m_textFieldInitDataGlue->m_nodeLayerId = env->GetFieldID(tfidClazz, "mNodeLayerId", "I"); - m_textFieldInitDataGlue->m_contentRect = env->GetFieldID(tfidClazz, "mContentRect", "Landroid/graphics/Rect;"); + m_textFieldInitDataGlue->m_clientRect = env->GetFieldID(tfidClazz, "mClientRect", "Landroid/graphics/Rect;"); m_textFieldInitDataGlue->m_constructor = GetJMethod(env, tfidClazz, "<init>", "()V"); env->DeleteLocalRef(tfidClazz); @@ -728,13 +722,6 @@ void WebViewCore::clearContent() updateLocale(); } -bool WebViewCore::focusBoundsChanged() -{ - bool result = m_focusBoundsChanged; - m_focusBoundsChanged = false; - return result; -} - void WebViewCore::paintContents(WebCore::GraphicsContext* gc, WebCore::IntRect& dirty) { WebCore::FrameView* view = m_mainFrame->view(); @@ -1507,6 +1494,7 @@ bool WebViewCore::selectWordAroundPosition(Frame* frame, VisiblePosition pos) VisibleSelection selection(pos); selection.expandUsingGranularity(WordGranularity); SelectionController* selectionController = frame->selection(); + selection = VisibleSelection(selection.start(), selection.end()); bool wordSelected = false; if (selectionController->shouldChangeSelection(selection)) { @@ -1566,7 +1554,8 @@ void WebViewCore::layerToAbsoluteOffset(const LayerAndroid* layer, IntPoint& off void WebViewCore::setSelectionCaretInfo(SelectText* selectTextContainer, const WebCore::Position& pos, const IntPoint& frameOffset, - SelectText::HandleId handleId, int caretRectOffset, EAffinity affinity) + SelectText::HandleId handleId, SelectText::HandleType handleType, + int caretRectOffset, EAffinity affinity) { Node* node = pos.anchorNode(); LayerAndroid* layer = 0; @@ -1584,6 +1573,7 @@ void WebViewCore::setSelectionCaretInfo(SelectText* selectTextContainer, caretRect.setX(absoluteOffset.x() - offset.x() + caretRectOffset); caretRect.setY(absoluteOffset.y() - offset.y()); selectTextContainer->setCaretRect(handleId, caretRect); + selectTextContainer->setHandleType(handleId, handleType); selectTextContainer->setTextRect(handleId, positionToTextRect(pos, affinity, offset)); } @@ -1601,14 +1591,28 @@ bool WebViewCore::isLtr(const Position& position) return isLtr; } +static Node* findInputParent(Node* node) +{ + Node* testNode = node; + while (testNode) { + RenderObject* renderer = testNode->renderer(); + if (renderer + && (renderer->isTextArea() || renderer->isTextControl())) { + return testNode; + } + testNode = testNode->parentOrHostNode(); + } + return node; +} + SelectText* WebViewCore::createSelectText(const VisibleSelection& selection) { bool isCaret = selection.isCaret(); + Position base = selection.base(); + Position extent = selection.extent(); if (selection.isNone() || (!selection.isContentEditable() && isCaret) - || !selection.start().anchorNode() - || !selection.start().anchorNode()->renderer() - || !selection.end().anchorNode() - || !selection.end().anchorNode()->renderer()) + || !base.anchorNode() || !base.anchorNode()->renderer() + || !extent.anchorNode() || !extent.anchorNode()->renderer()) return 0; RefPtr<Range> range = selection.firstRange(); @@ -1624,20 +1628,39 @@ SelectText* WebViewCore::createSelectText(const VisibleSelection& selection) IntPoint frameOffset = convertGlobalContentToFrameContent(IntPoint()); SelectText* selectTextContainer = new SelectText(); if (isCaret) { - setSelectionCaretInfo(selectTextContainer, selection.start(), frameOffset, - SelectText::LeftHandle, 0, selection.affinity()); - setSelectionCaretInfo(selectTextContainer, selection.start(), frameOffset, - SelectText::RightHandle, 0, selection.affinity()); + setSelectionCaretInfo(selectTextContainer, base, frameOffset, + SelectText::BaseHandle, SelectText::CenterHandle, 0, + selection.affinity()); + setSelectionCaretInfo(selectTextContainer, base, frameOffset, + SelectText::ExtentHandle, SelectText::CenterHandle, 0, + selection.affinity()); } else { - bool ltr = isLtr(selection.start()); - Position left = ltr ? selection.start() : selection.end(); - Position right = ltr ? selection.end() : selection.start(); - int leftOffset = isLtr(left) ? 0 : -1; - int rightOffset = isLtr(right) ? 0 : -1; - setSelectionCaretInfo(selectTextContainer, left, frameOffset, - SelectText::LeftHandle, leftOffset, selection.affinity()); - setSelectionCaretInfo(selectTextContainer, right, frameOffset, - SelectText::RightHandle, rightOffset, selection.affinity()); + bool isBaseLtr = isLtr(base); + bool isBaseStart = comparePositions(base, extent) <= 0; + int baseOffset = isBaseLtr ? 0 : -1; + SelectText::HandleType baseHandleType = (isBaseLtr == isBaseStart) + ? SelectText::LeftHandle : SelectText::RightHandle; + EAffinity affinity = selection.affinity(); + setSelectionCaretInfo(selectTextContainer, base, frameOffset, + SelectText::BaseHandle, baseHandleType, baseOffset, affinity); + bool isExtentLtr = isLtr(extent); + int extentOffset = isExtentLtr ? 0 : -1; + SelectText::HandleType extentHandleType = (isExtentLtr == isBaseStart) + ? SelectText::RightHandle : SelectText::LeftHandle; + setSelectionCaretInfo(selectTextContainer, extent, frameOffset, + SelectText::ExtentHandle, extentHandleType, extentOffset, affinity); + IntRect clipRect; + if (selection.isContentEditable()) { + Node* editable = findInputParent(base.anchorNode()); + RenderObject* render = editable->renderer(); + if (render && render->isBox() && !render->isBody()) { + RenderBox* renderBox = toRenderBox(render); + clipRect = renderBox->clientBoxRect(); + FloatPoint pos = renderBox->localToAbsolute(clipRect.location()); + clipRect.setX(pos.x()); + clipRect.setY(pos.y()); + } + } Node* stopNode = range->pastLastNode(); for (Node* node = range->firstNode(); node != stopNode; node = node->traverseNextNode()) { @@ -1651,7 +1674,8 @@ SelectText* WebViewCore::createSelectText(const VisibleSelection& selection) int layerId = platformLayerIdFromNode(node, &layer); Vector<IntRect> rects; renderText->absoluteRectsForRange(rects, startOffset, endOffset, true); - selectTextContainer->addHighlightRegion(layer, rects, frameOffset); + selectTextContainer->addHighlightRegion(layer, rects, frameOffset, + clipRect); } } selectTextContainer->setText(range->text()); @@ -1697,25 +1721,25 @@ IntPoint WebViewCore::convertGlobalContentToFrameContent(const IntPoint& point, return IntPoint(point.x() + frameOffset.x(), point.y() + frameOffset.y()); } -Position WebViewCore::trimSelectionPosition(const Position &start, const Position& stop) +VisiblePosition WebViewCore::trimSelectionPosition(const VisiblePosition &start, + const VisiblePosition& stop) { int direction = comparePositions(start, stop); if (direction == 0) return start; bool forward = direction < 0; - EAffinity affinity = forward ? DOWNSTREAM : UPSTREAM; bool move; - Position pos = start; + VisiblePosition pos = start; bool movedTooFar = false; do { move = true; - Node* node = pos.anchorNode(); + Node* node = pos.deepEquivalent().anchorNode(); if (node && node->isTextNode() && node->renderer()) { RenderText *textRenderer = toRenderText(node->renderer()); move = !textRenderer->textLength(); } if (move) { - Position nextPos = forward ? pos.next() : pos.previous(); + VisiblePosition nextPos = forward ? pos.next() : pos.previous(); movedTooFar = nextPos.isNull() || pos == nextPos || ((comparePositions(nextPos, stop) < 0) != forward); pos = nextPos; @@ -1726,47 +1750,65 @@ Position WebViewCore::trimSelectionPosition(const Position &start, const Positio return pos; } -void WebViewCore::selectText(int startX, int startY, int endX, int endY) +void WebViewCore::selectText(SelectText::HandleId handleId, int x, int y) { SelectionController* sc = focusedFrame()->selection(); - IntPoint startPoint = convertGlobalContentToFrameContent(IntPoint(startX, startY)); - VisiblePosition startPosition(visiblePositionForContentPoint(startPoint)); - IntPoint endPoint = convertGlobalContentToFrameContent(IntPoint(endX, endY)); - VisiblePosition endPosition(visiblePositionForContentPoint(endPoint)); + VisibleSelection selection = sc->selection(); + Position base = selection.base(); + Position extent = selection.extent(); + IntPoint dragPoint = convertGlobalContentToFrameContent(IntPoint(x, y)); + VisiblePosition dragPosition(visiblePositionForContentPoint(dragPoint)); - if (startPosition.isNull() || endPosition.isNull()) + if (base.isNull() || extent.isNull() || dragPosition.isNull()) return; + bool draggingBase = (handleId == SelectText::BaseHandle); + if (draggingBase) + base = dragPosition.deepEquivalent(); + else + extent = dragPosition.deepEquivalent(); - // Ensure startPosition is before endPosition - if (comparePositions(startPosition, endPosition) > 0) - swap(startPosition, endPosition); + bool baseIsStart = (comparePositions(base, extent) <= 0); + Position& start = baseIsStart ? base : extent; + Position& end = baseIsStart ? extent : base; + VisiblePosition startPosition(start, selection.affinity()); + VisiblePosition endPosition(end, selection.affinity()); + bool draggingStart = (baseIsStart == draggingBase); - if (sc->isContentEditable()) { - startPosition = sc->selection().visibleStart().honorEditableBoundaryAtOrAfter(startPosition); - endPosition = sc->selection().visibleEnd().honorEditableBoundaryAtOrBefore(endPosition); - if (startPosition.isNull() || endPosition.isNull()) { + if (draggingStart) { + if (selection.isRange()) { + startPosition = trimSelectionPosition(startPosition, endPosition); + if ((startPosition != endPosition) && isEndOfBlock(startPosition)) { + // Ensure startPosition is not at end of block + VisiblePosition nextStartPosition(startPosition.next()); + if (nextStartPosition.isNotNull()) + startPosition = nextStartPosition; + } + } + startPosition = endPosition.honorEditableBoundaryAtOrAfter(startPosition); + if (startPosition.isNull()) return; + start = startPosition.deepEquivalent(); + if (selection.isCaret()) + end = start; + } else { + if (selection.isRange()) { + endPosition = trimSelectionPosition(endPosition, startPosition); + if ((start != end) && isStartOfBlock(endPosition)) { + // Ensure endPosition is not at start of block + VisiblePosition prevEndPosition(endPosition.previous()); + if (!prevEndPosition.isNull()) + endPosition = prevEndPosition; + } } + endPosition = startPosition.honorEditableBoundaryAtOrAfter(endPosition); + if (endPosition.isNull()) + return; + end = endPosition.deepEquivalent(); + if (selection.isCaret()) + start = end; } - // Ensure startPosition is not at end of block - if (startPosition != endPosition && isEndOfBlock(startPosition)) { - VisiblePosition nextStartPosition(startPosition.next()); - if (!nextStartPosition.isNull()) - startPosition = nextStartPosition; - } - // Ensure endPosition is not at start of block - if (startPosition != endPosition && isStartOfBlock(endPosition)) { - VisiblePosition prevEndPosition(endPosition.previous()); - if (!prevEndPosition.isNull()) - endPosition = prevEndPosition; - } - - Position start = startPosition.deepEquivalent(); - Position end = endPosition.deepEquivalent(); - start = trimSelectionPosition(start, end); - end = trimSelectionPosition(end, start); - VisibleSelection selection(start, end); + selection = VisibleSelection(base, extent); // Only allow changes between caret positions or to text selection. bool selectChangeAllowed = (!selection.isCaret() || sc->isCaret()); if (selectChangeAllowed && sc->shouldChangeSelection(selection)) @@ -2944,33 +2986,31 @@ void WebViewCore::passToJs(int generation, const WTF::String& current, WTF::String test = getInputText(focus); if (test != current) { // If the text changed during the key event, update the UI text field. - updateTextfield(focus, false, test); + updateTextfield(focus, test); } // Now that the selection has settled down, send it. updateTextSelection(); } -WebCore::IntRect WebViewCore::scrollFocusedTextInput(float xPercent, int y) +void WebViewCore::scrollFocusedTextInput(float xPercent, int y) { WebCore::Node* focus = currentFocus(); if (!focus) { clearTextEntry(); - return WebCore::IntRect(); + return; } WebCore::RenderTextControl* renderText = toRenderTextControl(focus); if (!renderText) { clearTextEntry(); - return WebCore::IntRect(); + return; } - int x = (int) (xPercent * (renderText->scrollWidth() - + int x = (int)round(xPercent * (renderText->scrollWidth() - renderText->clientWidth())); renderText->setScrollLeft(x); renderText->setScrollTop(y); focus->document()->frame()->selection()->recomputeCaretRect(); - LayerAndroid* layer = 0; - platformLayerIdFromNode(focus, &layer); - return absoluteContentRect(focus, layer); + updateTextSelection(); } void WebViewCore::setFocusControllerActive(bool active) @@ -3364,10 +3404,10 @@ bool WebViewCore::isAutoCompleteEnabled(Node* node) return isEnabled; } -WebCore::IntRect WebViewCore::absoluteContentRect(WebCore::Node* node, +WebCore::IntRect WebViewCore::absoluteClientRect(WebCore::Node* node, LayerAndroid* layer) { - IntRect contentRect; + IntRect clientRect; if (node) { RenderObject* render = node->renderer(); if (render && render->isBox() && !render->isBody()) { @@ -3376,11 +3416,12 @@ WebCore::IntRect WebViewCore::absoluteContentRect(WebCore::Node* node, WebViewCore::layerToAbsoluteOffset(layer, offset); RenderBox* renderBox = toRenderBox(render); - contentRect = renderBox->absoluteContentBox(); - contentRect.move(-offset.x(), -offset.y()); + clientRect = renderBox->clientBoxRect(); + FloatPoint absPos = renderBox->localToAbsolute(FloatPoint()); + clientRect.move(absPos.x() - offset.x(), absPos.y() - offset.y()); } } - return contentRect; + return clientRect; } jobject WebViewCore::createTextFieldInitData(Node* node) @@ -3417,7 +3458,7 @@ jobject WebViewCore::createTextFieldInitData(Node* node) env->SetIntField(initData, classDef->m_maxLength, getMaxLength(node)); LayerAndroid* layer = 0; int layerId = platformLayerIdFromNode(node, &layer); - IntRect bounds = absoluteContentRect(node, layer); + IntRect bounds = absoluteClientRect(node, layer); ScopedLocalRef<jobject> jbounds(env, intRectToRect(env, bounds)); env->SetObjectField(initData, classDef->m_contentBounds, jbounds.get()); env->SetIntField(initData, classDef->m_nodeLayerId, layerId); @@ -3429,7 +3470,7 @@ jobject WebViewCore::createTextFieldInitData(Node* node) contentRect.move(-rtc->scrollLeft(), -rtc->scrollTop()); } ScopedLocalRef<jobject> jcontentRect(env, intRectToRect(env, contentRect)); - env->SetObjectField(initData, classDef->m_contentRect, jcontentRect.get()); + env->SetObjectField(initData, classDef->m_clientRect, jcontentRect.get()); return initData; } @@ -3611,6 +3652,19 @@ bool WebViewCore::exceededDatabaseQuota(const WTF::String& url, const WTF::Strin #endif } +/* + * TODO Note that this logic still needs to be cleaned up. Normally the + * information provided in this callback is used to resize the appcache. + * so we need to provide the current database size. However, webkit provides no + * way to reach this information. It can be calculated by fetching all the + * origins and their usage, however this is too expensize (requires one inner + * join operation for each origin). Rather, we simply return the maximum cache size, + * which should be equivalent to the current cache size. This is generally safe. + * However, setting the maximum database size to less than the current database size + * may cause a problem. In this case, ApplicationCacheStorage ("the owner of database") + * uses the updated value, while database internally ignores it and uses the current size + * as quota. This means the value we returned here won't reflect the actual database size. + */ bool WebViewCore::reachedMaxAppCacheSize(const unsigned long long spaceNeeded) { #if ENABLE(OFFLINE_WEB_APPLICATIONS) @@ -3618,7 +3672,7 @@ bool WebViewCore::reachedMaxAppCacheSize(const unsigned long long spaceNeeded) AutoJObject javaObject = m_javaGlue->object(env); if (!javaObject.get()) return false; - env->CallVoidMethod(javaObject.get(), m_javaGlue->m_reachedMaxAppCacheSize, spaceNeeded); + env->CallVoidMethod(javaObject.get(), m_javaGlue->m_reachedMaxAppCacheSize, spaceNeeded, WebCore::cacheStorage().maximumSize()); checkException(env); return true; #endif @@ -3848,8 +3902,7 @@ void WebViewCore::updateTextSizeAndScroll(WebCore::Node* node) checkException(env); } -void WebViewCore::updateTextfield(WebCore::Node* ptr, bool changeToPassword, - const WTF::String& text) +void WebViewCore::updateTextfield(WebCore::Node* ptr, const WTF::String& text) { JNIEnv* env = JSC::Bindings::getJNIEnv(); AutoJObject javaObject = m_javaGlue->object(env); @@ -3857,15 +3910,9 @@ void WebViewCore::updateTextfield(WebCore::Node* ptr, bool changeToPassword, return; if (m_blockTextfieldUpdates) return; - if (changeToPassword) { - env->CallVoidMethod(javaObject.get(), m_javaGlue->m_updateTextfield, - (int) ptr, true, 0, m_textGeneration); - checkException(env); - return; - } jstring string = wtfStringToJstring(env, text); env->CallVoidMethod(javaObject.get(), m_javaGlue->m_updateTextfield, - (int) ptr, false, string, m_textGeneration); + (int) ptr, string, m_textGeneration); env->DeleteLocalRef(string); checkException(env); } @@ -4059,27 +4106,11 @@ void WebViewCore::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode checkException(env); } -void WebViewCore::notifyWebAppCanBeInstalled() -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - AutoJObject javaObject = m_javaGlue->object(env); - if (!javaObject.get()) - return; - env->CallVoidMethod(javaObject.get(), m_javaGlue->m_setInstallableWebApp); - checkException(env); -} - #if ENABLE(VIDEO) -void WebViewCore::enterFullscreenForVideoLayer(int layerId, const WTF::String& url) +void WebViewCore::enterFullscreenForVideoLayer() { - JNIEnv* env = JSC::Bindings::getJNIEnv(); - AutoJObject javaObject = m_javaGlue->object(env); - if (!javaObject.get()) - return; - jstring jUrlStr = wtfStringToJstring(env, url); - env->CallVoidMethod(javaObject.get(), m_javaGlue->m_enterFullscreenForVideoLayer, layerId, jUrlStr); + // Just need to update the video mode, to avoid multiple exit full screen. m_fullscreenVideoMode = true; - checkException(env); } void WebViewCore::exitFullscreenVideo() @@ -4505,12 +4536,10 @@ static void PassToJs(JNIEnv* env, jobject obj, jint nativeClass, } static void ScrollFocusedTextInput(JNIEnv* env, jobject obj, jint nativeClass, - jfloat xPercent, jint y, jobject contentBounds) + jfloat xPercent, jint y) { WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); - IntRect bounds = viewImpl->scrollFocusedTextInput(xPercent, y); - if (contentBounds) - GraphicsJNI::irect_to_jrect(bounds, env, contentBounds); + viewImpl->scrollFocusedTextInput(xPercent, y); } static void SetFocusControllerActive(JNIEnv* env, jobject obj, jint nativeClass, @@ -4765,10 +4794,7 @@ static void GeolocationPermissionsProvide(JNIEnv* env, jobject obj, jint nativeClass, jstring origin, jboolean allow, jboolean remember) { WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); - Frame* frame = viewImpl->mainFrame(); - - ChromeClientAndroid* chromeClient = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client()); - chromeClient->provideGeolocationPermissions(jstringToWtfString(env, origin), allow, remember); + viewImpl->geolocationManager()->provideRealClientPermissionState(jstringToWtfString(env, origin), allow, remember); } static void RegisterURLSchemeAsLocal(JNIEnv* env, jobject obj, jint nativeClass, @@ -4777,20 +4803,6 @@ static void RegisterURLSchemeAsLocal(JNIEnv* env, jobject obj, jint nativeClass, WebCore::SchemeRegistry::registerURLSchemeAsLocal(jstringToWtfString(env, scheme)); } -static bool FocusBoundsChanged(JNIEnv* env, jobject obj, jint nativeClass) -{ - return reinterpret_cast<WebViewCore*>(nativeClass)->focusBoundsChanged(); -} - -static void SetIsPaused(JNIEnv* env, jobject obj, jint nativeClass, - jboolean isPaused) -{ - // tell the webcore thread to stop thinking while we do other work - // (selection and scrolling). This has nothing to do with the lifecycle - // pause and resume. - reinterpret_cast<WebViewCore*>(nativeClass)->setIsPaused(isPaused); -} - static void Pause(JNIEnv* env, jobject obj, jint nativeClass) { // This is called for the foreground tab when the browser is put to the @@ -4798,50 +4810,36 @@ static void Pause(JNIEnv* env, jobject obj, jint nativeClass) // browser). The browser can only be killed by the system when it is in the // background, so saving the Geolocation permission state now ensures that // is maintained when the browser is killed. - WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); - ChromeClient* chromeClient = viewImpl->mainFrame()->page()->chrome()->client(); - ChromeClientAndroid* chromeClientAndroid = static_cast<ChromeClientAndroid*>(chromeClient); - chromeClientAndroid->storeGeolocationPermissions(); + GeolocationPermissions::maybeStorePermanentPermissions(); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); Frame* mainFrame = viewImpl->mainFrame(); - for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) { - Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation(); - if (geolocation) - geolocation->suspend(); - } if (mainFrame) mainFrame->settings()->setMinDOMTimerInterval(BACKGROUND_TIMER_INTERVAL); viewImpl->deviceMotionAndOrientationManager()->maybeSuspendClients(); + viewImpl->geolocationManager()->suspendRealClient(); ANPEvent event; SkANP::InitEvent(&event, kLifecycle_ANPEventType); event.data.lifecycle.action = kPause_ANPLifecycleAction; viewImpl->sendPluginEvent(event); - - viewImpl->setIsPaused(true); } static void Resume(JNIEnv* env, jobject obj, jint nativeClass) { WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); Frame* mainFrame = viewImpl->mainFrame(); - for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) { - Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation(); - if (geolocation) - geolocation->resume(); - } if (mainFrame) mainFrame->settings()->setMinDOMTimerInterval(FOREGROUND_TIMER_INTERVAL); viewImpl->deviceMotionAndOrientationManager()->maybeResumeClients(); + viewImpl->geolocationManager()->resumeRealClient(); ANPEvent event; SkANP::InitEvent(&event, kLifecycle_ANPEventType); event.data.lifecycle.action = kResume_ANPLifecycleAction; viewImpl->sendPluginEvent(event); - - viewImpl->setIsPaused(false); } static void FreeMemory(JNIEnv* env, jobject obj, jint nativeClass) @@ -4959,10 +4957,10 @@ static jobject GetText(JNIEnv* env, jobject obj, jint nativeClass, } static void SelectText(JNIEnv* env, jobject obj, jint nativeClass, - jint startX, jint startY, jint endX, jint endY) + jint handleId, jint x, jint y) { WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); - viewImpl->selectText(startX, startY, endX, endY); + viewImpl->selectText(static_cast<SelectText::HandleId>(handleId), x, y); } static void ClearSelection(JNIEnv* env, jobject obj, jint nativeClass) @@ -5006,8 +5004,6 @@ static int FindNext(JNIEnv* env, jobject obj, jint nativeClass, static JNINativeMethod gJavaWebViewCoreMethods[] = { { "nativeClearContent", "(I)V", (void*) ClearContent }, - { "nativeFocusBoundsChanged", "(I)Z", - (void*) FocusBoundsChanged } , { "nativeKey", "(IIIIZZZZ)Z", (void*) Key }, { "nativeContentInvalidateAll", "(I)V", @@ -5034,7 +5030,7 @@ static JNINativeMethod gJavaWebViewCoreMethods[] = { (void*) MoveMouse }, { "passToJs", "(IILjava/lang/String;IIZZZZ)V", (void*) PassToJs }, - { "nativeScrollFocusedTextInput", "(IFILandroid/graphics/Rect;)V", + { "nativeScrollFocusedTextInput", "(IFI)V", (void*) ScrollFocusedTextInput }, { "nativeSetFocusControllerActive", "(IZ)V", (void*) SetFocusControllerActive }, @@ -5072,7 +5068,6 @@ static JNINativeMethod gJavaWebViewCoreMethods[] = { (void*) SetNewStorageLimit }, { "nativeGeolocationPermissionsProvide", "(ILjava/lang/String;ZZ)V", (void*) GeolocationPermissionsProvide }, - { "nativeSetIsPaused", "(IZ)V", (void*) SetIsPaused }, { "nativePause", "(I)V", (void*) Pause }, { "nativeResume", "(I)V", (void*) Resume }, { "nativeFreeMemory", "(I)V", (void*) FreeMemory }, @@ -5100,7 +5095,7 @@ static JNINativeMethod gJavaWebViewCoreMethods[] = { (void*) InsertText }, { "nativeGetText", "(IIIII)Ljava/lang/String;", (void*) GetText }, - { "nativeSelectText", "(IIIII)V", + { "nativeSelectText", "(IIII)V", (void*) SelectText }, { "nativeClearTextSelection", "(I)V", (void*) ClearSelection }, diff --git a/Source/WebKit/android/jni/WebViewCore.h b/Source/WebKit/android/jni/WebViewCore.h index 5264f7f..6e3604d 100644 --- a/Source/WebKit/android/jni/WebViewCore.h +++ b/Source/WebKit/android/jni/WebViewCore.h @@ -30,6 +30,7 @@ #include "DOMSelection.h" #include "FileChooser.h" #include "FocusDirection.h" +#include "GeolocationManager.h" #include "HitTestResult.h" #include "PicturePile.h" #include "PlatformGraphicsContext.h" @@ -201,13 +202,9 @@ namespace android { /** * Tell the java side to update the focused textfield * @param pointer Pointer to the node for the input field. - * @param changeToPassword If true, we are changing the textfield to - * a password field, and ignore the WTF::String - * @param text If changeToPassword is false, this is the new text that - * should go into the textfield. + * @param text This is the new text that should go into the textfield. */ - void updateTextfield(WebCore::Node* pointer, - bool changeToPassword, const WTF::String& text); + void updateTextfield(WebCore::Node* pointer, const WTF::String& text); /** * Tell the java side to update the current selection in the focused @@ -396,7 +393,7 @@ namespace android { /** * Scroll the focused textfield to (x, y) in document space */ - WebCore::IntRect scrollFocusedTextInput(float x, int y); + void scrollFocusedTextInput(float x, int y); /** * Set the FocusController's active and focused states, so that * the caret will draw (true) or not. @@ -508,8 +505,6 @@ namespace android { // reset the picture set to empty void clearContent(); - bool focusBoundsChanged(); - // record content in a new BaseLayerAndroid, copying the layer tree as well WebCore::BaseLayerAndroid* recordContent(SkIPoint* ); @@ -526,8 +521,6 @@ namespace android { WebCore::Frame* mainFrame() const { return m_mainFrame; } WebCore::Frame* focusedFrame() const; - void notifyWebAppCanBeInstalled(); - void deleteText(int startX, int startY, int endX, int endY); WTF::String getText(int startX, int startY, int endX, int endY); void insertText(const WTF::String &text); @@ -539,19 +532,18 @@ namespace android { void updateMatchCount() const; #if ENABLE(VIDEO) - void enterFullscreenForVideoLayer(int layerId, const WTF::String& url); + void enterFullscreenForVideoLayer(); void exitFullscreenVideo(); #endif void setWebTextViewAutoFillable(int queryId, const string16& previewSummary); DeviceMotionAndOrientationManager* deviceMotionAndOrientationManager() { return &m_deviceMotionAndOrientationManager; } + GeolocationManager* geolocationManager() { return &m_geolocationManager; } void listBoxRequest(WebCoreReply* reply, const uint16_t** labels, size_t count, const int enabled[], size_t enabledCount, bool multiple, const int selected[], size_t selectedCountOrSelection); - bool isPaused() const { return m_isPaused; } - void setIsPaused(bool isPaused) { m_isPaused = isPaused; } bool drawIsPaused() const; // The actual content (without title bar) size in doc coordinate int screenWidth() const { return m_screenWidth; } @@ -580,7 +572,7 @@ namespace android { int startX, int startY, int endX, int endY); static int platformLayerIdFromNode(WebCore::Node* node, WebCore::LayerAndroid** outLayer = 0); - void selectText(int startX, int startY, int endX, int endY); + void selectText(SelectText::HandleId handleId, int x, int y); bool selectWordAt(int x, int y); // Converts from the global content coordinates that WebView sends @@ -728,18 +720,19 @@ namespace android { void setSelectionCaretInfo(SelectText* selectTextContainer, const WebCore::Position& position, const WebCore::IntPoint& frameOffset, - SelectText::HandleId handleId, int offset, - EAffinity affinity); + SelectText::HandleId handleId, SelectText::HandleType handleType, + int offset, EAffinity affinity); static int getMaxLength(WebCore::Node* node); static WTF::String getFieldName(WebCore::Node* node); static bool isAutoCompleteEnabled(WebCore::Node* node); - WebCore::IntRect absoluteContentRect(WebCore::Node* node, + WebCore::IntRect absoluteClientRect(WebCore::Node* node, WebCore::LayerAndroid* layer); static WebCore::IntRect positionToTextRect(const WebCore::Position& position, WebCore::EAffinity affinity, const WebCore::IntPoint& offset); static bool isLtr(const WebCore::Position& position); - static WebCore::Position trimSelectionPosition( - const WebCore::Position& start, const WebCore::Position& stop); + static WebCore::VisiblePosition trimSelectionPosition( + const WebCore::VisiblePosition& start, + const WebCore::VisiblePosition& stop); // called from constructor, to add this to a global list static void addInstance(WebViewCore*); @@ -759,7 +752,6 @@ namespace android { // Used in passToJS to avoid updating the UI text field until after the // key event has been processed. bool m_blockTextfieldUpdates; - bool m_focusBoundsChanged; bool m_skipContentDraw; // Passed in with key events to know when they were generated. Store it // with the cache so that we can ignore stale text changes. @@ -782,7 +774,6 @@ namespace android { int m_textWrapWidth; float m_scale; WebCore::PageGroup* m_groupForVisitedLinks; - bool m_isPaused; int m_cacheMode; bool m_fullscreenVideoMode; @@ -801,6 +792,7 @@ namespace android { int m_screenOnCounter; WebCore::Node* m_currentNodeDomNavigationAxis; DeviceMotionAndOrientationManager m_deviceMotionAndOrientationManager; + GeolocationManager m_geolocationManager; #if ENABLE(TOUCH_EVENTS) bool m_forwardingTouchEvents; diff --git a/Source/WebKit/android/nav/DrawExtra.cpp b/Source/WebKit/android/nav/DrawExtra.cpp index 2f57dc1..a7d686c 100644 --- a/Source/WebKit/android/nav/DrawExtra.cpp +++ b/Source/WebKit/android/nav/DrawExtra.cpp @@ -52,7 +52,8 @@ SkRegion* RegionLayerDrawExtra::getHighlightRegionsForLayer(const LayerAndroid* } void RegionLayerDrawExtra::addHighlightRegion(const LayerAndroid* layer, const Vector<IntRect>& rects, - const IntPoint& additionalOffset) + const IntPoint& additionalOffset, + const IntRect& clipRect) { if (rects.isEmpty()) return; @@ -66,6 +67,11 @@ void RegionLayerDrawExtra::addHighlightRegion(const LayerAndroid* layer, const V WebViewCore::layerToAbsoluteOffset(layer, offset); for (size_t i = 0; i < rects.size(); i++) { IntRect r = rects.at(i); + if (!clipRect.isEmpty()) { + r.intersect(clipRect); + if (r.isEmpty()) + continue; // don't add it to the region + } r.move(-offset.x(), -offset.y()); region->op(r.x(), r.y(), r.maxX(), r.maxY(), SkRegion::kUnion_Op); } diff --git a/Source/WebKit/android/nav/DrawExtra.h b/Source/WebKit/android/nav/DrawExtra.h index cc94476..1850b6b 100644 --- a/Source/WebKit/android/nav/DrawExtra.h +++ b/Source/WebKit/android/nav/DrawExtra.h @@ -65,7 +65,8 @@ public: virtual ~RegionLayerDrawExtra(); void addHighlightRegion(const LayerAndroid* layer, const Vector<IntRect>& rects, - const IntPoint& additionalOffset = IntPoint()); + const IntPoint& additionalOffset = IntPoint(), + const IntRect& clipRect = IntRect()); virtual void draw(SkCanvas*, LayerAndroid*); virtual void drawGL(GLExtras*, const LayerAndroid*); diff --git a/Source/WebKit/android/nav/SelectText.h b/Source/WebKit/android/nav/SelectText.h index aaaf3bb..8f7592d 100644 --- a/Source/WebKit/android/nav/SelectText.h +++ b/Source/WebKit/android/nav/SelectText.h @@ -35,8 +35,13 @@ namespace android { class SelectText : public RegionLayerDrawExtra { public: enum HandleId { + BaseHandle = 0, + ExtentHandle = 1, + }; + enum HandleType { LeftHandle = 0, - RightHandle = 1, + CenterHandle = 1, + RightHandle = 2, }; IntRect& caretRect(HandleId id) { return m_caretRects[id]; } @@ -48,11 +53,14 @@ public: void setText(const String& text) { m_text = text.threadsafeCopy(); } String& getText() { return m_text; } + HandleType getHandleType(HandleId id) { return m_handleType[id]; } + void setHandleType(HandleId id, HandleType type) { m_handleType[id] = type; } private: IntRect m_caretRects[2]; IntRect m_textRects[2]; int m_caretLayerId[2]; + HandleType m_handleType[2]; String m_text; }; diff --git a/Source/WebKit/android/nav/WebView.cpp b/Source/WebKit/android/nav/WebView.cpp index a67b5fd..66dbdc1 100644 --- a/Source/WebKit/android/nav/WebView.cpp +++ b/Source/WebKit/android/nav/WebView.cpp @@ -32,6 +32,7 @@ #include "BaseLayerAndroid.h" #include "BaseRenderer.h" #include "DrawExtra.h" +#include "DumpLayer.h" #include "Frame.h" #include "GLWebViewState.h" #include "GraphicsJNI.h" @@ -57,7 +58,6 @@ #include "WebCoreJni.h" #include "WebRequestContext.h" #include "WebViewCore.h" -#include "android_graphics.h" #ifdef GET_NATIVE_VIEW #undef GET_NATIVE_VIEW @@ -716,7 +716,7 @@ void findMaxVisibleRect(int movingLayerId, SkIRect& visibleContentRect) if (findMaskedRectsForLayer(m_baseLayer, rects, movingLayerId)) { float maxSize = 0.0; const FloatRect* largest = 0; - for (int i = 0; i < rects.size(); i++) { + for (unsigned int i = 0; i < rects.size(); i++) { const FloatRect& rect = rects[i]; float size = rect.width() * rect.height(); if (size > maxSize) { @@ -731,6 +731,29 @@ void findMaxVisibleRect(int movingLayerId, SkIRect& visibleContentRect) } } +bool isHandleLeft(SelectText::HandleId handleId) +{ + SelectText* selectText = static_cast<SelectText*>(getDrawExtra(DrawExtrasSelection)); + if (!selectText) + return (handleId == SelectText::BaseHandle); + + return (selectText->getHandleType(handleId) == SelectText::LeftHandle); +} + +bool isPointVisible(int layerId, int contentX, int contentY) +{ + bool isVisible = true; + const TransformationMatrix* transform = getLayerTransform(layerId); + if (transform) { + // layer is guaranteed to be non-NULL because of getLayerTransform + LayerAndroid* layer = m_baseLayer->findById(layerId); + IntRect rect = layer->visibleContentArea(); + rect = transform->mapRect(rect); + isVisible = rect.contains(contentX, contentY); + } + return isVisible; +} + private: // local state for WebView bool m_isDrawingPaused; // private to getFrameCache(); other functions operate in a different thread @@ -972,6 +995,28 @@ static void nativeCopyBaseContentToPicture(JNIEnv *env, jobject obj, jobject pic GET_NATIVE_VIEW(env, obj)->copyBaseContentToPicture(picture); } +static jboolean nativeDumpLayerContentToPicture(JNIEnv *env, jobject obj, jint instance, + jstring jclassName, jint layerId, jobject pict) +{ + bool success = false; + SkPicture* picture = GraphicsJNI::getNativePicture(env, pict); + std::string classname = jstringToStdString(env, jclassName); + BaseLayerAndroid* baseLayer = reinterpret_cast<WebView*>(instance)->getBaseLayer(); + LayerAndroid* layer = baseLayer->findById(layerId); + SkSafeRef(layer); + if (layer && layer->subclassName() == classname) { + LayerContent* content = layer->content(); + if (content) { + SkCanvas* canvas = picture->beginRecording(content->width(), content->height()); + content->draw(canvas); + picture->endRecording(); + success = true; + } + } + SkSafeUnref(layer); + return success; +} + static bool nativeHasContent(JNIEnv *env, jobject obj) { return GET_NATIVE_VIEW(env, obj)->hasContent(); @@ -1164,7 +1209,8 @@ static void nativeDumpDisplayTree(JNIEnv* env, jobject jwebview, jstring jurl) if (baseLayer) { FILE* file = fopen(LAYERS_TREE_LOG_FILE,"w"); if (file) { - baseLayer->dumpLayers(file, 0); + WebCore::FileLayerDumper dumper(file); + baseLayer->dumpLayers(&dumper); fclose(file); } } @@ -1288,6 +1334,20 @@ static void nativeFindMaxVisibleRect(JNIEnv *env, jobject obj, jint nativeView, GraphicsJNI::irect_to_jrect(nativeRect, env, visibleContentRect); } +static bool nativeIsHandleLeft(JNIEnv *env, jobject obj, jint nativeView, + jint handleId) +{ + WebView* webview = reinterpret_cast<WebView*>(nativeView); + return webview->isHandleLeft(static_cast<SelectText::HandleId>(handleId)); +} + +static bool nativeIsPointVisible(JNIEnv *env, jobject obj, jint nativeView, + jint layerId, jint contentX, jint contentY) +{ + WebView* webview = reinterpret_cast<WebView*>(nativeView); + return webview->isPointVisible(layerId, contentX, contentY); +} + /* * JNI registration */ @@ -1318,6 +1378,8 @@ static JNINativeMethod gJavaWebViewMethods[] = { (void*) nativeGetBaseLayer }, { "nativeCopyBaseContentToPicture", "(Landroid/graphics/Picture;)V", (void*) nativeCopyBaseContentToPicture }, + { "nativeDumpLayerContentToPicture", "(ILjava/lang/String;ILandroid/graphics/Picture;)Z", + (void*) nativeDumpLayerContentToPicture }, { "nativeHasContent", "()Z", (void*) nativeHasContent }, { "nativeDiscardAllTextures", "()V", @@ -1366,6 +1428,10 @@ static JNINativeMethod gJavaWebViewMethods[] = { (void*) nativeSetHwAccelerated }, { "nativeFindMaxVisibleRect", "(IILandroid/graphics/Rect;)V", (void*) nativeFindMaxVisibleRect }, + { "nativeIsHandleLeft", "(II)Z", + (void*) nativeIsHandleLeft }, + { "nativeIsPointVisible", "(IIII)Z", + (void*) nativeIsPointVisible }, }; int registerWebView(JNIEnv* env) diff --git a/Source/WebKit/android/plugins/ANPSoundInterface.cpp b/Source/WebKit/android/plugins/ANPSoundInterface.cpp index 9d19443..929832b 100644 --- a/Source/WebKit/android/plugins/ANPSoundInterface.cpp +++ b/Source/WebKit/android/plugins/ANPSoundInterface.cpp @@ -100,7 +100,7 @@ static ANPAudioTrack* ANPCreateTrack(uint32_t sampleRate, track->mTrack = new android::AudioTrack(AUDIO_STREAM_MUSIC, sampleRate, fromANPFormat(format), - (channelCount > 1) ? AUDIO_CHANNEL_OUT_STEREO : AUDIO_CHANNEL_OUT_MONO, + audio_channel_out_mask_from_count(channelCount), 0, // frameCount (audio_output_flags_t) 0, // AUDIO_OUTPUT_FLAG_NONE, callbackProc, diff --git a/Source/WebKit/android/plugins/ANPSurfaceInterface.cpp b/Source/WebKit/android/plugins/ANPSurfaceInterface.cpp index 92dbbcd..2b593e2 100644 --- a/Source/WebKit/android/plugins/ANPSurfaceInterface.cpp +++ b/Source/WebKit/android/plugins/ANPSurfaceInterface.cpp @@ -30,7 +30,6 @@ #include "PluginView.h" #include "PluginWidgetAndroid.h" #include "SkANP.h" -#include "android_graphics.h" #include <JNIUtility.h> #include <gui/Surface.h> #include <ui/Rect.h> diff --git a/Source/WebKit/android/plugins/PluginWidgetAndroid.cpp b/Source/WebKit/android/plugins/PluginWidgetAndroid.cpp index 09bb24e..2fd2ef4 100644 --- a/Source/WebKit/android/plugins/PluginWidgetAndroid.cpp +++ b/Source/WebKit/android/plugins/PluginWidgetAndroid.cpp @@ -42,7 +42,6 @@ #include "SkString.h" #include "SkTime.h" #include "WebViewCore.h" -#include "android_graphics.h" #include <JNIUtility.h> //#define PLUGIN_DEBUG_LOCAL // controls the printing of log messages @@ -225,7 +224,7 @@ void PluginWidgetAndroid::viewInvalidate() { m_core->viewInvalidate(rect); } -void PluginWidgetAndroid::draw(SkCanvas* canvas) { +void PluginWidgetAndroid::draw(PlatformGraphicsContext* context) { if (NULL == m_flipPixelRef || !m_flipPixelRef->isDirty()) { return; } @@ -249,10 +248,11 @@ void PluginWidgetAndroid::draw(SkCanvas* canvas) { bitmap) && pkg->pluginFuncs()->event(instance, &event)) { - if (canvas && m_pluginWindow) { + if (context && m_pluginWindow) { SkBitmap bm(bitmap); bm.setPixelRef(m_flipPixelRef); - canvas->drawBitmap(bm, 0, 0); + IntRect dst(0, 0, bm.width(), bm.height()); + context->drawBitmapRect(bm, 0, dst); } } break; diff --git a/Source/WebKit/android/plugins/PluginWidgetAndroid.h b/Source/WebKit/android/plugins/PluginWidgetAndroid.h index 87612dd..73b116b 100644 --- a/Source/WebKit/android/plugins/PluginWidgetAndroid.h +++ b/Source/WebKit/android/plugins/PluginWidgetAndroid.h @@ -28,6 +28,7 @@ #include "android_npapi.h" #include "ANPSystem_npapi.h" +#include "GraphicsContext.h" #include "IntPoint.h" #include "IntRect.h" #include "MediaLayer.h" @@ -98,7 +99,7 @@ struct PluginWidgetAndroid { /* Called to draw into the plugin's bitmap. If canvas is non-null, the bitmap itself is then drawn into the canvas. */ - void draw(SkCanvas* canvas = NULL); + void draw(PlatformGraphicsContext* context = NULL); /* Send this event to the plugin instance. A non-zero value will be returned if the plugin handled the event. diff --git a/Source/WebKit/android/smoke/MessageThread.cpp b/Source/WebKit/android/smoke/MessageThread.cpp deleted file mode 100644 index 97ab18c..0000000 --- a/Source/WebKit/android/smoke/MessageThread.cpp +++ /dev/null @@ -1,146 +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. - */ - -#define LOG_TAG "MessageThread" - -#include "config.h" - -#include <sys/time.h> -#include <time.h> - -#include "MessageThread.h" -#include "ScriptController.h" - -#include <utils/Log.h> - -namespace android { - -static bool compareMessages(const Message& msg1, - const Message& msg2, - bool memberIsNull) { - return (msg1.object() == msg2.object() && - (memberIsNull || msg1.member() == msg2.member())); -} - -bool MessageQueue::hasMessages(const Message& message) { - AutoMutex lock(m_mutex); - - static const Message::GenericMemberFunction nullMember = NULL; - const bool memberIsNull = message.member() == nullMember; - - for (list<Message*>::iterator it = m_messages.begin(); - it != m_messages.end(); ++it) { - Message* m = *it; - if (compareMessages(message, *m, memberIsNull)) - return true; - } - return false; -} - -void MessageQueue::remove(const Message& message) { - AutoMutex lock(m_mutex); - - static const Message::GenericMemberFunction nullMember = NULL; - const bool memberIsNull = message.member() == nullMember; - - for (list<Message*>::iterator it = m_messages.begin(); - it != m_messages.end(); ++it) { - Message* m = *it; - if (compareMessages(message, *m, memberIsNull)) { - it = m_messages.erase(it); - delete m; - } - } -} - -void MessageQueue::post(Message* message) { - AutoMutex lock(m_mutex); - - double when = message->m_when; - ALOG_ASSERT(when > 0, "Message time may not be 0"); - - list<Message*>::iterator it; - for (it = m_messages.begin(); it != m_messages.end(); ++it) { - Message* m = *it; - if (when < m->m_when) { - break; - } - } - m_messages.insert(it, message); - m_condition.signal(); -} - -void MessageQueue::postAtFront(Message* message) { - AutoMutex lock(m_mutex); - message->m_when = 0; - m_messages.push_front(message); -} - -Message* MessageQueue::next() { - AutoMutex lock(m_mutex); - while (true) { - if (m_messages.empty()) { - // No messages, wait until another arrives - m_condition.wait(m_mutex); - } - Message* next = m_messages.front(); - double now = WTF::currentTimeMS(); - double diff = next->m_when - now; - if (diff > 0) { - // Not time for this message yet, wait the difference in nanos - m_condition.waitRelative(m_mutex, - static_cast<nsecs_t>(diff * 1000000) /* nanos */); - } else { - // Time for this message to run. - m_messages.pop_front(); - return next; - } - } -} - -bool MessageThread::threadLoop() { - WebCore::ScriptController::initializeThreading(); - - while (true) { - Message* message = m_queue.next(); - if (message != NULL) { - message->run(); - } - } - return false; -} - -// Global thread object obtained by messageThread(). -static sp<MessageThread> gMessageThread; - -MessageThread* messageThread() { - if (gMessageThread == NULL) { - gMessageThread = new MessageThread(); - gMessageThread->run("WebCoreThread"); - } - return gMessageThread.get(); -} - -} // namespace android diff --git a/Source/WebKit/android/smoke/MessageThread.h b/Source/WebKit/android/smoke/MessageThread.h deleted file mode 100644 index 34ff4af..0000000 --- a/Source/WebKit/android/smoke/MessageThread.h +++ /dev/null @@ -1,108 +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 MessageThread_h -#define MessageThread_h - -#include <list> - -#include "MessageTypes.h" - -#include <utils/threads.h> - -using std::list; - -namespace android { - -class MessageQueue { -public: - MessageQueue() {} - - // Return true if the queue has messages with the given object and member - // function. If member is null, return true if the message has the same - // object. - template <class T> - bool hasMessages(T* object, void (T::*member)(void)); - - // Remove all messages with the given object and member function. If - // member is null, remove all messages with the given object. - template <class T> - void remove(T* object, void (T::*member)(void)); - - // Post a new message to the queue. - void post(Message* closure); - - // Post a new message at the front of the queue. - void postAtFront(Message* closure); - - // Obtain the next message. Blocks until either a new message arrives or - // we reach the time of the next message. - Message* next(); - -private: - bool hasMessages(const Message& message); - void remove(const Message& message); - - list<Message*> m_messages; - Mutex m_mutex; - Condition m_condition; -}; - -template <class T> -bool MessageQueue::hasMessages(T* object, void (T::*member)(void)) { - MemberFunctionMessage<T, void> message(object, member); - return hasMessages(message); -} - -template <class T> -void MessageQueue::remove(T* object, void (T::*member)(void)) { - MemberFunctionMessage<T, void> message(object, member); - remove(message); -} - -class MessageThread : public Thread { -public: - MessageQueue& queue() { return m_queue; } - -private: - MessageThread() : Thread(true /* canCallJava */) {} - - virtual bool threadLoop(); - - MessageQueue m_queue; - // Used for thread initialization - Mutex m_mutex; - Condition m_condition; - - friend MessageThread* messageThread(); -}; - -// Get (possibly creating) the global MessageThread object used to pass -// messages to WebCore. -MessageThread* messageThread(); - -} // namespace android - -#endif // MessageThread_h diff --git a/Source/WebKit/android/smoke/MessageTypes.h b/Source/WebKit/android/smoke/MessageTypes.h deleted file mode 100644 index 4d30648..0000000 --- a/Source/WebKit/android/smoke/MessageTypes.h +++ /dev/null @@ -1,159 +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 MessageTypes_h -#define MessageTypes_h - -#include <wtf/CurrentTime.h> - -// TODO(phanna): autogenerate these types! - -namespace android { - -// Forward declared for friendship! -class MessageQueue; - -// Removes the reference from the typename so we store the actual value in the -// closure. -template <typename T> struct remove_reference { typedef T type; }; -template <typename T> struct remove_reference<T&> { typedef T type; }; - -// Prevent the compiler from inferring the type. -template <typename T> struct identity { typedef T type; }; - -// Message base class. Defines the public run() method and contains generic -// object and member function variables for use in MessageQueue. -// -// Note: The template subclass MemberFunctionMessage casts its object and -// member function to the generic void* and Message::* types. During run(), -// each template specialization downcasts to the original type and invokes the -// correct function. This may seem dangerous but the compiler enforces -// correctness in NewMessage and in the template constructor. -class Message { -public: - typedef void (Message::*GenericMemberFunction)(void); - - virtual ~Message() {} - virtual void run() = 0; - - // The wall time that the message is supposed to run. - double m_when; - - void* object() const { return m_object; } - GenericMemberFunction member() const { return m_member; } - -protected: - Message(void* object, GenericMemberFunction member, long delay = 0) - : m_object(object) - , m_member(member) { - m_when = WTF::currentTimeMS() + delay; - } - - // Downcast back to the original template params in run(). Also accessed - // by MessageQueue to compare messages. - void* m_object; - GenericMemberFunction m_member; - -private: - // Disallow copy - Message(const Message&); -}; - -// Forward declaration for partial specialization. -template <class T, typename A1> -class MemberFunctionMessage; - -template <class T> -class MemberFunctionMessage<T, void> : public Message { -private: - typedef void (T::*MemberSignature)(); - -public: - inline MemberFunctionMessage(T* object, - MemberSignature member, - long delay = 0) - : Message(reinterpret_cast<void*>(object), - reinterpret_cast<GenericMemberFunction>(member), - delay) {} - - virtual void run() { - MemberSignature member = reinterpret_cast<MemberSignature>(m_member); - (reinterpret_cast<T*>(m_object)->*member)(); - delete this; - } -}; - -template <class T> -inline Message* NewMessage(T* object, void (T::*member)()) { - return new MemberFunctionMessage<T, void>(object, member); -} - -template <class T> -inline Message* NewDelayedMessage(T* object, void (T::*member)(), long delay) { - return new MemberFunctionMessage<T, void>(object, member, delay); -} - -template <class T, typename A1> -class MemberFunctionMessage : public Message { -private: - typedef void (T::*MemberSignature)(A1); - -public: - inline MemberFunctionMessage(T* object, - MemberSignature member, - A1 arg1, - long delay = 0) - : Message(reinterpret_cast<void*>(object), - reinterpret_cast<GenericMemberFunction>(member), - delay) - , m_arg1(arg1) {} - - virtual void run() { - MemberSignature member = reinterpret_cast<MemberSignature>(m_member); - (reinterpret_cast<T*>(m_object)->*member)(m_arg1); - delete this; - } - -private: - typename remove_reference<A1>::type m_arg1; -}; - -template <class T, typename A1> -inline Message* NewMessage(T* object, void (T::*member)(A1), - typename identity<A1>::type arg1) { - return new MemberFunctionMessage<T, A1>( - object, member, arg1); -} - -template <class T, typename A1> -inline Message* NewDelayedMessage(T* object, void (T::*member)(A1), - typename identity<A1>::type arg1, long delay) { - return new MemberFunctionMessage<T, A1>(object, member, arg1, delay); -} - -} // namespace android - - -#endif // MessageTypes_h diff --git a/ThirdPartyProject.prop b/ThirdPartyProject.prop deleted file mode 100644 index ae9d227..0000000 --- a/ThirdPartyProject.prop +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright 2010 Google Inc. All Rights Reserved. -#Fri Sep 10 11:49:27 BST 2010 -currentVersion=55486 -version=84325 -isNative=true -name=webkit -keywords=webkit -onDevice=true -homepage=http\://webkit.org/ -# Currently we track the Chromium 12.0.742 release branch: -# http://trac.webkit.org/browser/branches/chromium/742 -# which is WebKit trunk r84325 plus stability cherry picks. -webkit.chromiumRelease=http\://src.chromium.org/svn/releases/12.0.742.130/DEPS diff --git a/WEBKIT_MERGE_REVISION b/WEBKIT_MERGE_REVISION new file mode 100644 index 0000000..956ae85 --- /dev/null +++ b/WEBKIT_MERGE_REVISION @@ -0,0 +1,5 @@ +Currently we track the Chromium 12.0.742 release branch: +http://trac.webkit.org/browser/branches/chromium/742 +which is WebKit trunk r84325 plus stability cherry picks. + +See also http://src.chromium.org/svn/releases/12.0.742.130/DEPS |