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); } }
bool ImageQualityController::shouldPaintAtLowQuality( const LayoutObject& object, Image* image, const void* layer, const LayoutSize& layoutSize, double lastFrameTimeMonotonic) { // 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()) return false; if (!layer) return false; if (object.style()->imageRendering() == ImageRenderingOptimizeContrast) return true; if (LocalFrame* frame = object.frame()) { if (frame->settings() && frame->settings()->useDefaultImageInterpolationQuality()) return false; } // Look ourselves up in the hashtables. ObjectLayerSizeMap::iterator i = m_objectLayerSizeMap.find(&object); LayerSizeMap* innerMap = nullptr; bool objectIsResizing = false; if (i != m_objectLayerSizeMap.end()) { innerMap = &i->value.layerSizeMap; objectIsResizing = i->value.isResizing; } LayoutSize oldSize; bool isFirstResize = true; if (innerMap) { LayerSizeMap::iterator j = innerMap->find(layer); if (j != innerMap->end()) { isFirstResize = false; oldSize = j->value; } } if (layoutSize == image->size()) { // 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; } // If an animated resize is active for this object, paint in low quality and // kick the timer ahead. if (objectIsResizing) { bool sizesChanged = oldSize != layoutSize; set(object, innerMap, layer, layoutSize, sizesChanged); if (sizesChanged) restartTimer(lastFrameTimeMonotonic); 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 == layoutSize) { restartTimer(lastFrameTimeMonotonic); set(object, innerMap, layer, layoutSize, false); 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, layoutSize, true); restartTimer(lastFrameTimeMonotonic); return true; }
bool ImageQualityController::shouldPaintAtLowQuality(GraphicsContext* context, RenderObject* object, Image* image, const void *layer, const LayoutSize& layoutSize) { // 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; if (object->style()->imageRendering() == ImageRenderingOptimizeContrast) return true; // 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; } } const AffineTransform& currentTransform = context->getCTM(); bool contextIsScaled = !currentTransform.isIdentityOrTranslationOrFlipped(); // Make sure to use the unzoomed image size, since if a full page zoom is in effect, the image // is actually being scaled. LayoutSize scaledImageSize = currentTransform.mapSize(image->size()); LayoutSize scaledLayoutSize = currentTransform.mapSize(roundedIntSize(layoutSize)); // 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, scaledLayoutSize); 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; } } if (!contextIsScaled && scaledLayoutSize == scaledImageSize) { // 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; } // If an animated resize is active, paint in low quality and kick the timer ahead. if (m_animatedResizeIsActive) { set(object, innerMap, layer, scaledLayoutSize); 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 == scaledLayoutSize) { restartTimer(); set(object, innerMap, layer, scaledLayoutSize); 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, scaledLayoutSize); m_animatedResizeIsActive = true; restartTimer(); return true; }
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() || image->isPDFDocumentImage()) || 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) 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; }