image-rendering: -webkit-optimize-contrast not working for background images
https://bugs.webkit.org/show_bug.cgi?id=97991

Reviewed by Darin Adler.
Source/WebCore:

Don't equate "pixelated" and "crisp-edges" values for image-rendering with low
quality scaling; they should map to InterpolationNone, not InterpolationLow.

To support this change ImageQualityController to return a InterpolationQuality
from the renamed chooseInterpolationQuality(). If the returned value is not
InterpolationDefault, set the GraphicsContext image interpolation when drawing
images and image buffers.

Remove the redundant "useLowQualityScale" from

Test: fast/images/image-rendering-interpolation.html

* html/HTMLCanvasElement.cpp:
(WebCore::HTMLCanvasElement::paint):
* html/HTMLCanvasElement.h:
* page/DragController.cpp:
(WebCore::DragController::doImageDrag):
* platform/graphics/GraphicsContext.cpp:
(WebCore::GraphicsContext::drawImage):
(WebCore::GraphicsContext::drawTiledImage):
(WebCore::GraphicsContext::drawImageBuffer):
(WebCore::GraphicsContext::drawConsumingImageBuffer):
(WebCore::InterpolationQualityMaintainer::InterpolationQualityMaintainer): Deleted.
(WebCore::InterpolationQualityMaintainer::~InterpolationQualityMaintainer): Deleted.
* platform/graphics/GraphicsContext.h:
(WebCore::ImagePaintingOptions::ImagePaintingOptions):
(WebCore::ImagePaintingOptions::usesDefaultInterpolation):
(WebCore::InterpolationQualityMaintainer::InterpolationQualityMaintainer):
(WebCore::InterpolationQualityMaintainer::~InterpolationQualityMaintainer):
* platform/graphics/GraphicsTypes.h:
* platform/graphics/ImageBuffer.h:
* platform/graphics/cg/ImageBufferCG.cpp:
(WebCore::ImageBuffer::drawConsuming):
(WebCore::ImageBuffer::draw):
* rendering/ImageQualityController.cpp:
(WebCore::ImageQualityController::interpolationQualityFromStyle):
(WebCore::ImageQualityController::chooseInterpolationQuality):
(WebCore::ImageQualityController::ImageQualityController): Deleted.
(WebCore::ImageQualityController::shouldPaintAtLowQuality): Deleted.
* rendering/ImageQualityController.h:
* rendering/RenderBoxModelObject.cpp:
(WebCore::RenderBoxModelObject::chooseInterpolationQuality):
(WebCore::RenderBoxModelObject::paintFillLayerExtended):
(WebCore::RenderBoxModelObject::shouldPaintAtLowQuality): Deleted.
* rendering/RenderBoxModelObject.h:
* rendering/RenderEmbeddedObject.cpp:
(WebCore::RenderEmbeddedObject::paintSnapshotImage):
* rendering/RenderHTMLCanvas.cpp:
(WebCore::RenderHTMLCanvas::paintReplaced):
* rendering/RenderImage.cpp:
(WebCore::RenderImage::paintIntoRect):
* rendering/RenderSnapshottedPlugIn.cpp:
(WebCore::RenderSnapshottedPlugIn::paintSnapshot):
* rendering/style/RenderStyle.h:

LayoutTests:

* fast/images/image-rendering-interpolation-expected.html: Added.
* fast/images/image-rendering-interpolation.html: Added.


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@195848 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index 69fd47c..384bc04 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,13 @@
+2016-01-29  Simon Fraser  <simon.fraser@apple.com>
+
+        image-rendering: -webkit-optimize-contrast not working for background images
+        https://bugs.webkit.org/show_bug.cgi?id=97991
+
+        Reviewed by Darin Adler.
+
+        * fast/images/image-rendering-interpolation-expected.html: Added.
+        * fast/images/image-rendering-interpolation.html: Added.
+
 2016-01-29  Brady Eidson  <beidson@apple.com>
 
         Modern IDB: storage/indexeddb/modern/index-3.html fails.
diff --git a/LayoutTests/fast/images/image-rendering-interpolation-expected.html b/LayoutTests/fast/images/image-rendering-interpolation-expected.html
new file mode 100644
index 0000000..8ca6fc6
--- /dev/null
+++ b/LayoutTests/fast/images/image-rendering-interpolation-expected.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <style>
+        .clipper {
+            display: inline-block;
+            margin: 2px;
+            height: 100px;
+            width: 100px;
+            overflow: hidden;
+            border: 1px solid black;
+        }
+        img {
+            height: 1100px;
+            width: 1100px;
+        }
+        
+        .backgrounder {
+            height: 1100px;
+            width: 1100px;
+            background-image: url('resources/grid-small.png');
+            background-size: 100%;
+        }
+    </style>
+</head>
+<body>
+
+<div class="clipper">
+    <img src="resources/grid-small.png" width="11" height="11">
+</div>
+
+<div class="clipper">
+</div>
+
+<div class="clipper">
+</div>
+
+<div class="clipper">
+    <div class="backgrounder"></div>
+</div>
+
+<div class="clipper">
+</div>
+
+<div class="clipper">
+</div>
+
+</body>
+</html>
diff --git a/LayoutTests/fast/images/image-rendering-interpolation.html b/LayoutTests/fast/images/image-rendering-interpolation.html
new file mode 100644
index 0000000..1dfd7da
--- /dev/null
+++ b/LayoutTests/fast/images/image-rendering-interpolation.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <style>
+        .clipper {
+            display: inline-block;
+            margin: 2px;
+            height: 100px;
+            width: 100px;
+            overflow: hidden;
+            border: 1px solid black;
+        }
+        img {
+            image-rendering: pixelated;
+            height: 1100px;
+            width: 1100px;
+        }
+        
+        .backgrounder {
+            height: 1100px;
+            width: 1100px;
+            background-image: url('resources/grid-small.png');
+            background-size: 100%;
+        }
+    </style>
+</head>
+<body>
+
+<div class="clipper">
+    <img src="resources/grid-small.png" width="11" height="11" style="image-rendering: auto;">
+</div>
+
+<div class="clipper">
+    <img src="resources/grid-small.png" width="11" height="11" style="image-rendering: pixelated;">
+</div>
+
+<div class="clipper">
+    <img src="resources/grid-small.png" width="11" height="11" style="image-rendering: crisp-edges;">
+</div>
+
+<div class="clipper">
+    <div class="backgrounder" style="image-rendering: auto;"></div>
+</div>
+
+<div class="clipper">
+    <div class="backgrounder" style="image-rendering: pixelated;"></div>
+</div>
+
+<div class="clipper">
+    <div class="backgrounder" style="image-rendering: crisp-edges;"></div>
+</div>
+
+</body>
+</html>
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index e51be2c..02338b5 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,65 @@
+2016-01-29  Simon Fraser  <simon.fraser@apple.com>
+
+        image-rendering: -webkit-optimize-contrast not working for background images
+        https://bugs.webkit.org/show_bug.cgi?id=97991
+
+        Reviewed by Darin Adler.
+        
+        Don't equate "pixelated" and "crisp-edges" values for image-rendering with low
+        quality scaling; they should map to InterpolationNone, not InterpolationLow.
+        
+        To support this change ImageQualityController to return a InterpolationQuality
+        from the renamed chooseInterpolationQuality(). If the returned value is not
+        InterpolationDefault, set the GraphicsContext image interpolation when drawing
+        images and image buffers.
+        
+        Remove the redundant "useLowQualityScale" from 
+
+        Test: fast/images/image-rendering-interpolation.html
+
+        * html/HTMLCanvasElement.cpp:
+        (WebCore::HTMLCanvasElement::paint):
+        * html/HTMLCanvasElement.h:
+        * page/DragController.cpp:
+        (WebCore::DragController::doImageDrag):
+        * platform/graphics/GraphicsContext.cpp:
+        (WebCore::GraphicsContext::drawImage):
+        (WebCore::GraphicsContext::drawTiledImage):
+        (WebCore::GraphicsContext::drawImageBuffer):
+        (WebCore::GraphicsContext::drawConsumingImageBuffer):
+        (WebCore::InterpolationQualityMaintainer::InterpolationQualityMaintainer): Deleted.
+        (WebCore::InterpolationQualityMaintainer::~InterpolationQualityMaintainer): Deleted.
+        * platform/graphics/GraphicsContext.h:
+        (WebCore::ImagePaintingOptions::ImagePaintingOptions):
+        (WebCore::ImagePaintingOptions::usesDefaultInterpolation):
+        (WebCore::InterpolationQualityMaintainer::InterpolationQualityMaintainer):
+        (WebCore::InterpolationQualityMaintainer::~InterpolationQualityMaintainer):
+        * platform/graphics/GraphicsTypes.h:
+        * platform/graphics/ImageBuffer.h:
+        * platform/graphics/cg/ImageBufferCG.cpp:
+        (WebCore::ImageBuffer::drawConsuming):
+        (WebCore::ImageBuffer::draw):
+        * rendering/ImageQualityController.cpp:
+        (WebCore::ImageQualityController::interpolationQualityFromStyle):
+        (WebCore::ImageQualityController::chooseInterpolationQuality):
+        (WebCore::ImageQualityController::ImageQualityController): Deleted.
+        (WebCore::ImageQualityController::shouldPaintAtLowQuality): Deleted.
+        * rendering/ImageQualityController.h:
+        * rendering/RenderBoxModelObject.cpp:
+        (WebCore::RenderBoxModelObject::chooseInterpolationQuality):
+        (WebCore::RenderBoxModelObject::paintFillLayerExtended):
+        (WebCore::RenderBoxModelObject::shouldPaintAtLowQuality): Deleted.
+        * rendering/RenderBoxModelObject.h:
+        * rendering/RenderEmbeddedObject.cpp:
+        (WebCore::RenderEmbeddedObject::paintSnapshotImage):
+        * rendering/RenderHTMLCanvas.cpp:
+        (WebCore::RenderHTMLCanvas::paintReplaced):
+        * rendering/RenderImage.cpp:
+        (WebCore::RenderImage::paintIntoRect):
+        * rendering/RenderSnapshottedPlugIn.cpp:
+        (WebCore::RenderSnapshottedPlugIn::paintSnapshot):
+        * rendering/style/RenderStyle.h:
+
 2016-01-29  Brady Eidson  <beidson@apple.com>
 
         Modern IDB: storage/indexeddb/modern/index-3.html fails.
diff --git a/Source/WebCore/html/HTMLCanvasElement.cpp b/Source/WebCore/html/HTMLCanvasElement.cpp
index f6f5165..7b35699 100644
--- a/Source/WebCore/html/HTMLCanvasElement.cpp
+++ b/Source/WebCore/html/HTMLCanvasElement.cpp
@@ -403,7 +403,7 @@
 }
 
 
-void HTMLCanvasElement::paint(GraphicsContext& context, const LayoutRect& r, bool useLowQualityScale)
+void HTMLCanvasElement::paint(GraphicsContext& context, const LayoutRect& r)
 {
     // Clear the dirty rect
     m_dirtyRect = FloatRect();
@@ -426,9 +426,9 @@
 #if ENABLE(CSS_IMAGE_ORIENTATION)
                 orientationDescription.setImageOrientationEnum(renderer()->style().imageOrientation());
 #endif 
-                context.drawImage(*m_presentedImage, snappedIntRect(r), ImagePaintingOptions(orientationDescription, useLowQualityScale));
+                context.drawImage(*m_presentedImage, snappedIntRect(r), ImagePaintingOptions(orientationDescription));
             } else
-                context.drawImageBuffer(*imageBuffer, snappedIntRect(r), useLowQualityScale);
+                context.drawImageBuffer(*imageBuffer, snappedIntRect(r));
         }
     }
 
diff --git a/Source/WebCore/html/HTMLCanvasElement.h b/Source/WebCore/html/HTMLCanvasElement.h
index 02dbc57..a774900 100644
--- a/Source/WebCore/html/HTMLCanvasElement.h
+++ b/Source/WebCore/html/HTMLCanvasElement.h
@@ -109,7 +109,7 @@
     void didDraw(const FloatRect&);
     void notifyObserversCanvasChanged(const FloatRect&);
 
-    void paint(GraphicsContext&, const LayoutRect&, bool useLowQualityScale = false);
+    void paint(GraphicsContext&, const LayoutRect&);
 
     GraphicsContext* drawingContext() const;
     GraphicsContext* existingDrawingContext() const;
diff --git a/Source/WebCore/page/DragController.cpp b/Source/WebCore/page/DragController.cpp
index 4c52a28..b01683e 100644
--- a/Source/WebCore/page/DragController.cpp
+++ b/Source/WebCore/page/DragController.cpp
@@ -935,10 +935,7 @@
     if (!element.renderer())
         return;
 
-    ImageOrientationDescription orientationDescription(element.renderer()->shouldRespectImageOrientation());
-#if ENABLE(CSS_IMAGE_ORIENTATION)
-    orientationDescription.setImageOrientationEnum(element.renderer()->style().imageOrientation());
-#endif
+    ImageOrientationDescription orientationDescription(element.renderer()->shouldRespectImageOrientation(), element.renderer()->style().imageOrientation());
 
     Image* image = getImage(element);
     if (image && image->size().height() * image->size().width() <= MaxOriginalImageArea
diff --git a/Source/WebCore/platform/graphics/GraphicsContext.cpp b/Source/WebCore/platform/graphics/GraphicsContext.cpp
index 7ddcc72..965503c 100644
--- a/Source/WebCore/platform/graphics/GraphicsContext.cpp
+++ b/Source/WebCore/platform/graphics/GraphicsContext.cpp
@@ -77,30 +77,6 @@
     unsigned m_offset;
 };
 
-class InterpolationQualityMaintainer {
-public:
-    explicit InterpolationQualityMaintainer(GraphicsContext& graphicsContext, InterpolationQuality interpolationQualityToUse)
-        : m_graphicsContext(graphicsContext)
-        , m_currentInterpolationQuality(graphicsContext.imageInterpolationQuality())
-        , m_interpolationQualityChanged(m_currentInterpolationQuality != interpolationQualityToUse)
-    {
-        if (m_interpolationQualityChanged)
-            m_graphicsContext.setImageInterpolationQuality(interpolationQualityToUse);
-    }
-
-    ~InterpolationQualityMaintainer()
-    {
-        if (m_interpolationQualityChanged)
-            m_graphicsContext.setImageInterpolationQuality(m_currentInterpolationQuality);
-    }
-
-private:
-    GraphicsContext& m_graphicsContext;
-    InterpolationQuality m_currentInterpolationQuality;
-    bool m_interpolationQualityChanged;
-};
-
-
 #define CHECK_FOR_CHANGED_PROPERTY(flag, property) \
     if ((m_changeFlags & GraphicsContextState::flag) && (m_state.property != state.property)) \
         changeFlags |= GraphicsContextState::flag;
@@ -767,7 +743,7 @@
         return;
     }
 
-    InterpolationQualityMaintainer interpolationQualityForThisScope(*this, imagePaintingOptions.m_useLowQualityScale ? InterpolationLow : imageInterpolationQuality());
+    InterpolationQualityMaintainer interpolationQualityForThisScope(*this, imagePaintingOptions.m_interpolationQuality);
     image.draw(*this, destination, source, imagePaintingOptions.m_compositeOperator, imagePaintingOptions.m_blendMode, imagePaintingOptions.m_orientationDescription);
 }
 
@@ -781,7 +757,7 @@
         return;
     }
 
-    InterpolationQualityMaintainer interpolationQualityForThisScope(*this, imagePaintingOptions.m_useLowQualityScale ? InterpolationLow : imageInterpolationQuality());
+    InterpolationQualityMaintainer interpolationQualityForThisScope(*this, imagePaintingOptions.m_interpolationQuality);
     image.drawTiled(*this, destination, source, tileSize, spacing, imagePaintingOptions.m_compositeOperator, imagePaintingOptions.m_blendMode);
 }
 
@@ -802,7 +778,7 @@
         return;
     }
 
-    InterpolationQualityMaintainer interpolationQualityForThisScope(*this, imagePaintingOptions.m_useLowQualityScale ? InterpolationLow : imageInterpolationQuality());
+    InterpolationQualityMaintainer interpolationQualityForThisScope(*this, imagePaintingOptions.m_interpolationQuality);
     image.drawTiled(*this, destination, source, tileScaleFactor, hRule, vRule, imagePaintingOptions.m_compositeOperator);
 }
 
@@ -821,8 +797,8 @@
     if (paintingDisabled())
         return;
 
-    InterpolationQualityMaintainer interpolationQualityForThisScope(*this, imagePaintingOptions.m_useLowQualityScale ? InterpolationLow : imageInterpolationQuality());
-    image.draw(*this, destination, source, imagePaintingOptions.m_compositeOperator, imagePaintingOptions.m_blendMode, imagePaintingOptions.m_useLowQualityScale);
+    InterpolationQualityMaintainer interpolationQualityForThisScope(*this, imagePaintingOptions.m_interpolationQuality);
+    image.draw(*this, destination, source, imagePaintingOptions.m_compositeOperator, imagePaintingOptions.m_blendMode);
 }
 
 void GraphicsContext::drawConsumingImageBuffer(std::unique_ptr<ImageBuffer> image, const FloatPoint& destination, const ImagePaintingOptions& imagePaintingOptions)
@@ -846,9 +822,8 @@
     if (paintingDisabled() || !image)
         return;
     
-    InterpolationQualityMaintainer interpolationQualityForThisScope(*this, imagePaintingOptions.m_useLowQualityScale ? InterpolationLow : imageInterpolationQuality());
-
-    ImageBuffer::drawConsuming(WTFMove(image), *this, destination, source, imagePaintingOptions.m_compositeOperator, imagePaintingOptions.m_blendMode, imagePaintingOptions.m_useLowQualityScale);
+    InterpolationQualityMaintainer interpolationQualityForThisScope(*this, imagePaintingOptions.m_interpolationQuality);
+    ImageBuffer::drawConsuming(WTFMove(image), *this, destination, source, imagePaintingOptions.m_compositeOperator, imagePaintingOptions.m_blendMode);
 }
 
 void GraphicsContext::clipRoundedRect(const FloatRoundedRect& rect)
diff --git a/Source/WebCore/platform/graphics/GraphicsContext.h b/Source/WebCore/platform/graphics/GraphicsContext.h
index 4ffa7c6..a4608e0 100644
--- a/Source/WebCore/platform/graphics/GraphicsContext.h
+++ b/Source/WebCore/platform/graphics/GraphicsContext.h
@@ -102,14 +102,6 @@
     WavyStroke,
 };
 
-enum InterpolationQuality {
-    InterpolationDefault,
-    InterpolationNone,
-    InterpolationLow,
-    InterpolationMedium,
-    InterpolationHigh
-};
-
 namespace DisplayList {
 class Recorder;
 }
@@ -194,34 +186,36 @@
 };
 
 struct ImagePaintingOptions {
-    ImagePaintingOptions(CompositeOperator compositeOperator = CompositeSourceOver, BlendMode blendMode = BlendModeNormal, ImageOrientationDescription orientationDescription = ImageOrientationDescription(), bool useLowQualityScale = false)
+    ImagePaintingOptions(CompositeOperator compositeOperator = CompositeSourceOver, BlendMode blendMode = BlendModeNormal, ImageOrientationDescription orientationDescription = ImageOrientationDescription(), InterpolationQuality interpolationQuality = InterpolationDefault)
         : m_compositeOperator(compositeOperator)
         , m_blendMode(blendMode)
         , m_orientationDescription(orientationDescription)
-        , m_useLowQualityScale(useLowQualityScale)
+        , m_interpolationQuality(interpolationQuality)
     {
     }
 
-    ImagePaintingOptions(ImageOrientationDescription orientationDescription, bool useLowQualityScale = false, CompositeOperator compositeOperator = CompositeSourceOver, BlendMode blendMode = BlendModeNormal)
+    ImagePaintingOptions(ImageOrientationDescription orientationDescription, InterpolationQuality interpolationQuality = InterpolationDefault, CompositeOperator compositeOperator = CompositeSourceOver, BlendMode blendMode = BlendModeNormal)
         : m_compositeOperator(compositeOperator)
         , m_blendMode(blendMode)
         , m_orientationDescription(orientationDescription)
-        , m_useLowQualityScale(useLowQualityScale)
+        , m_interpolationQuality(interpolationQuality)
     {
     }
 
-    ImagePaintingOptions(bool useLowQualityScale, ImageOrientationDescription orientationDescription = ImageOrientationDescription(), CompositeOperator compositeOperator = CompositeSourceOver, BlendMode blendMode = BlendModeNormal)
+    ImagePaintingOptions(InterpolationQuality interpolationQuality, ImageOrientationDescription orientationDescription = ImageOrientationDescription(), CompositeOperator compositeOperator = CompositeSourceOver, BlendMode blendMode = BlendModeNormal)
         : m_compositeOperator(compositeOperator)
         , m_blendMode(blendMode)
         , m_orientationDescription(orientationDescription)
-        , m_useLowQualityScale(useLowQualityScale)
+        , m_interpolationQuality(interpolationQuality)
     {
     }
+    
+    bool usesDefaultInterpolation() const { return m_interpolationQuality == InterpolationDefault; }
 
     CompositeOperator m_compositeOperator;
     BlendMode m_blendMode;
     ImageOrientationDescription m_orientationDescription;
-    bool m_useLowQualityScale;
+    InterpolationQuality m_interpolationQuality;
 };
 
 struct GraphicsContextStateChange {
@@ -657,6 +651,34 @@
     bool m_saveAndRestore;
 };
 
+class InterpolationQualityMaintainer {
+public:
+    explicit InterpolationQualityMaintainer(GraphicsContext& graphicsContext, InterpolationQuality interpolationQualityToUse)
+        : m_graphicsContext(graphicsContext)
+        , m_currentInterpolationQuality(graphicsContext.imageInterpolationQuality())
+        , m_interpolationQualityChanged(interpolationQualityToUse != InterpolationDefault && m_currentInterpolationQuality != interpolationQualityToUse)
+    {
+        if (m_interpolationQualityChanged)
+            m_graphicsContext.setImageInterpolationQuality(interpolationQualityToUse);
+    }
+
+    explicit InterpolationQualityMaintainer(GraphicsContext& graphicsContext, Optional<InterpolationQuality> interpolationQuality)
+        : InterpolationQualityMaintainer(graphicsContext, interpolationQuality ? interpolationQuality.value() : graphicsContext.imageInterpolationQuality())
+    {
+    }
+
+    ~InterpolationQualityMaintainer()
+    {
+        if (m_interpolationQualityChanged)
+            m_graphicsContext.setImageInterpolationQuality(m_currentInterpolationQuality);
+    }
+
+private:
+    GraphicsContext& m_graphicsContext;
+    InterpolationQuality m_currentInterpolationQuality;
+    bool m_interpolationQualityChanged;
+};
+
 } // namespace WebCore
 
 #endif // GraphicsContext_h
diff --git a/Source/WebCore/platform/graphics/GraphicsTypes.h b/Source/WebCore/platform/graphics/GraphicsTypes.h
index 4ef3be8..ede792d 100644
--- a/Source/WebCore/platform/graphics/GraphicsTypes.h
+++ b/Source/WebCore/platform/graphics/GraphicsTypes.h
@@ -75,6 +75,14 @@
     SpreadMethodRepeat
 };
 
+enum InterpolationQuality {
+    InterpolationDefault,
+    InterpolationNone,
+    InterpolationLow,
+    InterpolationMedium,
+    InterpolationHigh
+};
+
 enum LineCap { ButtCap, RoundCap, SquareCap };
 
 enum LineJoin { MiterJoin, RoundJoin, BevelJoin };
diff --git a/Source/WebCore/platform/graphics/ImageBuffer.h b/Source/WebCore/platform/graphics/ImageBuffer.h
index f419d32..04f9ef9 100644
--- a/Source/WebCore/platform/graphics/ImageBuffer.h
+++ b/Source/WebCore/platform/graphics/ImageBuffer.h
@@ -142,10 +142,10 @@
     void flushContext() const;
 #endif
     
-    void draw(GraphicsContext&, const FloatRect& destRect, const FloatRect& srcRect = FloatRect(0, 0, -1, -1), CompositeOperator = CompositeSourceOver, BlendMode = BlendModeNormal, bool useLowQualityScale = false);
+    void draw(GraphicsContext&, const FloatRect& destRect, const FloatRect& srcRect = FloatRect(0, 0, -1, -1), CompositeOperator = CompositeSourceOver, BlendMode = BlendModeNormal);
     void drawPattern(GraphicsContext&, const FloatRect& srcRect, const AffineTransform& patternTransform, const FloatPoint& phase, const FloatSize& spacing, CompositeOperator, const FloatRect& destRect, BlendMode = BlendModeNormal);
 
-    static void drawConsuming(std::unique_ptr<ImageBuffer>, GraphicsContext&, const FloatRect& destRect, const FloatRect& srcRect = FloatRect(0, 0, -1, -1), CompositeOperator = CompositeSourceOver, BlendMode = BlendModeNormal, bool useLowQualityScale = false);
+    static void drawConsuming(std::unique_ptr<ImageBuffer>, GraphicsContext&, const FloatRect& destRect, const FloatRect& srcRect = FloatRect(0, 0, -1, -1), CompositeOperator = CompositeSourceOver, BlendMode = BlendModeNormal);
 
     inline void genericConvertToLuminanceMask();
 
diff --git a/Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp b/Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp
index 4866519..387a20a 100644
--- a/Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp
+++ b/Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp
@@ -214,17 +214,17 @@
     return DontCopyBackingStore;
 }
 
-void ImageBuffer::drawConsuming(std::unique_ptr<ImageBuffer> imageBuffer, GraphicsContext& destContext, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator op, BlendMode blendMode, bool useLowQualityScale)
+void ImageBuffer::drawConsuming(std::unique_ptr<ImageBuffer> imageBuffer, GraphicsContext& destContext, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator op, BlendMode blendMode)
 {
-    imageBuffer->draw(destContext, destRect, srcRect, op, blendMode, useLowQualityScale);
+    imageBuffer->draw(destContext, destRect, srcRect, op, blendMode);
 }
 
 void ImageBuffer::draw(GraphicsContext& destinationContext, const FloatRect& destRect, const FloatRect& srcRect,
-    CompositeOperator op, BlendMode blendMode, bool useLowQualityScale)
+    CompositeOperator op, BlendMode blendMode)
 {
     BackingStoreCopy copyMode = &destinationContext == &context() ? CopyBackingStore : DontCopyBackingStore;
     RefPtr<Image> image = copyImage(copyMode);
-    destinationContext.drawImage(*image, destRect, srcRect, ImagePaintingOptions(op, blendMode, ImageOrientationDescription(), useLowQualityScale));
+    destinationContext.drawImage(*image, destRect, srcRect, ImagePaintingOptions(op, blendMode, ImageOrientationDescription()));
 }
 
 void ImageBuffer::drawPattern(GraphicsContext& context, const FloatRect& srcRect, const AffineTransform& patternTransform,
diff --git a/Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp b/Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp
index 95e4b15..846396c 100644
--- a/Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp
+++ b/Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp
@@ -264,11 +264,11 @@
     return image;
 }
 
-void ImageBuffer::drawConsuming(std::unique_ptr<ImageBuffer> imageBuffer, GraphicsContext& destContext, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator op, BlendMode blendMode, bool useLowQualityScale)
+void ImageBuffer::drawConsuming(std::unique_ptr<ImageBuffer> imageBuffer, GraphicsContext& destContext, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator op, BlendMode blendMode)
 {
 #if USE(IOSURFACE_CANVAS_BACKING_STORE)
     if (!imageBuffer->m_data.surface) {
-        imageBuffer->draw(destContext, destRect, srcRect, op, blendMode, useLowQualityScale);
+        imageBuffer->draw(destContext, destRect, srcRect, op, blendMode);
         return;
     }
     
@@ -283,11 +283,11 @@
     adjustedSrcRect.scale(resolutionScale, resolutionScale);
     destContext.drawNativeImage(image.get(), backingStoreSize, destRect, adjustedSrcRect, op, blendMode);
 #else
-    imageBuffer->draw(destContext, destRect, srcRect, op, blendMode, useLowQualityScale);
+    imageBuffer->draw(destContext, destRect, srcRect, op, blendMode);
 #endif
 }
 
-void ImageBuffer::draw(GraphicsContext& destContext, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator op, BlendMode blendMode, bool)
+void ImageBuffer::draw(GraphicsContext& destContext, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator op, BlendMode blendMode)
 {
     RetainPtr<CGImageRef> image;
     if (&destContext == &context() || destContext.isAcceleratedContext())
diff --git a/Source/WebCore/rendering/ImageQualityController.cpp b/Source/WebCore/rendering/ImageQualityController.cpp
index be0d94a..4ecd85a 100644
--- a/Source/WebCore/rendering/ImageQualityController.cpp
+++ b/Source/WebCore/rendering/ImageQualityController.cpp
@@ -40,8 +40,6 @@
 ImageQualityController::ImageQualityController(const RenderView& renderView)
     : m_renderView(renderView)
     , m_timer(*this, &ImageQualityController::highQualityRepaintTimerFired)
-    , m_animatedResizeIsActive(false)
-    , m_liveResizeOptimizationIsActive(false)
 {
 }
 
@@ -99,23 +97,30 @@
     m_timer.startOneShot(cLowQualityTimeThreshold);
 }
 
-bool ImageQualityController::shouldPaintAtLowQuality(GraphicsContext& context, RenderBoxModelObject* object, Image& image, const void *layer, const LayoutSize& size)
+Optional<InterpolationQuality> ImageQualityController::interpolationQualityFromStyle(const RenderStyle& style)
 {
-    // If the image is not a bitmap image, then none of this is relevant and we just paint at high
-    // quality.
-    if (!(image.isBitmapImage() || image.isPDFDocumentImage()) || context.paintingDisabled())
-        return false;
-
-    switch (object->style().imageRendering()) {
+    switch (style.imageRendering()) {
     case ImageRenderingOptimizeSpeed:
+        return InterpolationLow;
     case ImageRenderingCrispEdges:
     case ImageRenderingPixelated:
-        return true;
+        return InterpolationNone;
     case ImageRenderingOptimizeQuality:
-        return false; // FIXME: CSS 3 Images says that optimizeQuality should behave like 'auto', but that prevents authors from overriding this low quality rendering behavior.
+        return InterpolationDefault; // FIXME: CSS 3 Images says that optimizeQuality should behave like 'auto', but that prevents authors from overriding this low quality rendering behavior.
     case ImageRenderingAuto:
         break;
     }
+    return Nullopt;
+}
+
+InterpolationQuality ImageQualityController::chooseInterpolationQuality(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.isBitmapImage() || image.isPDFDocumentImage()) || context.paintingDisabled())
+        return InterpolationDefault;
+
+    if (Optional<InterpolationQuality> styleInterpolation = interpolationQualityFromStyle(object->style()))
+        return styleInterpolation.value();
 
     // Make sure to use the unzoomed image size, since if a full page zoom is in effect, the image
     // is actually being scaled.
@@ -141,10 +146,10 @@
             set(object, innerMap, layer, size);
             restartTimer();
             m_liveResizeOptimizationIsActive = true;
-            return true;
+            return InterpolationLow;
         }
         if (m_liveResizeOptimizationIsActive)
-            return false;
+            return InterpolationDefault;
     }
 
     const AffineTransform& currentTransform = context.getCTM();
@@ -152,21 +157,21 @@
     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;
+        return InterpolationDefault;
     }
 
     // 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;
+            return InterpolationLow;
     }
 
     // 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;
+        return InterpolationLow;
     }
     // 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
@@ -174,13 +179,13 @@
     if (isFirstResize || oldSize == size) {
         restartTimer();
         set(object, innerMap, layer, size);
-        return false;
+        return InterpolationDefault;
     }
     // 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;
+        return InterpolationDefault;
     }
     // 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
@@ -188,7 +193,7 @@
     set(object, innerMap, layer, size);
     m_animatedResizeIsActive = true;
     restartTimer();
-    return true;
+    return InterpolationLow;
 }
 
 }
diff --git a/Source/WebCore/rendering/ImageQualityController.h b/Source/WebCore/rendering/ImageQualityController.h
index 5f71164..4ff846f 100644
--- a/Source/WebCore/rendering/ImageQualityController.h
+++ b/Source/WebCore/rendering/ImageQualityController.h
@@ -26,24 +26,28 @@
 #ifndef ImageQualityController_h
 #define ImageQualityController_h
 
+#include "GraphicsTypes.h"
 #include "Timer.h"
 #include <wtf/HashMap.h>
+#include <wtf/Optional.h>
 
 namespace WebCore {
 
-class Frame;
 class GraphicsContext;
 class Image;
 class LayoutSize;
 class RenderBoxModelObject;
 class RenderView;
+class RenderStyle;
 
 class ImageQualityController {
     WTF_MAKE_NONCOPYABLE(ImageQualityController); WTF_MAKE_FAST_ALLOCATED;
 public:
     explicit ImageQualityController(const RenderView&);
 
-    bool shouldPaintAtLowQuality(GraphicsContext&, RenderBoxModelObject*, Image&, const void* layer, const LayoutSize&);
+    static Optional<InterpolationQuality> interpolationQualityFromStyle(const RenderStyle&);
+    InterpolationQuality chooseInterpolationQuality(GraphicsContext&, RenderBoxModelObject*, Image&, const void* layer, const LayoutSize&);
+
     void rendererWillBeDestroyed(RenderBoxModelObject& renderer) { removeObject(&renderer); }
 
 private:
@@ -59,8 +63,8 @@
     const RenderView& m_renderView;
     ObjectLayerSizeMap m_objectLayerSizeMap;
     Timer m_timer;
-    bool m_animatedResizeIsActive;
-    bool m_liveResizeOptimizationIsActive;
+    bool m_animatedResizeIsActive { false };
+    bool m_liveResizeOptimizationIsActive { false };
 };
 
 } // namespace
diff --git a/Source/WebCore/rendering/RenderBoxModelObject.cpp b/Source/WebCore/rendering/RenderBoxModelObject.cpp
index 7c1d0a7..747f6ff 100644
--- a/Source/WebCore/rendering/RenderBoxModelObject.cpp
+++ b/Source/WebCore/rendering/RenderBoxModelObject.cpp
@@ -161,11 +161,6 @@
     layer()->backing()->suspendAnimations(time);
 }
 
-bool RenderBoxModelObject::shouldPaintAtLowQuality(GraphicsContext& context, Image& image, const void* layer, const LayoutSize& size)
-{
-    return view().imageQualityController().shouldPaintAtLowQuality(context, this, image, layer, size);
-}
-
 RenderBoxModelObject::RenderBoxModelObject(Element& element, Ref<RenderStyle>&& style, BaseTypeFlags baseTypeFlags)
     : RenderLayerModelObject(element, WTFMove(style), baseTypeFlags | RenderBoxModelObjectFlag)
 {
@@ -594,6 +589,11 @@
         context.setLegacyShadow(shadowOffset, boxShadow->radius(), boxShadow->color());
 }
 
+InterpolationQuality RenderBoxModelObject::chooseInterpolationQuality(GraphicsContext& context, Image& image, const void* layer, const LayoutSize& size)
+{
+    return view().imageQualityController().chooseInterpolationQuality(context, this, image, layer, size);
+}
+
 void RenderBoxModelObject::paintMaskForTextFillBox(ImageBuffer* maskImage, const IntRect& maskRect, InlineFlowBox* box, const LayoutRect& scrolledPaintRect)
 {
     GraphicsContext& maskImageContext = maskImage->context();
@@ -834,8 +834,9 @@
         if (!geometry.destRect().isEmpty() && (image = bgImage->image(backgroundObject ? backgroundObject : this, geometry.tileSize()))) {
             CompositeOperator compositeOp = op == CompositeSourceOver ? bgLayer->composite() : op;
             context.setDrawLuminanceMask(bgLayer->maskSourceType() == MaskLuminance);
-            bool useLowQualityScaling = shouldPaintAtLowQuality(context, *image, bgLayer, geometry.tileSize());
-            context.drawTiledImage(*image, geometry.destRect(), toLayoutPoint(geometry.relativePhase()), geometry.tileSize(), geometry.spaceSize(), ImagePaintingOptions(compositeOp, bgLayer->blendMode(), ImageOrientationDescription(), useLowQualityScaling));
+
+            InterpolationQuality interpolation = chooseInterpolationQuality(context, *image, bgLayer, geometry.tileSize());
+            context.drawTiledImage(*image, geometry.destRect(), toLayoutPoint(geometry.relativePhase()), geometry.tileSize(), geometry.spaceSize(), ImagePaintingOptions(compositeOp, bgLayer->blendMode(), ImageOrientationDescription(), interpolation));
         }
     }
 
diff --git a/Source/WebCore/rendering/RenderBoxModelObject.h b/Source/WebCore/rendering/RenderBoxModelObject.h
index a509b39..b535811 100644
--- a/Source/WebCore/rendering/RenderBoxModelObject.h
+++ b/Source/WebCore/rendering/RenderBoxModelObject.h
@@ -251,7 +251,7 @@
     RoundedRect backgroundRoundedRectAdjustedForBleedAvoidance(const GraphicsContext&, const LayoutRect&, BackgroundBleedAvoidance, InlineFlowBox*, const LayoutSize&, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const;
     LayoutRect borderInnerRectAdjustedForBleedAvoidance(const GraphicsContext&, const LayoutRect&, BackgroundBleedAvoidance) const;
 
-    bool shouldPaintAtLowQuality(GraphicsContext&, Image&, const void*, const LayoutSize&);
+    InterpolationQuality chooseInterpolationQuality(GraphicsContext&, Image&, const void*, const LayoutSize&);
 
     RenderBoxModelObject* continuation() const;
     void setContinuation(RenderBoxModelObject*);
diff --git a/Source/WebCore/rendering/RenderEmbeddedObject.cpp b/Source/WebCore/rendering/RenderEmbeddedObject.cpp
index de91014..8805631 100644
--- a/Source/WebCore/rendering/RenderEmbeddedObject.cpp
+++ b/Source/WebCore/rendering/RenderEmbeddedObject.cpp
@@ -214,12 +214,9 @@
     if (alignedRect.width() <= 0 || alignedRect.height() <= 0)
         return;
 
-    bool useLowQualityScaling = shouldPaintAtLowQuality(context, image, &image, alignedRect.size());
-    ImageOrientationDescription orientationDescription(shouldRespectImageOrientation());
-#if ENABLE(CSS_IMAGE_ORIENTATION)
-    orientationDescription.setImageOrientationEnum(style().imageOrientation());
-#endif
-    context.drawImage(image, alignedRect, ImagePaintingOptions(orientationDescription, useLowQualityScaling));
+    InterpolationQuality interpolation = chooseInterpolationQuality(context, image, &image, alignedRect.size());
+    ImageOrientationDescription orientationDescription(shouldRespectImageOrientation(), style().imageOrientation());
+    context.drawImage(image, alignedRect, ImagePaintingOptions(orientationDescription, interpolation));
 }
 
 void RenderEmbeddedObject::paintContents(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
diff --git a/Source/WebCore/rendering/RenderHTMLCanvas.cpp b/Source/WebCore/rendering/RenderHTMLCanvas.cpp
index 37b588f..f2de75d 100644
--- a/Source/WebCore/rendering/RenderHTMLCanvas.cpp
+++ b/Source/WebCore/rendering/RenderHTMLCanvas.cpp
@@ -33,6 +33,7 @@
 #include "GraphicsContext.h"
 #include "HTMLCanvasElement.h"
 #include "HTMLNames.h"
+#include "ImageQualityController.h"
 #include "Page.h"
 #include "PaintInfo.h"
 #include "RenderView.h"
@@ -84,8 +85,8 @@
             page->addRelevantRepaintedObject(this, intersection(replacedContentRect, contentBoxRect));
     }
 
-    bool useLowQualityScale = style().imageRendering() == ImageRenderingCrispEdges || style().imageRendering() == ImageRenderingPixelated || style().imageRendering() == ImageRenderingOptimizeSpeed;
-    canvasElement().paint(context, replacedContentRect, useLowQualityScale);
+    InterpolationQualityMaintainer interpolationMaintainer(context, ImageQualityController::interpolationQualityFromStyle(style()));
+    canvasElement().paint(context, replacedContentRect);
 }
 
 void RenderHTMLCanvas::canvasSizeChanged()
diff --git a/Source/WebCore/rendering/RenderImage.cpp b/Source/WebCore/rendering/RenderImage.cpp
index c068eab..60270ae 100644
--- a/Source/WebCore/rendering/RenderImage.cpp
+++ b/Source/WebCore/rendering/RenderImage.cpp
@@ -547,14 +547,13 @@
 
     HTMLImageElement* imageElement = is<HTMLImageElement>(element()) ? downcast<HTMLImageElement>(element()) : nullptr;
     CompositeOperator compositeOperator = imageElement ? imageElement->compositeOperator() : CompositeSourceOver;
+
+    // FIXME: Document when image != img.get().
     Image* image = imageResource().image().get();
-    bool useLowQualityScaling = image && shouldPaintAtLowQuality(context, *image, image, LayoutSize(rect.size()));
-    ImageOrientationDescription orientationDescription(shouldRespectImageOrientation());
-#if ENABLE(CSS_IMAGE_ORIENTATION)
-    orientationDescription.setImageOrientationEnum(style().imageOrientation());
-#endif
-    context.drawImage(*img, rect,
-        ImagePaintingOptions(compositeOperator, BlendModeNormal, orientationDescription, useLowQualityScaling));
+    InterpolationQuality interpolation = image ? chooseInterpolationQuality(context, *image, image, LayoutSize(rect.size())) : InterpolationDefault;
+
+    ImageOrientationDescription orientationDescription(shouldRespectImageOrientation(), style().imageOrientation());
+    context.drawImage(*img, rect, ImagePaintingOptions(compositeOperator, BlendModeNormal, orientationDescription, interpolation));
 }
 
 bool RenderImage::boxShadowShouldBeAppliedToBackground(const LayoutPoint& paintOffset, BackgroundBleedAvoidance bleedAvoidance, InlineFlowBox*) const
diff --git a/Source/WebCore/rendering/RenderSnapshottedPlugIn.cpp b/Source/WebCore/rendering/RenderSnapshottedPlugIn.cpp
index 99c967a..8e100eb 100644
--- a/Source/WebCore/rendering/RenderSnapshottedPlugIn.cpp
+++ b/Source/WebCore/rendering/RenderSnapshottedPlugIn.cpp
@@ -135,13 +135,9 @@
     if (alignedRect.width() <= 0 || alignedRect.height() <= 0)
         return;
 
-    bool useLowQualityScaling = shouldPaintAtLowQuality(context, *image, image, alignedRect.size());
-
-    ImageOrientationDescription orientationDescription(shouldRespectImageOrientation());
-#if ENABLE(CSS_IMAGE_ORIENTATION)
-    orientationDescription.setImageOrientationEnum(style().imageOrientation());
-#endif
-    context.drawImage(*image, alignedRect, ImagePaintingOptions(orientationDescription, useLowQualityScaling));
+    InterpolationQuality interpolation = chooseInterpolationQuality(context, *image, image, alignedRect.size());
+    ImageOrientationDescription orientationDescription(shouldRespectImageOrientation(), style().imageOrientation());
+    context.drawImage(*image, alignedRect, ImagePaintingOptions(orientationDescription, interpolation));
 }
 
 CursorDirective RenderSnapshottedPlugIn::getCursor(const LayoutPoint& point, Cursor& overrideCursor) const
diff --git a/Source/WebCore/rendering/style/RenderStyle.h b/Source/WebCore/rendering/style/RenderStyle.h
index af666a4..adf105d 100644
--- a/Source/WebCore/rendering/style/RenderStyle.h
+++ b/Source/WebCore/rendering/style/RenderStyle.h
@@ -1163,9 +1163,14 @@
     bool isFlippedLinesWritingMode() const { return WebCore::isFlippedLinesWritingMode(writingMode()); }
     bool isFlippedBlocksWritingMode() const { return WebCore::isFlippedWritingMode(writingMode()); }
 
+    ImageOrientationEnum imageOrientation() const
+    {
 #if ENABLE(CSS_IMAGE_ORIENTATION)
-    ImageOrientationEnum imageOrientation() const { return static_cast<ImageOrientationEnum>(rareInheritedData->m_imageOrientation); }
+        return static_cast<ImageOrientationEnum>(rareInheritedData->m_imageOrientation);
+#else
+        return DefaultImageOrientation;
 #endif
+    }
 
     EImageRendering imageRendering() const { return static_cast<EImageRendering>(rareInheritedData->m_imageRendering); }