Created attachment 369367 [details]
Comparing visuals to another browser
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
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);
ctx.fillStyle = gradient;
ctx.fillText("1234567890", 10, 70);
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.
Created attachment 369899 [details]
*** Bug 227954 has been marked as a duplicate of this bug. ***
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.
Created attachment 433722 [details]
Simple and system drop-shadow