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 #ifndef nsImageRenderer_h__ 8 #define nsImageRenderer_h__ 9 10 #include "nsStyleStruct.h" 11 #include "Units.h" 12 #include "mozilla/AspectRatio.h" 13 #include "mozilla/SurfaceFromElementResult.h" 14 15 class gfxDrawable; 16 class nsDisplayItem; 17 namespace mozilla { 18 19 namespace layers { 20 class StackingContextHelper; 21 class WebRenderParentCommand; 22 class RenderRootStateManager; 23 } // namespace layers 24 25 namespace wr { 26 class DisplayListBuilder; 27 class IpcResourceUpdateQueue; 28 } // namespace wr 29 30 // A CSSSizeOrRatio represents a (possibly partially specified) size for use 31 // in computing image sizes. Either or both of the width and height might be 32 // given. A ratio of width to height may also be given. If we at least two 33 // of these then we can compute a concrete size, that is a width and height. 34 struct CSSSizeOrRatio { CSSSizeOrRatioCSSSizeOrRatio35 CSSSizeOrRatio() 36 : mWidth(0), mHeight(0), mHasWidth(false), mHasHeight(false) {} 37 CanComputeConcreteSizeCSSSizeOrRatio38 bool CanComputeConcreteSize() const { 39 return mHasWidth + mHasHeight + HasRatio() >= 2; 40 } IsConcreteCSSSizeOrRatio41 bool IsConcrete() const { return mHasWidth && mHasHeight; } HasRatioCSSSizeOrRatio42 bool HasRatio() const { return !!mRatio; } IsEmptyCSSSizeOrRatio43 bool IsEmpty() const { 44 return (mHasWidth && mWidth <= 0) || (mHasHeight && mHeight <= 0) || 45 !mRatio; 46 } 47 48 // CanComputeConcreteSize must return true when ComputeConcreteSize is 49 // called. 50 nsSize ComputeConcreteSize() const; 51 SetWidthCSSSizeOrRatio52 void SetWidth(nscoord aWidth) { 53 mWidth = aWidth; 54 mHasWidth = true; 55 if (mHasHeight) { 56 mRatio = AspectRatio::FromSize(mWidth, mHeight); 57 } 58 } SetHeightCSSSizeOrRatio59 void SetHeight(nscoord aHeight) { 60 mHeight = aHeight; 61 mHasHeight = true; 62 if (mHasWidth) { 63 mRatio = AspectRatio::FromSize(mWidth, mHeight); 64 } 65 } SetSizeCSSSizeOrRatio66 void SetSize(const nsSize& aSize) { 67 mWidth = aSize.width; 68 mHeight = aSize.height; 69 mHasWidth = true; 70 mHasHeight = true; 71 mRatio = AspectRatio::FromSize(mWidth, mHeight); 72 } SetRatioCSSSizeOrRatio73 void SetRatio(const AspectRatio& aRatio) { 74 MOZ_ASSERT( 75 !mHasWidth || !mHasHeight, 76 "Probably shouldn't be setting a ratio if we have a concrete size"); 77 mRatio = aRatio; 78 } 79 80 AspectRatio mRatio; 81 nscoord mWidth; 82 nscoord mHeight; 83 bool mHasWidth; 84 bool mHasHeight; 85 }; 86 87 /** 88 * This is a small wrapper class to encapsulate image drawing that can draw an 89 * StyleImage image, which may internally be a real image, a sub image, or a CSS 90 * gradient, etc... 91 * 92 * @note Always call the member functions in the order of PrepareImage(), 93 * SetSize(), and Draw*(). 94 */ 95 class nsImageRenderer { 96 public: 97 typedef mozilla::image::ImgDrawResult ImgDrawResult; 98 typedef mozilla::layers::LayerManager LayerManager; 99 typedef mozilla::layers::ImageContainer ImageContainer; 100 101 enum { 102 FLAG_SYNC_DECODE_IMAGES = 0x01, 103 FLAG_PAINTING_TO_WINDOW = 0x02, 104 FLAG_HIGH_QUALITY_SCALING = 0x04 105 }; 106 enum FitType { CONTAIN, COVER }; 107 108 nsImageRenderer(nsIFrame* aForFrame, const mozilla::StyleImage* aImage, 109 uint32_t aFlags); 110 ~nsImageRenderer() = default; 111 /** 112 * Populates member variables to get ready for rendering. 113 * @return true iff the image is ready, and there is at least a pixel to 114 * draw. 115 */ 116 bool PrepareImage(); 117 118 /** 119 * The three Compute*Size functions correspond to the sizing algorthms and 120 * definitions from the CSS Image Values and Replaced Content spec. See 121 * http://dev.w3.org/csswg/css-images-3/#sizing . 122 */ 123 124 /** 125 * Compute the intrinsic size of the image as defined in the CSS Image Values 126 * spec. The intrinsic size is the unscaled size which the image would ideally 127 * like to be in app units. 128 */ 129 mozilla::CSSSizeOrRatio ComputeIntrinsicSize(); 130 131 /** 132 * Computes the placement for a background image, or for the image data 133 * inside of a replaced element. 134 * 135 * @param aPos The CSS <position> value that specifies the image's position. 136 * @param aOriginBounds The box to which the tiling position should be 137 * relative. For background images, this should correspond to 138 * 'background-origin' for the frame, except when painting on the 139 * canvas, in which case the origin bounds should be the bounds 140 * of the root element's frame. For a replaced element, this should 141 * be the element's content-box. 142 * @param aTopLeft [out] The top-left corner where an image tile should be 143 * drawn. 144 * @param aAnchorPoint [out] A point which should be pixel-aligned by 145 * nsLayoutUtils::DrawImage. This is the same as aTopLeft, unless 146 * CSS specifies a percentage (including 'right' or 'bottom'), in 147 * which case it's that percentage within of aOriginBounds. So 148 * 'right' would set aAnchorPoint.x to aOriginBounds.XMost(). 149 * 150 * Points are returned relative to aOriginBounds. 151 */ 152 static void ComputeObjectAnchorPoint(const mozilla::Position& aPos, 153 const nsSize& aOriginBounds, 154 const nsSize& aImageSize, 155 nsPoint* aTopLeft, 156 nsPoint* aAnchorPoint); 157 158 /** 159 * Compute the size of the rendered image using either the 'cover' or 160 * 'contain' constraints (aFitType). 161 */ 162 static nsSize ComputeConstrainedSize( 163 const nsSize& aConstrainingSize, 164 const mozilla::AspectRatio& aIntrinsicRatio, FitType aFitType); 165 /** 166 * Compute the size of the rendered image (the concrete size) where no cover/ 167 * contain constraints are given. The 'default algorithm' from the CSS Image 168 * Values spec. 169 */ 170 static nsSize ComputeConcreteSize( 171 const mozilla::CSSSizeOrRatio& aSpecifiedSize, 172 const mozilla::CSSSizeOrRatio& aIntrinsicSize, 173 const nsSize& aDefaultSize); 174 175 /** 176 * Set this image's preferred size. This will be its intrinsic size where 177 * specified and the default size where it is not. Used as the unscaled size 178 * when rendering the image. 179 */ 180 void SetPreferredSize(const mozilla::CSSSizeOrRatio& aIntrinsicSize, 181 const nsSize& aDefaultSize); 182 183 /** 184 * Draws the image to the target rendering context using 185 * {background|mask}-specific arguments. 186 * @see nsLayoutUtils::DrawImage() for parameters. 187 */ 188 ImgDrawResult DrawLayer(nsPresContext* aPresContext, 189 gfxContext& aRenderingContext, const nsRect& aDest, 190 const nsRect& aFill, const nsPoint& aAnchor, 191 const nsRect& aDirty, const nsSize& aRepeatSize, 192 float aOpacity); 193 194 /** 195 * Builds WebRender DisplayItems for an image using 196 * {background|mask}-specific arguments. 197 * @see nsLayoutUtils::DrawImage() for parameters. 198 */ 199 ImgDrawResult BuildWebRenderDisplayItemsForLayer( 200 nsPresContext* aPresContext, mozilla::wr::DisplayListBuilder& aBuilder, 201 mozilla::wr::IpcResourceUpdateQueue& aResource, 202 const mozilla::layers::StackingContextHelper& aSc, 203 mozilla::layers::RenderRootStateManager* aManager, nsDisplayItem* aItem, 204 const nsRect& aDest, const nsRect& aFill, const nsPoint& aAnchor, 205 const nsRect& aDirty, const nsSize& aRepeatSize, float aOpacity); 206 207 /** 208 * Draw the image to a single component of a border-image style rendering. 209 * aFill The destination rect to be drawn into 210 * aSrc is the part of the image to be rendered into a tile (aUnitSize in 211 * aFill), if aSrc and the dest tile are different sizes, the image will be 212 * scaled to map aSrc onto the dest tile. 213 * aHFill and aVFill are the repeat patterns for the component - 214 * NS_STYLE_BORDER_IMAGE_REPEAT_* 215 * aUnitSize The scaled size of a single source rect (in destination coords) 216 * aIndex identifies the component: 0 1 2 217 * 3 4 5 218 * 6 7 8 219 * aSVGViewportSize The image size evaluated by default sizing algorithm. 220 * Pass Nothing() if we can read a valid viewport size or aspect-ratio from 221 * the drawing image directly, otherwise, pass Some() with viewport size 222 * evaluated from default sizing algorithm. 223 * aHasIntrinsicRatio is used to record if the source image has fixed 224 * intrinsic ratio. 225 */ 226 ImgDrawResult DrawBorderImageComponent( 227 nsPresContext* aPresContext, gfxContext& aRenderingContext, 228 const nsRect& aDirtyRect, const nsRect& aFill, 229 const mozilla::CSSIntRect& aSrc, mozilla::StyleBorderImageRepeat aHFill, 230 mozilla::StyleBorderImageRepeat aVFill, const nsSize& aUnitSize, 231 uint8_t aIndex, const mozilla::Maybe<nsSize>& aSVGViewportSize, 232 const bool aHasIntrinsicRatio); 233 234 /** 235 * Draw the image to aRenderingContext which can be used to define the 236 * float area in the presence of "shape-outside: <image>". 237 */ 238 ImgDrawResult DrawShapeImage(nsPresContext* aPresContext, 239 gfxContext& aRenderingContext); 240 241 bool IsRasterImage(); 242 bool IsAnimatedImage(); 243 244 /// Retrieves the image associated with this nsImageRenderer, if there is one. 245 already_AddRefed<imgIContainer> GetImage(); 246 247 bool IsImageContainerAvailable(layers::LayerManager* aManager, 248 uint32_t aFlags); IsReady()249 bool IsReady() const { return mPrepareResult == ImgDrawResult::SUCCESS; } PrepareResult()250 ImgDrawResult PrepareResult() const { return mPrepareResult; } SetExtendMode(mozilla::gfx::ExtendMode aMode)251 void SetExtendMode(mozilla::gfx::ExtendMode aMode) { mExtendMode = aMode; } SetMaskOp(mozilla::StyleMaskMode aMaskOp)252 void SetMaskOp(mozilla::StyleMaskMode aMaskOp) { mMaskOp = aMaskOp; } 253 void PurgeCacheForViewportChange( 254 const mozilla::Maybe<nsSize>& aSVGViewportSize, const bool aHasRatio); GetSize()255 const nsSize& GetSize() const { return mSize; } GetType()256 mozilla::StyleImage::Tag GetType() const { return mType; } GetGradientData()257 const mozilla::StyleGradient* GetGradientData() const { 258 return mGradientData; 259 } 260 261 private: 262 /** 263 * Draws the image to the target rendering context. 264 * aSrc is a rect on the source image which will be mapped to aDest; it's 265 * currently only used for gradients. 266 * 267 * @see nsLayoutUtils::DrawImage() for other parameters. 268 */ 269 ImgDrawResult Draw(nsPresContext* aPresContext, gfxContext& aRenderingContext, 270 const nsRect& aDirtyRect, const nsRect& aDest, 271 const nsRect& aFill, const nsPoint& aAnchor, 272 const nsSize& aRepeatSize, const mozilla::CSSIntRect& aSrc, 273 float aOpacity = 1.0); 274 275 /** 276 * Builds WebRender DisplayItems for the image. 277 * aSrc is a rect on the source image which will be mapped to aDest; it's 278 * currently only used for gradients. 279 * 280 * @see nsLayoutUtils::DrawImage() for other parameters. 281 */ 282 ImgDrawResult BuildWebRenderDisplayItems( 283 nsPresContext* aPresContext, mozilla::wr::DisplayListBuilder& aBuilder, 284 mozilla::wr::IpcResourceUpdateQueue& aResources, 285 const mozilla::layers::StackingContextHelper& aSc, 286 mozilla::layers::RenderRootStateManager* aManager, nsDisplayItem* aItem, 287 const nsRect& aDirtyRect, const nsRect& aDest, const nsRect& aFill, 288 const nsPoint& aAnchor, const nsSize& aRepeatSize, 289 const mozilla::CSSIntRect& aSrc, float aOpacity = 1.0); 290 291 /** 292 * Helper method for creating a gfxDrawable from mPaintServerFrame or 293 * mImageElementSurface. 294 * Requires mType to be Element. 295 * Returns null if we cannot create the drawable. 296 */ 297 already_AddRefed<gfxDrawable> DrawableForElement(const nsRect& aImageRect, 298 gfxContext& aContext); 299 300 nsIFrame* mForFrame; 301 const mozilla::StyleImage* mImage; 302 ImageResolution mImageResolution; 303 mozilla::StyleImage::Tag mType; 304 nsCOMPtr<imgIContainer> mImageContainer; 305 const mozilla::StyleGradient* mGradientData; 306 nsIFrame* mPaintServerFrame; 307 SurfaceFromElementResult mImageElementSurface; 308 ImgDrawResult mPrepareResult; 309 nsSize mSize; // unscaled size of the image, in app units 310 uint32_t mFlags; 311 mozilla::gfx::ExtendMode mExtendMode; 312 mozilla::StyleMaskMode mMaskOp; 313 }; 314 315 } // namespace mozilla 316 317 #endif /* nsImageRenderer_h__ */ 318