Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Store round corners in 16x16 patches instead of 8x8 #82

Merged
merged 16 commits into from
Dec 14, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 25 additions & 22 deletions src/style.toit
Original file line number Diff line number Diff line change
Expand Up @@ -283,16 +283,16 @@ class RoundedCornerBorder extends InvisibleBorder:
transparency-map.pixmap x y
--pixels = byte-opacity
--palette = palette
--source-width = 8
--source-width = RoundedCornerOpacity_.PATCH-SIZE_
--orientation = orientation
else:
draw-corners_ x2 y2 right bottom radius_: | _ bit-opacity x y orientation |
transparency-map.bitmap x y
--pixels = bit-opacity
--alpha = ONE-ZERO-ALPHA_
--palette = ONE-ZERO-PALETTE_
--source-width = 8
--source-line-stride = 1
--source-width = RoundedCornerOpacity_.PATCH-SIZE_
--source-line-stride = (RoundedCornerOpacity_.PATCH-SIZE_ >> 3)
--orientation = orientation

static ONE-ZERO-PALETTE_ ::= #[0, 0, 0, 1, 1, 1]
Expand All @@ -304,15 +304,15 @@ class RoundedCornerBorder extends InvisibleBorder:
- $corner-radius: The radius of the rounded corners.
- $block: A block to call to draw each corner.
Block arguments are:
- byte-opacity: a 64 entry byte array of 8x8 opacity values, or null if the patch is fully transparent.
- bit-opacity: an 8 entry byte array of 8x8 opacity values, or null if the patch is fully transparent.
- byte-opacity: a 256 entry byte array of 16x16 opacity values, or null if the patch is fully transparent.
- bit-opacity: a 32 entry byte array of 16x16 opacity values, or null if the patch is fully transparent.
- x: the x coordinate of the top left corner of the patch.
- y: the y coordinate of the top left corner of the patch.
- orientation: the orientation to draw the patch, one of $ORIENTATION-0, $ORIENTATION-90, $ORIENTATION-180, $ORIENTATION-270.
*/
draw-corners_ left/int top/int right/int bottom/int corner-radius/int [block]:
for j := 0; j < corner-radius; j += 8:
for i := 0; i < corner-radius; i += 8:
for j := 0; j < corner-radius; j += RoundedCornerOpacity_.PATCH-SIZE_:
for i := 0; i < corner-radius; i += RoundedCornerOpacity_.PATCH-SIZE_:
byte-opacity := opacities_.get-bytes-patch i j
if byte-opacity:
bit-opacity := opacities_.get-bits-patch i j
Expand Down Expand Up @@ -423,7 +423,8 @@ class RoundedCornerOpacity_:
radius/int
static cache_ := Map.weak

static OPAQUE-BYTES-8x8_/ByteArray ::= ByteArray 64: 0xff
static OPAQUE-CORNER-PATCH_/ByteArray ::=
ByteArray (PATCH-SIZE_ * PATCH-SIZE_): 0xff

static get corner-radius/int -> RoundedCornerOpacity_:
cached := cache_.get corner-radius
Expand All @@ -450,6 +451,8 @@ class RoundedCornerOpacity_:
get-bits-patch i/int j/int -> ByteArray?:
return bit-opacities_[(i << 16) + j]

static PATCH-SIZE_ ::= 16

constructor.private_ .radius:
// We have a quarter circle in a 256x256 square that we downsample to the
// radius. The quarter circle is represented by QUARTER-CIRCLE, a
Expand All @@ -460,14 +463,14 @@ class RoundedCornerOpacity_:
downsample := TABLE-SIZE_ / radius
// The steps are a list of the offsets of the pixels we are producing
// in the original 256x256 square. For example, for a radius of 5 the
// steps are [0, 51, 102, 153, 204]. We pad it up by 8 to make the code
// below simpler.
steps := List (radius + 8): (it * TABLE-SIZE_) / radius
for j := 0; j < radius; j += 8:
for i := 0; i < radius; i += 8:
max-b := steps[j + 8]
// steps are [0, 51, 102, 153, 204]. We pad it up by PATCH-SIZE_ to make
// the code below simpler.
steps := List (radius + PATCH-SIZE_): (it * TABLE-SIZE_) / radius
for j := 0; j < radius; j += PATCH-SIZE_:
for i := 0; i < radius; i += PATCH-SIZE_:
max-b := steps[j + PATCH-SIZE_]
min-b := steps[j]
max-a := steps[i + 8]
max-a := steps[i + PATCH-SIZE_]
min-a := steps[i]
column-height-index := max-b + downsample - 1
column-height := column-height-index >= QUARTER-CIRCLE_.size ? -1 : QUARTER-CIRCLE_[column-height-index]
Expand All @@ -476,17 +479,17 @@ class RoundedCornerOpacity_:
// the edge.
opacity-key := (i << 16) + j
if column-height >= max-a + downsample:
byte-opacities_[opacity-key] = OPAQUE-BYTES-8x8_
byte-opacities_[opacity-key] = OPAQUE-CORNER-PATCH_
else if QUARTER-CIRCLE_[min-b] < min-a:
byte-opacities_[opacity-key] = null
else:
// Edge of quarter circle, we have to make an 8x8 patch of
// opacity.
byte-opacity := ByteArray 64
(min 8 (radius - j)).repeat: | small-j |
byte-opacity := ByteArray (PATCH-SIZE_ * PATCH-SIZE_)
(min PATCH-SIZE_ (radius - j)).repeat: | small-j |
b := steps[j + small-j]
(min 8 (radius - i)).repeat: | small-i |
idx := small-j * 8 + small-i
(min PATCH-SIZE_ (radius - i)).repeat: | small-i |
idx := small-j * PATCH-SIZE_ + small-i
a := steps[i + small-i]
if QUARTER-CIRCLE_[b + downsample - 1] >= a + downsample:
byte-opacity[idx] = 0xff // Inside quarter circle.
Expand All @@ -508,9 +511,9 @@ class RoundedCornerOpacity_:
if byte-opacity == null:
bit-opacities_[key] = null
else:
bit-opacity := ByteArray 8: | line |
bit-opacity := ByteArray (byte-opacity.size >> 3): | part |
mask := 0
idx := line * 8
idx := part * 8
8.repeat: | bit |
mask = mask << 1
mask |= (byte-opacity[idx + bit] < 128 ? 0 : 1)
Expand Down