1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 /* utility functions for drawing borders and backgrounds */ 7 8 #ifndef nsCSSRendering_h___ 9 #define nsCSSRendering_h___ 10 11 #include "gfxBlur.h" 12 #include "gfxContext.h" 13 #include "imgIContainer.h" 14 #include "mozilla/gfx/PathHelpers.h" 15 #include "mozilla/gfx/Rect.h" 16 #include "mozilla/TypedEnumBits.h" 17 #include "nsLayoutUtils.h" 18 #include "nsStyleStruct.h" 19 #include "nsIFrame.h" 20 21 class gfxDrawable; 22 class nsStyleContext; 23 class nsPresContext; 24 class nsRenderingContext; 25 26 namespace mozilla { 27 28 namespace gfx { 29 struct Color; 30 class DrawTarget; 31 } // namespace gfx 32 33 namespace layers { 34 class ImageContainer; 35 } // namespace layers 36 37 // A CSSSizeOrRatio represents a (possibly partially specified) size for use 38 // in computing image sizes. Either or both of the width and height might be 39 // given. A ratio of width to height may also be given. If we at least two 40 // of these then we can compute a concrete size, that is a width and height. 41 struct CSSSizeOrRatio 42 { CSSSizeOrRatioCSSSizeOrRatio43 CSSSizeOrRatio() 44 : mRatio(0, 0) 45 , mHasWidth(false) 46 , mHasHeight(false) {} 47 CanComputeConcreteSizeCSSSizeOrRatio48 bool CanComputeConcreteSize() const 49 { 50 return mHasWidth + mHasHeight + HasRatio() >= 2; 51 } IsConcreteCSSSizeOrRatio52 bool IsConcrete() const { return mHasWidth && mHasHeight; } HasRatioCSSSizeOrRatio53 bool HasRatio() const { return mRatio.width > 0 && mRatio.height > 0; } IsEmptyCSSSizeOrRatio54 bool IsEmpty() const 55 { 56 return (mHasWidth && mWidth <= 0) || 57 (mHasHeight && mHeight <= 0) || 58 mRatio.width <= 0 || mRatio.height <= 0; 59 } 60 61 // CanComputeConcreteSize must return true when ComputeConcreteSize is 62 // called. 63 nsSize ComputeConcreteSize() const; 64 SetWidthCSSSizeOrRatio65 void SetWidth(nscoord aWidth) 66 { 67 mWidth = aWidth; 68 mHasWidth = true; 69 if (mHasHeight) { 70 mRatio = nsSize(mWidth, mHeight); 71 } 72 } SetHeightCSSSizeOrRatio73 void SetHeight(nscoord aHeight) 74 { 75 mHeight = aHeight; 76 mHasHeight = true; 77 if (mHasWidth) { 78 mRatio = nsSize(mWidth, mHeight); 79 } 80 } SetSizeCSSSizeOrRatio81 void SetSize(const nsSize& aSize) 82 { 83 mWidth = aSize.width; 84 mHeight = aSize.height; 85 mHasWidth = true; 86 mHasHeight = true; 87 mRatio = aSize; 88 } SetRatioCSSSizeOrRatio89 void SetRatio(const nsSize& aRatio) 90 { 91 MOZ_ASSERT(!mHasWidth || !mHasHeight, 92 "Probably shouldn't be setting a ratio if we have a concrete size"); 93 mRatio = aRatio; 94 } 95 96 nsSize mRatio; 97 nscoord mWidth; 98 nscoord mHeight; 99 bool mHasWidth; 100 bool mHasHeight; 101 }; 102 103 enum class PaintBorderFlags : uint8_t 104 { 105 SYNC_DECODE_IMAGES = 1 << 0 106 }; 107 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(PaintBorderFlags) 108 109 } // namespace mozilla 110 111 /** 112 * This is a small wrapper class to encapsulate image drawing that can draw an 113 * nsStyleImage image, which may internally be a real image, a sub image, or a 114 * CSS gradient. 115 * 116 * @note Always call the member functions in the order of PrepareImage(), 117 * SetSize(), and Draw*(). 118 */ 119 class nsImageRenderer { 120 public: 121 typedef mozilla::image::DrawResult DrawResult; 122 typedef mozilla::layers::LayerManager LayerManager; 123 typedef mozilla::layers::ImageContainer ImageContainer; 124 125 enum { 126 FLAG_SYNC_DECODE_IMAGES = 0x01, 127 FLAG_PAINTING_TO_WINDOW = 0x02 128 }; 129 enum FitType 130 { 131 CONTAIN, 132 COVER 133 }; 134 135 nsImageRenderer(nsIFrame* aForFrame, const nsStyleImage* aImage, uint32_t aFlags); 136 ~nsImageRenderer(); 137 /** 138 * Populates member variables to get ready for rendering. 139 * @return true iff the image is ready, and there is at least a pixel to 140 * draw. 141 */ 142 bool PrepareImage(); 143 144 /** 145 * The three Compute*Size functions correspond to the sizing algorthms and 146 * definitions from the CSS Image Values and Replaced Content spec. See 147 * http://dev.w3.org/csswg/css-images-3/#sizing . 148 */ 149 150 /** 151 * Compute the intrinsic size of the image as defined in the CSS Image Values 152 * spec. The intrinsic size is the unscaled size which the image would ideally 153 * like to be in app units. 154 */ 155 mozilla::CSSSizeOrRatio ComputeIntrinsicSize(); 156 157 /** 158 * Computes the placement for a background image, or for the image data 159 * inside of a replaced element. 160 * 161 * @param aPos The CSS <position> value that specifies the image's position. 162 * @param aOriginBounds The box to which the tiling position should be 163 * relative. For background images, this should correspond to 164 * 'background-origin' for the frame, except when painting on the 165 * canvas, in which case the origin bounds should be the bounds 166 * of the root element's frame. For a replaced element, this should 167 * be the element's content-box. 168 * @param aTopLeft [out] The top-left corner where an image tile should be 169 * drawn. 170 * @param aAnchorPoint [out] A point which should be pixel-aligned by 171 * nsLayoutUtils::DrawImage. This is the same as aTopLeft, unless 172 * CSS specifies a percentage (including 'right' or 'bottom'), in 173 * which case it's that percentage within of aOriginBounds. So 174 * 'right' would set aAnchorPoint.x to aOriginBounds.XMost(). 175 * 176 * Points are returned relative to aOriginBounds. 177 */ 178 static void ComputeObjectAnchorPoint(const mozilla::Position& aPos, 179 const nsSize& aOriginBounds, 180 const nsSize& aImageSize, 181 nsPoint* aTopLeft, 182 nsPoint* aAnchorPoint); 183 184 /** 185 * Compute the size of the rendered image using either the 'cover' or 186 * 'contain' constraints (aFitType). 187 * aIntrinsicRatio may be an invalid ratio, that is one or both of its 188 * dimensions can be less than or equal to zero. 189 */ 190 static nsSize ComputeConstrainedSize(const nsSize& aConstrainingSize, 191 const nsSize& aIntrinsicRatio, 192 FitType aFitType); 193 /** 194 * Compute the size of the rendered image (the concrete size) where no cover/ 195 * contain constraints are given. The 'default algorithm' from the CSS Image 196 * Values spec. 197 */ 198 static nsSize ComputeConcreteSize(const mozilla::CSSSizeOrRatio& aSpecifiedSize, 199 const mozilla::CSSSizeOrRatio& aIntrinsicSize, 200 const nsSize& aDefaultSize); 201 202 /** 203 * Set this image's preferred size. This will be its intrinsic size where 204 * specified and the default size where it is not. Used as the unscaled size 205 * when rendering the image. 206 */ 207 void SetPreferredSize(const mozilla::CSSSizeOrRatio& aIntrinsicSize, 208 const nsSize& aDefaultSize); 209 210 /** 211 * Draws the image to the target rendering context using background-specific 212 * arguments. 213 * @see nsLayoutUtils::DrawImage() for parameters. 214 */ 215 DrawResult DrawBackground(nsPresContext* aPresContext, 216 nsRenderingContext& aRenderingContext, 217 const nsRect& aDest, 218 const nsRect& aFill, 219 const nsPoint& aAnchor, 220 const nsRect& aDirty, 221 const nsSize& aRepeatSize); 222 223 /** 224 * Draw the image to a single component of a border-image style rendering. 225 * aFill The destination rect to be drawn into 226 * aSrc is the part of the image to be rendered into a tile (aUnitSize in 227 * aFill), if aSrc and the dest tile are different sizes, the image will be 228 * scaled to map aSrc onto the dest tile. 229 * aHFill and aVFill are the repeat patterns for the component - 230 * NS_STYLE_BORDER_IMAGE_REPEAT_* 231 * aUnitSize The scaled size of a single source rect (in destination coords) 232 * aIndex identifies the component: 0 1 2 233 * 3 4 5 234 * 6 7 8 235 * aSVGViewportSize The image size evaluated by default sizing algorithm. 236 * Pass Nothing() if we can read a valid viewport size or aspect-ratio from 237 * the drawing image directly, otherwise, pass Some() with viewport size 238 * evaluated from default sizing algorithm. 239 * aHasIntrinsicRatio is used to record if the source image has fixed 240 * intrinsic ratio. 241 */ 242 DrawResult 243 DrawBorderImageComponent(nsPresContext* aPresContext, 244 nsRenderingContext& aRenderingContext, 245 const nsRect& aDirtyRect, 246 const nsRect& aFill, 247 const mozilla::CSSIntRect& aSrc, 248 uint8_t aHFill, 249 uint8_t aVFill, 250 const nsSize& aUnitSize, 251 uint8_t aIndex, 252 const mozilla::Maybe<nsSize>& aSVGViewportSize, 253 const bool aHasIntrinsicRatio); 254 255 bool IsRasterImage(); 256 bool IsAnimatedImage(); 257 258 /// Retrieves the image associated with this nsImageRenderer, if there is one. 259 already_AddRefed<imgIContainer> GetImage(); 260 IsReady()261 bool IsReady() const { return mPrepareResult == DrawResult::SUCCESS; } PrepareResult()262 DrawResult PrepareResult() const { return mPrepareResult; } SetExtendMode(mozilla::gfx::ExtendMode aMode)263 void SetExtendMode(mozilla::gfx::ExtendMode aMode) { mExtendMode = aMode; } SetMaskOp(uint8_t aMaskOp)264 void SetMaskOp(uint8_t aMaskOp) { mMaskOp = aMaskOp; } 265 void PurgeCacheForViewportChange(const mozilla::Maybe<nsSize>& aSVGViewportSize, 266 const bool aHasRatio); 267 268 private: 269 /** 270 * Draws the image to the target rendering context. 271 * aSrc is a rect on the source image which will be mapped to aDest; it's 272 * currently only used for gradients. 273 * 274 * @see nsLayoutUtils::DrawImage() for other parameters. 275 */ 276 DrawResult Draw(nsPresContext* aPresContext, 277 nsRenderingContext& aRenderingContext, 278 const nsRect& aDirtyRect, 279 const nsRect& aDest, 280 const nsRect& aFill, 281 const nsPoint& aAnchor, 282 const nsSize& aRepeatSize, 283 const mozilla::CSSIntRect& aSrc); 284 285 /** 286 * Helper method for creating a gfxDrawable from mPaintServerFrame or 287 * mImageElementSurface. 288 * Requires mType is eStyleImageType_Element. 289 * Returns null if we cannot create the drawable. 290 */ 291 already_AddRefed<gfxDrawable> DrawableForElement(const nsRect& aImageRect, 292 nsRenderingContext& aRenderingContext); 293 294 nsIFrame* mForFrame; 295 const nsStyleImage* mImage; 296 nsStyleImageType mType; 297 nsCOMPtr<imgIContainer> mImageContainer; 298 RefPtr<nsStyleGradient> mGradientData; 299 nsIFrame* mPaintServerFrame; 300 nsLayoutUtils::SurfaceFromElementResult mImageElementSurface; 301 DrawResult mPrepareResult; 302 nsSize mSize; // unscaled size of the image, in app units 303 uint32_t mFlags; 304 mozilla::gfx::ExtendMode mExtendMode; 305 uint8_t mMaskOp; 306 }; 307 308 /** 309 * A struct representing all the information needed to paint a background 310 * image to some target, taking into account all CSS background-* properties. 311 * See PrepareImageLayer. 312 */ 313 struct nsBackgroundLayerState { 314 typedef mozilla::gfx::CompositionOp CompositionOp; 315 316 /** 317 * @param aFlags some combination of nsCSSRendering::PAINTBG_* flags 318 */ nsBackgroundLayerStatensBackgroundLayerState319 nsBackgroundLayerState(nsIFrame* aForFrame, const nsStyleImage* aImage, 320 uint32_t aFlags) 321 : mImageRenderer(aForFrame, aImage, aFlags) 322 {} 323 324 /** 325 * The nsImageRenderer that will be used to draw the background. 326 */ 327 nsImageRenderer mImageRenderer; 328 /** 329 * A rectangle that one copy of the image tile is mapped onto. Same 330 * coordinate system as aBorderArea/aBGClipRect passed into 331 * PrepareImageLayer. 332 */ 333 nsRect mDestArea; 334 /** 335 * The actual rectangle that should be filled with (complete or partial) 336 * image tiles. Same coordinate system as aBorderArea/aBGClipRect passed into 337 * PrepareImageLayer. 338 */ 339 nsRect mFillArea; 340 /** 341 * The anchor point that should be snapped to a pixel corner. Same 342 * coordinate system as aBorderArea/aBGClipRect passed into 343 * PrepareImageLayer. 344 */ 345 nsPoint mAnchor; 346 /** 347 * The background-repeat property space keyword computes the 348 * repeat size which is image size plus spacing. 349 */ 350 nsSize mRepeatSize; 351 }; 352 353 struct nsCSSRendering { 354 typedef mozilla::gfx::CompositionOp CompositionOp; 355 typedef mozilla::gfx::DrawTarget DrawTarget; 356 typedef mozilla::gfx::Float Float; 357 typedef mozilla::gfx::Point Point; 358 typedef mozilla::gfx::Rect Rect; 359 typedef mozilla::gfx::Size Size; 360 typedef mozilla::gfx::RectCornerRadii RectCornerRadii; 361 typedef mozilla::image::DrawResult DrawResult; 362 typedef nsIFrame::Sides Sides; 363 364 /** 365 * Initialize any static variables used by nsCSSRendering. 366 */ 367 static void Init(); 368 369 /** 370 * Clean up any static variables used by nsCSSRendering. 371 */ 372 static void Shutdown(); 373 374 static void PaintBoxShadowInner(nsPresContext* aPresContext, 375 nsRenderingContext& aRenderingContext, 376 nsIFrame* aForFrame, 377 const nsRect& aFrameArea); 378 379 static void PaintBoxShadowOuter(nsPresContext* aPresContext, 380 nsRenderingContext& aRenderingContext, 381 nsIFrame* aForFrame, 382 const nsRect& aFrameArea, 383 const nsRect& aDirtyRect, 384 float aOpacity = 1.0); 385 386 static void ComputePixelRadii(const nscoord *aAppUnitsRadii, 387 nscoord aAppUnitsPerPixel, 388 RectCornerRadii *oBorderRadii); 389 390 /** 391 * Render the border for an element using css rendering rules 392 * for borders. aSkipSides says which sides to skip 393 * when rendering, the default is to skip none. 394 */ 395 static DrawResult PaintBorder(nsPresContext* aPresContext, 396 nsRenderingContext& aRenderingContext, 397 nsIFrame* aForFrame, 398 const nsRect& aDirtyRect, 399 const nsRect& aBorderArea, 400 nsStyleContext* aStyleContext, 401 mozilla::PaintBorderFlags aFlags, 402 Sides aSkipSides = Sides()); 403 404 /** 405 * Like PaintBorder, but taking an nsStyleBorder argument instead of 406 * getting it from aStyleContext. aSkipSides says which sides to skip 407 * when rendering, the default is to skip none. 408 */ 409 static DrawResult PaintBorderWithStyleBorder(nsPresContext* aPresContext, 410 nsRenderingContext& aRenderingContext, 411 nsIFrame* aForFrame, 412 const nsRect& aDirtyRect, 413 const nsRect& aBorderArea, 414 const nsStyleBorder& aBorderStyle, 415 nsStyleContext* aStyleContext, 416 mozilla::PaintBorderFlags aFlags, 417 Sides aSkipSides = Sides()); 418 419 420 /** 421 * Render the outline for an element using css rendering rules 422 * for borders. 423 */ 424 static void PaintOutline(nsPresContext* aPresContext, 425 nsRenderingContext& aRenderingContext, 426 nsIFrame* aForFrame, 427 const nsRect& aDirtyRect, 428 const nsRect& aBorderArea, 429 nsStyleContext* aStyleContext); 430 431 /** 432 * Render keyboard focus on an element. 433 * |aFocusRect| is the outer rectangle of the focused element. 434 * Uses a fixed style equivalent to "1px dotted |aColor|". 435 * Not used for controls, because the native theme may differ. 436 */ 437 static void PaintFocus(nsPresContext* aPresContext, 438 DrawTarget* aDrawTarget, 439 const nsRect& aFocusRect, 440 nscolor aColor); 441 442 /** 443 * Render a gradient for an element. 444 * aDest is the rect for a single tile of the gradient on the destination. 445 * aFill is the rect on the destination to be covered by repeated tiling of 446 * the gradient. 447 * aSrc is the part of the gradient to be rendered into a tile (aDest), if 448 * aSrc and aDest are different sizes, the image will be scaled to map aSrc 449 * onto aDest. 450 * aIntrinsicSize is the size of the source gradient. 451 */ 452 static void PaintGradient(nsPresContext* aPresContext, 453 nsRenderingContext& aRenderingContext, 454 nsStyleGradient* aGradient, 455 const nsRect& aDirtyRect, 456 const nsRect& aDest, 457 const nsRect& aFill, 458 const nsSize& aRepeatSize, 459 const mozilla::CSSIntRect& aSrc, 460 const nsSize& aIntrinsiceSize); 461 462 /** 463 * Find the frame whose background style should be used to draw the 464 * canvas background. aForFrame must be the frame for the root element 465 * whose background style should be used. This function will return 466 * aForFrame unless the <body> background should be propagated, in 467 * which case we return the frame associated with the <body>'s background. 468 */ 469 static nsIFrame* FindBackgroundStyleFrame(nsIFrame* aForFrame); 470 471 /** 472 * @return true if |aFrame| is a canvas frame, in the CSS sense. 473 */ 474 static bool IsCanvasFrame(nsIFrame* aFrame); 475 476 /** 477 * Fill in an aBackgroundSC to be used to paint the background 478 * for an element. This applies the rules for propagating 479 * backgrounds between BODY, the root element, and the canvas. 480 * @return true if there is some meaningful background. 481 */ 482 static bool FindBackground(nsIFrame* aForFrame, 483 nsStyleContext** aBackgroundSC); 484 485 /** 486 * As FindBackground, but the passed-in frame is known to be a root frame 487 * (returned from nsCSSFrameConstructor::GetRootElementStyleFrame()) 488 * and there is always some meaningful background returned. 489 */ 490 static nsStyleContext* FindRootFrameBackground(nsIFrame* aForFrame); 491 492 /** 493 * Returns background style information for the canvas. 494 * 495 * @param aForFrame 496 * the frame used to represent the canvas, in the CSS sense (i.e. 497 * nsCSSRendering::IsCanvasFrame(aForFrame) must be true) 498 * @param aRootElementFrame 499 * the frame representing the root element of the document 500 * @param aBackground 501 * contains background style information for the canvas on return 502 */ 503 static nsStyleContext* FindCanvasBackgroundnsCSSRendering504 FindCanvasBackground(nsIFrame* aForFrame, nsIFrame* aRootElementFrame) 505 { 506 MOZ_ASSERT(IsCanvasFrame(aForFrame), "not a canvas frame"); 507 if (aRootElementFrame) 508 return FindRootFrameBackground(aRootElementFrame); 509 510 // This should always give transparent, so we'll fill it in with the 511 // default color if needed. This seems to happen a bit while a page is 512 // being loaded. 513 return aForFrame->StyleContext(); 514 } 515 516 /** 517 * Find a frame which draws a non-transparent background, 518 * for various table-related and HR-related backwards-compatibility hacks. 519 * This function will also stop if it finds themed frame which might draw 520 * background. 521 * 522 * Be very hesitant if you're considering calling this function -- it's 523 * usually not what you want. 524 */ 525 static nsIFrame* 526 FindNonTransparentBackgroundFrame(nsIFrame* aFrame, 527 bool aStartAtParent = false); 528 529 /** 530 * Determine the background color to draw taking into account print settings. 531 */ 532 static nscolor 533 DetermineBackgroundColor(nsPresContext* aPresContext, 534 nsStyleContext* aStyleContext, 535 nsIFrame* aFrame, 536 bool& aDrawBackgroundImage, 537 bool& aDrawBackgroundColor); 538 539 static nsRect 540 ComputeImageLayerPositioningArea(nsPresContext* aPresContext, 541 nsIFrame* aForFrame, 542 const nsRect& aBorderArea, 543 const nsStyleImageLayers::Layer& aLayer, 544 nsIFrame** aAttachedToFrame, 545 bool* aOutTransformedFixed); 546 547 static nsBackgroundLayerState 548 PrepareImageLayer(nsPresContext* aPresContext, 549 nsIFrame* aForFrame, 550 uint32_t aFlags, 551 const nsRect& aBorderArea, 552 const nsRect& aBGClipRect, 553 const nsStyleImageLayers::Layer& aLayer, 554 bool* aOutIsTransformedFixed = nullptr); 555 556 struct ImageLayerClipState { 557 nsRect mBGClipArea; // Affected by mClippedRadii 558 nsRect mAdditionalBGClipArea; // Not affected by mClippedRadii 559 nsRect mDirtyRect; 560 gfxRect mDirtyRectGfx; 561 562 nscoord mRadii[8]; 563 RectCornerRadii mClippedRadii; 564 bool mHasRoundedCorners; 565 bool mHasAdditionalBGClipArea; 566 567 // Whether we are being asked to draw with a caller provided background 568 // clipping area. If this is true we also disable rounded corners. 569 bool mCustomClip; 570 }; 571 572 static void 573 GetImageLayerClip(const nsStyleImageLayers::Layer& aLayer, 574 nsIFrame* aForFrame, const nsStyleBorder& aBorder, 575 const nsRect& aBorderArea, const nsRect& aCallerDirtyRect, 576 bool aWillPaintBorder, nscoord aAppUnitsPerPixel, 577 /* out */ ImageLayerClipState* aClipState); 578 579 /** 580 * Render the background for an element using css rendering rules 581 * for backgrounds or mask. 582 */ 583 enum { 584 /** 585 * When this flag is passed, the element's nsDisplayBorder will be 586 * painted immediately on top of this background. 587 */ 588 PAINTBG_WILL_PAINT_BORDER = 0x01, 589 /** 590 * When this flag is passed, images are synchronously decoded. 591 */ 592 PAINTBG_SYNC_DECODE_IMAGES = 0x02, 593 /** 594 * When this flag is passed, painting will go to the screen so we can 595 * take advantage of the fact that it will be clipped to the viewport. 596 */ 597 PAINTBG_TO_WINDOW = 0x04, 598 /** 599 * When this flag is passed, painting will read properties of mask-image 600 * style, instead of background-image. 601 */ 602 PAINTBG_MASK_IMAGE = 0x08 603 }; 604 605 struct PaintBGParams { 606 nsPresContext& presCtx; 607 nsRenderingContext& renderingCtx; 608 nsRect dirtyRect; 609 nsRect borderArea; 610 nsIFrame* frame; 611 uint32_t paintFlags; 612 nsRect* bgClipRect = nullptr; 613 int32_t layer; // -1 means painting all layers; other 614 // value means painting one specific 615 // layer only. 616 CompositionOp compositionOp; 617 618 static PaintBGParams ForAllLayers(nsPresContext& aPresCtx, 619 nsRenderingContext& aRenderingCtx, 620 const nsRect& aDirtyRect, 621 const nsRect& aBorderArea, 622 nsIFrame *aFrame, 623 uint32_t aPaintFlags); 624 static PaintBGParams ForSingleLayer(nsPresContext& aPresCtx, 625 nsRenderingContext& aRenderingCtx, 626 const nsRect& aDirtyRect, 627 const nsRect& aBorderArea, 628 nsIFrame *aFrame, 629 uint32_t aPaintFlags, 630 int32_t aLayer, 631 CompositionOp aCompositionOp = CompositionOp::OP_OVER); 632 633 private: PaintBGParamsnsCSSRendering::PaintBGParams634 PaintBGParams(nsPresContext& aPresCtx, 635 nsRenderingContext& aRenderingCtx, 636 const nsRect& aDirtyRect, 637 const nsRect& aBorderArea, 638 nsIFrame* aFrame, 639 uint32_t aPaintFlags, 640 int32_t aLayer, 641 CompositionOp aCompositionOp) 642 : presCtx(aPresCtx), 643 renderingCtx(aRenderingCtx), 644 dirtyRect(aDirtyRect), 645 borderArea(aBorderArea), 646 frame(aFrame), 647 paintFlags(aPaintFlags), 648 layer(aLayer), 649 compositionOp(aCompositionOp) {} 650 }; 651 652 static DrawResult PaintBackground(const PaintBGParams& aParams); 653 654 655 /** 656 * Same as |PaintBackground|, except using the provided style structs. 657 * This short-circuits the code that ensures that the root element's 658 * background is drawn on the canvas. 659 * The aLayer parameter allows you to paint a single layer of the background. 660 * The default value for aLayer, -1, means that all layers will be painted. 661 * The background color will only be painted if the back-most layer is also 662 * being painted. 663 * aCompositionOp is only respected if a single layer is specified (aLayer != -1). 664 * If all layers are painted, the image layer's blend mode (or the mask 665 * layer's composition mode) will be used. 666 */ 667 static DrawResult PaintBackgroundWithSC(const PaintBGParams& aParams, 668 nsStyleContext *mBackgroundSC, 669 const nsStyleBorder& aBorder); 670 671 /** 672 * Returns the rectangle covered by the given background layer image, taking 673 * into account background positioning, sizing, and repetition, but not 674 * clipping. 675 */ 676 static nsRect GetBackgroundLayerRect(nsPresContext* aPresContext, 677 nsIFrame* aForFrame, 678 const nsRect& aBorderArea, 679 const nsRect& aClipRect, 680 const nsStyleImageLayers::Layer& aLayer, 681 uint32_t aFlags); 682 683 /** 684 * Called when we start creating a display list. The frame tree will not 685 * change until a matching EndFrameTreeLocked is called. 686 */ 687 static void BeginFrameTreesLocked(); 688 /** 689 * Called when we've finished using a display list. When all 690 * BeginFrameTreeLocked calls have been balanced by an EndFrameTreeLocked, 691 * the frame tree may start changing again. 692 */ 693 static void EndFrameTreesLocked(); 694 695 // Draw a border segment in the table collapsing border model without 696 // beveling corners 697 static void DrawTableBorderSegment(DrawTarget& aDrawTarget, 698 uint8_t aBorderStyle, 699 nscolor aBorderColor, 700 const nsStyleBackground* aBGColor, 701 const nsRect& aBorderRect, 702 int32_t aAppUnitsPerDevPixel, 703 int32_t aAppUnitsPerCSSPixel, 704 uint8_t aStartBevelSide = 0, 705 nscoord aStartBevelOffset = 0, 706 uint8_t aEndBevelSide = 0, 707 nscoord aEndBevelOffset = 0); 708 709 // NOTE: pt, dirtyRect, lineSize, ascent, offset in the following 710 // structs are non-rounded device pixels, not app units. 711 struct DecorationRectParams 712 { 713 // The width [length] and the height [thickness] of the decoration 714 // line. This is a "logical" size in textRun orientation, so that 715 // for a vertical textrun, width will actually be a physical height; 716 // and conversely, height will be a physical width. 717 Size lineSize; 718 // The ascent of the text. 719 Float ascent = 0.0f; 720 // The offset of the decoration line from the baseline of the text 721 // (if the value is positive, the line is lifted up). 722 Float offset = 0.0f; 723 // If descentLimit is zero or larger and the underline overflows 724 // from the descent space, the underline should be lifted up as far 725 // as possible. Note that this does not mean the underline never 726 // overflows from this limitation, because if the underline is 727 // positioned to the baseline or upper, it causes unreadability. 728 // Note that if this is zero or larger, the underline rect may be 729 // shrunken if it's possible. Therefore, this value is used for 730 // strikeout line and overline too. 731 Float descentLimit = -1.0f; 732 // Which line will be painted. The value can be 733 // NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE or 734 // NS_STYLE_TEXT_DECORATION_LINE_OVERLINE or 735 // NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH. 736 uint8_t decoration = NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE; 737 // The style of the decoration line such as 738 // NS_STYLE_TEXT_DECORATION_STYLE_*. 739 uint8_t style = NS_STYLE_TEXT_DECORATION_STYLE_NONE; 740 bool vertical = false; 741 }; 742 struct PaintDecorationLineParams : DecorationRectParams 743 { 744 // No need to paint outside this rect. 745 Rect dirtyRect; 746 // The top/left edge of the text. 747 Point pt; 748 // The color of the decoration line. 749 nscolor color = NS_RGBA(0, 0, 0, 0); 750 // The distance between the left edge of the given frame and the 751 // position of the text as positioned without offset of the shadow. 752 Float icoordInFrame = 0.0f; 753 }; 754 755 /** 756 * Function for painting the decoration lines for the text. 757 * 758 * input: 759 * @param aFrame the frame which needs the decoration line 760 * @param aGfxContext 761 */ 762 static void PaintDecorationLine(nsIFrame* aFrame, DrawTarget& aDrawTarget, 763 const PaintDecorationLineParams& aParams); 764 765 /** 766 * Returns a Rect corresponding to the outline of the decoration line for the 767 * given text metrics. Arguments have the same meaning as for 768 * PaintDecorationLine. Currently this only works for solid 769 * decorations; for other decoration styles the returned Rect will be empty. 770 */ 771 static Rect DecorationLineToPath(const PaintDecorationLineParams& aParams); 772 773 /** 774 * Function for getting the decoration line rect for the text. 775 * NOTE: aLineSize, aAscent and aOffset are non-rounded device pixels, 776 * not app units. 777 * input: 778 * @param aPresContext 779 * output: 780 * @return the decoration line rect for the input, 781 * the each values are app units. 782 */ 783 static nsRect GetTextDecorationRect(nsPresContext* aPresContext, 784 const DecorationRectParams& aParams); 785 GetGFXBlendModensCSSRendering786 static CompositionOp GetGFXBlendMode(uint8_t mBlendMode) { 787 switch (mBlendMode) { 788 case NS_STYLE_BLEND_NORMAL: return CompositionOp::OP_OVER; 789 case NS_STYLE_BLEND_MULTIPLY: return CompositionOp::OP_MULTIPLY; 790 case NS_STYLE_BLEND_SCREEN: return CompositionOp::OP_SCREEN; 791 case NS_STYLE_BLEND_OVERLAY: return CompositionOp::OP_OVERLAY; 792 case NS_STYLE_BLEND_DARKEN: return CompositionOp::OP_DARKEN; 793 case NS_STYLE_BLEND_LIGHTEN: return CompositionOp::OP_LIGHTEN; 794 case NS_STYLE_BLEND_COLOR_DODGE: return CompositionOp::OP_COLOR_DODGE; 795 case NS_STYLE_BLEND_COLOR_BURN: return CompositionOp::OP_COLOR_BURN; 796 case NS_STYLE_BLEND_HARD_LIGHT: return CompositionOp::OP_HARD_LIGHT; 797 case NS_STYLE_BLEND_SOFT_LIGHT: return CompositionOp::OP_SOFT_LIGHT; 798 case NS_STYLE_BLEND_DIFFERENCE: return CompositionOp::OP_DIFFERENCE; 799 case NS_STYLE_BLEND_EXCLUSION: return CompositionOp::OP_EXCLUSION; 800 case NS_STYLE_BLEND_HUE: return CompositionOp::OP_HUE; 801 case NS_STYLE_BLEND_SATURATION: return CompositionOp::OP_SATURATION; 802 case NS_STYLE_BLEND_COLOR: return CompositionOp::OP_COLOR; 803 case NS_STYLE_BLEND_LUMINOSITY: return CompositionOp::OP_LUMINOSITY; 804 default: MOZ_ASSERT(false); return CompositionOp::OP_OVER; 805 } 806 } 807 GetGFXCompositeModensCSSRendering808 static CompositionOp GetGFXCompositeMode(uint8_t aCompositeMode) { 809 switch (aCompositeMode) { 810 case NS_STYLE_MASK_COMPOSITE_ADD: return CompositionOp::OP_OVER; 811 case NS_STYLE_MASK_COMPOSITE_SUBTRACT: return CompositionOp::OP_OUT; 812 case NS_STYLE_MASK_COMPOSITE_INTERSECT: return CompositionOp::OP_IN; 813 case NS_STYLE_MASK_COMPOSITE_EXCLUDE: return CompositionOp::OP_XOR; 814 default: MOZ_ASSERT(false); return CompositionOp::OP_OVER; 815 } 816 } 817 protected: 818 static gfxRect GetTextDecorationRectInternal( 819 const Point& aPt, const DecorationRectParams& aParams); 820 821 /** 822 * Returns inflated rect for painting a decoration line. 823 * Complex style decoration lines should be painted from leftmost of nearest 824 * ancestor block box because that makes better look of connection of lines 825 * for different nodes. ExpandPaintingRectForDecorationLine() returns 826 * a rect for actual painting rect for the clipped rect. 827 * 828 * input: 829 * @param aFrame the frame which needs the decoration line. 830 * @param aStyle the style of the complex decoration line 831 * NS_STYLE_TEXT_DECORATION_STYLE_DOTTED or 832 * NS_STYLE_TEXT_DECORATION_STYLE_DASHED or 833 * NS_STYLE_TEXT_DECORATION_STYLE_WAVY. 834 * @param aClippedRect the clipped rect for the decoration line. 835 * in other words, visible area of the line. 836 * @param aICoordInFrame the distance between inline-start edge of aFrame 837 * and aClippedRect.pos. 838 * @param aCycleLength the width of one cycle of the line style. 839 */ 840 static Rect ExpandPaintingRectForDecorationLine( 841 nsIFrame* aFrame, 842 const uint8_t aStyle, 843 const Rect &aClippedRect, 844 const Float aICoordInFrame, 845 const Float aCycleLength, 846 bool aVertical); 847 }; 848 849 /* 850 * nsContextBoxBlur 851 * Creates an 8-bit alpha channel context for callers to draw in, blurs the 852 * contents of that context and applies it as a 1-color mask on a 853 * different existing context. Uses gfxAlphaBoxBlur as its back end. 854 * 855 * You must call Init() first to create a suitable temporary surface to draw 856 * on. You must then draw any desired content onto the given context, then 857 * call DoPaint() to apply the blurred content as a single-color mask. You 858 * can only call Init() once, so objects cannot be reused. 859 * 860 * This is very useful for creating drop shadows or silhouettes. 861 */ 862 class nsContextBoxBlur { 863 typedef mozilla::gfx::Color Color; 864 typedef mozilla::gfx::DrawTarget DrawTarget; 865 typedef mozilla::gfx::RectCornerRadii RectCornerRadii; 866 867 public: 868 enum { 869 FORCE_MASK = 0x01 870 }; 871 /** 872 * Prepares a gfxContext to draw on. Do not call this twice; if you want 873 * to get the gfxContext again use GetContext(). 874 * 875 * @param aRect The coordinates of the surface to create. 876 * All coordinates must be in app units. 877 * This must not include the blur radius, pass 878 * it as the second parameter and everything 879 * is taken care of. 880 * 881 * @param aBlurRadius The blur radius in app units. 882 * 883 * @param aAppUnitsPerDevPixel The number of app units in a device pixel, 884 * for conversion. Most of the time you'll 885 * pass this from the current PresContext if 886 * available. 887 * 888 * @param aDestinationCtx The graphics context to apply the blurred 889 * mask to when you call DoPaint(). Make sure 890 * it is not destroyed before you call 891 * DoPaint(). To set the color of the 892 * resulting blurred graphic mask, you must 893 * set the color on this context before 894 * calling Init(). 895 * 896 * @param aDirtyRect The absolute dirty rect in app units. Used to 897 * optimize the temporary surface size and speed up blur. 898 * 899 * @param aSkipRect An area in device pixels (NOT app units!) to avoid 900 * blurring over, to prevent unnecessary work. 901 * 902 * @param aFlags FORCE_MASK to ensure that the content drawn to the 903 * returned gfxContext is used as a mask, and not 904 * drawn directly to aDestinationCtx. 905 * 906 * @return A blank 8-bit alpha-channel-only graphics context to 907 * draw on, or null on error. Must not be freed. The 908 * context has a device offset applied to it given by 909 * aRect. This means you can use coordinates as if it 910 * were at the desired position at aRect and you don't 911 * need to worry about translating any coordinates to 912 * draw on this temporary surface. 913 * 914 * If aBlurRadius is 0, the returned context is aDestinationCtx and 915 * DoPaint() does nothing, because no blurring is required. Therefore, you 916 * should prepare the destination context as if you were going to draw 917 * directly on it instead of any temporary surface created in this class. 918 */ 919 gfxContext* Init(const nsRect& aRect, nscoord aSpreadRadius, 920 nscoord aBlurRadius, 921 int32_t aAppUnitsPerDevPixel, gfxContext* aDestinationCtx, 922 const nsRect& aDirtyRect, const gfxRect* aSkipRect, 923 uint32_t aFlags = 0); 924 925 /** 926 * Does the actual blurring and mask applying. Users of this object *must* 927 * have called Init() first, then have drawn whatever they want to be 928 * blurred onto the internal gfxContext before calling this. 929 */ 930 void DoPaint(); 931 932 /** 933 * Gets the internal gfxContext at any time. Must not be freed. Avoid 934 * calling this before calling Init() since the context would not be 935 * constructed at that point. 936 */ 937 gfxContext* GetContext(); 938 939 940 /** 941 * Get the margin associated with the given blur radius, i.e., the 942 * additional area that might be painted as a result of it. (The 943 * margin for a spread radius is itself, on all sides.) 944 */ 945 static nsMargin GetBlurRadiusMargin(nscoord aBlurRadius, 946 int32_t aAppUnitsPerDevPixel); 947 948 /** 949 * Blurs a coloured rectangle onto aDestinationCtx. This is equivalent 950 * to calling Init(), drawing a rectangle onto the returned surface 951 * and then calling DoPaint, but may let us optimize better in the 952 * backend. 953 * 954 * @param aDestinationCtx The destination to blur to. 955 * @param aRect The rectangle to blur in app units. 956 * @param aAppUnitsPerDevPixel The number of app units in a device pixel, 957 * for conversion. Most of the time you'll 958 * pass this from the current PresContext if 959 * available. 960 * @param aCornerRadii Corner radii for aRect, if it is a rounded 961 * rectangle. 962 * @param aBlurRadius The blur radius in app units. 963 * @param aShadowColor The color to draw the blurred shadow. 964 * @param aDirtyRect The absolute dirty rect in app units. Used to 965 * optimize the temporary surface size and speed up blur. 966 * @param aSkipRect An area in device pixels (NOT app units!) to avoid 967 * blurring over, to prevent unnecessary work. 968 */ 969 static void BlurRectangle(gfxContext* aDestinationCtx, 970 const nsRect& aRect, 971 int32_t aAppUnitsPerDevPixel, 972 RectCornerRadii* aCornerRadii, 973 nscoord aBlurRadius, 974 const Color& aShadowColor, 975 const nsRect& aDirtyRect, 976 const gfxRect& aSkipRect); 977 978 /** 979 * Draws a blurred inset box shadow shape onto the destination surface. 980 * Like BlurRectangle, this is equivalent to calling Init(), 981 * drawing a rectangle onto the returned surface 982 * and then calling DoPaint, but may let us optimize better in the 983 * backend. 984 * 985 * @param aDestinationCtx The destination to blur to. 986 * @param aDestinationRect The rectangle to blur in app units. 987 * @param aShadowClipRect The inside clip rect that creates the path. 988 * @param aShadowColor The color of the blur 989 * @param aBlurRadiusAppUnits The blur radius in app units 990 * @param aSpreadRadiusAppUnits The spread radius in app units. 991 * @param aAppUnitsPerDevPixel The number of app units in a device pixel, 992 * for conversion. Most of the time you'll 993 * pass this from the current PresContext if 994 * available. 995 * @param aHasBorderRadius If this inset box blur has a border radius 996 * @param aInnerClipRectRadii The clip rect radii used for the inside rect's path. 997 * @param aSkipRect An area in device pixels (NOT app units!) to avoid 998 * blurring over, to prevent unnecessary work. 999 */ 1000 bool InsetBoxBlur(gfxContext* aDestinationCtx, 1001 mozilla::gfx::Rect aDestinationRect, 1002 mozilla::gfx::Rect aShadowClipRect, 1003 mozilla::gfx::Color& aShadowColor, 1004 nscoord aBlurRadiusAppUnits, 1005 nscoord aSpreadRadiusAppUnits, 1006 int32_t aAppUnitsPerDevPixel, 1007 bool aHasBorderRadius, 1008 RectCornerRadii& aInnerClipRectRadii, 1009 mozilla::gfx::Rect aSkipRect, 1010 mozilla::gfx::Point aShadowOffset); 1011 1012 protected: 1013 static void GetBlurAndSpreadRadius(DrawTarget* aDestDrawTarget, 1014 int32_t aAppUnitsPerDevPixel, 1015 nscoord aBlurRadius, 1016 nscoord aSpreadRadius, 1017 mozilla::gfx::IntSize& aOutBlurRadius, 1018 mozilla::gfx::IntSize& aOutSpreadRadius, 1019 bool aConstrainSpreadRadius = true); 1020 1021 gfxAlphaBoxBlur mAlphaBoxBlur; 1022 RefPtr<gfxContext> mContext; 1023 gfxContext* mDestinationCtx; 1024 1025 /* This is true if the blur already has it's content transformed 1026 * by mDestinationCtx's transform */ 1027 bool mPreTransformed; 1028 }; 1029 1030 #endif /* nsCSSRendering_h___ */ 1031