Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/layout/generic/nsImageFrame.h
Line
Count
Source (jump to first uncovered line)
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/. */
6
7
/* rendering object for replaced elements with image data */
8
9
#ifndef nsImageFrame_h___
10
#define nsImageFrame_h___
11
12
#include "nsAtomicContainerFrame.h"
13
#include "nsIIOService.h"
14
#include "nsIObserver.h"
15
16
#include "imgINotificationObserver.h"
17
18
#include "nsDisplayList.h"
19
#include "imgIContainer.h"
20
#include "mozilla/Attributes.h"
21
#include "mozilla/DebugOnly.h"
22
#include "mozilla/StaticPtr.h"
23
#include "nsIReflowCallback.h"
24
#include "nsTObserverArray.h"
25
26
class nsFontMetrics;
27
class nsImageMap;
28
class nsIURI;
29
class nsILoadGroup;
30
class nsDisplayImage;
31
class nsPresContext;
32
class nsImageFrame;
33
class nsTransform2D;
34
class nsImageLoadingContent;
35
36
namespace mozilla {
37
class PresShell;
38
namespace layers {
39
  class ImageContainer;
40
  class ImageLayer;
41
  class LayerManager;
42
} // namespace layers
43
} // namespace mozilla
44
45
class nsImageListener final : public imgINotificationObserver
46
{
47
protected:
48
  virtual ~nsImageListener();
49
50
public:
51
  explicit nsImageListener(nsImageFrame *aFrame);
52
53
  NS_DECL_ISUPPORTS
54
  NS_DECL_IMGINOTIFICATIONOBSERVER
55
56
0
  void SetFrame(nsImageFrame *frame) { mFrame = frame; }
57
58
private:
59
  nsImageFrame *mFrame;
60
};
61
62
class nsImageFrame : public nsAtomicContainerFrame
63
                   , public nsIReflowCallback {
64
public:
65
  template <typename T> using Maybe = mozilla::Maybe<T>;
66
  using Nothing = mozilla::Nothing;
67
  using Visibility = mozilla::Visibility;
68
69
  typedef mozilla::image::ImgDrawResult ImgDrawResult;
70
  typedef mozilla::layers::ImageContainer ImageContainer;
71
  typedef mozilla::layers::ImageLayer ImageLayer;
72
  typedef mozilla::layers::LayerManager LayerManager;
73
74
  NS_DECL_FRAMEARENA_HELPERS(nsImageFrame)
75
  NS_DECL_QUERYFRAME
76
77
  virtual void DestroyFrom(nsIFrame* aDestructRoot, PostDestroyData& aPostDestroyData) override;
78
  virtual void DidSetComputedStyle(ComputedStyle* aOldComputedStyle) override;
79
80
  virtual void Init(nsIContent*       aContent,
81
                    nsContainerFrame* aParent,
82
                    nsIFrame*         aPrevInFlow) override;
83
  virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
84
                                const nsDisplayListSet& aLists) override;
85
  virtual nscoord GetMinISize(gfxContext *aRenderingContext) override;
86
  virtual nscoord GetPrefISize(gfxContext *aRenderingContext) override;
87
  virtual mozilla::IntrinsicSize GetIntrinsicSize() override;
88
  virtual nsSize GetIntrinsicRatio() override;
89
  virtual void Reflow(nsPresContext*           aPresContext,
90
                      ReflowOutput&     aDesiredSize,
91
                      const ReflowInput& aReflowInput,
92
                      nsReflowStatus&          aStatus) override;
93
94
  virtual nsresult  GetContentForEvent(mozilla::WidgetEvent* aEvent,
95
                                       nsIContent** aContent) override;
96
  virtual nsresult HandleEvent(nsPresContext* aPresContext,
97
                               mozilla::WidgetGUIEvent* aEvent,
98
                               nsEventStatus* aEventStatus) override;
99
  virtual nsresult GetCursor(const nsPoint& aPoint,
100
                             nsIFrame::Cursor& aCursor) override;
101
  virtual nsresult AttributeChanged(int32_t aNameSpaceID,
102
                                    nsAtom* aAttribute,
103
                                    int32_t aModType) override;
104
105
  void OnVisibilityChange(Visibility aNewVisibility,
106
                          const Maybe<OnNonvisible>& aNonvisibleAction = Nothing()) override;
107
108
  void ResponsiveContentDensityChanged();
109
  void SetupForContentURLRequest();
110
111
#ifdef ACCESSIBILITY
112
  virtual mozilla::a11y::AccType AccessibleType() override;
113
#endif
114
115
  virtual bool IsFrameOfType(uint32_t aFlags) const override
116
0
  {
117
0
    return nsAtomicContainerFrame::IsFrameOfType(aFlags &
118
0
      ~(nsIFrame::eReplaced | nsIFrame::eReplacedSizing));
119
0
  }
120
121
#ifdef DEBUG_FRAME_DUMP
122
  virtual nsresult GetFrameName(nsAString& aResult) const override;
123
  void List(FILE* out = stderr, const char* aPrefix = "",
124
            uint32_t aFlags = 0) const override;
125
#endif
126
127
  nsSplittableType GetSplittableType() const override
128
0
  {
129
0
    return NS_FRAME_SPLITTABLE;
130
0
  }
131
132
  virtual LogicalSides GetLogicalSkipSides(const ReflowInput* aReflowInput = nullptr) const override;
133
134
  nsresult GetIntrinsicImageSize(nsSize& aSize);
135
136
0
  static void ReleaseGlobals() {
137
0
    if (gIconLoad) {
138
0
      gIconLoad->Shutdown();
139
0
      gIconLoad = nullptr;
140
0
    }
141
0
    NS_IF_RELEASE(sIOService);
142
0
  }
143
144
  already_AddRefed<imgIRequest> GetCurrentRequest() const;
145
  nsresult Notify(imgIRequest *aRequest, int32_t aType, const nsIntRect* aData);
146
147
  /**
148
   * Function to test whether aContent, which has aComputedStyle as its style,
149
   * should get an image frame.  Note that this method is only used by the
150
   * frame constructor; it's only here because it uses gIconLoad for now.
151
   */
152
  static bool ShouldCreateImageFrameFor(const mozilla::dom::Element& aElement,
153
                                        ComputedStyle& aStyle);
154
155
  ImgDrawResult DisplayAltFeedback(gfxContext& aRenderingContext,
156
                                const nsRect& aDirtyRect,
157
                                nsPoint aPt,
158
                                uint32_t aFlags);
159
160
  nsRect GetInnerArea() const;
161
162
  /**
163
   * Return a map element associated with this image.
164
   */
165
  mozilla::dom::Element* GetMapElement() const;
166
167
  /**
168
   * Return true if the image has associated image map.
169
   */
170
0
  bool HasImageMap() const { return mImageMap || GetMapElement(); }
171
172
  nsImageMap* GetImageMap();
173
0
  nsImageMap* GetExistingImageMap() const { return mImageMap; }
174
175
  virtual void AddInlineMinISize(gfxContext *aRenderingContext,
176
                                 InlineMinISizeData *aData) override;
177
178
  void DisconnectMap();
179
180
  // nsIReflowCallback
181
  virtual bool ReflowFinished() override;
182
  virtual void ReflowCallbackCanceled() override;
183
184
  // The kind of image frame we are.
185
  enum class Kind : uint8_t
186
  {
187
    // For an nsImageLoadingContent.
188
    ImageElement,
189
    // For css 'content: url(..)' on non-generated content.
190
    ContentProperty,
191
    // For a child of a ::before / ::after pseudo-element that had an url() item
192
    // for the content property.
193
    ContentPropertyAtIndex,
194
  };
195
196
  // Creates a suitable continuing frame for this frame.
197
  nsImageFrame* CreateContinuingFrame(nsIPresShell*, ComputedStyle*) const;
198
199
private:
200
  friend nsIFrame* NS_NewImageFrame(nsIPresShell*, ComputedStyle*);
201
  friend nsIFrame* NS_NewImageFrameForContentProperty(nsIPresShell*, ComputedStyle*);
202
  friend nsIFrame* NS_NewImageFrameForGeneratedContentIndex(nsIPresShell*, ComputedStyle*);
203
204
  nsImageFrame(ComputedStyle* aStyle, Kind aKind)
205
    : nsImageFrame(aStyle, kClassID, aKind)
206
0
  { }
207
208
  nsImageFrame(ComputedStyle*, ClassID, Kind);
209
210
protected:
211
  nsImageFrame(ComputedStyle* aStyle, ClassID aID)
212
    : nsImageFrame(aStyle, aID, Kind::ImageElement)
213
0
  { }
214
215
  virtual ~nsImageFrame();
216
217
  void EnsureIntrinsicSizeAndRatio();
218
219
  bool GotInitialReflow() const
220
0
  {
221
0
    return !HasAnyStateBits(NS_FRAME_FIRST_REFLOW);
222
0
  }
223
224
  virtual mozilla::LogicalSize
225
  ComputeSize(gfxContext *aRenderingContext,
226
              mozilla::WritingMode aWritingMode,
227
              const mozilla::LogicalSize& aCBSize,
228
              nscoord aAvailableISize,
229
              const mozilla::LogicalSize& aMargin,
230
              const mozilla::LogicalSize& aBorder,
231
              const mozilla::LogicalSize& aPadding,
232
              ComputeSizeFlags aFlags) override;
233
234
  bool IsServerImageMap();
235
236
  void TranslateEventCoords(const nsPoint& aPoint,
237
                            nsIntPoint& aResult);
238
239
  bool GetAnchorHREFTargetAndNode(nsIURI** aHref, nsString& aTarget,
240
                                    nsIContent** aNode);
241
  /**
242
   * Computes the width of the string that fits into the available space
243
   *
244
   * @param in aLength total length of the string in PRUnichars
245
   * @param in aMaxWidth width not to be exceeded
246
   * @param out aMaxFit length of the string that fits within aMaxWidth
247
   *            in PRUnichars
248
   * @return width of the string that fits within aMaxWidth
249
   */
250
  nscoord MeasureString(const char16_t*     aString,
251
                        int32_t              aLength,
252
                        nscoord              aMaxWidth,
253
                        uint32_t&            aMaxFit,
254
                        gfxContext&          aContext,
255
                        nsFontMetrics&      aFontMetrics);
256
257
  void DisplayAltText(nsPresContext*      aPresContext,
258
                      gfxContext&          aRenderingContext,
259
                      const nsString&      aAltText,
260
                      const nsRect&        aRect);
261
262
  ImgDrawResult PaintImage(gfxContext& aRenderingContext, nsPoint aPt,
263
                        const nsRect& aDirtyRect, imgIContainer* aImage,
264
                        uint32_t aFlags);
265
266
  /**
267
   * If we're ready to decode - that is, if our current request's image is
268
   * available and our decoding heuristics are satisfied - then trigger a decode
269
   * for our image at the size we predict it will be drawn next time it's
270
   * painted.
271
   */
272
  void MaybeDecodeForPredictedSize();
273
274
protected:
275
  friend class nsImageListener;
276
  friend class nsImageLoadingContent;
277
  friend class mozilla::PresShell;
278
279
  nsresult OnSizeAvailable(imgIRequest* aRequest, imgIContainer* aImage);
280
  nsresult OnFrameUpdate(imgIRequest* aRequest, const nsIntRect* aRect);
281
  nsresult OnLoadComplete(imgIRequest* aRequest, nsresult aStatus);
282
283
  /**
284
   * Notification that aRequest will now be the current request.
285
   */
286
  void NotifyNewCurrentRequest(imgIRequest *aRequest, nsresult aStatus);
287
288
  /// Always sync decode our image when painting if @aForce is true.
289
0
  void SetForceSyncDecoding(bool aForce) { mForceSyncDecoding = aForce; }
290
291
  /**
292
   * Computes the predicted dest rect that we'll draw into, in app units, based
293
   * upon the provided frame content box. (The content box is what
294
   * nsDisplayImage::GetBounds() returns.)
295
   * The result is not necessarily contained in the frame content box.
296
   */
297
  nsRect PredictedDestRect(const nsRect& aFrameContentBox);
298
299
private:
300
  // random helpers
301
  inline void SpecToURI(const nsAString& aSpec, nsIIOService *aIOService,
302
                        nsIURI **aURI);
303
304
  inline void GetLoadGroup(nsPresContext *aPresContext,
305
                           nsILoadGroup **aLoadGroup);
306
  nscoord GetContinuationOffset() const;
307
  void GetDocumentCharacterSet(nsACString& aCharset) const;
308
  bool ShouldDisplaySelection();
309
310
  /**
311
   * Recalculate mIntrinsicSize from the image.
312
   *
313
   * @return whether aImage's size did _not_
314
   *         match our previous intrinsic size.
315
   */
316
  bool UpdateIntrinsicSize(imgIContainer* aImage);
317
318
  /**
319
   * Recalculate mIntrinsicRatio from the image.
320
   *
321
   * @return whether aImage's ratio did _not_
322
   *         match our previous intrinsic ratio.
323
   */
324
  bool UpdateIntrinsicRatio(imgIContainer* aImage);
325
326
  /**
327
   * This function calculates the transform for converting between
328
   * source space & destination space. May fail if our image has a
329
   * percent-valued or zero-valued height or width.
330
   *
331
   * @param aTransform The transform object to populate.
332
   *
333
   * @return whether we succeeded in creating the transform.
334
   */
335
  bool GetSourceToDestTransform(nsTransform2D& aTransform);
336
337
  /**
338
   * Helper function to check whether the request corresponds to a load we don't
339
   * care about.  Most of the decoder observer methods will bail early if this
340
   * returns true.
341
   */
342
  bool IsPendingLoad(imgIRequest* aRequest) const;
343
344
  /**
345
   * Function to convert a dirty rect in the source image to a dirty
346
   * rect for the image frame.
347
   */
348
  nsRect SourceRectToDest(const nsIntRect & aRect);
349
350
  /**
351
   * Triggers invalidation for both our image display item and, if appropriate,
352
   * our alt-feedback display item.
353
   *
354
   * @param aLayerInvalidRect The area to invalidate in layer space. If null, the
355
   *                          entire layer will be invalidated.
356
   * @param aFrameInvalidRect The area to invalidate in frame space. If null, the
357
   *                          entire frame will be invalidated.
358
   */
359
  void InvalidateSelf(const nsIntRect* aLayerInvalidRect,
360
                      const nsRect* aFrameInvalidRect);
361
362
  RefPtr<nsImageMap> mImageMap;
363
364
  RefPtr<nsImageListener> mListener;
365
366
  // An image request created for content: url(..).
367
  RefPtr<imgRequestProxy> mContentURLRequest;
368
369
  nsCOMPtr<imgIContainer> mImage;
370
  nsCOMPtr<imgIContainer> mPrevImage;
371
  nsSize mComputedSize;
372
  mozilla::IntrinsicSize mIntrinsicSize;
373
  nsSize mIntrinsicRatio;
374
375
  const Kind mKind;
376
  bool mContentURLRequestRegistered;
377
  bool mDisplayingIcon;
378
  bool mFirstFrameComplete;
379
  bool mReflowCallbackPosted;
380
  bool mForceSyncDecoding;
381
382
  static nsIIOService* sIOService;
383
384
  /* loading / broken image icon support */
385
386
  // XXXbz this should be handled by the prescontext, I think; that
387
  // way we would have a single iconload per mozilla session instead
388
  // of one per document...
389
390
  // LoadIcons: initiate the loading of the static icons used to show
391
  // loading / broken images
392
  nsresult LoadIcons(nsPresContext *aPresContext);
393
  nsresult LoadIcon(const nsAString& aSpec, nsPresContext *aPresContext,
394
                    imgRequestProxy **aRequest);
395
396
  class IconLoad final : public nsIObserver,
397
                         public imgINotificationObserver
398
  {
399
    // private class that wraps the data and logic needed for
400
    // broken image and loading image icons
401
  public:
402
    IconLoad();
403
404
    void Shutdown();
405
406
    NS_DECL_ISUPPORTS
407
    NS_DECL_NSIOBSERVER
408
    NS_DECL_IMGINOTIFICATIONOBSERVER
409
410
0
    void AddIconObserver(nsImageFrame *frame) {
411
0
        MOZ_ASSERT(!mIconObservers.Contains(frame),
412
0
                   "Observer shouldn't aleady be in array");
413
0
        mIconObservers.AppendElement(frame);
414
0
    }
415
416
0
    void RemoveIconObserver(nsImageFrame *frame) {
417
0
      mozilla::DebugOnly<bool> didRemove = mIconObservers.RemoveElement(frame);
418
0
      MOZ_ASSERT(didRemove, "Observer not in array");
419
0
    }
420
421
  private:
422
0
    ~IconLoad() {}
423
424
    void GetPrefs();
425
    nsTObserverArray<nsImageFrame*> mIconObservers;
426
427
428
  public:
429
    RefPtr<imgRequestProxy> mLoadingImage;
430
    RefPtr<imgRequestProxy> mBrokenImage;
431
    bool             mPrefForceInlineAltText;
432
    bool             mPrefShowPlaceholders;
433
    bool             mPrefShowLoadingPlaceholder;
434
  };
435
436
public:
437
  // singleton pattern: one LoadIcons instance is used
438
  static mozilla::StaticRefPtr<IconLoad> gIconLoad;
439
440
  friend class nsDisplayImage;
441
};
442
443
/**
444
 * Note that nsDisplayImage does not receive events. However, an image element
445
 * is replaced content so its background will be z-adjacent to the
446
 * image itself, and hence receive events just as if the image itself
447
 * received events.
448
 */
449
class nsDisplayImage final : public nsDisplayImageContainer
450
{
451
public:
452
  typedef mozilla::layers::LayerManager LayerManager;
453
454
  nsDisplayImage(nsDisplayListBuilder* aBuilder, nsImageFrame* aFrame,
455
                 imgIContainer* aImage, imgIContainer* aPrevImage)
456
    : nsDisplayImageContainer(aBuilder, aFrame)
457
    , mImage(aImage)
458
    , mPrevImage(aPrevImage)
459
0
  {
460
0
    MOZ_COUNT_CTOR(nsDisplayImage);
461
0
  }
462
0
  virtual ~nsDisplayImage() {
463
0
    MOZ_COUNT_DTOR(nsDisplayImage);
464
0
  }
465
466
  virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) override;
467
  virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
468
                                         const nsDisplayItemGeometry* aGeometry,
469
                                         nsRegion* aInvalidRegion) const override;
470
  virtual void Paint(nsDisplayListBuilder* aBuilder,
471
                     gfxContext* aCtx) override;
472
473
  virtual already_AddRefed<imgIContainer> GetImage() override;
474
475
  /**
476
   * @return The dest rect we'll use when drawing this image, in app units.
477
   *         Not necessarily contained in this item's bounds.
478
   */
479
  virtual nsRect GetDestRect() const override;
480
481
  virtual void UpdateDrawResult(mozilla::image::ImgDrawResult aResult) override
482
0
  {
483
0
    nsDisplayItemGenericImageGeometry::UpdateDrawResult(this, aResult);
484
0
  }
485
486
  virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
487
                                   LayerManager* aManager,
488
                                   const ContainerLayerParameters& aParameters) override;
489
  nsRect GetBounds(bool* aSnap) const
490
0
  {
491
0
    *aSnap = true;
492
0
493
0
    nsImageFrame* imageFrame = static_cast<nsImageFrame*>(mFrame);
494
0
    return imageFrame->GetInnerArea() + ToReferenceFrame();
495
0
  }
496
497
  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
498
                           bool* aSnap) const override
499
0
  {
500
0
    return GetBounds(aSnap);
501
0
  }
502
503
  virtual nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
504
                                   bool* aSnap) const override;
505
506
  virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
507
                                             LayerManager* aManager,
508
                                             const ContainerLayerParameters& aContainerParameters) override;
509
  virtual bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
510
                                       mozilla::wr::IpcResourceUpdateQueue& aResources,
511
                                       const StackingContextHelper& aSc,
512
                                       mozilla::layers::WebRenderLayerManager* aManager,
513
                                       nsDisplayListBuilder* aDisplayListBuilder) override;
514
515
  NS_DISPLAY_DECL_NAME("Image", TYPE_IMAGE)
516
private:
517
  nsCOMPtr<imgIContainer> mImage;
518
  nsCOMPtr<imgIContainer> mPrevImage;
519
};
520
521
#endif /* nsImageFrame_h___ */