📄 renderimage.cpp
字号:
/* * Copyright (C) 1999 Lars Knoll (knoll@kde.org) * (C) 1999 Antti Koivisto (koivisto@kde.org) * (C) 2000 Dirk Mueller (mueller@kde.org) * (C) 2006 Allan Sandfeld Jensen (kde@carewolf.com) * (C) 2006 Samuel Weinig (sam.weinig@gmail.com) * Copyright (C) 2003, 2004, 2005, 2006, 2008 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * */#include "config.h"#include "RenderImage.h"#include "BitmapImage.h"#include "Document.h"#include "FrameView.h"#include "GraphicsContext.h"#include "HTMLImageElement.h"#include "HTMLInputElement.h"#include "HTMLMapElement.h"#include "HTMLNames.h"#include "HitTestResult.h"#include "Page.h"#include "RenderView.h"#include <wtf/CurrentTime.h>#if ENABLE(WML)#include "WMLImageElement.h"#include "WMLNames.h"#endifusing namespace std;namespace WebCore {static const double cInterpolationCutoff = 800. * 800.;static const double cLowQualityTimeThreshold = 0.050; // 50 msclass RenderImageScaleData {public: RenderImageScaleData(RenderImage* image, const IntSize& size, double time, bool lowQualityScale) : m_size(size) , m_time(time) , m_lowQualityScale(lowQualityScale) , m_highQualityRepaintTimer(image, &RenderImage::highQualityRepaintTimerFired) { } ~RenderImageScaleData() { m_highQualityRepaintTimer.stop(); } const IntSize& size() const { return m_size; } double time() const { return m_time; } bool useLowQualityScale() const { return m_lowQualityScale; } Timer<RenderImage>& hiqhQualityRepaintTimer() { return m_highQualityRepaintTimer; } void setSize(const IntSize& s) { m_size = s; } void setTime(double t) { m_time = t; } void setUseLowQualityScale(bool b) { m_highQualityRepaintTimer.stop(); m_lowQualityScale = b; if (b) m_highQualityRepaintTimer.startOneShot(cLowQualityTimeThreshold); } private: IntSize m_size; double m_time; bool m_lowQualityScale; Timer<RenderImage> m_highQualityRepaintTimer;};class RenderImageScaleObserver{public: static bool shouldImagePaintAtLowQuality(RenderImage*, const IntSize&); static void imageDestroyed(RenderImage* image) { if (gImages) { RenderImageScaleData* data = gImages->take(image); delete data; if (gImages->size() == 0) { delete gImages; gImages = 0; } } } static void highQualityRepaintTimerFired(RenderImage* image) { RenderImageScaleObserver::imageDestroyed(image); image->repaint(); } static HashMap<RenderImage*, RenderImageScaleData*>* gImages;};bool RenderImageScaleObserver::shouldImagePaintAtLowQuality(RenderImage* image, const IntSize& 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() || !image->image()->isBitmapImage()) return false; // 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->image()->width(), image->image()->height()); // Look ourselves up in the hashtable. RenderImageScaleData* data = 0; if (gImages) data = gImages->get(image); if (imageSize == size) { // There is no scale in effect. If we had a scale in effect before, we can just delete this data. if (data) { gImages->remove(image); delete data; } 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 (image->document()->page()->inLowQualityImageInterpolationMode()) { double totalPixels = static_cast<double>(image->image()->width()) * static_cast<double>(image->image()->height()); if (totalPixels > cInterpolationCutoff) return true; } // If there is no data yet, we will paint the first scale at high quality and record the paint time in case a second scale happens // very soon. if (!data) { data = new RenderImageScaleData(image, size, currentTime(), false); if (!gImages) gImages = new HashMap<RenderImage*, RenderImageScaleData*>; gImages->set(image, data); return false; } // We are scaled, but we painted already at this size, so just keep using whatever mode we last painted with. if (data->size() == size) return data->useLowQualityScale(); // We have data and our size just changed. If this change happened quickly, go into low quality mode and then set a repaint // timer to paint in high quality mode. Otherwise it is ok to just paint in high quality mode. double newTime = currentTime(); data->setUseLowQualityScale(newTime - data->time() < cLowQualityTimeThreshold); data->setTime(newTime); data->setSize(size); return data->useLowQualityScale();}HashMap<RenderImage*, RenderImageScaleData*>* RenderImageScaleObserver::gImages = 0;void RenderImage::highQualityRepaintTimerFired(Timer<RenderImage>*){ RenderImageScaleObserver::highQualityRepaintTimerFired(this);}using namespace HTMLNames;RenderImage::RenderImage(Node* node) : RenderReplaced(node, IntSize(0, 0)) , m_cachedImage(0){ updateAltText(); view()->frameView()->setIsVisuallyNonEmpty();}RenderImage::~RenderImage(){ if (m_cachedImage) m_cachedImage->removeClient(this); RenderImageScaleObserver::imageDestroyed(this);}void RenderImage::setCachedImage(CachedImage* newImage){ if (m_cachedImage == newImage) return; if (m_cachedImage) m_cachedImage->removeClient(this); m_cachedImage = newImage; if (m_cachedImage) { m_cachedImage->addClient(this); if (m_cachedImage->errorOccurred()) imageChanged(m_cachedImage.get()); }}// If we'll be displaying either alt text or an image, add some padding.static const unsigned short paddingWidth = 4;static const unsigned short paddingHeight = 4;// Alt text is restricted to this maximum size, in pixels. These are// signed integers because they are compared with other signed values.static const int maxAltTextWidth = 1024;static const int maxAltTextHeight = 256;// Sets the image height and width to fit the alt text. Returns true if the// image size changed.bool RenderImage::setImageSizeForAltText(CachedImage* newImage /* = 0 */){ int imageWidth = 0; int imageHeight = 0; // If we'll be displaying either text or an image, add a little padding. if (!m_altText.isEmpty() || newImage) { imageWidth = paddingWidth; imageHeight = paddingHeight; } if (newImage) { // imageSize() returns 0 for the error image. We need the true size of the // error image, so we have to get it by grabbing image() directly. imageWidth += newImage->image()->width() * style()->effectiveZoom(); imageHeight += newImage->image()->height() * style()->effectiveZoom(); } // we have an alt and the user meant it (its not a text we invented) if (!m_altText.isEmpty()) { const Font& font = style()->font(); imageWidth = max(imageWidth, min(font.width(TextRun(m_altText.characters(), m_altText.length())), maxAltTextWidth)); imageHeight = max(imageHeight, min(font.height(), maxAltTextHeight)); } IntSize imageSize = IntSize(imageWidth, imageHeight); if (imageSize == intrinsicSize()) return false; setIntrinsicSize(imageSize); return true;}void RenderImage::imageChanged(WrappedImagePtr newImage, const IntRect* rect){ if (documentBeingDestroyed()) return; if (hasBoxDecorations() || hasMask()) RenderReplaced::imageChanged(newImage, rect); if (newImage != imagePtr() || !newImage) return; bool imageSizeChanged = false; // Set image dimensions, taking into account the size of the alt text. if (errorOccurred()) imageSizeChanged = setImageSizeForAltText(m_cachedImage.get()); bool shouldRepaint = true; // Image dimensions have been changed, see what needs to be done if (imageSize(style()->effectiveZoom()) != intrinsicSize() || imageSizeChanged) { if (!errorOccurred()) setIntrinsicSize(imageSize(style()->effectiveZoom())); // In the case of generated image content using :before/:after, we might not be in the // render tree yet. In that case, we don't need to worry about check for layout, since we'll get a // layout when we get added in to the render tree hierarchy later. if (containingBlock()) { // lets see if we need to relayout at all.. int oldwidth = width(); int oldheight = height(); if (!prefWidthsDirty()) setPrefWidthsDirty(true); calcWidth(); calcHeight();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -