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