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;