Title: [155077] trunk/Source/WebCore
Revision
155077
Author
[email protected]
Date
2013-09-04 15:47:58 -0700 (Wed, 04 Sep 2013)

Log Message

Make ImageQualityController per-RenderView.
<https://webkit.org/b/120702>

Reviewed by Anders Carlsson.

Move ImageQualityController to its own files and add a RenderView::imageQualityController()
getter instead of using a global map for all render trees.

This avoids having to unregister every renderer (well, every RenderBoxModelObject) from the
global hash map during render tree teardown.

It also simplifies the live resize optimization a bit since it can now short-circuit if
the RenderView's FrameView is being resized. (Previously there could be any number of
RenderViews present in the map.)

* CMakeLists.txt:
* GNUmakefile.list.am:
* Target.pri:
* WebCore.vcxproj/WebCore.vcxproj:
* WebCore.xcodeproj/project.pbxproj:
* rendering/ImageQualityController.cpp: Added.
* rendering/ImageQualityController.h: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebCore/CMakeLists.txt (155076 => 155077)


--- trunk/Source/WebCore/CMakeLists.txt	2013-09-04 22:46:07 UTC (rev 155076)
+++ trunk/Source/WebCore/CMakeLists.txt	2013-09-04 22:47:58 UTC (rev 155077)
@@ -2099,6 +2099,7 @@
     rendering/HitTestingTransformState.cpp
     rendering/HitTestLocation.cpp
     rendering/HitTestResult.cpp
+    rendering/ImageQualityController.cpp
     rendering/InlineBox.cpp
     rendering/InlineFlowBox.cpp
     rendering/InlineTextBox.cpp

Modified: trunk/Source/WebCore/ChangeLog (155076 => 155077)


--- trunk/Source/WebCore/ChangeLog	2013-09-04 22:46:07 UTC (rev 155076)
+++ trunk/Source/WebCore/ChangeLog	2013-09-04 22:47:58 UTC (rev 155077)
@@ -1,3 +1,28 @@
+2013-09-04  Andreas Kling  <[email protected]>
+
+        Make ImageQualityController per-RenderView.
+        <https://webkit.org/b/120702>
+
+        Reviewed by Anders Carlsson.
+
+        Move ImageQualityController to its own files and add a RenderView::imageQualityController()
+        getter instead of using a global map for all render trees.
+
+        This avoids having to unregister every renderer (well, every RenderBoxModelObject) from the
+        global hash map during render tree teardown.
+
+        It also simplifies the live resize optimization a bit since it can now short-circuit if
+        the RenderView's FrameView is being resized. (Previously there could be any number of
+        RenderViews present in the map.)
+
+        * CMakeLists.txt:
+        * GNUmakefile.list.am:
+        * Target.pri:
+        * WebCore.vcxproj/WebCore.vcxproj:
+        * WebCore.xcodeproj/project.pbxproj:
+        * rendering/ImageQualityController.cpp: Added.
+        * rendering/ImageQualityController.h: Added.
+
 2013-09-04  Roger Fong  <[email protected]>
 
         Unreviewed Build fix for Windows DebugSuffix configuration.

Modified: trunk/Source/WebCore/GNUmakefile.list.am (155076 => 155077)


--- trunk/Source/WebCore/GNUmakefile.list.am	2013-09-04 22:46:07 UTC (rev 155076)
+++ trunk/Source/WebCore/GNUmakefile.list.am	2013-09-04 22:47:58 UTC (rev 155077)
@@ -4347,6 +4347,8 @@
 	Source/WebCore/rendering/HitTestLocation.h \
 	Source/WebCore/rendering/HitTestResult.cpp \
 	Source/WebCore/rendering/HitTestResult.h \
+	Source/WebCore/rendering/ImageQualityController.cpp \
+	Source/WebCore/rendering/ImageQualityController.h \
 	Source/WebCore/rendering/InlineBox.cpp \
 	Source/WebCore/rendering/InlineBox.h \
 	Source/WebCore/rendering/InlineFlowBox.cpp \

Modified: trunk/Source/WebCore/Target.pri (155076 => 155077)


--- trunk/Source/WebCore/Target.pri	2013-09-04 22:46:07 UTC (rev 155076)
+++ trunk/Source/WebCore/Target.pri	2013-09-04 22:47:58 UTC (rev 155077)
@@ -1146,6 +1146,7 @@
     rendering/HitTestingTransformState.cpp \
     rendering/HitTestLocation.cpp \
     rendering/HitTestResult.cpp \
+    rendering/ImageQualityController.cpp \
     rendering/InlineBox.cpp \
     rendering/InlineFlowBox.cpp \
     rendering/InlineTextBox.cpp \
@@ -2398,6 +2399,7 @@
     rendering/HitTestingTransformState.h \
     rendering/HitTestLocation.h \
     rendering/HitTestResult.h \
+    rendering/ImageQualityController.h \
     rendering/InlineBox.h \
     rendering/InlineFlowBox.h \
     rendering/InlineTextBox.h \

Modified: trunk/Source/WebCore/WebCore.vcxproj/WebCore.vcxproj (155076 => 155077)


--- trunk/Source/WebCore/WebCore.vcxproj/WebCore.vcxproj	2013-09-04 22:46:07 UTC (rev 155076)
+++ trunk/Source/WebCore/WebCore.vcxproj/WebCore.vcxproj	2013-09-04 22:47:58 UTC (rev 155077)
@@ -9537,6 +9537,20 @@
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Production|Win32'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Production|x64'">true</ExcludedFromBuild>
     </ClCompile>
+    <ClCompile Include="..\rendering\ImageQualityController.cpp">
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug_WinCairo|Win32'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug_WinCairo|x64'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='DebugSuffix|Win32'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='DebugSuffix|x64'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release_WinCairo|Win32'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release_WinCairo|x64'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Production|Win32'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Production|x64'">true</ExcludedFromBuild>
+    </ClCompile>
     <ClCompile Include="..\rendering\InlineBox.cpp">
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
@@ -19959,6 +19973,7 @@
     <ClInclude Include="..\rendering\HitTestingTransformState.h" />
     <ClInclude Include="..\rendering\HitTestRequest.h" />
     <ClInclude Include="..\rendering\HitTestResult.h" />
+    <ClInclude Include="..\rendering\ImageQualityController.h" />
     <ClInclude Include="..\rendering\InlineBox.h" />
     <ClInclude Include="..\rendering\InlineFlowBox.h" />
     <ClInclude Include="..\rendering\InlineIterator.h" />

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (155076 => 155077)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2013-09-04 22:46:07 UTC (rev 155076)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2013-09-04 22:47:58 UTC (rev 155077)
@@ -4625,6 +4625,8 @@
 		B2FA3E180AB75A6F000E5AC4 /* JSSVGZoomEvent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B2FA3D300AB75A6F000E5AC4 /* JSSVGZoomEvent.cpp */; };
 		B2FA3E190AB75A6F000E5AC4 /* JSSVGZoomEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = B2FA3D310AB75A6F000E5AC4 /* JSSVGZoomEvent.h */; };
 		B50F5B810E96CD9900AD71A6 /* WebCoreObjCExtras.mm in Sources */ = {isa = PBXBuildFile; fileRef = B50F5B800E96CD9900AD71A6 /* WebCoreObjCExtras.mm */; settings = {COMPILER_FLAGS = "-Wno-deprecated-declarations"; }; };
+		B51A2F3F17D7D3AE0072517A /* ImageQualityController.h in Headers */ = {isa = PBXBuildFile; fileRef = B51A2F3E17D7D3A40072517A /* ImageQualityController.h */; };
+		B51A2F4117D7D5DE0072517A /* ImageQualityController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B51A2F4017D7D5DA0072517A /* ImageQualityController.cpp */; };
 		B525A96511CA2340003A23A8 /* JSSQLException.h in Headers */ = {isa = PBXBuildFile; fileRef = B525A96311CA2340003A23A8 /* JSSQLException.h */; };
 		B525A96611CA2340003A23A8 /* JSSQLException.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B525A96411CA2340003A23A8 /* JSSQLException.cpp */; };
 		B5320D6B122A24E9002D1440 /* FontPlatformData.h in Headers */ = {isa = PBXBuildFile; fileRef = B5320D69122A24E9002D1440 /* FontPlatformData.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -11431,6 +11433,8 @@
 		B2FA3D300AB75A6F000E5AC4 /* JSSVGZoomEvent.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = JSSVGZoomEvent.cpp; sourceTree = "<group>"; };
 		B2FA3D310AB75A6F000E5AC4 /* JSSVGZoomEvent.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = JSSVGZoomEvent.h; sourceTree = "<group>"; };
 		B50F5B800E96CD9900AD71A6 /* WebCoreObjCExtras.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WebCoreObjCExtras.mm; sourceTree = "<group>"; };
+		B51A2F3E17D7D3A40072517A /* ImageQualityController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImageQualityController.h; sourceTree = "<group>"; };
+		B51A2F4017D7D5DA0072517A /* ImageQualityController.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ImageQualityController.cpp; sourceTree = "<group>"; };
 		B525A96311CA2340003A23A8 /* JSSQLException.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSSQLException.h; sourceTree = "<group>"; };
 		B525A96411CA2340003A23A8 /* JSSQLException.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSSQLException.cpp; sourceTree = "<group>"; };
 		B5320D69122A24E9002D1440 /* FontPlatformData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FontPlatformData.h; sourceTree = "<group>"; };
@@ -20360,6 +20364,8 @@
 				930908900AF7EDE40081DF01 /* HitTestRequest.h */,
 				9307F1D50AF2D59000DBA31A /* HitTestResult.cpp */,
 				9307F1D60AF2D59000DBA31A /* HitTestResult.h */,
+				B51A2F4017D7D5DA0072517A /* ImageQualityController.cpp */,
+				B51A2F3E17D7D3A40072517A /* ImageQualityController.h */,
 				A8CFF5DF0A155A05000A4234 /* InlineBox.cpp */,
 				A8CFF5DE0A155A05000A4234 /* InlineBox.h */,
 				A8CFF5DD0A155A05000A4234 /* InlineFlowBox.cpp */,
@@ -21611,6 +21617,7 @@
 				33D0212D131DB37B004091A8 /* CookieStorage.h in Headers */,
 				9746AF2114F4DDE6003E7A71 /* Coordinates.h in Headers */,
 				A80E6D040A1989CA007FB8C5 /* Counter.h in Headers */,
+				B51A2F3F17D7D3AE0072517A /* ImageQualityController.h in Headers */,
 				BC5EB9790E82069200B25965 /* CounterContent.h in Headers */,
 				BC5EB9510E82056B00B25965 /* CounterDirectives.h in Headers */,
 				9392F14C0AD1861B00691BD4 /* CounterNode.h in Headers */,
@@ -25345,6 +25352,7 @@
 				85DF812A0AA7787200486AD7 /* DOMHTMLImageElement.mm in Sources */,
 				85F32AED0AA63B8700FF3184 /* DOMHTMLInputElement.mm in Sources */,
 				A6148A6812E41D940044A784 /* DOMHTMLKeygenElement.mm in Sources */,
+				B51A2F4117D7D5DE0072517A /* ImageQualityController.cpp in Sources */,
 				85BA4CE20AA6861B0088052D /* DOMHTMLLabelElement.mm in Sources */,
 				85BA4CE40AA6861B0088052D /* DOMHTMLLegendElement.mm in Sources */,
 				85BA4D120AA688680088052D /* DOMHTMLLIElement.mm in Sources */,

Added: trunk/Source/WebCore/rendering/ImageQualityController.cpp (0 => 155077)


--- trunk/Source/WebCore/rendering/ImageQualityController.cpp	                        (rev 0)
+++ trunk/Source/WebCore/rendering/ImageQualityController.cpp	2013-09-04 22:47:58 UTC (rev 155077)
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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 APPLE INC. AND ITS CONTRIBUTORS ``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 APPLE INC. OR ITS 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 "ImageQualityController.h"
+
+#include "Frame.h"
+#include "GraphicsContext.h"
+#include "Page.h"
+#include "RenderBoxModelObject.h"
+#include "RenderView.h"
+
+namespace WebCore {
+
+static const double cInterpolationCutoff = 800. * 800.;
+static const double cLowQualityTimeThreshold = 0.500; // 500 ms
+
+ImageQualityController::ImageQualityController(const RenderView& renderView)
+    : m_renderView(renderView)
+    , m_timer(this, &ImageQualityController::highQualityRepaintTimerFired)
+    , m_animatedResizeIsActive(false)
+    , m_liveResizeOptimizationIsActive(false)
+{
+}
+
+void ImageQualityController::removeLayer(RenderBoxModelObject* object, LayerSizeMap* innerMap, const void* layer)
+{
+    if (!innerMap)
+        return;
+    innerMap->remove(layer);
+    if (innerMap->isEmpty())
+        removeObject(object);
+}
+
+void ImageQualityController::set(RenderBoxModelObject* object, LayerSizeMap* innerMap, const void* layer, const LayoutSize& size)
+{
+    if (innerMap)
+        innerMap->set(layer, size);
+    else {
+        LayerSizeMap newInnerMap;
+        newInnerMap.set(layer, size);
+        m_objectLayerSizeMap.set(object, newInnerMap);
+    }
+}
+
+void ImageQualityController::removeObject(RenderBoxModelObject* object)
+{
+    m_objectLayerSizeMap.remove(object);
+    if (m_objectLayerSizeMap.isEmpty()) {
+        m_animatedResizeIsActive = false;
+        m_timer.stop();
+    }
+}
+
+void ImageQualityController::highQualityRepaintTimerFired(Timer<ImageQualityController>*)
+{
+    if (m_renderView.documentBeingDestroyed())
+        return;
+    if (!m_animatedResizeIsActive && !m_liveResizeOptimizationIsActive)
+        return;
+    m_animatedResizeIsActive = false;
+
+    // If the FrameView is in live resize, punt the timer and hold back for now.
+    if (m_renderView.frameView().inLiveResize()) {
+        restartTimer();
+        return;
+    }
+
+    for (auto it = m_objectLayerSizeMap.begin(), end = m_objectLayerSizeMap.end(); it != end; ++it)
+        it->key->repaint();
+
+    m_liveResizeOptimizationIsActive = false;
+}
+
+void ImageQualityController::restartTimer()
+{
+    m_timer.startOneShot(cLowQualityTimeThreshold);
+}
+
+bool ImageQualityController::shouldPaintAtLowQuality(GraphicsContext* context, RenderBoxModelObject* object, Image* image, const void *layer, const LayoutSize& size)
+{
+    // If the image is not a bitmap image, then none of this is relevant and we just paint at high
+    // quality.
+    if (!image || !image->isBitmapImage() || context->paintingDisabled())
+        return false;
+
+    switch (object->style()->imageRendering()) {
+    case ImageRenderingOptimizeSpeed:
+    case ImageRenderingCrispEdges:
+        return true;
+    case ImageRenderingOptimizeQuality:
+        return false;
+    case ImageRenderingAuto:
+        break;
+    }
+
+    // Make sure to use the unzoomed image size, since if a full page zoom is in effect, the image
+    // is actually being scaled.
+    IntSize imageSize(image->width(), image->height());
+
+    // Look ourselves up in the hashtables.
+    auto i = m_objectLayerSizeMap.find(object);
+    LayerSizeMap* innerMap = i != m_objectLayerSizeMap.end() ? &i->value : 0;
+    LayoutSize oldSize;
+    bool isFirstResize = true;
+    if (innerMap) {
+        LayerSizeMap::iterator j = innerMap->find(layer);
+        if (j != innerMap->end()) {
+            isFirstResize = false;
+            oldSize = j->value;
+        }
+    }
+
+    // If the containing FrameView is being resized, paint at low quality until resizing is finished.
+    if (Frame* frame = object->document().frame()) {
+        bool frameViewIsCurrentlyInLiveResize = frame->view() && frame->view()->inLiveResize();
+        if (frameViewIsCurrentlyInLiveResize) {
+            set(object, innerMap, layer, size);
+            restartTimer();
+            m_liveResizeOptimizationIsActive = true;
+            return true;
+        }
+        if (m_liveResizeOptimizationIsActive) {
+            // Live resize has ended, paint in HQ and remove this object from the list.
+            removeLayer(object, innerMap, layer);
+            return false;
+        }
+    }
+
+    const AffineTransform& currentTransform = context->getCTM();
+    bool contextIsScaled = !currentTransform.isIdentityOrTranslationOrFlipped();
+    if (!contextIsScaled && size == imageSize) {
+        // There is no scale in effect. If we had a scale in effect before, we can just remove this object from the list.
+        removeLayer(object, innerMap, layer);
+        return false;
+    }
+
+    // There is no need to hash scaled images that always use low quality mode when the page demands it. This is the iChat case.
+    if (m_renderView.frame().page()->inLowQualityImageInterpolationMode()) {
+        double totalPixels = static_cast<double>(image->width()) * static_cast<double>(image->height());
+        if (totalPixels > cInterpolationCutoff)
+            return true;
+    }
+
+    // If an animated resize is active, paint in low quality and kick the timer ahead.
+    if (m_animatedResizeIsActive) {
+        set(object, innerMap, layer, size);
+        restartTimer();
+        return true;
+    }
+    // If this is the first time resizing this image, or its size is the
+    // same as the last resize, draw at high res, but record the paint
+    // size and set the timer.
+    if (isFirstResize || oldSize == size) {
+        restartTimer();
+        set(object, innerMap, layer, size);
+        return false;
+    }
+    // If the timer is no longer active, draw at high quality and don't
+    // set the timer.
+    if (!m_timer.isActive()) {
+        removeLayer(object, innerMap, layer);
+        return false;
+    }
+    // This object has been resized to two different sizes while the timer
+    // is active, so draw at low quality, set the flag for animated resizes and
+    // the object to the list for high quality redraw.
+    set(object, innerMap, layer, size);
+    m_animatedResizeIsActive = true;
+    restartTimer();
+    return true;
+}
+
+}

Added: trunk/Source/WebCore/rendering/ImageQualityController.h (0 => 155077)


--- trunk/Source/WebCore/rendering/ImageQualityController.h	                        (rev 0)
+++ trunk/Source/WebCore/rendering/ImageQualityController.h	2013-09-04 22:47:58 UTC (rev 155077)
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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 APPLE INC. AND ITS CONTRIBUTORS ``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 APPLE INC. OR ITS 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 ImageQualityController_h
+#define ImageQualityController_h
+
+#include "Timer.h"
+#include <wtf/HashMap.h>
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+class Frame;
+class GraphicsContext;
+class Image;
+class LayoutSize;
+class RenderBoxModelObject;
+class RenderView;
+
+class ImageQualityController {
+    WTF_MAKE_NONCOPYABLE(ImageQualityController)
+public:
+    static PassOwnPtr<ImageQualityController> create(const RenderView& renderView) { return adoptPtr(new ImageQualityController(renderView)); }
+
+    bool shouldPaintAtLowQuality(GraphicsContext*, RenderBoxModelObject*, Image*, const void* layer, const LayoutSize&);
+    void rendererWillBeDestroyed(RenderBoxModelObject& renderer) { removeObject(&renderer); }
+
+private:
+    typedef HashMap<const void*, LayoutSize> LayerSizeMap;
+    typedef HashMap<RenderBoxModelObject*, LayerSizeMap> ObjectLayerSizeMap;
+
+    ImageQualityController(const RenderView&);
+
+    void removeLayer(RenderBoxModelObject*, LayerSizeMap* innerMap, const void* layer);
+    void set(RenderBoxModelObject*, LayerSizeMap* innerMap, const void* layer, const LayoutSize&);
+    void highQualityRepaintTimerFired(Timer<ImageQualityController>*);
+    void restartTimer();
+    void removeObject(RenderBoxModelObject*);
+
+    const RenderView& m_renderView;
+    ObjectLayerSizeMap m_objectLayerSizeMap;
+    Timer<ImageQualityController> m_timer;
+    bool m_animatedResizeIsActive;
+    bool m_liveResizeOptimizationIsActive;
+};
+
+} // namespace
+
+#endif

Modified: trunk/Source/WebCore/rendering/RenderBoxModelObject.cpp (155076 => 155077)


--- trunk/Source/WebCore/rendering/RenderBoxModelObject.cpp	2013-09-04 22:46:07 UTC (rev 155076)
+++ trunk/Source/WebCore/rendering/RenderBoxModelObject.cpp	2013-09-04 22:47:58 UTC (rev 155077)
@@ -3,7 +3,7 @@
  *           (C) 1999 Antti Koivisto ([email protected])
  *           (C) 2005 Allan Sandfeld Jensen ([email protected])
  *           (C) 2005, 2006 Samuel Weinig ([email protected])
- * Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2013 Apple Inc. All rights reserved.
  * Copyright (C) 2010 Google Inc. All rights reserved.
  *
  * This library is free software; you can redistribute it and/or
@@ -30,6 +30,7 @@
 #include "HTMLFrameOwnerElement.h"
 #include "HTMLNames.h"
 #include "ImageBuffer.h"
+#include "ImageQualityController.h"
 #include "Page.h"
 #include "Path.h"
 #include "RenderBlock.h"
@@ -54,12 +55,6 @@
 
 using namespace HTMLNames;
 
-static const double cInterpolationCutoff = 800. * 800.;
-static const double cLowQualityTimeThreshold = 0.500; // 500 ms
-
-typedef HashMap<const void*, LayoutSize> LayerSizeMap;
-typedef HashMap<RenderBoxModelObject*, LayerSizeMap> ObjectLayerSizeMap;
-
 // The HashMap for storing continuation pointers.
 // An inline can be split with blocks occuring in between the inline content.
 // When this occurs we need a pointer to the next object. We can basically be
@@ -75,191 +70,6 @@
 typedef HashMap<const RenderBoxModelObject*, RenderTextFragment*> FirstLetterRemainingTextMap;
 static FirstLetterRemainingTextMap* firstLetterRemainingTextMap = 0;
 
-class ImageQualityController {
-    WTF_MAKE_NONCOPYABLE(ImageQualityController); WTF_MAKE_FAST_ALLOCATED;
-public:
-    ImageQualityController();
-    bool shouldPaintAtLowQuality(GraphicsContext*, RenderBoxModelObject*, Image*, const void* layer, const LayoutSize&);
-    void removeLayer(RenderBoxModelObject*, LayerSizeMap* innerMap, const void* layer);
-    void set(RenderBoxModelObject*, LayerSizeMap* innerMap, const void* layer, const LayoutSize&);
-    void objectDestroyed(RenderBoxModelObject*);
-    bool isEmpty() { return m_objectLayerSizeMap.isEmpty(); }
-
-private:
-    void highQualityRepaintTimerFired(Timer<ImageQualityController>*);
-    void restartTimer();
-
-    ObjectLayerSizeMap m_objectLayerSizeMap;
-    Timer<ImageQualityController> m_timer;
-    bool m_animatedResizeIsActive;
-    bool m_liveResizeOptimizationIsActive;
-};
-
-ImageQualityController::ImageQualityController()
-    : m_timer(this, &ImageQualityController::highQualityRepaintTimerFired)
-    , m_animatedResizeIsActive(false)
-    , m_liveResizeOptimizationIsActive(false)
-{
-}
-
-void ImageQualityController::removeLayer(RenderBoxModelObject* object, LayerSizeMap* innerMap, const void* layer)
-{
-    if (innerMap) {
-        innerMap->remove(layer);
-        if (innerMap->isEmpty())
-            objectDestroyed(object);
-    }
-}
-    
-void ImageQualityController::set(RenderBoxModelObject* object, LayerSizeMap* innerMap, const void* layer, const LayoutSize& size)
-{
-    if (innerMap)
-        innerMap->set(layer, size);
-    else {
-        LayerSizeMap newInnerMap;
-        newInnerMap.set(layer, size);
-        m_objectLayerSizeMap.set(object, newInnerMap);
-    }
-}
-    
-void ImageQualityController::objectDestroyed(RenderBoxModelObject* object)
-{
-    m_objectLayerSizeMap.remove(object);
-    if (m_objectLayerSizeMap.isEmpty()) {
-        m_animatedResizeIsActive = false;
-        m_timer.stop();
-    }
-}
-
-void ImageQualityController::highQualityRepaintTimerFired(Timer<ImageQualityController>*)
-{
-    if (!m_animatedResizeIsActive && !m_liveResizeOptimizationIsActive)
-        return;
-    m_animatedResizeIsActive = false;
-
-    for (ObjectLayerSizeMap::iterator it = m_objectLayerSizeMap.begin(); it != m_objectLayerSizeMap.end(); ++it) {
-        if (Frame* frame = it->key->document().frame()) {
-            // If this renderer's containing FrameView is in live resize, punt the timer and hold back for now.
-            if (frame->view() && frame->view()->inLiveResize()) {
-                restartTimer();
-                return;
-            }
-        }
-        it->key->repaint();
-    }
-
-    m_liveResizeOptimizationIsActive = false;
-}
-
-void ImageQualityController::restartTimer()
-{
-    m_timer.startOneShot(cLowQualityTimeThreshold);
-}
-
-bool ImageQualityController::shouldPaintAtLowQuality(GraphicsContext* context, RenderBoxModelObject* object, Image* image, const void *layer, const LayoutSize& size)
-{
-    // If the image is not a bitmap image, then none of this is relevant and we just paint at high
-    // quality.
-    if (!image || !image->isBitmapImage() || context->paintingDisabled())
-        return false;
-
-    switch (object->style()->imageRendering()) {
-    case ImageRenderingOptimizeSpeed:
-    case ImageRenderingCrispEdges:
-        return true;
-    case ImageRenderingOptimizeQuality:
-        return false;
-    case ImageRenderingAuto:
-        break;
-    }
-
-    // Make sure to use the unzoomed image size, since if a full page zoom is in effect, the image
-    // is actually being scaled.
-    IntSize imageSize(image->width(), image->height());
-
-    // Look ourselves up in the hashtables.
-    ObjectLayerSizeMap::iterator i = m_objectLayerSizeMap.find(object);
-    LayerSizeMap* innerMap = i != m_objectLayerSizeMap.end() ? &i->value : 0;
-    LayoutSize oldSize;
-    bool isFirstResize = true;
-    if (innerMap) {
-        LayerSizeMap::iterator j = innerMap->find(layer);
-        if (j != innerMap->end()) {
-            isFirstResize = false;
-            oldSize = j->value;
-        }
-    }
-
-    // If the containing FrameView is being resized, paint at low quality until resizing is finished.
-    if (Frame* frame = object->document().frame()) {
-        bool frameViewIsCurrentlyInLiveResize = frame->view() && frame->view()->inLiveResize();
-        if (frameViewIsCurrentlyInLiveResize) {
-            set(object, innerMap, layer, size);
-            restartTimer();
-            m_liveResizeOptimizationIsActive = true;
-            return true;
-        }
-        if (m_liveResizeOptimizationIsActive) {
-            // Live resize has ended, paint in HQ and remove this object from the list.
-            removeLayer(object, innerMap, layer);
-            return false;
-        }
-    }
-
-    const AffineTransform& currentTransform = context->getCTM();
-    bool contextIsScaled = !currentTransform.isIdentityOrTranslationOrFlipped();
-    if (!contextIsScaled && size == imageSize) {
-        // There is no scale in effect. If we had a scale in effect before, we can just remove this object from the list.
-        removeLayer(object, innerMap, layer);
-        return false;
-    }
-
-    // There is no need to hash scaled images that always use low quality mode when the page demands it. This is the iChat case.
-    if (object->document().page()->inLowQualityImageInterpolationMode()) {
-        double totalPixels = static_cast<double>(image->width()) * static_cast<double>(image->height());
-        if (totalPixels > cInterpolationCutoff)
-            return true;
-    }
-
-    // If an animated resize is active, paint in low quality and kick the timer ahead.
-    if (m_animatedResizeIsActive) {
-        set(object, innerMap, layer, size);
-        restartTimer();
-        return true;
-    }
-    // If this is the first time resizing this image, or its size is the
-    // same as the last resize, draw at high res, but record the paint
-    // size and set the timer.
-    if (isFirstResize || oldSize == size) {
-        restartTimer();
-        set(object, innerMap, layer, size);
-        return false;
-    }
-    // If the timer is no longer active, draw at high quality and don't
-    // set the timer.
-    if (!m_timer.isActive()) {
-        removeLayer(object, innerMap, layer);
-        return false;
-    }
-    // This object has been resized to two different sizes while the timer
-    // is active, so draw at low quality, set the flag for animated resizes and
-    // the object to the list for high quality redraw.
-    set(object, innerMap, layer, size);
-    m_animatedResizeIsActive = true;
-    restartTimer();
-    return true;
-}
-
-static ImageQualityController* gImageQualityController = 0;
-
-static ImageQualityController* imageQualityController()
-{
-    if (!gImageQualityController)
-        gImageQualityController = new ImageQualityController;
-
-    return gImageQualityController;
-}
-
 void RenderBoxModelObject::setSelectionState(SelectionState state)
 {
     if (state == SelectionInside && selectionState() != SelectionNone)
@@ -345,7 +155,7 @@
 
 bool RenderBoxModelObject::shouldPaintAtLowQuality(GraphicsContext* context, Image* image, const void* layer, const LayoutSize& size)
 {
-    return imageQualityController()->shouldPaintAtLowQuality(context, this, image, layer, size);
+    return view().imageQualityController().shouldPaintAtLowQuality(context, this, image, layer, size);
 }
 
 RenderBoxModelObject::RenderBoxModelObject(ContainerNode* node)
@@ -355,13 +165,6 @@
 
 RenderBoxModelObject::~RenderBoxModelObject()
 {
-    if (gImageQualityController) {
-        gImageQualityController->objectDestroyed(this);
-        if (gImageQualityController->isEmpty()) {
-            delete gImageQualityController;
-            gImageQualityController = 0;
-        }
-    }
 }
 
 void RenderBoxModelObject::willBeDestroyed()
@@ -374,6 +177,9 @@
     if (firstLetterRemainingText())
         setFirstLetterRemainingText(0);
 
+    if (!documentBeingDestroyed())
+        view().imageQualityController().rendererWillBeDestroyed(*this);
+
     RenderLayerModelObject::willBeDestroyed();
 }
 

Modified: trunk/Source/WebCore/rendering/RenderView.cpp (155076 => 155077)


--- trunk/Source/WebCore/rendering/RenderView.cpp	2013-09-04 22:46:07 UTC (rev 155076)
+++ trunk/Source/WebCore/rendering/RenderView.cpp	2013-09-04 22:47:58 UTC (rev 155077)
@@ -33,6 +33,7 @@
 #include "HTMLFrameOwnerElement.h"
 #include "HTMLIFrameElement.h"
 #include "HitTestResult.h"
+#include "ImageQualityController.h"
 #include "Page.h"
 #include "RenderGeometryMap.h"
 #include "RenderLayer.h"
@@ -1242,6 +1243,13 @@
     return m_intervalArena.get();
 }
 
+ImageQualityController& RenderView::imageQualityController()
+{
+    if (!m_imageQualityController)
+        m_imageQualityController = ImageQualityController::create(*this);
+    return *m_imageQualityController;
+}
+
 FragmentationDisabler::FragmentationDisabler(RenderObject* root)
 {
     LayoutState* layoutState = root->view().layoutState();

Modified: trunk/Source/WebCore/rendering/RenderView.h (155076 => 155077)


--- trunk/Source/WebCore/rendering/RenderView.h	2013-09-04 22:46:07 UTC (rev 155076)
+++ trunk/Source/WebCore/rendering/RenderView.h	2013-09-04 22:47:58 UTC (rev 155077)
@@ -31,6 +31,7 @@
 namespace WebCore {
 
 class FlowThreadController;
+class ImageQualityController;
 class RenderQuote;
 class RenderWidget;
 
@@ -231,6 +232,8 @@
 
     IntRect pixelSnappedLayoutOverflowRect() const { return pixelSnappedIntRect(layoutOverflowRect()); }
 
+    ImageQualityController& imageQualityController();
+
 protected:
     virtual void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = 0) const OVERRIDE;
     virtual const RenderObject* pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap&) const OVERRIDE;
@@ -329,6 +332,7 @@
 private:
     bool shouldUsePrintingLayout() const;
 
+    OwnPtr<ImageQualityController> m_imageQualityController;
     LayoutUnit m_pageLogicalHeight;
     bool m_pageLogicalHeightChanged;
     LayoutState* m_layoutState;
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to