Coverage Report

Created: 2018-09-25 14:53

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