fix: close Θ-W7-T1 review — scaling guard, opacity claims, two vacuous test fixes

Guards the stroke blend against LICE_EXT_GET_SCALING, tightens the analytic-stroker's boxes and NaN handling, corrects the opaque-core threshold and inner-dial rationale in the docs, and re-derives two review-flagged tautological tests so they actually fail against the bugs they claim to catch.
This commit is contained in:
2026-08-01 13:45:43 -04:00
parent 2e09776342
commit 3fb77027c6
11 changed files with 181 additions and 30 deletions
+27 -8
View File
@@ -56,16 +56,26 @@ void StrokeCanvas::extendRow(int y, int x0, int x1) {
}
void StrokeCanvas::addPiece(float ax, float ay, float bx, float by, float halfWidth) {
// Every current caller feeds bounded geometry, but this is a pure module: a NaN/Inf
// coordinate would otherwise reach static_cast<int> below, which is UB rather than a
// clipped no-op.
if (!(std::isfinite(ax) && std::isfinite(ay) && std::isfinite(bx) && std::isfinite(by) &&
std::isfinite(halfWidth))) {
return;
}
const float reach = halfWidth + 0.5f; // beyond this the coverage is 0
const float dx = bx - ax;
const float dy = by - ay;
const float len2 = dx * dx + dy * dy;
const float invLen2 = len2 > 0.0f ? 1.0f / len2 : 0.0f;
int x0 = static_cast<int>(std::floor((std::min)(ax, bx) - reach));
int x1 = static_cast<int>(std::ceil((std::max)(ax, bx) + reach)) + 1;
int y0 = static_cast<int>(std::floor((std::min)(ay, by) - reach));
int y1 = static_cast<int>(std::ceil((std::max)(ay, by) + reach)) + 1;
// A pixel can only take ink when its centre (x+0.5) is within `reach` of the piece, i.e.
// x + 0.5 < maxX + reach — so the exclusive upper bound is floor(maxX + reach + 0.5), not
// ceil(maxX + reach) + 1 (a whole extra pixel of guaranteed-zero coverage on every side).
int x0 = static_cast<int>(std::ceil((std::min)(ax, bx) - reach - 0.5f));
int x1 = static_cast<int>(std::floor((std::max)(ax, bx) + reach + 0.5f));
int y0 = static_cast<int>(std::ceil((std::min)(ay, by) - reach - 0.5f));
int y1 = static_cast<int>(std::floor((std::max)(ay, by) + reach + 0.5f));
x0 = (std::max)(x0, bounds_.x);
y0 = (std::max)(y0, bounds_.y);
x1 = (std::min)(x1, bounds_.right());
@@ -123,11 +133,20 @@ Rect strokeBounds(const StrokePoint* pts, std::size_t count, float halfWidth, co
minY = (std::min)(minY, pts[i].y);
maxY = (std::max)(maxY, pts[i].y);
}
// Same NaN/Inf guard as addPiece: an unbounded coordinate must clip to nothing, not reach
// the static_cast<int> below as UB.
if (!(std::isfinite(minX) && std::isfinite(maxX) && std::isfinite(minY) &&
std::isfinite(maxY) && std::isfinite(halfWidth))) {
return Rect{};
}
const float reach = halfWidth + 0.5f;
const int x0 = (std::max)(clip.x, static_cast<int>(std::floor(minX - reach)));
const int y0 = (std::max)(clip.y, static_cast<int>(std::floor(minY - reach)));
const int x1 = (std::min)(clip.right(), static_cast<int>(std::ceil(maxX + reach)) + 1);
const int y1 = (std::min)(clip.bottom(), static_cast<int>(std::ceil(maxY + reach)) + 1);
// Same tightened box as addPiece (see its comment): a pixel only takes ink when its centre
// is within `reach`, so this is [ceil(min-reach-0.5), floor(max+reach+0.5)) rather than the
// old ceil/floor pair that padded a whole extra pixel on every side.
const int x0 = (std::max)(clip.x, static_cast<int>(std::ceil(minX - reach - 0.5f)));
const int y0 = (std::max)(clip.y, static_cast<int>(std::ceil(minY - reach - 0.5f)));
const int x1 = (std::min)(clip.right(), static_cast<int>(std::floor(maxX + reach + 0.5f)));
const int y1 = (std::min)(clip.bottom(), static_cast<int>(std::floor(maxY + reach + 0.5f)));
if (x0 >= x1 || y0 >= y1) return Rect{};
return Rect::ltrb(x0, y0, x1, y1);
}