Changeset 49394 in webkit
- Timestamp:
- Oct 9, 2009 10:03:48 AM (15 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 11 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/WebCore/ChangeLog
r49393 r49394 1 2009-10-08 Dave Hyatt <hyatt@apple.com> 2 3 Reviewed by Adam Roben. 4 5 Implement beforeload for images. ImageLoadEventSender has been refactored into a more generic 6 ImageEventSender that can be used by both load and beforeload events. If the document has any 7 beforeload listeners, then the installation of images onto the renderer becomes asynchronous 8 and will be held up until the beforeload event can fire at a later date. 9 10 Both beforeload and load events now fire at the end of the tokenizer write() methods, so that 11 in the typical parsing case we don't have to put off the beforeload/load events until after 12 a layout or paint might already have happened. This lets beforeload/load not cause extra 13 layouts and repaints. 14 15 * dom/ContainerNode.cpp: 16 (WebCore::ContainerNode::dispatchBeforeLoadEvent): 17 * dom/Document.cpp: 18 (WebCore::Document::implicitClose): 19 (WebCore::Document::addListenerTypeIfNeeded): 20 * dom/Document.h: 21 (WebCore::Document::): 22 * dom/XMLTokenizer.cpp: 23 (WebCore::XMLTokenizer::write): 24 * html/HTMLImageElement.cpp: 25 (WebCore::HTMLImageElement::attach): 26 * html/HTMLInputElement.cpp: 27 (WebCore::HTMLInputElement::attach): 28 * html/HTMLTokenizer.cpp: 29 (WebCore::HTMLTokenizer::write): 30 * loader/ImageLoader.cpp: 31 (WebCore::ImageBeforeLoadEventSender::ImageBeforeLoadEventSender): 32 (WebCore::ImageLoadEventSender::ImageLoadEventSender): 33 (WebCore::beforeLoadEventSender): 34 (WebCore::ImageLoader::ImageLoader): 35 (WebCore::ImageLoader::~ImageLoader): 36 (WebCore::ImageLoader::setImage): 37 (WebCore::ImageLoader::setLoadingImage): 38 (WebCore::ImageLoader::updateFromElement): 39 (WebCore::ImageLoader::notifyFinished): 40 (WebCore::ImageLoader::dispatchPendingBeforeLoadEvent): 41 (WebCore::ImageLoader::dispatchPendingEvents): 42 (WebCore::ImageEventSender::ImageEventSender): 43 (WebCore::ImageEventSender::dispatchEventSoon): 44 (WebCore::ImageEventSender::cancelEvent): 45 (WebCore::ImageEventSender::dispatchPendingEvents): 46 (WebCore::ImageEventSender::timerFired): 47 * loader/ImageLoader.h: 48 (WebCore::ImageLoader::haveFiredBeforeLoadEvent): 49 * wml/WMLImageElement.cpp: 50 (WebCore::WMLImageElement::attach): 51 1 52 2009-10-09 Pavel Feldman <pfeldman@chromium.org> 2 53 -
trunk/WebCore/dom/ContainerNode.cpp
r49313 r49394 913 913 bool ContainerNode::dispatchBeforeLoadEvent(const String& sourceURL) 914 914 { 915 if (!document()->hasListenerType(Document::BEFORELOAD_LISTENER)) 916 return true; 917 915 918 RefPtr<ContainerNode> protector(this); 916 919 RefPtr<BeforeLoadEvent> beforeLoadEvent = BeforeLoadEvent::create(sourceURL); -
trunk/WebCore/dom/Document.cpp
r49211 r49394 1712 1712 f->animation()->resumeAnimations(this); 1713 1713 1714 ImageLoader::dispatchPending LoadEvents();1714 ImageLoader::dispatchPendingEvents(); 1715 1715 dispatchWindowLoadEvent(); 1716 1716 dispatchWindowEvent(PageTransitionEvent::create(eventNames().pageshowEvent, false), this); … … 2961 2961 else if (eventType == eventNames().webkitTransitionEndEvent) 2962 2962 addListenerType(TRANSITIONEND_LISTENER); 2963 else if (eventType == eventNames().beforeloadEvent) 2964 addListenerType(BEFORELOAD_LISTENER); 2963 2965 } 2964 2966 -
trunk/WebCore/dom/Document.h
r48826 r49394 616 616 ANIMATIONSTART_LISTENER = 0x200, 617 617 ANIMATIONITERATION_LISTENER = 0x400, 618 TRANSITIONEND_LISTENER = 0x800 618 TRANSITIONEND_LISTENER = 0x800, 619 BEFORELOAD_LISTENER = 0x1000 619 620 }; 620 621 -
trunk/WebCore/dom/XMLTokenizer.cpp
r49372 r49394 41 41 #include "HTMLNames.h" 42 42 #include "HTMLStyleElement.h" 43 #include "ImageLoader.h" 43 44 #include "ProcessingInstruction.h" 44 45 #include "ResourceError.h" … … 106 107 107 108 doWrite(s.toString()); 109 110 // After parsing, go ahead and dispatch image beforeload/load events. 111 ImageLoader::dispatchPendingEvents(); 108 112 } 109 113 -
trunk/WebCore/html/HTMLImageElement.cpp
r47367 r49394 119 119 else if (attrName == onloadAttr) 120 120 setAttributeEventListener(eventNames().loadEvent, createAttributeEventListener(this, attr)); 121 else if (attrName == onbeforeloadAttr) 122 setAttributeEventListener(eventNames().beforeloadEvent, createAttributeEventListener(this, attr)); 121 123 else if (attrName == compositeAttr) { 122 124 if (!parseCompositeOperator(attr->value(), m_compositeOperator)) … … 168 170 HTMLElement::attach(); 169 171 170 if (renderer() && renderer()->isImage() ) {172 if (renderer() && renderer()->isImage() && m_imageLoader.haveFiredBeforeLoadEvent()) { 171 173 RenderImage* imageObj = toRenderImage(renderer()); 172 174 if (imageObj->hasImage()) -
trunk/WebCore/html/HTMLInputElement.cpp
r49199 r49394 863 863 m_imageLoader.set(new HTMLImageLoader(this)); 864 864 m_imageLoader->updateFromElement(); 865 if (renderer() ) {865 if (renderer() && m_imageLoader->haveFiredBeforeLoadEvent()) { 866 866 RenderImage* imageObj = toRenderImage(renderer()); 867 867 imageObj->setCachedImage(m_imageLoader->image()); -
trunk/WebCore/html/HTMLTokenizer.cpp
r49372 r49394 44 44 #include "HTMLScriptElement.h" 45 45 #include "HTMLViewSourceDocument.h" 46 #include "ImageLoader.h" 46 47 #include "InspectorTimelineAgent.h" 47 48 #include "MappedAttribute.h" … … 1803 1804 if (m_noMoreData && !m_inWrite && !state.loadingExtScript() && !m_executingScript && !m_timer.isActive()) 1804 1805 end(); // this actually causes us to be deleted 1806 1807 // After parsing, go ahead and dispatch image beforeload/load events. 1808 ImageLoader::dispatchPendingEvents(); 1805 1809 } 1806 1810 -
trunk/WebCore/loader/ImageLoader.cpp
r42002 r49394 32 32 namespace WebCore { 33 33 34 class Image LoadEventSender {34 class ImageEventSender { 35 35 public: 36 Image LoadEventSender();37 38 void dispatch LoadEventSoon(ImageLoader*);39 void cancel LoadEvent(ImageLoader*);40 41 void dispatchPending LoadEvents();36 ImageEventSender(const AtomicString& eventType); 37 38 void dispatchEventSoon(ImageLoader*); 39 void cancelEvent(ImageLoader*); 40 41 void dispatchPendingEvents(); 42 42 43 43 private: 44 ~ImageLoadEventSender(); 45 46 void timerFired(Timer<ImageLoadEventSender>*); 47 48 Timer<ImageLoadEventSender> m_timer; 44 void timerFired(Timer<ImageEventSender>*); 45 46 AtomicString m_eventType; 47 Timer<ImageEventSender> m_timer; 49 48 Vector<ImageLoader*> m_dispatchSoonList; 50 49 Vector<ImageLoader*> m_dispatchingList; 51 50 }; 52 51 53 static ImageLoadEventSender& loadEventSender() 54 { 55 DEFINE_STATIC_LOCAL(ImageLoadEventSender, sender, ()); 52 static ImageEventSender& beforeLoadEventSender() 53 { 54 DEFINE_STATIC_LOCAL(ImageEventSender, sender, (eventNames().beforeloadEvent)); 55 return sender; 56 } 57 58 static ImageEventSender& loadEventSender() 59 { 60 DEFINE_STATIC_LOCAL(ImageEventSender, sender, (eventNames().loadEvent)); 56 61 return sender; 57 62 } … … 60 65 : m_element(element) 61 66 , m_image(0) 67 , m_firedBeforeLoad(true) 62 68 , m_firedLoad(true) 63 69 , m_imageComplete(true) … … 70 76 if (m_image) 71 77 m_image->removeClient(this); 72 loadEventSender().cancelLoadEvent(this); 78 if (!m_firedBeforeLoad) 79 beforeLoadEventSender().cancelEvent(this); 80 if (!m_firedLoad) 81 loadEventSender().cancelEvent(this); 73 82 } 74 83 … … 79 88 if (newImage != oldImage) { 80 89 setLoadingImage(newImage); 90 m_firedBeforeLoad = true; 81 91 m_firedLoad = true; 82 92 m_imageComplete = true; … … 90 100 if (!renderer->isImage()) 91 101 return; 92 93 102 toRenderImage(renderer)->resetAnimation(); 94 103 } … … 97 106 void ImageLoader::setLoadingImage(CachedImage* loadingImage) 98 107 { 99 m_firedLoad = false;100 m_imageComplete = false;101 108 m_image = loadingImage; 109 m_firedBeforeLoad = !loadingImage; 110 m_firedLoad = !loadingImage; 111 m_imageComplete = !loadingImage; 102 112 } 103 113 … … 138 148 if (newImage != oldImage) { 139 149 setLoadingImage(newImage); 140 if (newImage) 150 if (newImage) { 141 151 newImage->addClient(this); 152 if (!m_element->document()->hasListenerType(Document::BEFORELOAD_LISTENER)) 153 dispatchPendingBeforeLoadEvent(); 154 else 155 beforeLoadEventSender().dispatchEventSoon(this); 156 } 142 157 if (oldImage) 143 158 oldImage->removeClient(this); … … 147 162 if (!renderer->isImage()) 148 163 return; 149 150 164 toRenderImage(renderer)->resetAnimation(); 151 165 } … … 162 176 { 163 177 ASSERT(m_failedLoadURL.isEmpty()); 178 164 179 m_imageComplete = true; 165 166 loadEventSender().dispatchLoadEventSoon(this); 167 180 if (haveFiredBeforeLoadEvent()) 181 updateRenderer(); 182 183 loadEventSender().dispatchEventSoon(this); 184 } 185 186 void ImageLoader::updateRenderer() 187 { 168 188 if (RenderObject* renderer = m_element->renderer()) { 169 189 if (!renderer->isImage()) 170 190 return; 171 172 toRenderImage(renderer)->setCachedImage(m_image.get()); 173 } 191 RenderImage* imageRenderer = toRenderImage(renderer); 192 193 // Only update the renderer if it doesn't have an image or if what we have 194 // is a complete image. This prevents flickering in the case where a dynamic 195 // change is happening between two images. 196 CachedImage* cachedImage = imageRenderer->cachedImage(); 197 if (m_image != cachedImage && (m_imageComplete || !imageRenderer->cachedImage())) 198 imageRenderer->setCachedImage(m_image.get()); 199 } 200 } 201 202 void ImageLoader::dispatchPendingBeforeLoadEvent() 203 { 204 if (m_firedBeforeLoad) 205 return; 206 if (!m_image) 207 return; 208 if (!m_element->document()->attached()) 209 return; 210 m_firedBeforeLoad = true; 211 if (m_element->dispatchBeforeLoadEvent(m_image->url())) { 212 updateRenderer(); 213 return; 214 } 215 if (m_image) { 216 m_image->removeClient(this); 217 m_image = 0; 218 } 219 loadEventSender().cancelEvent(this); 174 220 } 175 221 … … 186 232 } 187 233 188 void ImageLoader::dispatchPendingLoadEvents() 189 { 190 loadEventSender().dispatchPendingLoadEvents(); 191 } 192 193 ImageLoadEventSender::ImageLoadEventSender() 194 : m_timer(this, &ImageLoadEventSender::timerFired) 195 { 196 } 197 198 void ImageLoadEventSender::dispatchLoadEventSoon(ImageLoader* loader) 234 void ImageLoader::dispatchPendingEvents() 235 { 236 beforeLoadEventSender().dispatchPendingEvents(); 237 loadEventSender().dispatchPendingEvents(); 238 } 239 240 ImageEventSender::ImageEventSender(const AtomicString& eventType) 241 : m_eventType(eventType) 242 , m_timer(this, &ImageEventSender::timerFired) 243 { 244 } 245 246 void ImageEventSender::dispatchEventSoon(ImageLoader* loader) 199 247 { 200 248 m_dispatchSoonList.append(loader); … … 203 251 } 204 252 205 void Image LoadEventSender::cancelLoadEvent(ImageLoader* loader)253 void ImageEventSender::cancelEvent(ImageLoader* loader) 206 254 { 207 255 // Remove instances of this loader from both lists. … … 221 269 } 222 270 223 void Image LoadEventSender::dispatchPendingLoadEvents()271 void ImageEventSender::dispatchPendingEvents() 224 272 { 225 273 // Need to avoid re-entering this function; if new dispatches are … … 234 282 size_t size = m_dispatchingList.size(); 235 283 for (size_t i = 0; i < size; ++i) { 236 if (ImageLoader* loader = m_dispatchingList[i]) 237 loader->dispatchPendingLoadEvent(); 284 if (ImageLoader* loader = m_dispatchingList[i]) { 285 if (m_eventType == eventNames().beforeloadEvent) 286 loader->dispatchPendingBeforeLoadEvent(); 287 else 288 loader->dispatchPendingLoadEvent(); 289 } 238 290 } 239 291 m_dispatchingList.clear(); 240 292 } 241 293 242 void Image LoadEventSender::timerFired(Timer<ImageLoadEventSender>*)243 { 244 dispatchPending LoadEvents();245 } 246 247 } 294 void ImageEventSender::timerFired(Timer<ImageEventSender>*) 295 { 296 dispatchPendingEvents(); 297 } 298 299 } -
trunk/WebCore/loader/ImageLoader.h
r41766 r49394 54 54 void setLoadManually(bool loadManually) { m_loadManually = loadManually; } 55 55 56 bool haveFiredBeforeLoadEvent() const { return m_firedBeforeLoad; } 56 57 bool haveFiredLoadEvent() const { return m_firedLoad; } 57 58 58 static void dispatchPending LoadEvents();59 static void dispatchPendingEvents(); 59 60 60 61 protected: … … 65 66 virtual String sourceURI(const AtomicString&) const = 0; 66 67 67 friend class ImageLoadEventSender; 68 friend class ImageEventSender; 69 void dispatchPendingBeforeLoadEvent(); 68 70 void dispatchPendingLoadEvent(); 69 71 70 72 void setLoadingImage(CachedImage*); 71 73 74 void updateRenderer(); 75 72 76 Element* m_element; 73 77 CachedResourceHandle<CachedImage> m_image; 74 78 AtomicString m_failedLoadURL; 79 bool m_firedBeforeLoad : 1; 75 80 bool m_firedLoad : 1; 76 81 bool m_imageComplete : 1; -
trunk/WebCore/wml/WMLImageElement.cpp
r43310 r49394 95 95 WMLElement::attach(); 96 96 97 if (renderer() && renderer()->isImage() ) {97 if (renderer() && renderer()->isImage() && m_imageLoader.haveFiredBeforeLoadEvent()) { 98 98 RenderImage* imageObj = toRenderImage(renderer()); 99 99 if (imageObj->hasImage()) 100 100 return; 101 102 101 imageObj->setCachedImage(m_imageLoader.image()); 103 102 104 103 // If we have no image at all because we have no src attribute, set 105 104 // image height and width for the alt text instead.
Note: See TracChangeset
for help on using the changeset viewer.