tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nsImageFrame.h (17037B)


      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 "imgIContainer.h"
     13 #include "imgINotificationObserver.h"
     14 #include "mozilla/Attributes.h"
     15 #include "mozilla/StaticPtr.h"
     16 #include "nsAtomicContainerFrame.h"
     17 #include "nsDisplayList.h"
     18 #include "nsIObserver.h"
     19 #include "nsIReflowCallback.h"
     20 #include "nsTObserverArray.h"
     21 
     22 class nsFontMetrics;
     23 class nsImageMap;
     24 class nsIURI;
     25 class nsILoadGroup;
     26 class nsPresContext;
     27 class nsImageFrame;
     28 class nsTransform2D;
     29 class nsImageLoadingContent;
     30 
     31 namespace mozilla {
     32 class nsDisplayImage;
     33 class PresShell;
     34 namespace layers {
     35 class ImageContainer;
     36 class LayerManager;
     37 }  // namespace layers
     38 }  // namespace mozilla
     39 
     40 class nsImageListener final : public imgINotificationObserver {
     41 protected:
     42  virtual ~nsImageListener();
     43 
     44 public:
     45  explicit nsImageListener(nsImageFrame* aFrame);
     46 
     47  NS_DECL_ISUPPORTS
     48  NS_DECL_IMGINOTIFICATIONOBSERVER
     49 
     50  void SetFrame(nsImageFrame* frame) { mFrame = frame; }
     51 
     52 private:
     53  nsImageFrame* mFrame;
     54 };
     55 
     56 class nsImageFrame : public nsAtomicContainerFrame, public nsIReflowCallback {
     57 public:
     58  template <typename T>
     59  using Maybe = mozilla::Maybe<T>;
     60  using Nothing = mozilla::Nothing;
     61  using Visibility = mozilla::Visibility;
     62 
     63  typedef mozilla::image::ImgDrawResult ImgDrawResult;
     64  typedef mozilla::layers::ImageContainer ImageContainer;
     65  typedef mozilla::layers::LayerManager LayerManager;
     66 
     67  NS_DECL_FRAMEARENA_HELPERS(nsImageFrame)
     68  NS_DECL_QUERYFRAME
     69 
     70  void Destroy(DestroyContext&) override;
     71  void DidSetComputedStyle(ComputedStyle* aOldStyle) final;
     72 
     73  void Init(nsIContent* aContent, nsContainerFrame* aParent,
     74            nsIFrame* aPrevInFlow) override;
     75  void BuildDisplayList(nsDisplayListBuilder*, const nsDisplayListSet&) final;
     76 
     77  nscoord IntrinsicISize(const mozilla::IntrinsicSizeInput& aInput,
     78                         mozilla::IntrinsicISizeType aType) final;
     79 
     80  mozilla::IntrinsicSize GetIntrinsicSize() final { return mIntrinsicSize; }
     81  mozilla::AspectRatio GetIntrinsicRatio() const final {
     82    return mIntrinsicRatio;
     83  }
     84  void Reflow(nsPresContext*, ReflowOutput&, const ReflowInput&,
     85              nsReflowStatus&) override;
     86  bool IsLeafDynamic() const override;
     87 
     88  nsIContent* GetContentForEvent(const mozilla::WidgetEvent*) const final;
     89  MOZ_CAN_RUN_SCRIPT_BOUNDARY
     90  nsresult HandleEvent(nsPresContext*, mozilla::WidgetGUIEvent*,
     91                       nsEventStatus*) override;
     92  Cursor GetCursor(const nsPoint&) override;
     93  nsresult AttributeChanged(int32_t aNameSpaceID, nsAtom* aAttribute,
     94                            AttrModType aModType) final;
     95 
     96  void OnVisibilityChange(
     97      Visibility aNewVisibility,
     98      const Maybe<OnNonvisible>& aNonvisibleAction = Nothing()) final;
     99 
    100  void MarkIntrinsicISizesDirty() override;
    101 
    102  void ResponsiveContentDensityChanged();
    103  void ElementStateChanged(mozilla::dom::ElementState) override;
    104  void SetupOwnedRequest();
    105  void DeinitOwnedRequest();
    106  bool ShouldShowBrokenImageIcon() const;
    107 
    108  bool IsForImageLoadingContent() const {
    109    return mKind == Kind::ImageLoadingContent;
    110  }
    111 
    112  void UpdateXULImage();
    113  const mozilla::StyleImage* GetImageFromStyle() const;
    114 
    115 #ifdef ACCESSIBILITY
    116  mozilla::a11y::AccType AccessibleType() override;
    117 #endif
    118 
    119 #ifdef DEBUG_FRAME_DUMP
    120  nsresult GetFrameName(nsAString& aResult) const override;
    121  void List(FILE* out = stderr, const char* aPrefix = "",
    122            ListFlags aFlags = ListFlags()) const final;
    123 #endif
    124 
    125  LogicalSides GetLogicalSkipSides() const final;
    126 
    127  static void ReleaseGlobals();
    128 
    129  already_AddRefed<imgIRequest> GetCurrentRequest() const;
    130  void Notify(imgIRequest*, int32_t aType, const nsIntRect* aData);
    131 
    132  /**
    133   * Returns whether we should replace an element with an image corresponding to
    134   * its 'content' CSS property.
    135   */
    136  static bool ShouldCreateImageFrameForContentProperty(
    137      const mozilla::dom::Element&, const ComputedStyle&);
    138 
    139  /**
    140   * Function to test whether given an element and its style, that element
    141   * should get an image frame, and if so, which kind of image frame (for
    142   * `content`, or for the element itself).
    143   */
    144  enum class ImageFrameType {
    145    ForContentProperty,
    146    ForElementRequest,
    147    None,
    148  };
    149  static ImageFrameType ImageFrameTypeFor(const mozilla::dom::Element&,
    150                                          const ComputedStyle&);
    151 
    152  ImgDrawResult DisplayAltFeedback(gfxContext& aRenderingContext,
    153                                   const nsRect& aDirtyRect, nsPoint aPt,
    154                                   uint32_t aFlags);
    155 
    156  ImgDrawResult DisplayAltFeedbackWithoutLayer(
    157      nsDisplayItem*, mozilla::wr::DisplayListBuilder&,
    158      mozilla::wr::IpcResourceUpdateQueue&,
    159      const mozilla::layers::StackingContextHelper&,
    160      mozilla::layers::RenderRootStateManager*, nsDisplayListBuilder*,
    161      nsPoint aPt, uint32_t aFlags);
    162 
    163  /**
    164   * Return a map element associated with this image.
    165   */
    166  mozilla::dom::Element* GetMapElement() const;
    167 
    168  /**
    169   * Return true if the image has associated image map.
    170   */
    171  bool HasImageMap() const { return mImageMap || GetMapElement(); }
    172 
    173  nsImageMap* GetImageMap();
    174  nsImageMap* GetExistingImageMap() const { return mImageMap; }
    175 
    176  void AddInlineMinISize(const mozilla::IntrinsicSizeInput& aInput,
    177                         InlineMinISizeData* aData) final;
    178 
    179  void DisconnectMap();
    180 
    181  // nsIReflowCallback
    182  bool ReflowFinished() final;
    183  void ReflowCallbackCanceled() final;
    184 
    185  // The kind of image frame we are.
    186  enum class Kind : uint8_t {
    187    // For an nsImageLoadingContent.
    188    ImageLoadingContent,
    189    // For a <xul:image> element.
    190    XULImage,
    191    // For css 'content: url(..)' on non-generated content.
    192    ContentProperty,
    193    // For a child of a ::before / ::after pseudo-element that had an url() item
    194    // for the content property.
    195    ContentPropertyAtIndex,
    196    // For a list-style-image ::marker.
    197    ListStyleImage,
    198    // For a ::view-transition-old or ::view-transition-new pseudo-element.
    199    // Which one of the two is determined by the PseudoStyleType applying to us.
    200    ViewTransition,
    201  };
    202 
    203  // Creates a suitable continuing frame for this frame.
    204  nsImageFrame* CreateContinuingFrame(mozilla::PresShell*,
    205                                      ComputedStyle*) const;
    206 
    207  mozilla::AspectRatio ComputeIntrinsicRatioForImage(
    208      imgIContainer*, bool aIgnoreContainment = false) const;
    209 
    210 private:
    211  friend nsIFrame* NS_NewImageFrame(mozilla::PresShell*, ComputedStyle*);
    212  friend nsIFrame* NS_NewXULImageFrame(mozilla::PresShell*, ComputedStyle*);
    213  friend nsIFrame* NS_NewImageFrameForContentProperty(mozilla::PresShell*,
    214                                                      ComputedStyle*);
    215  friend nsIFrame* NS_NewImageFrameForGeneratedContentIndex(mozilla::PresShell*,
    216                                                            ComputedStyle*);
    217  friend nsIFrame* NS_NewImageFrameForListStyleImage(mozilla::PresShell*,
    218                                                     ComputedStyle*);
    219  friend nsIFrame* NS_NewImageFrameForViewTransition(mozilla::PresShell*,
    220                                                     ComputedStyle*);
    221 
    222  nsImageFrame(ComputedStyle* aStyle, nsPresContext* aPresContext, Kind aKind)
    223      : nsImageFrame(aStyle, aPresContext, kClassID, aKind) {}
    224 
    225  nsImageFrame(ComputedStyle*, nsPresContext* aPresContext, ClassID, Kind);
    226 
    227  void ReflowChildren(nsPresContext*, const ReflowInput&,
    228                      const mozilla::LogicalSize& aImageSize);
    229 
    230  void UpdateIntrinsicSizeAndRatio();
    231 
    232 protected:
    233  nsImageFrame(ComputedStyle* aStyle, nsPresContext* aPresContext, ClassID aID)
    234      : nsImageFrame(aStyle, aPresContext, aID, Kind::ImageLoadingContent) {}
    235 
    236  ~nsImageFrame() override;
    237 
    238  /**
    239   * Populate/update mIntrinsicSize and mIntrinsicSize if necessary.
    240   *
    241   * @param aConsiderIntrinsicsDirty if true, then this function will update
    242   *   mIntrinsicSize and mIntrinsicRatio *regardless* of what their current
    243   *   value is. (We'll still reason about whether the value changed or not
    244   *   when deciding whether additional notifications are needed.)  This param
    245   *   defaults to false, but it's used in MarkIntrinsicISizesDirty.
    246   */
    247  void EnsureIntrinsicSizeAndRatio(bool aConsiderIntrinsicsDirty = false);
    248 
    249  bool GotInitialReflow() const {
    250    return !HasAnyStateBits(NS_FRAME_FIRST_REFLOW);
    251  }
    252 
    253  SizeComputationResult ComputeSize(
    254      const SizeComputationInput& aSizingInput, mozilla::WritingMode aWM,
    255      const mozilla::LogicalSize& aCBSize, nscoord aAvailableISize,
    256      const mozilla::LogicalSize& aMargin,
    257      const mozilla::LogicalSize& aBorderPadding,
    258      const mozilla::StyleSizeOverrides& aSizeOverrides,
    259      mozilla::ComputeSizeFlags aFlags) final;
    260 
    261  bool IsServerImageMap();
    262 
    263  // Translate a point that is relative to our frame into a localized CSS pixel
    264  // coordinate that is relative to the content area of this frame (inside the
    265  // border+padding).
    266  mozilla::CSSIntPoint TranslateEventCoords(const nsPoint&) const;
    267 
    268  bool GetAnchorHREFTargetAndNode(nsIURI** aHref, nsString& aTarget,
    269                                  nsIContent** aNode);
    270  /**
    271   * Computes the width of the string that fits into the available space
    272   *
    273   * @param in aLength total length of the string in PRUnichars
    274   * @param in aMaxWidth width not to be exceeded
    275   * @param out aMaxFit length of the string that fits within aMaxWidth
    276   *            in PRUnichars
    277   * @return width of the string that fits within aMaxWidth
    278   */
    279  nscoord MeasureString(const char16_t* aString, int32_t aLength,
    280                        nscoord aMaxWidth, uint32_t& aMaxFit,
    281                        gfxContext& aContext, nsFontMetrics& aFontMetrics);
    282 
    283  void DisplayAltText(nsPresContext* aPresContext,
    284                      gfxContext& aRenderingContext, const nsString& aAltText,
    285                      const nsRect& aRect);
    286 
    287  ImgDrawResult PaintImage(gfxContext& aRenderingContext, nsPoint aPt,
    288                           const nsRect& aDirtyRect, imgIContainer* aImage,
    289                           uint32_t aFlags);
    290 
    291  /**
    292   * If we're ready to decode - that is, if our current request's image is
    293   * available and our decoding heuristics are satisfied - then trigger a decode
    294   * for our image at the size we predict it will be drawn next time it's
    295   * painted.
    296   */
    297  void MaybeDecodeForPredictedSize();
    298 
    299 protected:
    300  friend class nsImageListener;
    301  friend class nsImageLoadingContent;
    302  friend class mozilla::PresShell;
    303 
    304  void OnSizeAvailable(imgIRequest* aRequest, imgIContainer* aImage);
    305  void OnFrameUpdate(imgIRequest* aRequest, const nsIntRect* aRect);
    306  void OnLoadComplete(imgIRequest* aRequest);
    307  mozilla::IntrinsicSize ComputeIntrinsicSize(
    308      bool aIgnoreContainment = false) const;
    309  // Whether the image frame should use the mapped aspect ratio from width=""
    310  // and height="".
    311  bool ShouldUseMappedAspectRatio() const;
    312 
    313  nsAtom* GetViewTransitionName() const;
    314  Maybe<nsSize> GetViewTransitionBorderBoxSize() const;
    315  mozilla::wr::ImageKey GetViewTransitionImageKey(
    316      mozilla::layers::RenderRootStateManager*,
    317      mozilla::wr::IpcResourceUpdateQueue&) const;
    318 
    319  /**
    320   * Notification that aRequest will now be the current request.
    321   */
    322  void NotifyNewCurrentRequest(imgIRequest* aRequest);
    323 
    324  /// Always sync decode our image when painting if @aForce is true.
    325  void SetForceSyncDecoding(bool aForce) { mForceSyncDecoding = aForce; }
    326 
    327  void AssertSyncDecodingHintIsInSync() const
    328 #ifndef DEBUG
    329      {}
    330 #else
    331      ;
    332 #endif
    333 
    334  /**
    335   * Computes the dest rect that we'll draw into, in app units, based upon the
    336   * provided frame content box. The result is not necessarily contained in the
    337   * frame content box.
    338   */
    339  nsRect GetDestRect(const nsRect& aFrameContentBox,
    340                     nsPoint* aAnchorPoint = nullptr);
    341 
    342 private:
    343  nscoord GetContinuationOffset() const;
    344  bool ShouldDisplaySelection();
    345 
    346  // Recalculate mIntrinsicSize from the image.
    347  bool UpdateIntrinsicSize();
    348 
    349  // Recalculate mIntrinsicRatio from the image.
    350  bool UpdateIntrinsicRatio();
    351 
    352  /**
    353   * This function calculates the transform for converting between
    354   * source space & destination space. May fail if our image has a
    355   * percent-valued or zero-valued height or width.
    356   *
    357   * @param aTransform The transform object to populate.
    358   *
    359   * @return whether we succeeded in creating the transform.
    360   */
    361  bool GetSourceToDestTransform(nsTransform2D& aTransform);
    362 
    363  /**
    364   * Helper function to check whether the request corresponds to a load we don't
    365   * care about.  Most of the decoder observer methods will bail early if this
    366   * returns true.
    367   */
    368  bool IsPendingLoad(imgIRequest*) const;
    369 
    370  /**
    371   * Updates mImage based on the current image request, and the image passed in
    372   * (both can be null), and invalidate layout and paint as needed.
    373   */
    374  void UpdateImage(imgIRequest*, imgIContainer*);
    375 
    376  /**
    377   * Function to convert a dirty rect in the source image to a dirty
    378   * rect for the image frame.
    379   */
    380  nsRect SourceRectToDest(const nsIntRect& aRect);
    381 
    382  /**
    383   * Triggers invalidation for both our image display item and, if appropriate,
    384   * our alt-feedback display item.
    385   *
    386   * @param aLayerInvalidRect The area to invalidate in layer space. If null,
    387   * the entire layer will be invalidated.
    388   * @param aFrameInvalidRect The area to invalidate in frame space. If null,
    389   * the entire frame will be invalidated.
    390   */
    391  void InvalidateSelf(const nsIntRect* aLayerInvalidRect,
    392                      const nsRect* aFrameInvalidRect);
    393 
    394  void MaybeSendIntrinsicSizeAndRatioToEmbedder();
    395  void MaybeSendIntrinsicSizeAndRatioToEmbedder(Maybe<mozilla::IntrinsicSize>,
    396                                                Maybe<mozilla::AspectRatio>);
    397 
    398  RefPtr<nsImageMap> mImageMap;
    399 
    400  RefPtr<nsImageListener> mListener;
    401 
    402  // An image request created for content: url(..), list-style-image, or
    403  // <xul:image>.
    404  RefPtr<imgRequestProxy> mOwnedRequest;
    405 
    406  nsCOMPtr<imgIContainer> mImage;
    407  nsCOMPtr<imgIContainer> mPrevImage;
    408 
    409  // The content-box size as if we are not fragmented, cached in the most recent
    410  // reflow.
    411  nsSize mComputedSize;
    412 
    413  mozilla::IntrinsicSize mIntrinsicSize;
    414 
    415  // Stores mImage's intrinsic ratio, or a default AspectRatio if there's no
    416  // intrinsic ratio.
    417  mozilla::AspectRatio mIntrinsicRatio;
    418 
    419  const Kind mKind;
    420  bool mOwnedRequestRegistered = false;
    421  bool mDisplayingIcon = false;
    422  bool mFirstFrameComplete = false;
    423  bool mReflowCallbackPosted = false;
    424  bool mForceSyncDecoding = false;
    425  bool mIsInObjectOrEmbed = false;
    426 
    427 public:
    428  friend class mozilla::nsDisplayImage;
    429  friend class nsDisplayGradient;
    430 };
    431 
    432 namespace mozilla {
    433 /**
    434 * Note that nsDisplayImage does not receive events. However, an image element
    435 * is replaced content so its background will be z-adjacent to the
    436 * image itself, and hence receive events just as if the image itself
    437 * received events.
    438 */
    439 class nsDisplayImage final : public nsPaintedDisplayItem {
    440 public:
    441  typedef mozilla::layers::LayerManager LayerManager;
    442 
    443  nsDisplayImage(nsDisplayListBuilder* aBuilder, nsImageFrame* aFrame)
    444      : nsPaintedDisplayItem(aBuilder, aFrame) {
    445    MOZ_COUNT_CTOR(nsDisplayImage);
    446  }
    447 
    448  MOZ_COUNTED_DTOR_FINAL(nsDisplayImage)
    449 
    450  void Paint(nsDisplayListBuilder*, gfxContext* aCtx) final;
    451 
    452  /**
    453   * @return The dest rect we'll use when drawing this image, in app units.
    454   *         Not necessarily contained in this item's bounds.
    455   */
    456  nsRect GetDestRect() const;
    457  nsRect GetDestRectViewTransition() const;
    458 
    459  nsRect GetBounds(bool* aSnap) const {
    460    *aSnap = true;
    461    return Frame()->InkOverflowRectRelativeToSelf() + ToReferenceFrame();
    462  }
    463 
    464  nsRect GetBounds(nsDisplayListBuilder*, bool* aSnap) const final {
    465    return GetBounds(aSnap);
    466  }
    467 
    468  nsRegion GetOpaqueRegion(nsDisplayListBuilder*, bool* aSnap) const final;
    469 
    470  bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder&,
    471                               mozilla::wr::IpcResourceUpdateQueue&,
    472                               const StackingContextHelper&,
    473                               mozilla::layers::RenderRootStateManager*,
    474                               nsDisplayListBuilder*) final;
    475 
    476  void MaybeCreateWebRenderCommandsForViewTransition(
    477      mozilla::wr::DisplayListBuilder&, mozilla::wr::IpcResourceUpdateQueue&,
    478      const StackingContextHelper&, mozilla::layers::RenderRootStateManager*,
    479      nsDisplayListBuilder*);
    480 
    481  nsImageFrame* Frame() const {
    482    MOZ_ASSERT(mFrame->IsImageFrame() || mFrame->IsImageControlFrame());
    483    return static_cast<nsImageFrame*>(mFrame);
    484  }
    485 
    486  NS_DISPLAY_DECL_NAME("Image", TYPE_IMAGE)
    487 };
    488 
    489 }  // namespace mozilla
    490 
    491 #endif /* nsImageFrame_h___ */