Changeset 21686 in webkit


Ignore:
Timestamp:
May 23, 2007 6:01:02 PM (17 years ago)
Author:
andersca
Message:

Reviewed by Geoff.

<rdar://problem/3663808> Resize large images to fit in the browser window


  • WebCore.exp: Add new settings method.


  • loader/ImageDocument.cpp: (WebCore::ImageEventListener::ImageEventListener): New class that handles resize events and click events and forwards them to the image document.


(WebCore::ImageTokenizer::ImageTokenizer):
(WebCore::ImageTokenizer::writeRawData):
(WebCore::ImageTokenizer::finish):
(WebCore::ImageDocument::ImageDocument):
(WebCore::ImageDocument::createDocumentStructure):
(WebCore::ImageDocument::cachedImage):
Let the ImageDocument class keep track of its document structure.


(WebCore::ImageDocument::scale):
Returns the scale that should be used when resizing the image.


(WebCore::ImageDocument::resizeImage):
Update the image size.


(WebCore::ImageDocument::imageClicked):
Toggle between resized and not resized. When restoring the size, scroll the image so that the area under
the mouse stays the same.


(WebCore::ImageDocument::imageChanged):
When the image size is known, resize the image if needed.


(WebCore::ImageDocument::restoreImageSize):
Restore the image size.


(WebCore::ImageDocument::imageNeedsResizing):
Return whether the image is too big for its window or not.


(WebCore::ImageDocument::windowSizeChanged):
Called when the window's size changes. Determine if the window fits or not and resize it if it doesn't fit.


(WebCore::ImageEventListener::handleEvent):
Forward events to the image document.


  • page/Settings.cpp: (WebCore::Settings::Settings): (WebCore::Settings::setEnableAutomaticImageResizing):
  • page/Settings.h: (WebCore::Settings::enableAutomaticImageResizing): Add new setting.
Location:
trunk/WebCore
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/WebCore/ChangeLog

    r21685 r21686  
     12007-05-23  Anders Carlsson  <andersca@apple.com>
     2
     3        Reviewed by Geoff.
     4
     5        <rdar://problem/3663808> Resize large images to fit in the browser window
     6       
     7        * WebCore.exp:
     8        Add new settings method.
     9       
     10        * loader/ImageDocument.cpp:
     11        (WebCore::ImageEventListener::ImageEventListener):
     12        New class that handles resize events and click events and forwards them to the image document.
     13       
     14        (WebCore::ImageTokenizer::ImageTokenizer):
     15        (WebCore::ImageTokenizer::writeRawData):
     16        (WebCore::ImageTokenizer::finish):
     17        (WebCore::ImageDocument::ImageDocument):
     18        (WebCore::ImageDocument::createDocumentStructure):
     19        (WebCore::ImageDocument::cachedImage):
     20        Let the ImageDocument class keep track of its document structure.
     21       
     22        (WebCore::ImageDocument::scale):
     23        Returns the scale that should be used when resizing the image.
     24       
     25        (WebCore::ImageDocument::resizeImage):
     26        Update the image size.
     27       
     28        (WebCore::ImageDocument::imageClicked):
     29        Toggle between resized and not resized. When restoring the size, scroll the image so that the area under
     30        the mouse stays the same.
     31       
     32        (WebCore::ImageDocument::imageChanged):
     33        When the image size is known, resize the image if needed.
     34       
     35        (WebCore::ImageDocument::restoreImageSize):
     36        Restore the image size.
     37       
     38        (WebCore::ImageDocument::imageNeedsResizing):
     39        Return whether the image is too big for its window or not.
     40       
     41        (WebCore::ImageDocument::windowSizeChanged):
     42        Called when the window's size changes. Determine if the window fits or not and resize it if it doesn't fit.
     43       
     44        (WebCore::ImageEventListener::handleEvent):
     45        Forward events to the image document.
     46       
     47        * page/Settings.cpp:
     48        (WebCore::Settings::Settings):
     49        (WebCore::Settings::setEnableAutomaticImageResizing):
     50        * page/Settings.h:
     51        (WebCore::Settings::enableAutomaticImageResizing):
     52        Add new setting.
     53       
    1542007-05-23  Anders Carlsson  <andersca@apple.com>
    255
  • trunk/WebCore/WebCore.exp

    r21596 r21686  
    447447__ZN7WebCore8Settings26setDefaultTextEncodingNameERKNS_6StringE
    448448__ZN7WebCore8Settings27setLoadsImagesAutomaticallyEb
     449__ZN7WebCore8Settings31setShrinksStandaloneImagesToFitEb
    449450__ZN7WebCore8Settings34setNeedsAcrobatFrameReloadingQuirkEb
    450451__ZN7WebCore8Settings40setJavaScriptCanOpenWindowsAutomaticallyEb
  • trunk/WebCore/loader/ImageDocument.cpp

    r21179 r21686  
    2929#include "DocumentLoader.h"
    3030#include "Element.h"
     31#include "EventListener.h"
     32#include "EventNames.h"
    3133#include "Frame.h"
    3234#include "FrameLoader.h"
     35#include "FrameView.h"
    3336#include "HTMLImageElement.h"
    3437#include "HTMLNames.h"
     38#include "MouseEvent.h"
     39#include "Page.h"
    3540#include "SegmentedString.h"
     41#include "Settings.h"
    3642#include "Text.h"
    3743#include "XMLTokenizer.h"
     
    4147#endif
    4248
     49using std::min;
     50
    4351namespace WebCore {
    44    
     52
     53using namespace EventNames;
    4554using namespace HTMLNames;
     55
     56class ImageEventListener : public EventListener {
     57public:
     58    ImageEventListener(ImageDocument* doc) : m_doc(doc) { }
     59   
     60    virtual void handleEvent(Event*, bool isWindowEvent);
     61private:
     62    ImageDocument* m_doc;
     63};
    4664   
    4765class ImageTokenizer : public Tokenizer {
    4866public:
    49     ImageTokenizer(Document* doc) : m_doc(doc), m_imageElement(0) {}
     67    ImageTokenizer(ImageDocument* doc) : m_doc(doc) {}
    5068       
    5169    virtual bool write(const SegmentedString&, bool appendData);
     
    5573    virtual bool wantsRawData() const { return true; }
    5674    virtual bool writeRawData(const char* data, int len);
    57 
    58     void createDocumentStructure();
    5975private:
    60     Document* m_doc;
    61     HTMLImageElement* m_imageElement;
     76    ImageDocument* m_doc;
    6277};
    6378
     
    6883}
    6984
    70 void ImageTokenizer::createDocumentStructure()
    71 {
    72     ExceptionCode ec;
    73    
    74     RefPtr<Element> rootElement = m_doc->createElementNS(xhtmlNamespaceURI, "html", ec);
    75     m_doc->appendChild(rootElement, ec);
    76    
    77     RefPtr<Element> body = m_doc->createElementNS(xhtmlNamespaceURI, "body", ec);
    78     body->setAttribute(styleAttr, "margin: 0px;");
    79    
    80     rootElement->appendChild(body, ec);
    81    
    82     RefPtr<Element> imageElement = m_doc->createElementNS(xhtmlNamespaceURI, "img", ec);
    83    
    84     m_imageElement = static_cast<HTMLImageElement *>(imageElement.get());
    85     m_imageElement->setAttribute(styleAttr, "-webkit-user-select: none");       
    86     m_imageElement->setLoadManually(true);
    87     m_imageElement->setSrc(m_doc->URL());
    88    
    89     body->appendChild(imageElement, ec);   
    90 }
    91 
    9285bool ImageTokenizer::writeRawData(const char* data, int len)
    9386{
    94     if (!m_imageElement)
    95         createDocumentStructure();
    96 
    97     CachedImage* cachedImage = m_imageElement->cachedImage();
     87    CachedImage* cachedImage = m_doc->cachedImage();
    9888    cachedImage->data(m_doc->frame()->loader()->documentLoader()->mainResourceData(), false);
    9989
     90    m_doc->imageChanged();
     91   
    10092    return false;
    10193}
     
    10395void ImageTokenizer::finish()
    10496{
    105     if (!m_parserStopped && m_imageElement) {
    106         CachedImage* cachedImage = m_imageElement->cachedImage();
     97    if (!m_parserStopped && m_doc->imageElement()) {
     98        CachedImage* cachedImage = m_doc->cachedImage();
    10799        cachedImage->data(m_doc->frame()->loader()->documentLoader()->mainResourceData(), true);
    108100        cachedImage->finish();
     
    127119ImageDocument::ImageDocument(DOMImplementation* implementation, Frame* frame)
    128120    : HTMLDocument(implementation, frame)
    129 {
     121    , m_imageElement(0)
     122    , m_imageSizeIsKnown(false)
     123    , m_didShrinkImage(false)
     124    , m_shouldShrinkImage(true)
     125{
     126    setParseMode(Compat);
    130127}
    131128   
     
    134131    return new ImageTokenizer(this);
    135132}
    136    
    137 }
     133
     134void ImageDocument::createDocumentStructure()
     135{
     136    ExceptionCode ec;
     137   
     138    RefPtr<Element> rootElement = createElementNS(xhtmlNamespaceURI, "html", ec);
     139    appendChild(rootElement, ec);
     140   
     141    RefPtr<Element> body = createElementNS(xhtmlNamespaceURI, "body", ec);
     142    body->setAttribute(styleAttr, "margin: 0px;");
     143   
     144    rootElement->appendChild(body, ec);
     145   
     146    RefPtr<Element> imageElement = createElementNS(xhtmlNamespaceURI, "img", ec);
     147   
     148    m_imageElement = static_cast<HTMLImageElement *>(imageElement.get());
     149    m_imageElement->setAttribute(styleAttr, "-webkit-user-select: none");       
     150    m_imageElement->setLoadManually(true);
     151    m_imageElement->setSrc(URL());
     152   
     153    body->appendChild(imageElement, ec);
     154   
     155    if (!frame()->page()->settings()->shrinksStandaloneImagesToFit())
     156        return;
     157   
     158    // Add event listeners
     159    RefPtr<EventListener> listener = new ImageEventListener(this);
     160    addWindowEventListener("resize", listener, false);
     161    m_imageElement->addEventListener("click", listener.release(), false);
     162}
     163
     164float ImageDocument::scale() const
     165{
     166    IntSize imageSize = m_imageElement->cachedImage()->imageSize();
     167    IntSize windowSize = IntSize(frame()->view()->width(), frame()->view()->height());
     168   
     169    float widthScale = (float)windowSize.width() / imageSize.width();
     170    float heightScale = (float)windowSize.height() / imageSize.height();
     171
     172    return min(widthScale, heightScale);
     173}
     174
     175void ImageDocument::resizeImageToFit()
     176{
     177    IntSize imageSize = m_imageElement->cachedImage()->imageSize();
     178
     179    float scale = this->scale();
     180    m_imageElement->setWidth(imageSize.width() * scale);
     181    m_imageElement->setHeight(imageSize.height() * scale);
     182}
     183
     184void ImageDocument::imageClicked(int x, int y)
     185{
     186    if (!m_imageSizeIsKnown || imageFitsInWindow())
     187        return;
     188
     189    m_shouldShrinkImage = !m_shouldShrinkImage;
     190   
     191    if (m_shouldShrinkImage)
     192        windowSizeChanged();
     193    else {
     194        restoreImageSize();
     195       
     196        updateLayout();
     197       
     198        float scale = this->scale();
     199       
     200        int scrollX = x / scale - (float)frame()->view()->width() / 2;
     201        int scrollY = y / scale - (float)frame()->view()->height() / 2;
     202       
     203        frame()->view()->setContentsPos(scrollX, scrollY);
     204    }
     205}
     206
     207void ImageDocument::imageChanged()
     208{
     209    ASSERT(m_imageElement);
     210   
     211    if (m_imageSizeIsKnown)
     212        return;
     213
     214    if (m_imageElement->cachedImage()->imageSize().isEmpty())
     215        return;
     216   
     217    m_imageSizeIsKnown = true;
     218   
     219    if (!frame()->page()->settings()->shrinksStandaloneImagesToFit())
     220        return;
     221   
     222    // Force resizing of the image
     223    windowSizeChanged();
     224}
     225
     226void ImageDocument::restoreImageSize()
     227{
     228    if (!m_imageSizeIsKnown)
     229        return;
     230   
     231    m_imageElement->setWidth(m_imageElement->cachedImage()->imageSize().width());
     232    m_imageElement->setHeight(m_imageElement->cachedImage()->imageSize().height());
     233   
     234    m_didShrinkImage = false;
     235}
     236
     237bool ImageDocument::imageFitsInWindow() const
     238{
     239    IntSize imageSize = m_imageElement->cachedImage()->imageSize();
     240    IntSize windowSize = IntSize(frame()->view()->width(), frame()->view()->height());
     241   
     242    return imageSize.width() <= windowSize.width() && imageSize.height() <= windowSize.height();   
     243}
     244
     245void ImageDocument::windowSizeChanged()
     246{
     247    if (!m_imageSizeIsKnown || !m_shouldShrinkImage)
     248        return;
     249
     250    bool fitsInWindow = imageFitsInWindow();
     251   
     252    if (m_didShrinkImage) {
     253        // If the window has been resized so that the image fits, restore the image size
     254        // otherwise update the restored image size.
     255        if (fitsInWindow)
     256            restoreImageSize();
     257        else
     258            resizeImageToFit();
     259    } else {
     260        // If the image isn't resized but needs to be, then resize it.
     261        if (!fitsInWindow) {
     262            resizeImageToFit();
     263            m_didShrinkImage = true;
     264        }
     265    }
     266}
     267
     268CachedImage* ImageDocument::cachedImage()
     269{
     270    if (!m_imageElement)
     271        createDocumentStructure();
     272   
     273    return m_imageElement->cachedImage();
     274}
     275
     276void ImageEventListener::handleEvent(Event* event, bool isWindowEvent)
     277{
     278    if (event->type() == resizeEvent)
     279        m_doc->windowSizeChanged();
     280    else if (event->type() == clickEvent) {
     281        MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
     282        m_doc->imageClicked(mouseEvent->x(), mouseEvent->y());
     283    }
     284}
     285
     286}
  • trunk/WebCore/loader/ImageDocument.h

    r21179 r21686  
    3131class DOMImplementation;
    3232class FrameView;
    33    
     33class HTMLImageElement;
     34
    3435class ImageDocument : public HTMLDocument
    3536{
     
    4041   
    4142    virtual Tokenizer* createTokenizer();
     43   
     44    CachedImage* cachedImage();
     45    HTMLImageElement* imageElement() const { return m_imageElement; }
     46   
     47    void windowSizeChanged();
     48    void imageChanged();
     49    void imageClicked(int x, int y);
     50private:
     51    void createDocumentStructure();
     52    void resizeImageToFit();
     53    void restoreImageSize();
     54    bool imageFitsInWindow() const;
     55    float scale() const;
     56   
     57    HTMLImageElement* m_imageElement;
     58   
     59    // Whether enough of the image has been loaded to determine its size
     60    bool m_imageSizeIsKnown;
     61   
     62    // Whether the image is shrunk to fit or not
     63    bool m_didShrinkImage;
     64   
     65    // Whether the image should be shrunk or not
     66    bool m_shouldShrinkImage;
    4267};
    4368   
  • trunk/WebCore/page/Settings.cpp

    r20820 r21686  
    4747    , m_usesDashboardBackwardCompatibilityMode(false)
    4848    , m_needsAcrobatFrameReloadingQuirk(false)
     49    , m_shrinksStandaloneImagesToFit(true)
    4950{
    5051    // A Frame may not have been created yet, so we initialize the AtomicString
     
    224225}
    225226
     227void Settings::setShrinksStandaloneImagesToFit(bool shrinksStandaloneImagesToFit)
     228{
     229    m_shrinksStandaloneImagesToFit = shrinksStandaloneImagesToFit;
     230}
     231
    226232} // namespace WebCore
  • trunk/WebCore/page/Settings.h

    r20820 r21686  
    118118        bool isDOMPasteAllowed() const { return m_isDOMPasteAllowed; }
    119119       
     120        void setShrinksStandaloneImagesToFit(bool);
     121        bool shrinksStandaloneImagesToFit() const { return m_shrinksStandaloneImagesToFit; }
     122       
    120123    private:
    121124        String m_defaultTextEncodingName;
     
    142145        bool m_usesDashboardBackwardCompatibilityMode : 1;
    143146        bool m_needsAcrobatFrameReloadingQuirk : 1;
    144         bool m_isDOMPasteAllowed: 1;
     147        bool m_isDOMPasteAllowed : 1;
     148        bool m_shrinksStandaloneImagesToFit : 1;
    145149    };
    146150
Note: See TracChangeset for help on using the changeset viewer.