Skip to content

Commit

Permalink
Store round corners in 16x16 patches instead of 8x8 (#82)
Browse files Browse the repository at this point in the history
* Store round corners in 16x16 patches instead of 8x8

* feedback
  • Loading branch information
Erik Corry authored Dec 14, 2023
1 parent 2b521e1 commit b3b869c
Showing 1 changed file with 25 additions and 22 deletions.
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

0 comments on commit b3b869c

Please sign in to comment.