|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 /* rendering object for replaced elements with bitmap image data */ |
|
7 |
|
8 #ifndef nsImageFrame_h___ |
|
9 #define nsImageFrame_h___ |
|
10 |
|
11 #include "nsSplittableFrame.h" |
|
12 #include "nsIIOService.h" |
|
13 #include "nsIObserver.h" |
|
14 |
|
15 #include "imgINotificationObserver.h" |
|
16 |
|
17 #include "nsDisplayList.h" |
|
18 #include "imgIContainer.h" |
|
19 #include "mozilla/Attributes.h" |
|
20 #include "mozilla/DebugOnly.h" |
|
21 #include "nsIReflowCallback.h" |
|
22 |
|
23 class nsImageMap; |
|
24 class nsIURI; |
|
25 class nsILoadGroup; |
|
26 struct nsHTMLReflowState; |
|
27 struct nsHTMLReflowMetrics; |
|
28 class nsDisplayImage; |
|
29 class nsPresContext; |
|
30 class nsImageFrame; |
|
31 class nsTransform2D; |
|
32 class nsImageLoadingContent; |
|
33 |
|
34 namespace mozilla { |
|
35 namespace layers { |
|
36 class ImageContainer; |
|
37 class ImageLayer; |
|
38 class LayerManager; |
|
39 } |
|
40 } |
|
41 |
|
42 class nsImageListener : public imgINotificationObserver |
|
43 { |
|
44 public: |
|
45 nsImageListener(nsImageFrame *aFrame); |
|
46 virtual ~nsImageListener(); |
|
47 |
|
48 NS_DECL_ISUPPORTS |
|
49 NS_DECL_IMGINOTIFICATIONOBSERVER |
|
50 |
|
51 void SetFrame(nsImageFrame *frame) { mFrame = frame; } |
|
52 |
|
53 private: |
|
54 nsImageFrame *mFrame; |
|
55 }; |
|
56 |
|
57 typedef nsSplittableFrame ImageFrameSuper; |
|
58 |
|
59 class nsImageFrame : public ImageFrameSuper, |
|
60 public nsIReflowCallback { |
|
61 public: |
|
62 typedef mozilla::layers::ImageContainer ImageContainer; |
|
63 typedef mozilla::layers::ImageLayer ImageLayer; |
|
64 typedef mozilla::layers::LayerManager LayerManager; |
|
65 |
|
66 NS_DECL_FRAMEARENA_HELPERS |
|
67 |
|
68 nsImageFrame(nsStyleContext* aContext); |
|
69 |
|
70 NS_DECL_QUERYFRAME_TARGET(nsImageFrame) |
|
71 NS_DECL_QUERYFRAME |
|
72 |
|
73 virtual void DestroyFrom(nsIFrame* aDestructRoot) MOZ_OVERRIDE; |
|
74 virtual void Init(nsIContent* aContent, |
|
75 nsIFrame* aParent, |
|
76 nsIFrame* aPrevInFlow) MOZ_OVERRIDE; |
|
77 virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder, |
|
78 const nsRect& aDirtyRect, |
|
79 const nsDisplayListSet& aLists) MOZ_OVERRIDE; |
|
80 virtual nscoord GetMinWidth(nsRenderingContext *aRenderingContext) MOZ_OVERRIDE; |
|
81 virtual nscoord GetPrefWidth(nsRenderingContext *aRenderingContext) MOZ_OVERRIDE; |
|
82 virtual mozilla::IntrinsicSize GetIntrinsicSize() MOZ_OVERRIDE; |
|
83 virtual nsSize GetIntrinsicRatio() MOZ_OVERRIDE; |
|
84 virtual nsresult Reflow(nsPresContext* aPresContext, |
|
85 nsHTMLReflowMetrics& aDesiredSize, |
|
86 const nsHTMLReflowState& aReflowState, |
|
87 nsReflowStatus& aStatus) MOZ_OVERRIDE; |
|
88 |
|
89 virtual nsresult GetContentForEvent(mozilla::WidgetEvent* aEvent, |
|
90 nsIContent** aContent) MOZ_OVERRIDE; |
|
91 virtual nsresult HandleEvent(nsPresContext* aPresContext, |
|
92 mozilla::WidgetGUIEvent* aEvent, |
|
93 nsEventStatus* aEventStatus) MOZ_OVERRIDE; |
|
94 virtual nsresult GetCursor(const nsPoint& aPoint, |
|
95 nsIFrame::Cursor& aCursor) MOZ_OVERRIDE; |
|
96 virtual nsresult AttributeChanged(int32_t aNameSpaceID, |
|
97 nsIAtom* aAttribute, |
|
98 int32_t aModType) MOZ_OVERRIDE; |
|
99 |
|
100 #ifdef ACCESSIBILITY |
|
101 virtual mozilla::a11y::AccType AccessibleType() MOZ_OVERRIDE; |
|
102 #endif |
|
103 |
|
104 virtual nsIAtom* GetType() const MOZ_OVERRIDE; |
|
105 |
|
106 virtual bool IsFrameOfType(uint32_t aFlags) const MOZ_OVERRIDE |
|
107 { |
|
108 return ImageFrameSuper::IsFrameOfType(aFlags & ~(nsIFrame::eReplaced)); |
|
109 } |
|
110 |
|
111 #ifdef DEBUG_FRAME_DUMP |
|
112 virtual nsresult GetFrameName(nsAString& aResult) const MOZ_OVERRIDE; |
|
113 void List(FILE* out = stderr, const char* aPrefix = "", |
|
114 uint32_t aFlags = 0) const MOZ_OVERRIDE; |
|
115 #endif |
|
116 |
|
117 virtual int GetLogicalSkipSides(const nsHTMLReflowState* aReflowState = nullptr) const MOZ_OVERRIDE; |
|
118 |
|
119 nsresult GetIntrinsicImageSize(nsSize& aSize); |
|
120 |
|
121 static void ReleaseGlobals() { |
|
122 if (gIconLoad) { |
|
123 gIconLoad->Shutdown(); |
|
124 NS_RELEASE(gIconLoad); |
|
125 } |
|
126 NS_IF_RELEASE(sIOService); |
|
127 } |
|
128 |
|
129 nsresult Notify(imgIRequest *aRequest, int32_t aType, const nsIntRect* aData); |
|
130 |
|
131 /** |
|
132 * Function to test whether aContent, which has aStyleContext as its style, |
|
133 * should get an image frame. Note that this method is only used by the |
|
134 * frame constructor; it's only here because it uses gIconLoad for now. |
|
135 */ |
|
136 static bool ShouldCreateImageFrameFor(mozilla::dom::Element* aElement, |
|
137 nsStyleContext* aStyleContext); |
|
138 |
|
139 void DisplayAltFeedback(nsRenderingContext& aRenderingContext, |
|
140 const nsRect& aDirtyRect, |
|
141 imgIRequest* aRequest, |
|
142 nsPoint aPt); |
|
143 |
|
144 nsRect GetInnerArea() const; |
|
145 |
|
146 /** |
|
147 * Return a map element associated with this image. |
|
148 */ |
|
149 mozilla::dom::Element* GetMapElement() const |
|
150 { |
|
151 nsAutoString usemap; |
|
152 if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::usemap, usemap)) { |
|
153 return mContent->OwnerDoc()->FindImageMap(usemap); |
|
154 } |
|
155 return nullptr; |
|
156 } |
|
157 |
|
158 /** |
|
159 * Return true if the image has associated image map. |
|
160 */ |
|
161 bool HasImageMap() const { return mImageMap || GetMapElement(); } |
|
162 |
|
163 nsImageMap* GetImageMap(); |
|
164 nsImageMap* GetExistingImageMap() const { return mImageMap; } |
|
165 |
|
166 virtual void AddInlineMinWidth(nsRenderingContext *aRenderingContext, |
|
167 InlineMinWidthData *aData) MOZ_OVERRIDE; |
|
168 |
|
169 void DisconnectMap(); |
|
170 |
|
171 // nsIReflowCallback |
|
172 virtual bool ReflowFinished() MOZ_OVERRIDE; |
|
173 virtual void ReflowCallbackCanceled() MOZ_OVERRIDE; |
|
174 |
|
175 protected: |
|
176 virtual ~nsImageFrame(); |
|
177 |
|
178 void EnsureIntrinsicSizeAndRatio(nsPresContext* aPresContext); |
|
179 |
|
180 virtual nsSize ComputeSize(nsRenderingContext *aRenderingContext, |
|
181 nsSize aCBSize, nscoord aAvailableWidth, |
|
182 nsSize aMargin, nsSize aBorder, nsSize aPadding, |
|
183 uint32_t aFlags) MOZ_OVERRIDE; |
|
184 |
|
185 bool IsServerImageMap(); |
|
186 |
|
187 void TranslateEventCoords(const nsPoint& aPoint, |
|
188 nsIntPoint& aResult); |
|
189 |
|
190 bool GetAnchorHREFTargetAndNode(nsIURI** aHref, nsString& aTarget, |
|
191 nsIContent** aNode); |
|
192 /** |
|
193 * Computes the width of the string that fits into the available space |
|
194 * |
|
195 * @param in aLength total length of the string in PRUnichars |
|
196 * @param in aMaxWidth width not to be exceeded |
|
197 * @param out aMaxFit length of the string that fits within aMaxWidth |
|
198 * in PRUnichars |
|
199 * @return width of the string that fits within aMaxWidth |
|
200 */ |
|
201 nscoord MeasureString(const char16_t* aString, |
|
202 int32_t aLength, |
|
203 nscoord aMaxWidth, |
|
204 uint32_t& aMaxFit, |
|
205 nsRenderingContext& aContext); |
|
206 |
|
207 void DisplayAltText(nsPresContext* aPresContext, |
|
208 nsRenderingContext& aRenderingContext, |
|
209 const nsString& aAltText, |
|
210 const nsRect& aRect); |
|
211 |
|
212 void PaintImage(nsRenderingContext& aRenderingContext, nsPoint aPt, |
|
213 const nsRect& aDirtyRect, imgIContainer* aImage, |
|
214 uint32_t aFlags); |
|
215 |
|
216 protected: |
|
217 friend class nsImageListener; |
|
218 friend class nsImageLoadingContent; |
|
219 nsresult OnStartContainer(imgIRequest *aRequest, imgIContainer *aImage); |
|
220 nsresult OnDataAvailable(imgIRequest *aRequest, const nsIntRect *rect); |
|
221 nsresult OnStopRequest(imgIRequest *aRequest, |
|
222 nsresult aStatus); |
|
223 nsresult FrameChanged(imgIRequest *aRequest, |
|
224 imgIContainer *aContainer); |
|
225 /** |
|
226 * Notification that aRequest will now be the current request. |
|
227 */ |
|
228 void NotifyNewCurrentRequest(imgIRequest *aRequest, nsresult aStatus); |
|
229 |
|
230 private: |
|
231 // random helpers |
|
232 inline void SpecToURI(const nsAString& aSpec, nsIIOService *aIOService, |
|
233 nsIURI **aURI); |
|
234 |
|
235 inline void GetLoadGroup(nsPresContext *aPresContext, |
|
236 nsILoadGroup **aLoadGroup); |
|
237 nscoord GetContinuationOffset() const; |
|
238 void GetDocumentCharacterSet(nsACString& aCharset) const; |
|
239 bool ShouldDisplaySelection(); |
|
240 |
|
241 /** |
|
242 * Recalculate mIntrinsicSize from the image. |
|
243 * |
|
244 * @return whether aImage's size did _not_ |
|
245 * match our previous intrinsic size. |
|
246 */ |
|
247 bool UpdateIntrinsicSize(imgIContainer* aImage); |
|
248 |
|
249 /** |
|
250 * Recalculate mIntrinsicRatio from the image. |
|
251 * |
|
252 * @return whether aImage's ratio did _not_ |
|
253 * match our previous intrinsic ratio. |
|
254 */ |
|
255 bool UpdateIntrinsicRatio(imgIContainer* aImage); |
|
256 |
|
257 /** |
|
258 * This function calculates the transform for converting between |
|
259 * source space & destination space. May fail if our image has a |
|
260 * percent-valued or zero-valued height or width. |
|
261 * |
|
262 * @param aTransform The transform object to populate. |
|
263 * |
|
264 * @return whether we succeeded in creating the transform. |
|
265 */ |
|
266 bool GetSourceToDestTransform(nsTransform2D& aTransform); |
|
267 |
|
268 /** |
|
269 * Helper functions to check whether the request or image container |
|
270 * corresponds to a load we don't care about. Most of the decoder |
|
271 * observer methods will bail early if these return true. |
|
272 */ |
|
273 bool IsPendingLoad(imgIRequest* aRequest) const; |
|
274 bool IsPendingLoad(imgIContainer* aContainer) const; |
|
275 |
|
276 /** |
|
277 * Function to convert a dirty rect in the source image to a dirty |
|
278 * rect for the image frame. |
|
279 */ |
|
280 nsRect SourceRectToDest(const nsIntRect & aRect); |
|
281 |
|
282 nsImageMap* mImageMap; |
|
283 |
|
284 nsCOMPtr<imgINotificationObserver> mListener; |
|
285 |
|
286 nsCOMPtr<imgIContainer> mImage; |
|
287 nsSize mComputedSize; |
|
288 mozilla::IntrinsicSize mIntrinsicSize; |
|
289 nsSize mIntrinsicRatio; |
|
290 |
|
291 bool mDisplayingIcon; |
|
292 bool mFirstFrameComplete; |
|
293 bool mReflowCallbackPosted; |
|
294 |
|
295 static nsIIOService* sIOService; |
|
296 |
|
297 /* loading / broken image icon support */ |
|
298 |
|
299 // XXXbz this should be handled by the prescontext, I think; that |
|
300 // way we would have a single iconload per mozilla session instead |
|
301 // of one per document... |
|
302 |
|
303 // LoadIcons: initiate the loading of the static icons used to show |
|
304 // loading / broken images |
|
305 nsresult LoadIcons(nsPresContext *aPresContext); |
|
306 nsresult LoadIcon(const nsAString& aSpec, nsPresContext *aPresContext, |
|
307 imgRequestProxy **aRequest); |
|
308 |
|
309 class IconLoad MOZ_FINAL : public nsIObserver, |
|
310 public imgINotificationObserver { |
|
311 // private class that wraps the data and logic needed for |
|
312 // broken image and loading image icons |
|
313 public: |
|
314 IconLoad(); |
|
315 |
|
316 void Shutdown(); |
|
317 |
|
318 NS_DECL_ISUPPORTS |
|
319 NS_DECL_NSIOBSERVER |
|
320 NS_DECL_IMGINOTIFICATIONOBSERVER |
|
321 |
|
322 void AddIconObserver(nsImageFrame *frame) { |
|
323 NS_ABORT_IF_FALSE(!mIconObservers.Contains(frame), |
|
324 "Observer shouldn't aleady be in array"); |
|
325 mIconObservers.AppendElement(frame); |
|
326 } |
|
327 |
|
328 void RemoveIconObserver(nsImageFrame *frame) { |
|
329 mozilla::DebugOnly<bool> didRemove = mIconObservers.RemoveElement(frame); |
|
330 NS_ABORT_IF_FALSE(didRemove, "Observer not in array"); |
|
331 } |
|
332 |
|
333 private: |
|
334 void GetPrefs(); |
|
335 nsTObserverArray<nsImageFrame*> mIconObservers; |
|
336 |
|
337 |
|
338 public: |
|
339 nsRefPtr<imgRequestProxy> mLoadingImage; |
|
340 nsRefPtr<imgRequestProxy> mBrokenImage; |
|
341 bool mPrefForceInlineAltText; |
|
342 bool mPrefShowPlaceholders; |
|
343 }; |
|
344 |
|
345 public: |
|
346 static IconLoad* gIconLoad; // singleton pattern: one LoadIcons instance is used |
|
347 |
|
348 friend class nsDisplayImage; |
|
349 }; |
|
350 |
|
351 /** |
|
352 * Note that nsDisplayImage does not receive events. However, an image element |
|
353 * is replaced content so its background will be z-adjacent to the |
|
354 * image itself, and hence receive events just as if the image itself |
|
355 * received events. |
|
356 */ |
|
357 class nsDisplayImage : public nsDisplayImageContainer { |
|
358 public: |
|
359 typedef mozilla::layers::LayerManager LayerManager; |
|
360 |
|
361 nsDisplayImage(nsDisplayListBuilder* aBuilder, nsImageFrame* aFrame, |
|
362 imgIContainer* aImage) |
|
363 : nsDisplayImageContainer(aBuilder, aFrame), mImage(aImage) { |
|
364 MOZ_COUNT_CTOR(nsDisplayImage); |
|
365 } |
|
366 virtual ~nsDisplayImage() { |
|
367 MOZ_COUNT_DTOR(nsDisplayImage); |
|
368 } |
|
369 virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, |
|
370 const nsDisplayItemGeometry* aGeometry, |
|
371 nsRegion* aInvalidRegion) MOZ_OVERRIDE; |
|
372 virtual void Paint(nsDisplayListBuilder* aBuilder, |
|
373 nsRenderingContext* aCtx) MOZ_OVERRIDE; |
|
374 |
|
375 /** |
|
376 * Returns an ImageContainer for this image if the image type |
|
377 * supports it (TYPE_RASTER only). |
|
378 */ |
|
379 virtual already_AddRefed<ImageContainer> GetContainer(LayerManager* aManager, |
|
380 nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE; |
|
381 |
|
382 gfxRect GetDestRect(); |
|
383 |
|
384 virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder, |
|
385 LayerManager* aManager, |
|
386 const ContainerLayerParameters& aParameters) MOZ_OVERRIDE; |
|
387 virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE |
|
388 { |
|
389 *aSnap = true; |
|
390 return nsRect(ToReferenceFrame(), Frame()->GetSize()); |
|
391 } |
|
392 |
|
393 virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder, |
|
394 LayerManager* aManager, |
|
395 const ContainerLayerParameters& aContainerParameters) MOZ_OVERRIDE; |
|
396 |
|
397 /** |
|
398 * Configure an ImageLayer for this display item. |
|
399 * Set the required filter and scaling transform. |
|
400 */ |
|
401 virtual void ConfigureLayer(ImageLayer* aLayer, const nsIntPoint& aOffset) MOZ_OVERRIDE; |
|
402 |
|
403 NS_DISPLAY_DECL_NAME("Image", TYPE_IMAGE) |
|
404 private: |
|
405 nsCOMPtr<imgIContainer> mImage; |
|
406 }; |
|
407 |
|
408 #endif /* nsImageFrame_h___ */ |