Bug 1708422: part 13) Factor code out to `mozInlineSpellChecker::SpellCheckerTimeSlic...
[gecko.git] / layout / generic / nsImageFrame.h
blob8b7908ae867f73686bb6312376a88210de92d8a0
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /* rendering object for replaced elements with image data */
9 #ifndef nsImageFrame_h___
10 #define nsImageFrame_h___
12 #include "nsAtomicContainerFrame.h"
13 #include "nsIObserver.h"
15 #include "imgINotificationObserver.h"
17 #include "nsDisplayList.h"
18 #include "imgIContainer.h"
19 #include "mozilla/Attributes.h"
20 #include "mozilla/DebugOnly.h"
21 #include "mozilla/StaticPtr.h"
22 #include "nsIReflowCallback.h"
23 #include "nsTObserverArray.h"
25 class nsFontMetrics;
26 class nsImageMap;
27 class nsIURI;
28 class nsILoadGroup;
29 class nsDisplayImage;
30 class nsPresContext;
31 class nsImageFrame;
32 class nsTransform2D;
33 class nsImageLoadingContent;
35 namespace mozilla {
36 class PresShell;
37 namespace layers {
38 class ImageContainer;
39 class ImageLayer;
40 class LayerManager;
41 } // namespace layers
42 } // namespace mozilla
44 class nsImageListener final : public imgINotificationObserver {
45 protected:
46 virtual ~nsImageListener();
48 public:
49 explicit nsImageListener(nsImageFrame* aFrame);
51 NS_DECL_ISUPPORTS
52 NS_DECL_IMGINOTIFICATIONOBSERVER
54 void SetFrame(nsImageFrame* frame) { mFrame = frame; }
56 private:
57 nsImageFrame* mFrame;
60 class nsImageFrame : public nsAtomicContainerFrame, public nsIReflowCallback {
61 public:
62 template <typename T>
63 using Maybe = mozilla::Maybe<T>;
64 using Nothing = mozilla::Nothing;
65 using Visibility = mozilla::Visibility;
67 typedef mozilla::image::ImgDrawResult ImgDrawResult;
68 typedef mozilla::layers::ImageContainer ImageContainer;
69 typedef mozilla::layers::ImageLayer ImageLayer;
70 typedef mozilla::layers::LayerManager LayerManager;
72 NS_DECL_FRAMEARENA_HELPERS(nsImageFrame)
73 NS_DECL_QUERYFRAME
75 void DestroyFrom(nsIFrame* aDestructRoot, PostDestroyData&) override;
76 void DidSetComputedStyle(ComputedStyle* aOldStyle) final;
78 void Init(nsIContent* aContent, nsContainerFrame* aParent,
79 nsIFrame* aPrevInFlow) override;
80 void BuildDisplayList(nsDisplayListBuilder*, const nsDisplayListSet&) final;
81 nscoord GetMinISize(gfxContext* aRenderingContext) final;
82 nscoord GetPrefISize(gfxContext* aRenderingContext) final;
83 mozilla::IntrinsicSize GetIntrinsicSize() final { return mIntrinsicSize; }
84 mozilla::AspectRatio GetIntrinsicRatio() const final {
85 return mIntrinsicRatio;
87 void Reflow(nsPresContext*, ReflowOutput&, const ReflowInput&,
88 nsReflowStatus&) override;
90 nsresult GetContentForEvent(mozilla::WidgetEvent*,
91 nsIContent** aContent) final;
92 nsresult HandleEvent(nsPresContext*, mozilla::WidgetGUIEvent*,
93 nsEventStatus*) override;
94 mozilla::Maybe<Cursor> GetCursor(const nsPoint&) override;
95 nsresult AttributeChanged(int32_t aNameSpaceID, nsAtom* aAttribute,
96 int32_t aModType) final;
98 void OnVisibilityChange(
99 Visibility aNewVisibility,
100 const Maybe<OnNonvisible>& aNonvisibleAction = Nothing()) final;
102 void ResponsiveContentDensityChanged();
103 void SetupForContentURLRequest();
104 bool ShouldShowBrokenImageIcon() const;
106 const mozilla::StyleImage* GetImageFromStyle() const;
108 #ifdef ACCESSIBILITY
109 mozilla::a11y::AccType AccessibleType() override;
110 #endif
112 bool IsFrameOfType(uint32_t aFlags) const final {
113 return nsAtomicContainerFrame::IsFrameOfType(
114 aFlags & ~(nsIFrame::eReplaced | nsIFrame::eReplacedSizing));
117 #ifdef DEBUG_FRAME_DUMP
118 nsresult GetFrameName(nsAString& aResult) const override;
119 void List(FILE* out = stderr, const char* aPrefix = "",
120 ListFlags aFlags = ListFlags()) const final;
121 #endif
123 LogicalSides GetLogicalSkipSides() const final;
125 static void ReleaseGlobals() {
126 if (gIconLoad) {
127 gIconLoad->Shutdown();
128 gIconLoad = nullptr;
132 nsresult RestartAnimation();
133 nsresult StopAnimation();
135 already_AddRefed<imgIRequest> GetCurrentRequest() const;
136 void Notify(imgIRequest*, int32_t aType, const nsIntRect* aData);
139 * Function to test whether given an element and its style, that element
140 * should get an image frame. Note that this method is only used by the
141 * frame constructor; it's only here because it uses gIconLoad for now.
143 static bool ShouldCreateImageFrameFor(const mozilla::dom::Element&,
144 ComputedStyle&);
146 ImgDrawResult DisplayAltFeedback(gfxContext& aRenderingContext,
147 const nsRect& aDirtyRect, nsPoint aPt,
148 uint32_t aFlags);
150 ImgDrawResult DisplayAltFeedbackWithoutLayer(
151 nsDisplayItem*, mozilla::wr::DisplayListBuilder&,
152 mozilla::wr::IpcResourceUpdateQueue&,
153 const mozilla::layers::StackingContextHelper&,
154 mozilla::layers::RenderRootStateManager*, nsDisplayListBuilder*,
155 nsPoint aPt, uint32_t aFlags);
157 nsRect GetInnerArea() const;
160 * Return a map element associated with this image.
162 mozilla::dom::Element* GetMapElement() const;
165 * Return true if the image has associated image map.
167 bool HasImageMap() const { return mImageMap || GetMapElement(); }
169 nsImageMap* GetImageMap();
170 nsImageMap* GetExistingImageMap() const { return mImageMap; }
172 void AddInlineMinISize(gfxContext* aRenderingContext,
173 InlineMinISizeData* aData) final;
175 void DisconnectMap();
177 // nsIReflowCallback
178 bool ReflowFinished() final;
179 void ReflowCallbackCanceled() final;
181 // The kind of image frame we are.
182 enum class Kind : uint8_t {
183 // For an nsImageLoadingContent.
184 ImageElement,
185 // For css 'content: url(..)' on non-generated content.
186 ContentProperty,
187 // For a child of a ::before / ::after pseudo-element that had an url() item
188 // for the content property.
189 ContentPropertyAtIndex,
192 // Creates a suitable continuing frame for this frame.
193 nsImageFrame* CreateContinuingFrame(mozilla::PresShell*,
194 ComputedStyle*) const;
196 private:
197 friend nsIFrame* NS_NewImageFrame(mozilla::PresShell*, ComputedStyle*);
198 friend nsIFrame* NS_NewImageFrameForContentProperty(mozilla::PresShell*,
199 ComputedStyle*);
200 friend nsIFrame* NS_NewImageFrameForGeneratedContentIndex(mozilla::PresShell*,
201 ComputedStyle*);
203 nsImageFrame(ComputedStyle* aStyle, nsPresContext* aPresContext, Kind aKind)
204 : nsImageFrame(aStyle, aPresContext, kClassID, aKind) {}
206 nsImageFrame(ComputedStyle*, nsPresContext* aPresContext, ClassID, Kind);
208 protected:
209 nsImageFrame(ComputedStyle* aStyle, nsPresContext* aPresContext, ClassID aID)
210 : nsImageFrame(aStyle, aPresContext, aID, Kind::ImageElement) {}
212 ~nsImageFrame() override;
214 void EnsureIntrinsicSizeAndRatio();
216 bool GotInitialReflow() const {
217 return !HasAnyStateBits(NS_FRAME_FIRST_REFLOW);
220 SizeComputationResult ComputeSize(
221 gfxContext* aRenderingContext, mozilla::WritingMode aWM,
222 const mozilla::LogicalSize& aCBSize, nscoord aAvailableISize,
223 const mozilla::LogicalSize& aMargin,
224 const mozilla::LogicalSize& aBorderPadding,
225 const mozilla::StyleSizeOverrides& aSizeOverrides,
226 mozilla::ComputeSizeFlags aFlags) final;
228 bool IsServerImageMap();
230 void TranslateEventCoords(const nsPoint& aPoint, nsIntPoint& aResult);
232 bool GetAnchorHREFTargetAndNode(nsIURI** aHref, nsString& aTarget,
233 nsIContent** aNode);
235 * Computes the width of the string that fits into the available space
237 * @param in aLength total length of the string in PRUnichars
238 * @param in aMaxWidth width not to be exceeded
239 * @param out aMaxFit length of the string that fits within aMaxWidth
240 * in PRUnichars
241 * @return width of the string that fits within aMaxWidth
243 nscoord MeasureString(const char16_t* aString, int32_t aLength,
244 nscoord aMaxWidth, uint32_t& aMaxFit,
245 gfxContext& aContext, nsFontMetrics& aFontMetrics);
247 void DisplayAltText(nsPresContext* aPresContext,
248 gfxContext& aRenderingContext, const nsString& aAltText,
249 const nsRect& aRect);
251 ImgDrawResult PaintImage(gfxContext& aRenderingContext, nsPoint aPt,
252 const nsRect& aDirtyRect, imgIContainer* aImage,
253 uint32_t aFlags);
256 * If we're ready to decode - that is, if our current request's image is
257 * available and our decoding heuristics are satisfied - then trigger a decode
258 * for our image at the size we predict it will be drawn next time it's
259 * painted.
261 void MaybeDecodeForPredictedSize();
263 protected:
264 friend class nsImageListener;
265 friend class nsImageLoadingContent;
266 friend class mozilla::PresShell;
268 void OnSizeAvailable(imgIRequest* aRequest, imgIContainer* aImage);
269 void OnFrameUpdate(imgIRequest* aRequest, const nsIntRect* aRect);
270 void OnLoadComplete(imgIRequest* aRequest, nsresult aStatus);
273 * Notification that aRequest will now be the current request.
275 void NotifyNewCurrentRequest(imgIRequest* aRequest, nsresult aStatus);
277 /// Always sync decode our image when painting if @aForce is true.
278 void SetForceSyncDecoding(bool aForce) { mForceSyncDecoding = aForce; }
281 * Computes the predicted dest rect that we'll draw into, in app units, based
282 * upon the provided frame content box. (The content box is what
283 * nsDisplayImage::GetBounds() returns.)
284 * The result is not necessarily contained in the frame content box.
286 nsRect PredictedDestRect(const nsRect& aFrameContentBox);
288 private:
289 void MaybeRecordContentUrlOnImageTelemetry();
291 // random helpers
292 inline void SpecToURI(const nsAString& aSpec, nsIURI** aURI);
294 inline void GetLoadGroup(nsPresContext* aPresContext,
295 nsILoadGroup** aLoadGroup);
296 nscoord GetContinuationOffset() const;
297 void GetDocumentCharacterSet(nsACString& aCharset) const;
298 bool ShouldDisplaySelection();
300 // Whether the image frame should use the mapped aspect ratio from width=""
301 // and height="".
302 bool ShouldUseMappedAspectRatio() const;
304 // Recalculate mIntrinsicSize from the image.
305 bool UpdateIntrinsicSize();
307 // Recalculate mIntrinsicRatio from the image.
308 bool UpdateIntrinsicRatio();
311 * This function calculates the transform for converting between
312 * source space & destination space. May fail if our image has a
313 * percent-valued or zero-valued height or width.
315 * @param aTransform The transform object to populate.
317 * @return whether we succeeded in creating the transform.
319 bool GetSourceToDestTransform(nsTransform2D& aTransform);
322 * Helper function to check whether the request corresponds to a load we don't
323 * care about. Most of the decoder observer methods will bail early if this
324 * returns true.
326 bool IsPendingLoad(imgIRequest*) const;
329 * Updates mImage based on the current image request (cannot be null), and the
330 * image passed in (can be null), and invalidate layout and paint as needed.
332 void UpdateImage(imgIRequest*, imgIContainer*);
335 * Function to convert a dirty rect in the source image to a dirty
336 * rect for the image frame.
338 nsRect SourceRectToDest(const nsIntRect& aRect);
341 * Triggers invalidation for both our image display item and, if appropriate,
342 * our alt-feedback display item.
344 * @param aLayerInvalidRect The area to invalidate in layer space. If null,
345 * the entire layer will be invalidated.
346 * @param aFrameInvalidRect The area to invalidate in frame space. If null,
347 * the entire frame will be invalidated.
349 void InvalidateSelf(const nsIntRect* aLayerInvalidRect,
350 const nsRect* aFrameInvalidRect);
352 RefPtr<nsImageMap> mImageMap;
354 RefPtr<nsImageListener> mListener;
356 // An image request created for content: url(..).
357 RefPtr<imgRequestProxy> mContentURLRequest;
359 nsCOMPtr<imgIContainer> mImage;
360 nsCOMPtr<imgIContainer> mPrevImage;
361 nsSize mComputedSize;
362 mozilla::IntrinsicSize mIntrinsicSize;
364 // Stores mImage's intrinsic ratio, or a default AspectRatio if there's no
365 // intrinsic ratio.
366 mozilla::AspectRatio mIntrinsicRatio;
368 const Kind mKind;
369 bool mContentURLRequestRegistered;
370 bool mDisplayingIcon;
371 bool mFirstFrameComplete;
372 bool mReflowCallbackPosted;
373 bool mForceSyncDecoding;
375 /* loading / broken image icon support */
377 // XXXbz this should be handled by the prescontext, I think; that
378 // way we would have a single iconload per mozilla session instead
379 // of one per document...
381 // LoadIcons: initiate the loading of the static icons used to show
382 // loading / broken images
383 nsresult LoadIcons(nsPresContext* aPresContext);
384 nsresult LoadIcon(const nsAString& aSpec, nsPresContext* aPresContext,
385 imgRequestProxy** aRequest);
387 class IconLoad final : public nsIObserver, public imgINotificationObserver {
388 // private class that wraps the data and logic needed for
389 // broken image and loading image icons
390 public:
391 IconLoad();
393 void Shutdown();
395 NS_DECL_ISUPPORTS
396 NS_DECL_NSIOBSERVER
397 NS_DECL_IMGINOTIFICATIONOBSERVER
399 void AddIconObserver(nsImageFrame* frame) {
400 MOZ_ASSERT(!mIconObservers.Contains(frame),
401 "Observer shouldn't aleady be in array");
402 mIconObservers.AppendElement(frame);
405 void RemoveIconObserver(nsImageFrame* frame) {
406 mozilla::DebugOnly<bool> didRemove = mIconObservers.RemoveElement(frame);
407 MOZ_ASSERT(didRemove, "Observer not in array");
410 private:
411 ~IconLoad() = default;
413 void GetPrefs();
414 nsTObserverArray<nsImageFrame*> mIconObservers;
416 public:
417 RefPtr<imgRequestProxy> mLoadingImage;
418 RefPtr<imgRequestProxy> mBrokenImage;
419 bool mPrefForceInlineAltText;
420 bool mPrefShowPlaceholders;
421 bool mPrefShowLoadingPlaceholder;
424 public:
425 // singleton pattern: one LoadIcons instance is used
426 static mozilla::StaticRefPtr<IconLoad> gIconLoad;
428 friend class nsDisplayImage;
432 * Note that nsDisplayImage does not receive events. However, an image element
433 * is replaced content so its background will be z-adjacent to the
434 * image itself, and hence receive events just as if the image itself
435 * received events.
437 class nsDisplayImage final : public nsDisplayImageContainer {
438 public:
439 typedef mozilla::layers::LayerManager LayerManager;
441 nsDisplayImage(nsDisplayListBuilder* aBuilder, nsImageFrame* aFrame,
442 imgIContainer* aImage, imgIContainer* aPrevImage)
443 : nsDisplayImageContainer(aBuilder, aFrame),
444 mImage(aImage),
445 mPrevImage(aPrevImage) {
446 MOZ_COUNT_CTOR(nsDisplayImage);
448 ~nsDisplayImage() final { MOZ_COUNT_DTOR(nsDisplayImage); }
450 nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder*) final;
451 void ComputeInvalidationRegion(nsDisplayListBuilder*,
452 const nsDisplayItemGeometry*,
453 nsRegion* aInvalidRegion) const final;
454 void Paint(nsDisplayListBuilder*, gfxContext* aCtx) final;
456 already_AddRefed<imgIContainer> GetImage() final;
459 * @return The dest rect we'll use when drawing this image, in app units.
460 * Not necessarily contained in this item's bounds.
462 nsRect GetDestRect() const final;
464 void UpdateDrawResult(mozilla::image::ImgDrawResult aResult) final {
465 nsDisplayItemGenericImageGeometry::UpdateDrawResult(this, aResult);
468 LayerState GetLayerState(nsDisplayListBuilder*, LayerManager*,
469 const ContainerLayerParameters&) final;
470 nsRect GetBounds(bool* aSnap) const {
471 *aSnap = true;
473 nsImageFrame* imageFrame = static_cast<nsImageFrame*>(mFrame);
474 return imageFrame->GetInnerArea() + ToReferenceFrame();
477 nsRect GetBounds(nsDisplayListBuilder*, bool* aSnap) const final {
478 return GetBounds(aSnap);
481 nsRegion GetOpaqueRegion(nsDisplayListBuilder*, bool* aSnap) const final;
483 already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder*, LayerManager*,
484 const ContainerLayerParameters&) final;
485 bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder&,
486 mozilla::wr::IpcResourceUpdateQueue&,
487 const StackingContextHelper&,
488 mozilla::layers::RenderRootStateManager*,
489 nsDisplayListBuilder*) final;
491 NS_DISPLAY_DECL_NAME("Image", TYPE_IMAGE)
492 private:
493 nsCOMPtr<imgIContainer> mImage;
494 nsCOMPtr<imgIContainer> mPrevImage;
497 #endif /* nsImageFrame_h___ */