Skip to content

Commit

Permalink
Fix opacity bugs (#1183)
Browse files Browse the repository at this point in the history
  • Loading branch information
wcandillon authored Dec 5, 2022
1 parent d1cfd15 commit 8b84597
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 27 deletions.
8 changes: 6 additions & 2 deletions package/cpp/rnskia/dom/base/DrawingContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,12 @@ double DrawingContext::getOpacity() {
Sets the opacity value
*/
void DrawingContext::setOpacity(double opacity) {
getMutablePaint()->setAlphaf(_opacity);
_opacity = opacity;
auto currentOpacity = opacity;
if (_parent != nullptr) {
currentOpacity *= _parent->getOpacity();
}
getMutablePaint()->setAlphaf(currentOpacity);
_opacity = currentOpacity;
}

/**
Expand Down
3 changes: 1 addition & 2 deletions package/cpp/rnskia/dom/props/PaintProps.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,7 @@ class PaintProps : public BaseDerivedProp {
// Opacity
if (_opacity->isChanged() || context->isChanged()) {
if (_opacity->isSet()) {
context->setOpacity(context->getOpacity() *
_opacity->value().getAsNumber());
context->setOpacity(_opacity->value().getAsNumber());
} else {
context->clearOpacity();
}
Expand Down
26 changes: 20 additions & 6 deletions package/src/__tests__/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,27 @@ export const processResult = (
ckSurface.getCanvas().clear(Float32Array.of(0, 0, 0, 0));
};

interface CheckImageOptions {
maxPixelDiff?: number;
threshold?: number;
overwrite?: boolean;
mute?: boolean;
}

const defaultCheckImageOptions = {
maxPixelDiff: 0,
threshold: 0.1,
overwrite: false,
mute: false,
};

export const checkImage = (
image: SkImage,
relPath: string,
overwrite = false,
mute = false,
threshold = 0.1
opts?: CheckImageOptions
) => {
const options = { ...defaultCheckImageOptions, ...opts };
const { overwrite, threshold, mute, maxPixelDiff } = options;
const png = image.encodeToBytes();
const p = path.resolve(__dirname, relPath);
if (fs.existsSync(p) && !overwrite) {
Expand All @@ -61,11 +75,11 @@ export const checkImage = (
{ threshold }
);
if (!mute) {
if (diffPixelsCount !== 0) {
if (diffPixelsCount > maxPixelDiff) {
fs.writeFileSync(`${p}.test.png`, PNG.sync.write(toTest));
// fs.writeFileSync(`${p}-diff-test.png`, PNG.sync.write(diffImage));
fs.writeFileSync(`${p}-diff-test.png`, PNG.sync.write(diffImage));
}
expect(diffPixelsCount).toBe(0);
expect(diffPixelsCount).toBeLessThanOrEqual(maxPixelDiff);
}
return diffPixelsCount;
} else {
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 8 additions & 13 deletions package/src/dom/nodes/RenderNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,27 +208,19 @@ export abstract class JsiRenderNode<P extends GroupProps>
const { invertClip, layer, matrix, transform } = this.props;
const { canvas } = parentCtx;

const opacity =
this.props.opacity !== undefined
? parentCtx.paint.getAlphaf() * this.props.opacity
: parentCtx.paint.getAlphaf();

if (
this.paintCache === null ||
this.paintCache.parent !== parentCtx.paint
) {
const paintCtx = this.getPaintCtx();
if (paintCtx) {
paintCtx.opacity = opacity;
}
const child = paintCtx
? concatPaint(parentCtx.paint, paintCtx)
? concatPaint(parentCtx.paint.copy(), paintCtx)
: parentCtx.paint;
this.paintCache = { parent: parentCtx.paint, child };
}
const paint = this.paintCache.child;
// TODO: can we only recreate a new context here if needed?
const ctx = { ...parentCtx, opacity, paint };
const ctx = { ...parentCtx, paint };
const hasTransform = matrix !== undefined || transform !== undefined;
const hasClip =
this.clipRect !== undefined ||
Expand Down Expand Up @@ -270,7 +262,7 @@ export abstract class JsiRenderNode<P extends GroupProps>
}

const concatPaint = (
parent: SkPaint,
paint: SkPaint,
{
color,
strokeWidth,
Expand All @@ -288,10 +280,14 @@ const concatPaint = (
style,
}: PaintContext
) => {
const paint = parent.copy();
if (opacity !== undefined) {
paint.setAlphaf(paint.getAlphaf() * opacity);
}
if (color !== undefined) {
const currentOpacity = paint.getAlphaf();
paint.setShader(null);
paint.setColor(color);
paint.setAlphaf(currentOpacity * paint.getAlphaf());
}
if (strokeWidth !== undefined) {
paint.setStrokeWidth(strokeWidth);
Expand Down Expand Up @@ -329,6 +325,5 @@ const concatPaint = (
if (style !== undefined) {
paint.setStyle(style);
}
paint.setAlphaf(paint.getAlphaf() * (opacity ?? 1));
return paint;
};
4 changes: 3 additions & 1 deletion package/src/renderer/__tests__/e2e/Drawings.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ describe("Drawings", () => {
<Circle cx={width / 2} cy={height - r} r={r} color="yellow" />
</Group>
);
const diff = checkImage(image, "snapshots/drawings/blur.png", false, true);
const diff = checkImage(image, "snapshots/drawings/blur.png", {
mute: true,
});
expect(diff).not.toBe(0);
});

Expand Down
43 changes: 40 additions & 3 deletions package/src/renderer/__tests__/e2e/Opacity.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,39 @@ import { setupSkia } from "../../../skia/__tests__/setup";
import { fitRects } from "../../../dom/nodes/datatypes/Fitting";

describe("Opacity", () => {
it("Build reference result", async () => {
const image = await surface.draw(
<>
<Fill color="white" />
<Fill color="rgba(0, 0, 255, 0.25)" />
</>
);
checkImage(image, "snapshots/drawings/violet.png");
});
it("Should multiply multiply the color opacity (1)", async () => {
const image = await surface.draw(
<>
<Fill color="white" />
<Group opacity={0.5}>
<Fill color="rgba(0, 0, 255, 0.5)" />
</Group>
</>
);
checkImage(image, "snapshots/drawings/violet.png");
});
it("Should multiply multiply the color opacity (2)", async () => {
const image = await surface.draw(
<>
<Fill color="white" />
<Group opacity={0.5}>
<Group opacity={0.5}>
<Fill color="blue" />
</Group>
</Group>
</>
);
checkImage(image, "snapshots/drawings/violet.png");
});
it("Should multiply the opacity to 0", async () => {
const { rect, rrect } = importSkia();
const { width } = surface;
Expand Down Expand Up @@ -134,7 +167,7 @@ describe("Opacity", () => {
);
checkImage(image, "snapshots/drawings/opacity-multiplication2.png");
});
it("Build reference result", () => {
it("Build reference result (2)", () => {
const {
surface: ckSurface,
Skia,
Expand Down Expand Up @@ -217,7 +250,9 @@ describe("Opacity", () => {
</Fill>
</Group>
);
checkImage(img, "snapshots/drawings/opacity-image.png", false, false, 0.2);
checkImage(img, "snapshots/drawings/opacity-image.png", {
maxPixelDiff: 8,
});
});
it("Should apply opacity to an image shader (2)", async () => {
const { oslo } = images;
Expand All @@ -240,6 +275,8 @@ describe("Opacity", () => {
</Group>
</Group>
);
checkImage(img, "snapshots/drawings/opacity-image.png", false, false, 0.2);
checkImage(img, "snapshots/drawings/opacity-image.png", {
maxPixelDiff: 8,
});
});
});

0 comments on commit 8b84597

Please sign in to comment.