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