Bug 1838546 [wpt PR 40558] - Update wpt metadata, a=testonly
[gecko.git] / widget / ThemeDrawing.cpp
blob93e317a41bb95341ec39de8729a05171904c5323
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/. */
7 #include "ThemeDrawing.h"
9 namespace mozilla::widget {
11 /*static*/
12 void ThemeDrawing::FillRect(DrawTarget& aDt, const LayoutDeviceRect& aRect,
13 const sRGBColor& aColor) {
14 aDt.FillRect(aRect.ToUnknownRect(), gfx::ColorPattern(ToDeviceColor(aColor)));
17 /*static*/
18 void ThemeDrawing::FillRect(WebRenderBackendData& aWrData,
19 const LayoutDeviceRect& aRect,
20 const sRGBColor& aColor) {
21 const bool kBackfaceIsVisible = true;
22 auto dest = wr::ToLayoutRect(aRect);
23 aWrData.mBuilder.PushRect(dest, dest, kBackfaceIsVisible, false, false,
24 wr::ToColorF(ToDeviceColor(aColor)));
27 /*static*/
28 LayoutDeviceIntCoord ThemeDrawing::SnapBorderWidth(const CSSCoord& aCssWidth,
29 const DPIRatio& aDpiRatio) {
30 if (aCssWidth == 0.0f) {
31 return 0;
33 return std::max(LayoutDeviceIntCoord(1), (aCssWidth * aDpiRatio).Truncated());
36 /*static*/
37 void ThemeDrawing::PaintArrow(DrawTarget& aDrawTarget,
38 const LayoutDeviceRect& aRect,
39 const float aArrowPolygonX[],
40 const float aArrowPolygonY[],
41 const float aArrowPolygonSize,
42 const int32_t aArrowNumPoints,
43 const sRGBColor aFillColor) {
44 const float scale = ScaleToFillRect(aRect, aArrowPolygonSize);
46 auto center = aRect.Center().ToUnknownPoint();
48 RefPtr<gfx::PathBuilder> builder = aDrawTarget.CreatePathBuilder();
49 gfx::Point p =
50 center + gfx::Point(aArrowPolygonX[0] * scale, aArrowPolygonY[0] * scale);
51 builder->MoveTo(p);
52 for (int32_t i = 1; i < aArrowNumPoints; i++) {
53 p = center +
54 gfx::Point(aArrowPolygonX[i] * scale, aArrowPolygonY[i] * scale);
55 builder->LineTo(p);
57 RefPtr<gfx::Path> path = builder->Finish();
59 aDrawTarget.Fill(path, gfx::ColorPattern(ToDeviceColor(aFillColor)));
62 void ThemeDrawing::PaintRoundedRectWithRadius(
63 WebRenderBackendData& aWrData, const LayoutDeviceRect& aRect,
64 const LayoutDeviceRect& aClipRect, const sRGBColor& aBackgroundColor,
65 const sRGBColor& aBorderColor, const CSSCoord& aBorderWidth,
66 const CSSCoord& aRadius, const DPIRatio& aDpiRatio) {
67 const bool kBackfaceIsVisible = true;
68 const LayoutDeviceCoord borderWidth(SnapBorderWidth(aBorderWidth, aDpiRatio));
69 const LayoutDeviceCoord radius(aRadius * aDpiRatio);
70 const wr::LayoutRect dest = wr::ToLayoutRect(aRect);
71 const wr::LayoutRect clip = wr::ToLayoutRect(aClipRect);
73 // Push the background.
74 if (aBackgroundColor.a != 0.0f) {
75 auto backgroundColor = wr::ToColorF(ToDeviceColor(aBackgroundColor));
76 wr::LayoutRect backgroundRect = [&] {
77 LayoutDeviceRect bg = aRect;
78 bg.Deflate(borderWidth);
79 return wr::ToLayoutRect(bg);
80 }();
81 if (radius == 0.0f) {
82 aWrData.mBuilder.PushRect(backgroundRect, clip, kBackfaceIsVisible, false,
83 false, backgroundColor);
84 } else {
85 // NOTE(emilio): This follows DisplayListBuilder::PushRoundedRect and
86 // draws the rounded fill as an extra thick rounded border instead of a
87 // rectangle that's clipped to a rounded clip. Refer to that method for a
88 // justification. See bug 1694269.
89 LayoutDeviceCoord backgroundRadius =
90 std::max(0.0f, float(radius) - float(borderWidth));
91 wr::BorderSide side = {backgroundColor, wr::BorderStyle::Solid};
92 const wr::BorderSide sides[4] = {side, side, side, side};
93 float h = backgroundRect.width() * 0.6f;
94 float v = backgroundRect.height() * 0.6f;
95 wr::LayoutSideOffsets widths = {v, h, v, h};
96 wr::BorderRadius radii = {{backgroundRadius, backgroundRadius},
97 {backgroundRadius, backgroundRadius},
98 {backgroundRadius, backgroundRadius},
99 {backgroundRadius, backgroundRadius}};
100 aWrData.mBuilder.PushBorder(backgroundRect, clip, kBackfaceIsVisible,
101 widths, {sides, 4}, radii);
105 if (borderWidth != 0.0f && aBorderColor.a != 0.0f) {
106 // Push the border.
107 const auto borderColor = ToDeviceColor(aBorderColor);
108 const auto side = wr::ToBorderSide(borderColor, StyleBorderStyle::Solid);
109 const wr::BorderSide sides[4] = {side, side, side, side};
110 const LayoutDeviceSize sideRadius(radius, radius);
111 const auto widths =
112 wr::ToBorderWidths(borderWidth, borderWidth, borderWidth, borderWidth);
113 const auto wrRadius =
114 wr::ToBorderRadius(sideRadius, sideRadius, sideRadius, sideRadius);
115 aWrData.mBuilder.PushBorder(dest, clip, kBackfaceIsVisible, widths,
116 {sides, 4}, wrRadius);
120 void ThemeDrawing::PaintRoundedRectWithRadius(
121 DrawTarget& aDrawTarget, const LayoutDeviceRect& aRect,
122 const LayoutDeviceRect& aClipRect, const sRGBColor& aBackgroundColor,
123 const sRGBColor& aBorderColor, const CSSCoord& aBorderWidth,
124 const CSSCoord& aRadius, const DPIRatio& aDpiRatio) {
125 const LayoutDeviceCoord borderWidth(SnapBorderWidth(aBorderWidth, aDpiRatio));
126 const bool needsClip = !(aRect == aClipRect);
127 if (needsClip) {
128 aDrawTarget.PushClipRect(aClipRect.ToUnknownRect());
131 LayoutDeviceRect rect(aRect);
132 // Deflate the rect by half the border width, so that the middle of the
133 // stroke fills exactly the area we want to fill and not more.
134 rect.Deflate(borderWidth * 0.5f);
136 LayoutDeviceCoord radius(aRadius * aDpiRatio - borderWidth * 0.5f);
137 // Fix up the radius if it's too large with the rect we're going to paint.
139 LayoutDeviceCoord min = std::min(rect.width, rect.height);
140 if (radius * 2.0f > min) {
141 radius = min * 0.5f;
145 Maybe<gfx::ColorPattern> backgroundPattern;
146 if (aBackgroundColor.a != 0.0f) {
147 backgroundPattern.emplace(ToDeviceColor(aBackgroundColor));
149 Maybe<gfx::ColorPattern> borderPattern;
150 if (borderWidth != 0.0f && aBorderColor.a != 0.0f) {
151 borderPattern.emplace(ToDeviceColor(aBorderColor));
154 if (borderPattern || backgroundPattern) {
155 if (radius != 0.0f) {
156 gfx::RectCornerRadii radii(radius, radius, radius, radius);
157 RefPtr<gfx::Path> roundedRect =
158 MakePathForRoundedRect(aDrawTarget, rect.ToUnknownRect(), radii);
160 if (backgroundPattern) {
161 aDrawTarget.Fill(roundedRect, *backgroundPattern);
163 if (borderPattern) {
164 aDrawTarget.Stroke(roundedRect, *borderPattern,
165 gfx::StrokeOptions(borderWidth));
167 } else {
168 if (backgroundPattern) {
169 aDrawTarget.FillRect(rect.ToUnknownRect(), *backgroundPattern);
171 if (borderPattern) {
172 aDrawTarget.StrokeRect(rect.ToUnknownRect(), *borderPattern,
173 gfx::StrokeOptions(borderWidth));
178 if (needsClip) {
179 aDrawTarget.PopClip();
183 } // namespace mozilla::widget