| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) | |
| 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) | |
| 4 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2010 Apple Inc. All rights reserv
ed. | |
| 5 * Copyright (C) 2010 Google Inc. All rights reserved. | |
| 6 * | |
| 7 * This library is free software; you can redistribute it and/or | |
| 8 * modify it under the terms of the GNU Library General Public | |
| 9 * License as published by the Free Software Foundation; either | |
| 10 * version 2 of the License, or (at your option) any later version. | |
| 11 * | |
| 12 * This library is distributed in the hope that it will be useful, | |
| 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 15 * Library General Public License for more details. | |
| 16 * | |
| 17 * You should have received a copy of the GNU Library General Public License | |
| 18 * along with this library; see the file COPYING.LIB. If not, write to | |
| 19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | |
| 20 * Boston, MA 02110-1301, USA. | |
| 21 */ | |
| 22 | |
| 23 #include "sky/engine/core/html/HTMLImageElement.h" | |
| 24 | |
| 25 #include "gen/sky/core/CSSPropertyNames.h" | |
| 26 #include "gen/sky/core/HTMLNames.h" | |
| 27 #include "gen/sky/core/MediaTypeNames.h" | |
| 28 #include "gen/sky/platform/RuntimeEnabledFeatures.h" | |
| 29 #include "sky/engine/core/css/MediaQueryListListener.h" | |
| 30 #include "sky/engine/core/css/MediaQueryMatcher.h" | |
| 31 #include "sky/engine/core/css/MediaValuesDynamic.h" | |
| 32 #include "sky/engine/core/dom/Attribute.h" | |
| 33 #include "sky/engine/core/dom/NodeTraversal.h" | |
| 34 #include "sky/engine/core/fetch/ImageResource.h" | |
| 35 #include "sky/engine/core/html/HTMLAnchorElement.h" | |
| 36 #include "sky/engine/core/html/parser/HTMLParserIdioms.h" | |
| 37 #include "sky/engine/core/html/parser/HTMLSrcsetParser.h" | |
| 38 #include "sky/engine/core/inspector/ConsoleMessage.h" | |
| 39 #include "sky/engine/core/rendering/RenderImage.h" | |
| 40 #include "sky/engine/platform/MIMETypeRegistry.h" | |
| 41 | |
| 42 namespace blink { | |
| 43 | |
| 44 class HTMLImageElement::ViewportChangeListener final : public MediaQueryListList
ener { | |
| 45 public: | |
| 46 static RefPtr<ViewportChangeListener> create(HTMLImageElement* element) | |
| 47 { | |
| 48 return adoptRef(new ViewportChangeListener(element)); | |
| 49 } | |
| 50 | |
| 51 virtual void notifyMediaQueryChanged() override | |
| 52 { | |
| 53 if (m_element) | |
| 54 m_element->notifyViewportChanged(); | |
| 55 } | |
| 56 | |
| 57 void clearElement() { m_element = nullptr; } | |
| 58 | |
| 59 private: | |
| 60 explicit ViewportChangeListener(HTMLImageElement* element) : m_element(eleme
nt) { } | |
| 61 RawPtr<HTMLImageElement> m_element; | |
| 62 }; | |
| 63 | |
| 64 HTMLImageElement::HTMLImageElement(Document& document, bool createdByParser) | |
| 65 : HTMLElement(HTMLNames::imgTag, document) | |
| 66 , m_imageLoader(HTMLImageLoader::create(this)) | |
| 67 , m_imageDevicePixelRatio(1.0f) | |
| 68 , m_elementCreatedByParser(createdByParser) | |
| 69 , m_intrinsicSizingViewportDependant(false) | |
| 70 , m_effectiveSizeViewportDependant(false) | |
| 71 { | |
| 72 } | |
| 73 | |
| 74 PassRefPtr<HTMLImageElement> HTMLImageElement::create(Document& document) | |
| 75 { | |
| 76 return adoptRef(new HTMLImageElement(document)); | |
| 77 } | |
| 78 | |
| 79 PassRefPtr<HTMLImageElement> HTMLImageElement::create(Document& document, bool c
reatedByParser) | |
| 80 { | |
| 81 return adoptRef(new HTMLImageElement(document, createdByParser)); | |
| 82 } | |
| 83 | |
| 84 HTMLImageElement::~HTMLImageElement() | |
| 85 { | |
| 86 #if !ENABLE(OILPAN) | |
| 87 if (m_listener) { | |
| 88 document().mediaQueryMatcher().removeViewportListener(m_listener.get()); | |
| 89 m_listener->clearElement(); | |
| 90 } | |
| 91 #endif | |
| 92 } | |
| 93 | |
| 94 void HTMLImageElement::notifyViewportChanged() | |
| 95 { | |
| 96 // Re-selecting the source URL in order to pick a more fitting resource | |
| 97 // And update the image's intrinsic dimensions when the viewport changes. | |
| 98 // Picking of a better fitting resource is UA dependant, not spec required. | |
| 99 selectSourceURL(ImageLoader::UpdateSizeChanged); | |
| 100 } | |
| 101 | |
| 102 PassRefPtr<HTMLImageElement> HTMLImageElement::createForJSConstructor(Document&
document, int width, int height) | |
| 103 { | |
| 104 RefPtr<HTMLImageElement> image = adoptRef(new HTMLImageElement(document)); | |
| 105 if (width) | |
| 106 image->setWidth(width); | |
| 107 if (height) | |
| 108 image->setHeight(height); | |
| 109 image->m_elementCreatedByParser = false; | |
| 110 return image.release(); | |
| 111 } | |
| 112 | |
| 113 const AtomicString HTMLImageElement::imageSourceURL() const | |
| 114 { | |
| 115 return m_bestFitImageURL.isNull() ? getAttribute(HTMLNames::srcAttr) : m_bes
tFitImageURL; | |
| 116 } | |
| 117 | |
| 118 void HTMLImageElement::setBestFitURLAndDPRFromImageCandidate(const ImageCandidat
e& candidate) | |
| 119 { | |
| 120 m_bestFitImageURL = candidate.url(); | |
| 121 float candidateDensity = candidate.density(); | |
| 122 if (candidateDensity >= 0) | |
| 123 m_imageDevicePixelRatio = 1.0 / candidateDensity; | |
| 124 if (candidate.resourceWidth() > 0) | |
| 125 m_intrinsicSizingViewportDependant = true; | |
| 126 if (renderer() && renderer()->isImage()) | |
| 127 toRenderImage(renderer())->setImageDevicePixelRatio(m_imageDevicePixelRa
tio); | |
| 128 } | |
| 129 | |
| 130 void HTMLImageElement::parseAttribute(const QualifiedName& name, const AtomicStr
ing& value) | |
| 131 { | |
| 132 if (name == HTMLNames::srcAttr) { | |
| 133 selectSourceURL(ImageLoader::UpdateIgnorePreviousError); | |
| 134 } else { | |
| 135 HTMLElement::parseAttribute(name, value); | |
| 136 } | |
| 137 } | |
| 138 | |
| 139 RenderObject* HTMLImageElement::createRenderer(RenderStyle* style) | |
| 140 { | |
| 141 RenderImage* image = new RenderImage(this); | |
| 142 image->setImageResource(RenderImageResource::create()); | |
| 143 image->setImageDevicePixelRatio(m_imageDevicePixelRatio); | |
| 144 | |
| 145 RenderImageResource* imageResource = image->imageResource(); | |
| 146 if (cachedImage() || imageResource->cachedImage()) | |
| 147 imageResource->setImageResource(cachedImage()); | |
| 148 | |
| 149 return image; | |
| 150 } | |
| 151 | |
| 152 bool HTMLImageElement::canStartSelection() const | |
| 153 { | |
| 154 if (shadow()) | |
| 155 return HTMLElement::canStartSelection(); | |
| 156 | |
| 157 return false; | |
| 158 } | |
| 159 | |
| 160 void HTMLImageElement::insertedInto(ContainerNode* insertionPoint) | |
| 161 { | |
| 162 HTMLElement::insertedInto(insertionPoint); | |
| 163 | |
| 164 if (m_listener) | |
| 165 document().mediaQueryMatcher().addViewportListener(m_listener.get()); | |
| 166 | |
| 167 // If we have been inserted from a renderer-less document, | |
| 168 // our loader may have not fetched the image, so do it now. | |
| 169 if ((insertionPoint->inDocument() && !imageLoader().image())) | |
| 170 imageLoader().updateFromElement(ImageLoader::UpdateNormal, m_elementCrea
tedByParser ? ImageLoader::ForceLoadImmediately : ImageLoader::LoadNormally); | |
| 171 } | |
| 172 | |
| 173 void HTMLImageElement::removedFrom(ContainerNode* insertionPoint) | |
| 174 { | |
| 175 if (m_listener) | |
| 176 document().mediaQueryMatcher().removeViewportListener(m_listener.get()); | |
| 177 HTMLElement::removedFrom(insertionPoint); | |
| 178 } | |
| 179 | |
| 180 int HTMLImageElement::naturalWidth() const | |
| 181 { | |
| 182 if (!imageLoader().image()) | |
| 183 return 0; | |
| 184 | |
| 185 return imageLoader().image()->imageSizeForRenderer(renderer(), ImageResource
::IntrinsicSize).width(); | |
| 186 } | |
| 187 | |
| 188 int HTMLImageElement::naturalHeight() const | |
| 189 { | |
| 190 if (!imageLoader().image()) | |
| 191 return 0; | |
| 192 | |
| 193 return imageLoader().image()->imageSizeForRenderer(renderer(), ImageResource
::IntrinsicSize).height(); | |
| 194 } | |
| 195 | |
| 196 const String& HTMLImageElement::currentSrc() const | |
| 197 { | |
| 198 // http://www.whatwg.org/specs/web-apps/current-work/multipage/edits.html#do
m-img-currentsrc | |
| 199 // The currentSrc IDL attribute must return the img element's current reques
t's current URL. | |
| 200 // Initially, the pending request turns into current request when it is eith
er available or broken. | |
| 201 // We use the image's dimensions as a proxy to it being in any of these stat
es. | |
| 202 if (!imageLoader().image() || !imageLoader().image()->image() || !imageLoade
r().image()->image()->width()) | |
| 203 return emptyAtom; | |
| 204 | |
| 205 return imageLoader().image()->url().string(); | |
| 206 } | |
| 207 | |
| 208 bool HTMLImageElement::isURLAttribute(const Attribute& attribute) const | |
| 209 { | |
| 210 return attribute.name() == HTMLNames::srcAttr | |
| 211 || HTMLElement::isURLAttribute(attribute); | |
| 212 } | |
| 213 | |
| 214 KURL HTMLImageElement::src() const | |
| 215 { | |
| 216 return document().completeURL(getAttribute(HTMLNames::srcAttr)); | |
| 217 } | |
| 218 | |
| 219 void HTMLImageElement::setSrc(const String& value) | |
| 220 { | |
| 221 setAttribute(HTMLNames::srcAttr, AtomicString(value)); | |
| 222 } | |
| 223 | |
| 224 bool HTMLImageElement::complete() const | |
| 225 { | |
| 226 return imageLoader().imageComplete(); | |
| 227 } | |
| 228 | |
| 229 void HTMLImageElement::didMoveToNewDocument(Document& oldDocument) | |
| 230 { | |
| 231 imageLoader().elementDidMoveToNewDocument(); | |
| 232 HTMLElement::didMoveToNewDocument(oldDocument); | |
| 233 } | |
| 234 | |
| 235 void HTMLImageElement::selectSourceURL(ImageLoader::UpdateFromElementBehavior be
havior) | |
| 236 { | |
| 237 unsigned effectiveSize = 0; | |
| 238 ImageCandidate candidate = bestFitSourceForImageAttributes( | |
| 239 document().devicePixelRatio(), effectiveSize, | |
| 240 getAttribute(HTMLNames::srcAttr), AtomicString()); | |
| 241 setBestFitURLAndDPRFromImageCandidate(candidate); | |
| 242 if (m_intrinsicSizingViewportDependant && m_effectiveSizeViewportDependant &
& !m_listener.get()) { | |
| 243 m_listener = ViewportChangeListener::create(this); | |
| 244 document().mediaQueryMatcher().addViewportListener(m_listener.get()); | |
| 245 } | |
| 246 imageLoader().updateFromElement(behavior); | |
| 247 } | |
| 248 | |
| 249 } | |
| OLD | NEW |