Ω-W1-T3 review fixes: skip meter invalidate when covered; push fast-path predicates into core
Fixes the critical finding — Browse/curve-popup no longer trigger 60 Hz whole-client repaints when the meter is invisible. Pushes the fast-path and self-containment geometry into master_meter with tests; batches the four minor findings.
This commit is contained in:
@@ -5,6 +5,8 @@
|
||||
// the mono bar taking the whole field, the two stereo bars, all inside the column.
|
||||
// * bar count — the SAME LaneSplit resolveLaneSplit folds, over channel mode x source
|
||||
// channel count, so it can never become a second rule.
|
||||
// * the editor's dirty-rect fast path — meterFastPathEligible's wholly-inside test, and
|
||||
// meterBarsWithinField, the self-containment invariant the fast path rests on.
|
||||
// * the dB axis — top/floor on the field's edges, an interior value, and the clamps.
|
||||
// * ballistics — instantaneous rise, 20 dB/s fall, the 1.5 s hold and its release AT RATE;
|
||||
// the audio thread's clip latch surviving a UI frame; the per-field single-lane fold.
|
||||
@@ -287,6 +289,29 @@ static void testDrawEqualityCoversTheDrawnQuantities() {
|
||||
CHECK(meterDrawEqual(a, graze));
|
||||
}
|
||||
|
||||
// The editor's WM_PAINT fast-path test: a dirty rect wholly inside the field takes the
|
||||
// meter-only redraw; anything that pokes outside it, or a field that hasn't been laid out yet,
|
||||
// falls back to the full compose.
|
||||
static void testFastPathEligibleOnlyForADirtyRectInsideTheField() {
|
||||
const MeterRects m = meterRects(kColumn, LaneSplit::Single);
|
||||
CHECK(meterFastPathEligible(m, m.field)); // the whole field
|
||||
CHECK(meterFastPathEligible(
|
||||
m, Rect::ltrb(m.field.x + 2, m.field.y + 2, m.field.right() - 2, m.field.bottom() - 2)));
|
||||
CHECK(!meterFastPathEligible(m, Rect::ltrb(m.field.x - 1, m.field.y, m.field.right(),
|
||||
m.field.bottom()))); // pokes left of the field
|
||||
CHECK(!meterFastPathEligible(
|
||||
m, Rect::ltrb(kColumn.x, kColumn.y, kColumn.right(), kColumn.bottom()))); // whole column
|
||||
CHECK(!meterFastPathEligible(MeterRects{}, m.field)); // no cached layout at all
|
||||
}
|
||||
|
||||
// The self-containment invariant drawMeterField's redraw-the-field-alone shortcut rests on:
|
||||
// every bar meterRects() hands back stays inside the field, in both lane splits.
|
||||
static void testFieldBoundsEveryBarItPaints() {
|
||||
CHECK(meterBarsWithinField(meterRects(kColumn, LaneSplit::Single)));
|
||||
CHECK(meterBarsWithinField(meterRects(kColumn, LaneSplit::Stereo)));
|
||||
CHECK(meterBarsWithinField(MeterRects{})); // degenerate: nothing to bound, nothing drawn
|
||||
}
|
||||
|
||||
static void testDegenerateColumnYieldsNothing() {
|
||||
const MeterRects m = meterRects(Rect::ltrb(0, 0, 0, 0), LaneSplit::Stereo);
|
||||
CHECK(m.field.empty() && m.barA.empty() && m.barB.empty());
|
||||
@@ -300,6 +325,8 @@ int main() {
|
||||
testEveryOtherTickCarriesANumeral();
|
||||
testTheFloorNumeralStaysInsideTheGutter();
|
||||
testAColumnTooNarrowForTheInteriorDrawsNothing();
|
||||
testFastPathEligibleOnlyForADirtyRectInsideTheField();
|
||||
testFieldBoundsEveryBarItPaints();
|
||||
testPeakRisesAtOnceAndFallsAtTwentyDbPerSecond();
|
||||
testPeakHoldSitsForItsFullWindowThenReleases();
|
||||
testClipLatchesFromThePublishedFlagAndClearsOnDemand();
|
||||
|
||||
Reference in New Issue
Block a user