ImageQualityController.cpp [plain text]
#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;
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 (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 (!image || !(image->isBitmapImage() || image->isPDFDocumentImage()) || context->paintingDisabled())
return false;
switch (object->style().imageRendering()) {
case ImageRenderingOptimizeSpeed:
case ImageRenderingCrispEdges:
return true;
case ImageRenderingOptimizeQuality:
return false;
case ImageRenderingAuto:
break;
}
IntSize imageSize(image->width(), image->height());
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 (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)
return false;
}
const AffineTransform& currentTransform = context->getCTM();
bool contextIsScaled = !currentTransform.isIdentityOrTranslationOrFlipped();
if (!contextIsScaled && size == imageSize) {
removeLayer(object, innerMap, layer);
return false;
}
if (m_renderView.frame().page()->inLowQualityImageInterpolationMode()) {
double totalPixels = static_cast<double>(image->width()) * static_cast<double>(image->height());
if (totalPixels > cInterpolationCutoff)
return true;
}
if (m_animatedResizeIsActive) {
set(object, innerMap, layer, size);
restartTimer();
return true;
}
if (isFirstResize || oldSize == size) {
restartTimer();
set(object, innerMap, layer, size);
return false;
}
if (!m_timer.isActive()) {
removeLayer(object, innerMap, layer);
return false;
}
set(object, innerMap, layer, size);
m_animatedResizeIsActive = true;
restartTimer();
return true;
}
}