Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
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/. */
6 /* utility functions for drawing borders and backgrounds */
8 #ifndef nsCSSRendering_h___
9 #define nsCSSRendering_h___
11 #include "gfxBlur.h"
12 #include "gfxContext.h"
13 #include "nsLayoutUtils.h"
14 #include "nsStyleStruct.h"
15 #include "nsIFrame.h"
17 class nsStyleContext;
18 class nsPresContext;
19 class nsRenderingContext;
21 namespace mozilla {
23 namespace layers {
24 class ImageContainer;
25 }
27 // A CSSSizeOrRatio represents a (possibly partially specified) size for use
28 // in computing image sizes. Either or both of the width and height might be
29 // given. A ratio of width to height may also be given. If we at least two
30 // of these then we can compute a concrete size, that is a width and height.
31 struct CSSSizeOrRatio
32 {
33 CSSSizeOrRatio()
34 : mRatio(0, 0)
35 , mHasWidth(false)
36 , mHasHeight(false) {}
38 bool CanComputeConcreteSize() const
39 {
40 return mHasWidth + mHasHeight + HasRatio() >= 2;
41 }
42 bool IsConcrete() const { return mHasWidth && mHasHeight; }
43 bool HasRatio() const { return mRatio.width > 0 && mRatio.height > 0; }
44 bool IsEmpty() const
45 {
46 return (mHasWidth && mWidth <= 0) ||
47 (mHasHeight && mHeight <= 0) ||
48 mRatio.width <= 0 || mRatio.height <= 0;
49 }
51 // CanComputeConcreteSize must return true when ComputeConcreteSize is
52 // called.
53 nsSize ComputeConcreteSize() const;
55 void SetWidth(nscoord aWidth)
56 {
57 mWidth = aWidth;
58 mHasWidth = true;
59 if (mHasHeight) {
60 mRatio = nsSize(mWidth, mHeight);
61 }
62 }
63 void SetHeight(nscoord aHeight)
64 {
65 mHeight = aHeight;
66 mHasHeight = true;
67 if (mHasWidth) {
68 mRatio = nsSize(mWidth, mHeight);
69 }
70 }
71 void SetSize(const nsSize& aSize)
72 {
73 mWidth = aSize.width;
74 mHeight = aSize.height;
75 mHasWidth = true;
76 mHasHeight = true;
77 mRatio = aSize;
78 }
79 void SetRatio(const nsSize& aRatio)
80 {
81 MOZ_ASSERT(!mHasWidth || !mHasHeight,
82 "Probably shouldn't be setting a ratio if we have a concrete size");
83 mRatio = aRatio;
84 }
86 nsSize mRatio;
87 nscoord mWidth;
88 nscoord mHeight;
89 bool mHasWidth;
90 bool mHasHeight;
91 };
93 }
95 /**
96 * This is a small wrapper class to encapsulate image drawing that can draw an
97 * nsStyleImage image, which may internally be a real image, a sub image, or a
98 * CSS gradient.
99 *
100 * @note Always call the member functions in the order of PrepareImage(),
101 * SetSize(), and Draw*().
102 */
103 class nsImageRenderer {
104 public:
105 typedef mozilla::layers::LayerManager LayerManager;
106 typedef mozilla::layers::ImageContainer ImageContainer;
108 enum {
109 FLAG_SYNC_DECODE_IMAGES = 0x01,
110 FLAG_PAINTING_TO_WINDOW = 0x02
111 };
112 enum FitType
113 {
114 CONTAIN,
115 COVER
116 };
118 nsImageRenderer(nsIFrame* aForFrame, const nsStyleImage* aImage, uint32_t aFlags);
119 ~nsImageRenderer();
120 /**
121 * Populates member variables to get ready for rendering.
122 * @return true iff the image is ready, and there is at least a pixel to
123 * draw.
124 */
125 bool PrepareImage();
127 /**
128 * The three Compute*Size functions correspond to the sizing algorthms and
129 * definitions from the CSS Image Values and Replaced Content spec. See
130 * http://dev.w3.org/csswg/css-images-3/#sizing .
131 */
133 /**
134 * Compute the intrinsic size of the image as defined in the CSS Image Values
135 * spec. The intrinsic size is the unscaled size which the image would ideally
136 * like to be in app units.
137 */
138 mozilla::CSSSizeOrRatio ComputeIntrinsicSize();
140 /**
141 * Compute the size of the rendered image using either the 'cover' or
142 * 'contain' constraints (aFitType).
143 * aIntrinsicRatio may be an invalid ratio, that is one or both of its
144 * dimensions can be less than or equal to zero.
145 */
146 static nsSize ComputeConstrainedSize(const nsSize& aConstrainingSize,
147 const nsSize& aIntrinsicRatio,
148 FitType aFitType);
149 /**
150 * Compute the size of the rendered image (the concrete size) where no cover/
151 * contain constraints are given. The 'default algorithm' from the CSS Image
152 * Values spec.
153 */
154 static nsSize ComputeConcreteSize(const mozilla::CSSSizeOrRatio& aSpecifiedSize,
155 const mozilla::CSSSizeOrRatio& aIntrinsicSize,
156 const nsSize& aDefaultSize);
158 /**
159 * Set this image's preferred size. This will be its intrinsic size where
160 * specified and the default size where it is not. Used as the unscaled size
161 * when rendering the image.
162 */
163 void SetPreferredSize(const mozilla::CSSSizeOrRatio& aIntrinsicSize,
164 const nsSize& aDefaultSize);
166 /**
167 * Draws the image to the target rendering context.
168 * aSrc is a rect on the source image which will be mapped to aDest.
169 * @see nsLayoutUtils::DrawImage() for other parameters.
170 */
171 void Draw(nsPresContext* aPresContext,
172 nsRenderingContext& aRenderingContext,
173 const nsRect& aDirtyRect,
174 const nsRect& aFill,
175 const nsRect& aDest,
176 const mozilla::CSSIntRect& aSrc);
177 /**
178 * Draws the image to the target rendering context using background-specific
179 * arguments.
180 * @see nsLayoutUtils::DrawImage() for parameters.
181 */
182 void DrawBackground(nsPresContext* aPresContext,
183 nsRenderingContext& aRenderingContext,
184 const nsRect& aDest,
185 const nsRect& aFill,
186 const nsPoint& aAnchor,
187 const nsRect& aDirty);
189 /**
190 * Draw the image to a single component of a border-image style rendering.
191 * aFill The destination rect to be drawn into
192 * aSrc is the part of the image to be rendered into a tile (aUnitSize in
193 * aFill), if aSrc and the dest tile are different sizes, the image will be
194 * scaled to map aSrc onto the dest tile.
195 * aHFill and aVFill are the repeat patterns for the component -
196 * NS_STYLE_BORDER_IMAGE_REPEAT_*
197 * aUnitSize The scaled size of a single source rect (in destination coords)
198 * aIndex identifies the component: 0 1 2
199 * 3 4 5
200 * 6 7 8
201 */
202 void
203 DrawBorderImageComponent(nsPresContext* aPresContext,
204 nsRenderingContext& aRenderingContext,
205 const nsRect& aDirtyRect,
206 const nsRect& aFill,
207 const mozilla::CSSIntRect& aSrc,
208 uint8_t aHFill,
209 uint8_t aVFill,
210 const nsSize& aUnitSize,
211 uint8_t aIndex);
213 bool IsRasterImage();
214 bool IsAnimatedImage();
215 already_AddRefed<ImageContainer> GetContainer(LayerManager* aManager);
217 bool IsReady() { return mIsReady; }
219 private:
220 /**
221 * Helper method for creating a gfxDrawable from mPaintServerFrame or
222 * mImageElementSurface.
223 * Requires mType is eStyleImageType_Element.
224 * Returns null if we cannot create the drawable.
225 */
226 already_AddRefed<gfxDrawable> DrawableForElement(const nsRect& aImageRect,
227 nsRenderingContext& aRenderingContext);
229 nsIFrame* mForFrame;
230 const nsStyleImage* mImage;
231 nsStyleImageType mType;
232 nsCOMPtr<imgIContainer> mImageContainer;
233 nsRefPtr<nsStyleGradient> mGradientData;
234 nsIFrame* mPaintServerFrame;
235 nsLayoutUtils::SurfaceFromElementResult mImageElementSurface;
236 bool mIsReady;
237 nsSize mSize; // unscaled size of the image, in app units
238 uint32_t mFlags;
239 };
241 /**
242 * A struct representing all the information needed to paint a background
243 * image to some target, taking into account all CSS background-* properties.
244 * See PrepareBackgroundLayer.
245 */
246 struct nsBackgroundLayerState {
247 /**
248 * @param aFlags some combination of nsCSSRendering::PAINTBG_* flags
249 */
250 nsBackgroundLayerState(nsIFrame* aForFrame, const nsStyleImage* aImage, uint32_t aFlags)
251 : mImageRenderer(aForFrame, aImage, aFlags), mCompositingOp(gfxContext::OPERATOR_OVER) {}
253 /**
254 * The nsImageRenderer that will be used to draw the background.
255 */
256 nsImageRenderer mImageRenderer;
257 /**
258 * A rectangle that one copy of the image tile is mapped onto. Same
259 * coordinate system as aBorderArea/aBGClipRect passed into
260 * PrepareBackgroundLayer.
261 */
262 nsRect mDestArea;
263 /**
264 * The actual rectangle that should be filled with (complete or partial)
265 * image tiles. Same coordinate system as aBorderArea/aBGClipRect passed into
266 * PrepareBackgroundLayer.
267 */
268 nsRect mFillArea;
269 /**
270 * The anchor point that should be snapped to a pixel corner. Same
271 * coordinate system as aBorderArea/aBGClipRect passed into
272 * PrepareBackgroundLayer.
273 */
274 nsPoint mAnchor;
275 /**
276 * The compositing operation that the image should use
277 */
278 gfxContext::GraphicsOperator mCompositingOp;
279 };
281 struct nsCSSRendering {
282 /**
283 * Initialize any static variables used by nsCSSRendering.
284 */
285 static void Init();
287 /**
288 * Clean up any static variables used by nsCSSRendering.
289 */
290 static void Shutdown();
292 static void PaintBoxShadowInner(nsPresContext* aPresContext,
293 nsRenderingContext& aRenderingContext,
294 nsIFrame* aForFrame,
295 const nsRect& aFrameArea,
296 const nsRect& aDirtyRect);
298 static void PaintBoxShadowOuter(nsPresContext* aPresContext,
299 nsRenderingContext& aRenderingContext,
300 nsIFrame* aForFrame,
301 const nsRect& aFrameArea,
302 const nsRect& aDirtyRect,
303 float aOpacity = 1.0);
305 static void ComputePixelRadii(const nscoord *aAppUnitsRadii,
306 nscoord aAppUnitsPerPixel,
307 gfxCornerSizes *oBorderRadii);
309 /**
310 * Render the border for an element using css rendering rules
311 * for borders. aSkipSides is a bitmask of the sides to skip
312 * when rendering. If 0 then no sides are skipped.
313 */
314 static void PaintBorder(nsPresContext* aPresContext,
315 nsRenderingContext& aRenderingContext,
316 nsIFrame* aForFrame,
317 const nsRect& aDirtyRect,
318 const nsRect& aBorderArea,
319 nsStyleContext* aStyleContext,
320 int aSkipSides = 0);
322 /**
323 * Like PaintBorder, but taking an nsStyleBorder argument instead of
324 * getting it from aStyleContext.
325 */
326 static void PaintBorderWithStyleBorder(nsPresContext* aPresContext,
327 nsRenderingContext& aRenderingContext,
328 nsIFrame* aForFrame,
329 const nsRect& aDirtyRect,
330 const nsRect& aBorderArea,
331 const nsStyleBorder& aBorderStyle,
332 nsStyleContext* aStyleContext,
333 int aSkipSides = 0);
336 /**
337 * Render the outline for an element using css rendering rules
338 * for borders. aSkipSides is a bitmask of the sides to skip
339 * when rendering. If 0 then no sides are skipped.
340 */
341 static void PaintOutline(nsPresContext* aPresContext,
342 nsRenderingContext& aRenderingContext,
343 nsIFrame* aForFrame,
344 const nsRect& aDirtyRect,
345 const nsRect& aBorderArea,
346 nsStyleContext* aStyleContext);
348 /**
349 * Render keyboard focus on an element.
350 * |aFocusRect| is the outer rectangle of the focused element.
351 * Uses a fixed style equivalent to "1px dotted |aColor|".
352 * Not used for controls, because the native theme may differ.
353 */
354 static void PaintFocus(nsPresContext* aPresContext,
355 nsRenderingContext& aRenderingContext,
356 const nsRect& aFocusRect,
357 nscolor aColor);
359 /**
360 * Render a gradient for an element.
361 * aDest is the rect for a single tile of the gradient on the destination.
362 * aFill is the rect on the destination to be covered by repeated tiling of
363 * the gradient.
364 * aSrc is the part of the gradient to be rendered into a tile (aDest), if
365 * aSrc and aDest are different sizes, the image will be scaled to map aSrc
366 * onto aDest.
367 * aIntrinsicSize is the size of the source gradient.
368 */
369 static void PaintGradient(nsPresContext* aPresContext,
370 nsRenderingContext& aRenderingContext,
371 nsStyleGradient* aGradient,
372 const nsRect& aDirtyRect,
373 const nsRect& aDest,
374 const nsRect& aFill,
375 const mozilla::CSSIntRect& aSrc,
376 const nsSize& aIntrinsiceSize);
378 /**
379 * Find the frame whose background style should be used to draw the
380 * canvas background. aForFrame must be the frame for the root element
381 * whose background style should be used. This function will return
382 * aForFrame unless the <body> background should be propagated, in
383 * which case we return the frame associated with the <body>'s background.
384 */
385 static nsIFrame* FindBackgroundStyleFrame(nsIFrame* aForFrame);
387 /**
388 * @return true if |aFrame| is a canvas frame, in the CSS sense.
389 */
390 static bool IsCanvasFrame(nsIFrame* aFrame);
392 /**
393 * Fill in an aBackgroundSC to be used to paint the background
394 * for an element. This applies the rules for propagating
395 * backgrounds between BODY, the root element, and the canvas.
396 * @return true if there is some meaningful background.
397 */
398 static bool FindBackground(nsIFrame* aForFrame,
399 nsStyleContext** aBackgroundSC);
401 /**
402 * As FindBackground, but the passed-in frame is known to be a root frame
403 * (returned from nsCSSFrameConstructor::GetRootElementStyleFrame())
404 * and there is always some meaningful background returned.
405 */
406 static nsStyleContext* FindRootFrameBackground(nsIFrame* aForFrame);
408 /**
409 * Returns background style information for the canvas.
410 *
411 * @param aForFrame
412 * the frame used to represent the canvas, in the CSS sense (i.e.
413 * nsCSSRendering::IsCanvasFrame(aForFrame) must be true)
414 * @param aRootElementFrame
415 * the frame representing the root element of the document
416 * @param aBackground
417 * contains background style information for the canvas on return
418 */
419 static nsStyleContext*
420 FindCanvasBackground(nsIFrame* aForFrame, nsIFrame* aRootElementFrame)
421 {
422 NS_ABORT_IF_FALSE(IsCanvasFrame(aForFrame), "not a canvas frame");
423 if (aRootElementFrame)
424 return FindRootFrameBackground(aRootElementFrame);
426 // This should always give transparent, so we'll fill it in with the
427 // default color if needed. This seems to happen a bit while a page is
428 // being loaded.
429 return aForFrame->StyleContext();
430 }
432 /**
433 * Find a frame which draws a non-transparent background,
434 * for various table-related and HR-related backwards-compatibility hacks.
435 * This function will also stop if it finds themed frame which might draw
436 * background.
437 *
438 * Be very hesitant if you're considering calling this function -- it's
439 * usually not what you want.
440 */
441 static nsIFrame*
442 FindNonTransparentBackgroundFrame(nsIFrame* aFrame,
443 bool aStartAtParent = false);
445 /**
446 * Determine the background color to draw taking into account print settings.
447 */
448 static nscolor
449 DetermineBackgroundColor(nsPresContext* aPresContext,
450 nsStyleContext* aStyleContext,
451 nsIFrame* aFrame,
452 bool& aDrawBackgroundImage,
453 bool& aDrawBackgroundColor);
455 static nsRect
456 ComputeBackgroundPositioningArea(nsPresContext* aPresContext,
457 nsIFrame* aForFrame,
458 const nsRect& aBorderArea,
459 const nsStyleBackground& aBackground,
460 const nsStyleBackground::Layer& aLayer,
461 nsIFrame** aAttachedToFrame);
463 static nsBackgroundLayerState
464 PrepareBackgroundLayer(nsPresContext* aPresContext,
465 nsIFrame* aForFrame,
466 uint32_t aFlags,
467 const nsRect& aBorderArea,
468 const nsRect& aBGClipRect,
469 const nsStyleBackground& aBackground,
470 const nsStyleBackground::Layer& aLayer);
472 /**
473 * Render the background for an element using css rendering rules
474 * for backgrounds.
475 */
476 enum {
477 /**
478 * When this flag is passed, the element's nsDisplayBorder will be
479 * painted immediately on top of this background.
480 */
481 PAINTBG_WILL_PAINT_BORDER = 0x01,
482 /**
483 * When this flag is passed, images are synchronously decoded.
484 */
485 PAINTBG_SYNC_DECODE_IMAGES = 0x02,
486 /**
487 * When this flag is passed, painting will go to the screen so we can
488 * take advantage of the fact that it will be clipped to the viewport.
489 */
490 PAINTBG_TO_WINDOW = 0x04
491 };
492 static void PaintBackground(nsPresContext* aPresContext,
493 nsRenderingContext& aRenderingContext,
494 nsIFrame* aForFrame,
495 const nsRect& aDirtyRect,
496 const nsRect& aBorderArea,
497 uint32_t aFlags,
498 nsRect* aBGClipRect = nullptr,
499 int32_t aLayer = -1);
501 static void PaintBackgroundColor(nsPresContext* aPresContext,
502 nsRenderingContext& aRenderingContext,
503 nsIFrame* aForFrame,
504 const nsRect& aDirtyRect,
505 const nsRect& aBorderArea,
506 uint32_t aFlags);
508 /**
509 * Same as |PaintBackground|, except using the provided style structs.
510 * This short-circuits the code that ensures that the root element's
511 * background is drawn on the canvas.
512 * The aLayer parameter allows you to paint a single layer of the background.
513 * The default value for aLayer, -1, means that all layers will be painted.
514 * The background color will only be painted if the back-most layer is also
515 * being painted.
516 */
517 static void PaintBackgroundWithSC(nsPresContext* aPresContext,
518 nsRenderingContext& aRenderingContext,
519 nsIFrame* aForFrame,
520 const nsRect& aDirtyRect,
521 const nsRect& aBorderArea,
522 nsStyleContext *aStyleContext,
523 const nsStyleBorder& aBorder,
524 uint32_t aFlags,
525 nsRect* aBGClipRect = nullptr,
526 int32_t aLayer = -1);
528 static void PaintBackgroundColorWithSC(nsPresContext* aPresContext,
529 nsRenderingContext& aRenderingContext,
530 nsIFrame* aForFrame,
531 const nsRect& aDirtyRect,
532 const nsRect& aBorderArea,
533 nsStyleContext *aStyleContext,
534 const nsStyleBorder& aBorder,
535 uint32_t aFlags);
536 /**
537 * Returns the rectangle covered by the given background layer image, taking
538 * into account background positioning, sizing, and repetition, but not
539 * clipping.
540 */
541 static nsRect GetBackgroundLayerRect(nsPresContext* aPresContext,
542 nsIFrame* aForFrame,
543 const nsRect& aBorderArea,
544 const nsRect& aClipRect,
545 const nsStyleBackground& aBackground,
546 const nsStyleBackground::Layer& aLayer,
547 uint32_t aFlags);
549 /**
550 * Checks if image in layer aLayer of aBackground is currently decoded.
551 */
552 static bool IsBackgroundImageDecodedForStyleContextAndLayer(
553 const nsStyleBackground *aBackground, uint32_t aLayer);
555 /**
556 * Checks if all images that are part of the background for aFrame are
557 * currently decoded.
558 */
559 static bool AreAllBackgroundImagesDecodedForFrame(nsIFrame* aFrame);
561 /**
562 * Called when we start creating a display list. The frame tree will not
563 * change until a matching EndFrameTreeLocked is called.
564 */
565 static void BeginFrameTreesLocked();
566 /**
567 * Called when we've finished using a display list. When all
568 * BeginFrameTreeLocked calls have been balanced by an EndFrameTreeLocked,
569 * the frame tree may start changing again.
570 */
571 static void EndFrameTreesLocked();
573 // Draw a border segment in the table collapsing border model without
574 // beveling corners
575 static void DrawTableBorderSegment(nsRenderingContext& aContext,
576 uint8_t aBorderStyle,
577 nscolor aBorderColor,
578 const nsStyleBackground* aBGColor,
579 const nsRect& aBorderRect,
580 int32_t aAppUnitsPerCSSPixel,
581 uint8_t aStartBevelSide = 0,
582 nscoord aStartBevelOffset = 0,
583 uint8_t aEndBevelSide = 0,
584 nscoord aEndBevelOffset = 0);
586 /**
587 * Function for painting the decoration lines for the text.
588 * NOTE: aPt, aLineSize, aAscent and aOffset are non-rounded device pixels,
589 * not app units.
590 * input:
591 * @param aFrame the frame which needs the decoration line
592 * @param aGfxContext
593 * @param aDirtyRect no need to paint outside this rect
594 * @param aColor the color of the decoration line
595 * @param aPt the top/left edge of the text
596 * @param aXInFrame the distance between aPt.x and left edge of
597 * aFrame. If the decoration line is for shadow,
598 * set the distance between the left edge of
599 * the aFrame and the position of the text as
600 * positioned without offset of the shadow.
601 * @param aLineSize the width and the height of the decoration
602 * line
603 * @param aAscent the ascent of the text
604 * @param aOffset the offset of the decoration line from
605 * the baseline of the text (if the value is
606 * positive, the line is lifted up)
607 * @param aDecoration which line will be painted. The value can be
608 * NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE or
609 * NS_STYLE_TEXT_DECORATION_LINE_OVERLINE or
610 * NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH.
611 * @param aStyle the style of the decoration line such as
612 * NS_STYLE_TEXT_DECORATION_STYLE_*.
613 * @param aDescentLimit If aDescentLimit is zero or larger and the
614 * underline overflows from the descent space,
615 * the underline should be lifted up as far as
616 * possible. Note that this does not mean the
617 * underline never overflows from this
618 * limitation. Because if the underline is
619 * positioned to the baseline or upper, it causes
620 * unreadability. Note that if this is zero
621 * or larger, the underline rect may be shrunken
622 * if it's possible. Therefore, this value is
623 * used for strikeout line and overline too.
624 */
625 static void PaintDecorationLine(nsIFrame* aFrame,
626 gfxContext* aGfxContext,
627 const gfxRect& aDirtyRect,
628 const nscolor aColor,
629 const gfxPoint& aPt,
630 const gfxFloat aXInFrame,
631 const gfxSize& aLineSize,
632 const gfxFloat aAscent,
633 const gfxFloat aOffset,
634 const uint8_t aDecoration,
635 const uint8_t aStyle,
636 const gfxFloat aDescentLimit = -1.0);
638 /**
639 * Adds a path corresponding to the outline of the decoration line to
640 * the specified context. Arguments have the same meaning as for
641 * PaintDecorationLine. Currently this only works for solid
642 * decorations; for other decoration styles, an empty path is added
643 * to the context.
644 */
645 static void DecorationLineToPath(nsIFrame* aFrame,
646 gfxContext* aGfxContext,
647 const gfxRect& aDirtyRect,
648 const nscolor aColor,
649 const gfxPoint& aPt,
650 const gfxFloat aXInFrame,
651 const gfxSize& aLineSize,
652 const gfxFloat aAscent,
653 const gfxFloat aOffset,
654 const uint8_t aDecoration,
655 const uint8_t aStyle,
656 const gfxFloat aDescentLimit = -1.0);
658 /**
659 * Function for getting the decoration line rect for the text.
660 * NOTE: aLineSize, aAscent and aOffset are non-rounded device pixels,
661 * not app units.
662 * input:
663 * @param aPresContext
664 * @param aLineSize the width and the height of the decoration
665 * line
666 * @param aAscent the ascent of the text
667 * @param aOffset the offset of the decoration line from
668 * the baseline of the text (if the value is
669 * positive, the line is lifted up)
670 * @param aDecoration which line will be painted. The value can be
671 * NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE or
672 * NS_STYLE_TEXT_DECORATION_LINE_OVERLINE or
673 * NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH.
674 * @param aStyle the style of the decoration line such as
675 * NS_STYLE_TEXT_DECORATION_STYLE_*.
676 * @param aDescentLimit If aDescentLimit is zero or larger and the
677 * underline overflows from the descent space,
678 * the underline should be lifted up as far as
679 * possible. Note that this does not mean the
680 * underline never overflows from this
681 * limitation. Because if the underline is
682 * positioned to the baseline or upper, it causes
683 * unreadability. Note that if this is zero
684 * or larger, the underline rect may be shrunken
685 * if it's possible. Therefore, this value is
686 * used for strikeout line and overline too.
687 * output:
688 * @return the decoration line rect for the input,
689 * the each values are app units.
690 */
691 static nsRect GetTextDecorationRect(nsPresContext* aPresContext,
692 const gfxSize& aLineSize,
693 const gfxFloat aAscent,
694 const gfxFloat aOffset,
695 const uint8_t aDecoration,
696 const uint8_t aStyle,
697 const gfxFloat aDescentLimit = -1.0);
699 static gfxContext::GraphicsOperator GetGFXBlendMode(uint8_t mBlendMode) {
700 switch (mBlendMode) {
701 case NS_STYLE_BLEND_NORMAL: return gfxContext::OPERATOR_OVER;
702 case NS_STYLE_BLEND_MULTIPLY: return gfxContext::OPERATOR_MULTIPLY;
703 case NS_STYLE_BLEND_SCREEN: return gfxContext::OPERATOR_SCREEN;
704 case NS_STYLE_BLEND_OVERLAY: return gfxContext::OPERATOR_OVERLAY;
705 case NS_STYLE_BLEND_DARKEN: return gfxContext::OPERATOR_DARKEN;
706 case NS_STYLE_BLEND_LIGHTEN: return gfxContext::OPERATOR_LIGHTEN;
707 case NS_STYLE_BLEND_COLOR_DODGE: return gfxContext::OPERATOR_COLOR_DODGE;
708 case NS_STYLE_BLEND_COLOR_BURN: return gfxContext::OPERATOR_COLOR_BURN;
709 case NS_STYLE_BLEND_HARD_LIGHT: return gfxContext::OPERATOR_HARD_LIGHT;
710 case NS_STYLE_BLEND_SOFT_LIGHT: return gfxContext::OPERATOR_SOFT_LIGHT;
711 case NS_STYLE_BLEND_DIFFERENCE: return gfxContext::OPERATOR_DIFFERENCE;
712 case NS_STYLE_BLEND_EXCLUSION: return gfxContext::OPERATOR_EXCLUSION;
713 case NS_STYLE_BLEND_HUE: return gfxContext::OPERATOR_HUE;
714 case NS_STYLE_BLEND_SATURATION: return gfxContext::OPERATOR_SATURATION;
715 case NS_STYLE_BLEND_COLOR: return gfxContext::OPERATOR_COLOR;
716 case NS_STYLE_BLEND_LUMINOSITY: return gfxContext::OPERATOR_LUMINOSITY;
717 default: MOZ_ASSERT(false); return gfxContext::OPERATOR_OVER;
718 }
720 return gfxContext::OPERATOR_OVER;
721 }
723 protected:
724 static gfxRect GetTextDecorationRectInternal(const gfxPoint& aPt,
725 const gfxSize& aLineSize,
726 const gfxFloat aAscent,
727 const gfxFloat aOffset,
728 const uint8_t aDecoration,
729 const uint8_t aStyle,
730 const gfxFloat aDscentLimit);
732 /**
733 * Returns inflated rect for painting a decoration line.
734 * Complex style decoration lines should be painted from leftmost of nearest
735 * ancestor block box because that makes better look of connection of lines
736 * for different nodes. ExpandPaintingRectForDecorationLine() returns
737 * a rect for actual painting rect for the clipped rect.
738 *
739 * input:
740 * @param aFrame the frame which needs the decoration line.
741 * @param aStyle the style of the complex decoration line
742 * NS_STYLE_TEXT_DECORATION_STYLE_DOTTED or
743 * NS_STYLE_TEXT_DECORATION_STYLE_DASHED or
744 * NS_STYLE_TEXT_DECORATION_STYLE_WAVY.
745 * @param aClippedRect the clipped rect for the decoration line.
746 * in other words, visible area of the line.
747 * @param aXInFrame the distance between left edge of aFrame and
748 * aClippedRect.pos.x.
749 * @param aCycleLength the width of one cycle of the line style.
750 */
751 static gfxRect ExpandPaintingRectForDecorationLine(
752 nsIFrame* aFrame,
753 const uint8_t aStyle,
754 const gfxRect &aClippedRect,
755 const gfxFloat aXInFrame,
756 const gfxFloat aCycleLength);
757 };
759 /*
760 * nsContextBoxBlur
761 * Creates an 8-bit alpha channel context for callers to draw in, blurs the
762 * contents of that context and applies it as a 1-color mask on a
763 * different existing context. Uses gfxAlphaBoxBlur as its back end.
764 *
765 * You must call Init() first to create a suitable temporary surface to draw
766 * on. You must then draw any desired content onto the given context, then
767 * call DoPaint() to apply the blurred content as a single-color mask. You
768 * can only call Init() once, so objects cannot be reused.
769 *
770 * This is very useful for creating drop shadows or silhouettes.
771 */
772 class nsContextBoxBlur {
773 public:
774 enum {
775 FORCE_MASK = 0x01
776 };
777 /**
778 * Prepares a gfxContext to draw on. Do not call this twice; if you want
779 * to get the gfxContext again use GetContext().
780 *
781 * @param aRect The coordinates of the surface to create.
782 * All coordinates must be in app units.
783 * This must not include the blur radius, pass
784 * it as the second parameter and everything
785 * is taken care of.
786 *
787 * @param aBlurRadius The blur radius in app units.
788 *
789 * @param aAppUnitsPerDevPixel The number of app units in a device pixel,
790 * for conversion. Most of the time you'll
791 * pass this from the current PresContext if
792 * available.
793 *
794 * @param aDestinationCtx The graphics context to apply the blurred
795 * mask to when you call DoPaint(). Make sure
796 * it is not destroyed before you call
797 * DoPaint(). To set the color of the
798 * resulting blurred graphic mask, you must
799 * set the color on this context before
800 * calling Init().
801 *
802 * @param aDirtyRect The absolute dirty rect in app units. Used to
803 * optimize the temporary surface size and speed up blur.
804 *
805 * @param aSkipRect An area in device pixels (NOT app units!) to avoid
806 * blurring over, to prevent unnecessary work.
807 *
808 * @param aFlags FORCE_MASK to ensure that the content drawn to the
809 * returned gfxContext is used as a mask, and not
810 * drawn directly to aDestinationCtx.
811 *
812 * @return A blank 8-bit alpha-channel-only graphics context to
813 * draw on, or null on error. Must not be freed. The
814 * context has a device offset applied to it given by
815 * aRect. This means you can use coordinates as if it
816 * were at the desired position at aRect and you don't
817 * need to worry about translating any coordinates to
818 * draw on this temporary surface.
819 *
820 * If aBlurRadius is 0, the returned context is aDestinationCtx and
821 * DoPaint() does nothing, because no blurring is required. Therefore, you
822 * should prepare the destination context as if you were going to draw
823 * directly on it instead of any temporary surface created in this class.
824 */
825 gfxContext* Init(const nsRect& aRect, nscoord aSpreadRadius,
826 nscoord aBlurRadius,
827 int32_t aAppUnitsPerDevPixel, gfxContext* aDestinationCtx,
828 const nsRect& aDirtyRect, const gfxRect* aSkipRect,
829 uint32_t aFlags = 0);
831 /**
832 * Does the actual blurring and mask applying. Users of this object *must*
833 * have called Init() first, then have drawn whatever they want to be
834 * blurred onto the internal gfxContext before calling this.
835 */
836 void DoPaint();
838 /**
839 * Gets the internal gfxContext at any time. Must not be freed. Avoid
840 * calling this before calling Init() since the context would not be
841 * constructed at that point.
842 */
843 gfxContext* GetContext();
846 /**
847 * Get the margin associated with the given blur radius, i.e., the
848 * additional area that might be painted as a result of it. (The
849 * margin for a spread radius is itself, on all sides.)
850 */
851 static nsMargin GetBlurRadiusMargin(nscoord aBlurRadius,
852 int32_t aAppUnitsPerDevPixel);
854 /**
855 * Blurs a coloured rectangle onto aDestinationCtx. This is equivalent
856 * to calling Init(), drawing a rectangle onto the returned surface
857 * and then calling DoPaint, but may let us optimize better in the
858 * backend.
859 *
860 * @param aDestinationCtx The destination to blur to.
861 * @param aRect The rectangle to blur in app units.
862 * @param aAppUnitsPerDevPixel The number of app units in a device pixel,
863 * for conversion. Most of the time you'll
864 * pass this from the current PresContext if
865 * available.
866 * @param aCornerRadii Corner radii for aRect, if it is a rounded
867 * rectangle.
868 * @param aBlurRadius The blur radius in app units.
869 * @param aShadowColor The color to draw the blurred shadow.
870 * @param aDirtyRect The absolute dirty rect in app units. Used to
871 * optimize the temporary surface size and speed up blur.
872 * @param aSkipRect An area in device pixels (NOT app units!) to avoid
873 * blurring over, to prevent unnecessary work.
874 */
875 static void BlurRectangle(gfxContext* aDestinationCtx,
876 const nsRect& aRect,
877 int32_t aAppUnitsPerDevPixel,
878 gfxCornerSizes* aCornerRadii,
879 nscoord aBlurRadius,
880 const gfxRGBA& aShadowColor,
881 const nsRect& aDirtyRect,
882 const gfxRect& aSkipRect);
884 protected:
885 gfxAlphaBoxBlur blur;
886 nsRefPtr<gfxContext> mContext;
887 gfxContext* mDestinationCtx;
889 /* This is true if the blur already has it's content transformed
890 * by mDestinationCtx's transform */
891 bool mPreTransformed;
893 };
895 #endif /* nsCSSRendering_h___ */