Bug 197689 - Text with a gradient and drop shadow does not display properly if the canvas context is scaled
Summary: Text with a gradient and drop shadow does not display properly if the canvas ...
Status: NEW
Alias: None
Product: WebKit
Classification: Unclassified
Component: Canvas (show other bugs)
Version: Safari 11
Hardware: All All
: P2 Normal
Assignee: Nobody
URL:
Keywords: BrowserCompat, InRadar
: 227954 (view as bug list)
Depends on:
Blocks:
 
Reported: 2019-05-08 02:36 PDT by themoonrat
Modified: 2021-10-05 09:47 PDT (History)
6 users (show)

See Also:


Attachments
Comparing visuals to another browser (25.80 KB, image/png)
2019-05-08 02:36 PDT, themoonrat
no flags Details
Testcase (714 bytes, text/html)
2019-05-14 15:20 PDT, Simon Fraser (smfr)
no flags Details
Simple and system drop-shadow (1.50 KB, text/html)
2021-07-16 17:36 PDT, Said Abou-Hallawa
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description themoonrat 2019-05-08 02:36:40 PDT
Created attachment 369367 [details]
Comparing visuals to another browser

Seen on:
Safari 11.1.2on MacOS High Sierra 10.13.6
iPad Pro on 12.1.3
iPad Air on 12.x (can't remember exact version)
iPhone S8+ on 11.4.1

On an empty html page, as this script in the body

<script>
	var canvas = document.getElementById("myCanvas");
	var ctx = canvas.getContext('2d');
	ctx.shadowColor = "#000000";
	ctx.shadowOffsetX = 5;
	ctx.shadowOffsetY = 5
	ctx.shadowBlur = 10;
	ctx.font = "70px arial";
	var gradient = ctx.createLinearGradient(300, 0, 300, 100);
	gradient.addColorStop(0, '#FF0000');
	gradient.addColorStop(0.25, '#FF0000');
	gradient.addColorStop(0.5, '#00FF00');
	gradient.addColorStop(0.75, '#0000FF');
	gradient.addColorStop(1, '#0000FF');
	ctx.fillStyle = gradient;
	ctx.scale(0.75, 0.75);
	ctx.fillText("1234567890", 10, 70);
</script>

On every other browser / os combination I've tried, you get the correct visual you see at the top of my attachment. But on Safari for MacOS and iOS, the drop shadow appears incorrectly way above the text.

If you remove the gradient and use a simple fill style, the drop shadow will appear in the correct place.
If you keep the gradient but remove the ctx.scale line, the drop shadow will appear in the correct place.

It's the combination of both gradient and scale where things go wrong.
Comment 1 Radar WebKit Bug Importer 2019-05-08 09:36:26 PDT
<rdar://problem/50583846>
Comment 2 Simon Fraser (smfr) 2019-05-14 15:20:12 PDT
Created attachment 369899 [details]
Testcase
Comment 3 Simon Fraser (smfr) 2021-07-15 19:47:45 PDT
*** Bug 227954 has been marked as a duplicate of this bug. ***
Comment 4 Said Abou-Hallawa 2021-07-16 16:47:47 PDT
The drop-shadow is drawn separate from drawing the text. But we have two different code paths for drawing the drop-shadow: simple and system. In the "simple" case, we draw the drop-shadow ourselves and in the "system" case we let the system draw the drop-shadow for dummy clipped-out text.

In FontCascade::drawGlyphs() we make a distinction between these two cases by the boolean hasSimpleShadow. When it is true we draw normal text and we clear the shadow setting temporarily by calling context.clearShadow()/context.setShadow().

It is important to note that,

1. In CanvasRenderingContext2DBase::drawTextUnchecked() and if (shouldDrawShadows()) is true, we call fontProxy.drawBidiText() but we clip the drawing such that text is clipped but the drop-shadow appears. I think the calculation under this if-statement is the cause of this bug.

2. In FontCascade::drawGlyphs(), hasSimpleShadow is set to true if the drop-shadow is not blurred and the GraphicsContext is not scaled, rotated or sheared.
Comment 5 Said Abou-Hallawa 2021-07-16 17:36:43 PDT
Created attachment 433722 [details]
Simple and system drop-shadow
Comment 6 Alexey Proskuryakov 2021-10-05 08:48:54 PDT
*** Bug 227954 has been marked as a duplicate of this bug. ***