Skip to content

Commit 089a39f

Browse files
author
Nader Jawad
committed
Add BrushPainter API
Relnote: "Introduced BrushPainter API to support drawing of an arbitrary Brush within a Painter, similar to ColorPainter Updated Brush API to have an intrinsic size parameter that is queried within BrushPainter " Fixes: 189466433 Test: Added BrushPainterTest added intrinsic size tests to ShaderTest Change-Id: Ia27529070e6f2acdac9d2c73f41e886b36452f34
1 parent 6c69ad3 commit 089a39f

File tree

11 files changed

+407
-4
lines changed

11 files changed

+407
-4
lines changed

compose/ui/ui-graphics/api/current.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,8 @@ package androidx.compose.ui.graphics {
206206

207207
@androidx.compose.runtime.Immutable public abstract sealed class Brush {
208208
method public abstract void applyTo(long size, androidx.compose.ui.graphics.Paint p, float alpha);
209+
method public long getIntrinsicSize();
210+
property public long intrinsicSize;
209211
field public static final androidx.compose.ui.graphics.Brush.Companion Companion;
210212
}
211213

@@ -417,6 +419,7 @@ package androidx.compose.ui.graphics {
417419

418420
@androidx.compose.runtime.Immutable public final class LinearGradient extends androidx.compose.ui.graphics.ShaderBrush {
419421
method public android.graphics.Shader createShader(long size);
422+
property public long intrinsicSize;
420423
}
421424

422425
public final inline class Matrix {
@@ -646,6 +649,7 @@ package androidx.compose.ui.graphics {
646649

647650
@androidx.compose.runtime.Immutable public final class RadialGradient extends androidx.compose.ui.graphics.ShaderBrush {
648651
method public android.graphics.Shader createShader(long size);
652+
property public long intrinsicSize;
649653
}
650654

651655
public final class RectHelper_androidKt {
@@ -1177,6 +1181,15 @@ package androidx.compose.ui.graphics.painter {
11771181
method public static androidx.compose.ui.graphics.painter.BitmapPainter BitmapPainter(androidx.compose.ui.graphics.ImageBitmap image, optional long srcOffset, optional long srcSize, optional int filterQuality);
11781182
}
11791183

1184+
public final class BrushPainter extends androidx.compose.ui.graphics.painter.Painter {
1185+
ctor public BrushPainter(androidx.compose.ui.graphics.Brush brush);
1186+
method public androidx.compose.ui.graphics.Brush getBrush();
1187+
method public long getIntrinsicSize();
1188+
method protected void onDraw(androidx.compose.ui.graphics.drawscope.DrawScope);
1189+
property public final androidx.compose.ui.graphics.Brush brush;
1190+
property public long intrinsicSize;
1191+
}
1192+
11801193
public final class ColorPainter extends androidx.compose.ui.graphics.painter.Painter {
11811194
ctor public ColorPainter(long color);
11821195
method public long getColor();

compose/ui/ui-graphics/api/public_plus_experimental_current.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,8 @@ package androidx.compose.ui.graphics {
206206

207207
@androidx.compose.runtime.Immutable public abstract sealed class Brush {
208208
method public abstract void applyTo(long size, androidx.compose.ui.graphics.Paint p, float alpha);
209+
method public long getIntrinsicSize();
210+
property public long intrinsicSize;
209211
field public static final androidx.compose.ui.graphics.Brush.Companion Companion;
210212
}
211213

@@ -422,6 +424,7 @@ package androidx.compose.ui.graphics {
422424

423425
@androidx.compose.runtime.Immutable public final class LinearGradient extends androidx.compose.ui.graphics.ShaderBrush {
424426
method public android.graphics.Shader createShader(long size);
427+
property public long intrinsicSize;
425428
}
426429

427430
public final inline class Matrix {
@@ -651,6 +654,7 @@ package androidx.compose.ui.graphics {
651654

652655
@androidx.compose.runtime.Immutable public final class RadialGradient extends androidx.compose.ui.graphics.ShaderBrush {
653656
method public android.graphics.Shader createShader(long size);
657+
property public long intrinsicSize;
654658
}
655659

656660
public final class RectHelper_androidKt {
@@ -1182,6 +1186,15 @@ package androidx.compose.ui.graphics.painter {
11821186
method public static androidx.compose.ui.graphics.painter.BitmapPainter BitmapPainter(androidx.compose.ui.graphics.ImageBitmap image, optional long srcOffset, optional long srcSize, optional int filterQuality);
11831187
}
11841188

1189+
public final class BrushPainter extends androidx.compose.ui.graphics.painter.Painter {
1190+
ctor public BrushPainter(androidx.compose.ui.graphics.Brush brush);
1191+
method public androidx.compose.ui.graphics.Brush getBrush();
1192+
method public long getIntrinsicSize();
1193+
method protected void onDraw(androidx.compose.ui.graphics.drawscope.DrawScope);
1194+
property public final androidx.compose.ui.graphics.Brush brush;
1195+
property public long intrinsicSize;
1196+
}
1197+
11851198
public final class ColorPainter extends androidx.compose.ui.graphics.painter.Painter {
11861199
ctor public ColorPainter(long color);
11871200
method public long getColor();

compose/ui/ui-graphics/api/restricted_current.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,8 @@ package androidx.compose.ui.graphics {
236236

237237
@androidx.compose.runtime.Immutable public abstract sealed class Brush {
238238
method public abstract void applyTo(long size, androidx.compose.ui.graphics.Paint p, float alpha);
239+
method public long getIntrinsicSize();
240+
property public long intrinsicSize;
239241
field public static final androidx.compose.ui.graphics.Brush.Companion Companion;
240242
}
241243

@@ -449,6 +451,7 @@ package androidx.compose.ui.graphics {
449451

450452
@androidx.compose.runtime.Immutable public final class LinearGradient extends androidx.compose.ui.graphics.ShaderBrush {
451453
method public android.graphics.Shader createShader(long size);
454+
property public long intrinsicSize;
452455
}
453456

454457
public final inline class Matrix {
@@ -678,6 +681,7 @@ package androidx.compose.ui.graphics {
678681

679682
@androidx.compose.runtime.Immutable public final class RadialGradient extends androidx.compose.ui.graphics.ShaderBrush {
680683
method public android.graphics.Shader createShader(long size);
684+
property public long intrinsicSize;
681685
}
682686

683687
public final class RectHelper_androidKt {
@@ -1233,6 +1237,15 @@ package androidx.compose.ui.graphics.painter {
12331237
method public static androidx.compose.ui.graphics.painter.BitmapPainter BitmapPainter(androidx.compose.ui.graphics.ImageBitmap image, optional long srcOffset, optional long srcSize, optional int filterQuality);
12341238
}
12351239

1240+
public final class BrushPainter extends androidx.compose.ui.graphics.painter.Painter {
1241+
ctor public BrushPainter(androidx.compose.ui.graphics.Brush brush);
1242+
method public androidx.compose.ui.graphics.Brush getBrush();
1243+
method public long getIntrinsicSize();
1244+
method protected void onDraw(androidx.compose.ui.graphics.drawscope.DrawScope);
1245+
property public final androidx.compose.ui.graphics.Brush brush;
1246+
property public long intrinsicSize;
1247+
}
1248+
12361249
public final class ColorPainter extends androidx.compose.ui.graphics.painter.Painter {
12371250
ctor public ColorPainter(long color);
12381251
method public long getColor();

compose/ui/ui-graphics/src/androidAndroidTest/kotlin/androidx/compose/ui/graphics/ShaderTest.kt

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,83 @@ class ShaderTest {
120120
assertEquals(Color.Blue, pixelMap[5, centerY - 5])
121121
}
122122

123+
@Test
124+
fun testLinearGradientIntrinsicSize() {
125+
assertEquals(
126+
Size(100f, 200f),
127+
Brush.linearGradient(
128+
listOf(Color.Red, Color.Blue),
129+
start = Offset(200f, 100f),
130+
end = Offset(300f, 300f)
131+
).intrinsicSize
132+
)
133+
}
134+
135+
@Test
136+
fun testLinearGradientNegativePosition() {
137+
assertEquals(
138+
Size(100f, 200f),
139+
Brush.linearGradient(
140+
listOf(Color.Red, Color.Blue),
141+
start = Offset(200f, 100f),
142+
end = Offset(100f, -100f)
143+
).intrinsicSize
144+
)
145+
}
146+
147+
@Test
148+
fun testLinearGradientInfiniteWidth() {
149+
assertEquals(
150+
Size(Float.NaN, 200f),
151+
Brush.linearGradient(
152+
listOf(Color.Red, Color.Blue),
153+
start = Offset(Float.POSITIVE_INFINITY, 100f),
154+
end = Offset(Float.POSITIVE_INFINITY, 300f)
155+
).intrinsicSize
156+
)
157+
}
158+
159+
@Test
160+
fun testLinearGradientInfiniteHeight() {
161+
assertEquals(
162+
Size(100f, Float.NaN),
163+
Brush.linearGradient(
164+
listOf(Color.Red, Color.Blue),
165+
start = Offset(100f, 0f),
166+
end = Offset(200f, Float.POSITIVE_INFINITY)
167+
).intrinsicSize
168+
)
169+
}
170+
171+
@Test
172+
fun testSweepGradientIntrinsicSize() {
173+
// Sweep gradients do not have an intrinsic size as they sweep/fill the geometry they are
174+
// drawn with
175+
assertEquals(
176+
Size.Unspecified,
177+
Brush.sweepGradient(listOf(Color.Red, Color.Blue)).intrinsicSize
178+
)
179+
}
180+
181+
@Test
182+
fun testRadialGradientIntrinsicSize() {
183+
assertEquals(
184+
Size(100f, 100f),
185+
Brush.radialGradient(
186+
listOf(Color.Red, Color.Blue),
187+
radius = 50f
188+
).intrinsicSize
189+
)
190+
}
191+
192+
@Test
193+
fun testRadialGradientInfiniteSize() {
194+
assertEquals(
195+
Size.Unspecified,
196+
Brush.radialGradient(listOf(Color.Red, Color.Blue)).intrinsicSize
197+
)
198+
}
199+
123200
private fun ImageBitmap.drawInto(
124201
block: DrawScope.() -> Unit
125202
) = CanvasDrawScope().draw(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
/*
2+
* Copyright 2021 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package androidx.compose.ui.graphics.painter
18+
19+
import androidx.compose.ui.geometry.Size
20+
import androidx.compose.ui.graphics.BlendMode
21+
import androidx.compose.ui.graphics.Brush
22+
import androidx.compose.ui.graphics.Canvas
23+
import androidx.compose.ui.graphics.Color
24+
import androidx.compose.ui.graphics.ColorFilter
25+
import androidx.compose.ui.graphics.ImageBitmap
26+
import androidx.compose.ui.graphics.Paint
27+
import androidx.compose.ui.graphics.compositeOver
28+
import androidx.compose.ui.graphics.toPixelMap
29+
import androidx.test.ext.junit.runners.AndroidJUnit4
30+
import androidx.test.filters.SmallTest
31+
import org.junit.Assert.assertEquals
32+
import org.junit.Test
33+
import org.junit.runner.RunWith
34+
35+
@SmallTest
36+
@RunWith(AndroidJUnit4::class)
37+
class BrushPainterTest {
38+
39+
private fun createImageBitmap(): ImageBitmap {
40+
val image = ImageBitmap(100, 100)
41+
Canvas(image).drawRect(
42+
0f,
43+
0f,
44+
100f,
45+
100f,
46+
Paint().apply { color = Color.White }
47+
)
48+
return image
49+
}
50+
51+
@Test
52+
fun testBrushPainter() {
53+
val brushPainter = BrushPainter(
54+
Brush.verticalGradient(
55+
0.0f to Color.Red,
56+
0.5f to Color.Red,
57+
0.5f to Color.Blue,
58+
1.0f to Color.Blue
59+
)
60+
)
61+
val image = createImageBitmap()
62+
drawPainter(brushPainter, Canvas(image), Size(100f, 100f))
63+
val pixelMap = image.toPixelMap()
64+
assertEquals(Color.Red, pixelMap[0, 0])
65+
assertEquals(Color.Red, pixelMap[99, 0])
66+
assertEquals(Color.Red, pixelMap[0, 49])
67+
assertEquals(Color.Red, pixelMap[99, 49])
68+
69+
assertEquals(Color.Blue, pixelMap[0, 50])
70+
assertEquals(Color.Blue, pixelMap[99, 50])
71+
assertEquals(Color.Blue, pixelMap[0, 99])
72+
assertEquals(Color.Blue, pixelMap[99, 99])
73+
}
74+
75+
@Test
76+
fun testBrushPainterAlphaApplied() {
77+
val brushPainter = BrushPainter(
78+
Brush.verticalGradient(
79+
0.0f to Color.Red,
80+
0.5f to Color.Red,
81+
0.5f to Color.Blue,
82+
1.0f to Color.Blue
83+
)
84+
)
85+
val image = createImageBitmap()
86+
drawPainter(brushPainter, Canvas(image), Size(100f, 100f), alpha = 0.5f)
87+
88+
val expectedRed = Color(
89+
alpha = 0.5f,
90+
red = Color.Red.red,
91+
green = 0f,
92+
blue = 0f
93+
).compositeOver(Color.White)
94+
95+
val expectedBlue = Color(
96+
alpha = 0.5f,
97+
red = 0f,
98+
green = 0f,
99+
blue = Color.Blue.blue
100+
).compositeOver(Color.White)
101+
102+
val pixelMap = image.toPixelMap()
103+
assertEquals(expectedRed, pixelMap[0, 0])
104+
assertEquals(expectedRed, pixelMap[99, 0])
105+
assertEquals(expectedRed, pixelMap[0, 49])
106+
assertEquals(expectedRed, pixelMap[99, 49])
107+
108+
assertEquals(expectedBlue, pixelMap[0, 50])
109+
assertEquals(expectedBlue, pixelMap[99, 50])
110+
assertEquals(expectedBlue, pixelMap[0, 99])
111+
assertEquals(expectedBlue, pixelMap[99, 99])
112+
}
113+
114+
@Test
115+
fun testBrushPainterTint() {
116+
val brushPainter = BrushPainter(
117+
Brush.verticalGradient(
118+
0.0f to Color.Red,
119+
0.5f to Color.Red,
120+
0.5f to Color.Blue,
121+
1.0f to Color.Blue
122+
)
123+
)
124+
val image = createImageBitmap()
125+
drawPainter(
126+
brushPainter,
127+
Canvas(image),
128+
Size(100f, 100f),
129+
colorFilter = ColorFilter.tint(Color.Cyan, BlendMode.SrcIn)
130+
)
131+
val pixelMap = image.toPixelMap()
132+
assertEquals(Color.Cyan, pixelMap[0, 0])
133+
assertEquals(Color.Cyan, pixelMap[99, 0])
134+
assertEquals(Color.Cyan, pixelMap[0, 49])
135+
assertEquals(Color.Cyan, pixelMap[99, 49])
136+
137+
assertEquals(Color.Cyan, pixelMap[0, 50])
138+
assertEquals(Color.Cyan, pixelMap[99, 50])
139+
assertEquals(Color.Cyan, pixelMap[0, 99])
140+
assertEquals(Color.Cyan, pixelMap[99, 99])
141+
}
142+
143+
@Test
144+
fun testBrushPainterEquals() {
145+
val brush1 = Brush.verticalGradient(
146+
0.0f to Color.Red,
147+
0.3f to Color.Blue,
148+
0.7f to Color.Green
149+
)
150+
151+
val brush2 = Brush.verticalGradient(
152+
0.0f to Color.Red,
153+
0.3f to Color.Blue,
154+
0.7f to Color.Green
155+
)
156+
157+
assertEquals(BrushPainter(brush1), BrushPainter(brush2))
158+
}
159+
160+
@Test
161+
fun testBrushPainterHashCode() {
162+
val brush = Brush.horizontalGradient(listOf(Color.Red, Color.Blue, Color.Yellow))
163+
assertEquals(BrushPainter(brush).hashCode(), brush.hashCode())
164+
}
165+
166+
@Test
167+
fun testBrushPainterToString() {
168+
val brush = Brush.verticalGradient(
169+
listOf(Color.White, Color.Black, Color.Gray, Color.LightGray)
170+
)
171+
assertEquals("BrushPainter(brush=$brush)", BrushPainter(brush).toString())
172+
}
173+
174+
@Test
175+
fun testBrushPainterIntrinsicSize() {
176+
val brush = Brush.verticalGradient(
177+
listOf(Color.White, Color.Black),
178+
startY = 0f,
179+
endY = 100f
180+
)
181+
assertEquals(Size(0.0f, 100f), BrushPainter(brush).intrinsicSize)
182+
}
183+
}

0 commit comments

Comments
 (0)