This source file includes following definitions.
- imageQualityController
- remove
- chooseInterpolationQuality
- m_liveResizeOptimizationIsActive
- removeLayer
- set
- objectDestroyed
- highQualityRepaintTimerFired
- restartTimer
- shouldPaintAtLowQuality
#include "config.h"
#include "core/rendering/ImageQualityController.h"
#include "core/frame/FrameView.h"
#include "core/frame/LocalFrame.h"
#include "platform/graphics/GraphicsContext.h"
namespace WebCore {
static const double cLowQualityTimeThreshold = 0.500;
static ImageQualityController* gImageQualityController = 0;
ImageQualityController* ImageQualityController::imageQualityController()
{
if (!gImageQualityController)
gImageQualityController = new ImageQualityController;
return gImageQualityController;
}
void ImageQualityController::remove(RenderObject* renderer)
{
if (gImageQualityController) {
gImageQualityController->objectDestroyed(renderer);
if (gImageQualityController->isEmpty()) {
delete gImageQualityController;
gImageQualityController = 0;
}
}
}
InterpolationQuality ImageQualityController::chooseInterpolationQuality(GraphicsContext* context, RenderObject* object, Image* image, const void* layer, const LayoutSize& layoutSize)
{
if (InterpolationDefault == InterpolationLow)
return InterpolationLow;
if (shouldPaintAtLowQuality(context, object, image, layer, layoutSize))
return InterpolationLow;
if (image && image->maybeAnimated())
return InterpolationMedium;
return InterpolationDefault;
}
ImageQualityController::~ImageQualityController()
{
ASSERT(!gImageQualityController || gImageQualityController->isEmpty());
}
ImageQualityController::ImageQualityController()
: m_timer(this, &ImageQualityController::highQualityRepaintTimerFired)
, m_animatedResizeIsActive(false)
, m_liveResizeOptimizationIsActive(false)
{
}
void ImageQualityController::removeLayer(RenderObject* object, LayerSizeMap* innerMap, const void* layer)
{
if (innerMap) {
innerMap->remove(layer);
if (innerMap->isEmpty())
objectDestroyed(object);
}
}
void ImageQualityController::set(RenderObject* 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(RenderObject* 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 (LocalFrame* frame = it->key->document().frame()) {
if (frame->view() && frame->view()->inLiveResize()) {
restartTimer();
return;
}
}
it->key->repaint();
}
m_liveResizeOptimizationIsActive = false;
}
void ImageQualityController::restartTimer()
{
m_timer.startOneShot(cLowQualityTimeThreshold, FROM_HERE);
}
bool ImageQualityController::shouldPaintAtLowQuality(GraphicsContext* context, RenderObject* object, Image* image, const void *layer, const LayoutSize& layoutSize)
{
if (!image || !image->isBitmapImage() || context->paintingDisabled())
return false;
if (object->style()->imageRendering() == ImageRenderingOptimizeContrast)
return true;
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;
}
}
const AffineTransform& currentTransform = context->getCTM();
bool contextIsScaled = !currentTransform.isIdentityOrTranslationOrFlipped();
LayoutSize scaledImageSize = currentTransform.mapSize(image->size());
LayoutSize scaledLayoutSize = currentTransform.mapSize(roundedIntSize(layoutSize));
if (LocalFrame* frame = object->document().frame()) {
bool frameViewIsCurrentlyInLiveResize = frame->view() && frame->view()->inLiveResize();
if (frameViewIsCurrentlyInLiveResize) {
set(object, innerMap, layer, scaledLayoutSize);
restartTimer();
m_liveResizeOptimizationIsActive = true;
return true;
}
if (m_liveResizeOptimizationIsActive) {
removeLayer(object, innerMap, layer);
return false;
}
}
if (!contextIsScaled && scaledLayoutSize == scaledImageSize) {
removeLayer(object, innerMap, layer);
return false;
}
if (m_animatedResizeIsActive) {
set(object, innerMap, layer, scaledLayoutSize);
restartTimer();
return true;
}
if (isFirstResize || oldSize == scaledLayoutSize) {
restartTimer();
set(object, innerMap, layer, scaledLayoutSize);
return false;
}
if (!m_timer.isActive()) {
removeLayer(object, innerMap, layer);
return false;
}
set(object, innerMap, layer, scaledLayoutSize);
m_animatedResizeIsActive = true;
restartTimer();
return true;
}
}