RESOLVED FIXED 82560
Implement canvas v5 line dash feature
https://bugs.webkit.org/show_bug.cgi?id=82560
Summary Implement canvas v5 line dash feature
Lu Guanqun
Reported 2012-03-28 18:40:22 PDT
The new canvas v5 api is released by Ian. Adapt the old webkitLineDash to the new setLineDash() interface.
Attachments
Patch (22.15 KB, patch)
2012-03-28 18:50 PDT, Lu Guanqun
no flags
Patch (22.16 KB, patch)
2012-03-28 18:59 PDT, Lu Guanqun
no flags
Patch (22.16 KB, patch)
2012-03-28 19:06 PDT, Lu Guanqun
no flags
Patch (22.81 KB, patch)
2012-03-28 23:29 PDT, Lu Guanqun
no flags
Patch (24.17 KB, patch)
2012-03-29 18:11 PDT, Lu Guanqun
no flags
Archive of layout-test-results from ec2-cr-linux-04 (10.04 MB, application/zip)
2012-03-29 20:59 PDT, WebKit Review Bot
no flags
Patch (14.38 KB, patch)
2012-09-04 13:15 PDT, Justin Novosad
no flags
Patch (16.28 KB, patch)
2012-09-05 08:43 PDT, Justin Novosad
no flags
Patch (16.28 KB, patch)
2012-09-05 09:30 PDT, Justin Novosad
no flags
Patch (16.21 KB, patch)
2012-09-05 11:10 PDT, Justin Novosad
no flags
Patch (16.20 KB, patch)
2012-09-05 12:10 PDT, Justin Novosad
no flags
Patch (22.18 KB, patch)
2012-09-07 07:13 PDT, Justin Novosad
no flags
Patch (20.11 KB, patch)
2012-09-07 12:47 PDT, Justin Novosad
no flags
Patch (21.09 KB, patch)
2012-09-10 07:09 PDT, Justin Novosad
no flags
Patch for landing (20.96 KB, patch)
2012-09-10 08:16 PDT, Justin Novosad
no flags
Lu Guanqun
Comment 1 2012-03-28 18:50:49 PDT
WebKit Review Bot
Comment 2 2012-03-28 18:54:07 PDT
Attachment 134468 [details] did not pass style-queue: Failed to run "['Tools/Scripts/check-webkit-style', '--diff-files', u'LayoutTests/ChangeLog', u'LayoutTests/fast..." exit_code: 1 Source/WebCore/ChangeLog:8: You should remove the 'No new tests' and either add and list tests, or explain why no new tests were possible. [changelog/nonewtests] [5] Total errors found: 1 in 13 files If any of these errors are false positives, please file a bug against check-webkit-style.
Lu Guanqun
Comment 3 2012-03-28 18:59:28 PDT
Lu Guanqun
Comment 4 2012-03-28 19:06:07 PDT
Lu Guanqun
Comment 5 2012-03-28 23:29:05 PDT
Lu Guanqun
Comment 6 2012-03-29 18:11:48 PDT
WebKit Review Bot
Comment 7 2012-03-29 20:59:03 PDT
Comment on attachment 134707 [details] Patch Attachment 134707 [details] did not pass chromium-ews (chromium-xvfb): Output: http://queues.webkit.org/results/12267042 New failing tests: fast/canvas/canvas-lineDash-invalid.html platform/chromium/virtual/gpu/fast/canvas/canvas-lineDash-invalid.html
WebKit Review Bot
Comment 8 2012-03-29 20:59:11 PDT
Created attachment 134719 [details] Archive of layout-test-results from ec2-cr-linux-04 The attached test failures were seen while running run-webkit-tests on the chromium-ews. Bot: ec2-cr-linux-04 Port: <class 'webkitpy.common.config.ports.ChromiumXVFBPort'> Platform: Linux-2.6.35-28-virtual-x86_64-with-Ubuntu-10.10-maverick
Igor Trindade Oliveira
Comment 9 2012-03-29 21:12:13 PDT
this patch can be a problem because a browser can already be using the old behavior.
Lu Guanqun
Comment 10 2012-03-29 21:38:22 PDT
(In reply to comment #9) > this patch can be a problem because a browser can already be using the old behavior. Hi Igor, Thanks for your comments. So what's the best practices for doing things like this(add new interfaces while deprecating old ones)? I can add the new interface while keeping the old ones intact. Is that acceptable? Thanks! --guanqun
Radar WebKit Bug Importer
Comment 12 2012-03-30 16:23:46 PDT
Tim Horton
Comment 13 2012-06-24 08:00:51 PDT
Comment on attachment 134707 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=134707&action=review > Source/WebCore/ChangeLog:8 > + Can you explain here what's different from the old behavior? Also, I believe that keeping the old behavior (and implementing the new one under the unprefixed name) is the right thing to do. > Source/WebCore/bindings/js/JSCanvasRenderingContext2DCustom.cpp:106 > +JSValue JSCanvasRenderingContext2D::setLineDash(ExecState* exec) Why does this return a value that is always jsUndefined now? > Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp:491 > + if ((dash.size() % 2) == 1) I don't think the == 1 is necessary. > LayoutTests/ChangeLog:8 > + I'm not positive, but I think you should test both the old prefixed behavior and the new behavior. Is there a test of the new odd-length-dash-array doubling behavior? > LayoutTests/fast/canvas/canvas-lineDash-expected.txt:12 > +PASS lineDash[2] is 15 I guess so.
Dean Jackson
Comment 14 2012-06-25 14:13:06 PDT
Comment on attachment 134707 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=134707&action=review +1 to Tim's comments > Source/WebCore/html/canvas/CanvasRenderingContext2D.idl:-80 > - attribute [Custom] Array webkitLineDash; > - attribute float webkitLineDashOffset; We shouldn't remove the existing API yet.
Justin Novosad
Comment 15 2012-08-31 13:52:14 PDT
This implementation does not conform to the spec. The IDL in the spec uses sequence<unrestricted-double> as the type for the dash array.
Justin Novosad
Comment 16 2012-08-31 13:58:43 PDT
Comment on attachment 134707 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=134707&action=review > Source/WebCore/bindings/v8/custom/V8CanvasRenderingContext2DCustom.cpp:123 > + return throwError(TYPE_MISMATCH_ERR); We usually throw INDEX_SIZE_ERR in this type of situation. Spec needs clarification: https://www.w3.org/Bugs/Public/show_bug.cgi?id=18754
Justin Novosad
Comment 17 2012-08-31 14:09:27 PDT
Filed another issue against the spec for this feature to clarify whether the argument should be an array or a sequence: https://www.w3.org/Bugs/Public/show_bug.cgi?id=18758
Justin Novosad
Comment 18 2012-08-31 20:46:26 PDT
(In reply to comment #17) Already got answers back from Hixie: 1. No exceptions are to be thrown when a value in the dash array is negative or non-finite. 2. The dash array is a sequence, not an array.
Justin Novosad
Comment 19 2012-09-04 05:52:58 PDT
Contacted Guanqun Lu, he is working on different projects now. I'll finish it up.
Justin Novosad
Comment 20 2012-09-04 13:15:07 PDT
Justin Novosad
Comment 21 2012-09-04 13:20:00 PDT
New patch: * Leaves the old webkitLineDash behavior intact and tested. * Does not use custom bindings * Fixes spec compliance issues (In reply to comment #20) > Created an attachment (id=162089) [details] > Patch
Build Bot
Comment 22 2012-09-04 13:56:18 PDT
Early Warning System Bot
Comment 23 2012-09-04 14:14:48 PDT
Early Warning System Bot
Comment 24 2012-09-04 14:23:49 PDT
kov's GTK+ EWS bot
Comment 25 2012-09-04 14:42:46 PDT
Build Bot
Comment 26 2012-09-04 14:51:48 PDT
Gyuyoung Kim
Comment 27 2012-09-04 15:01:05 PDT
Early Warning System Bot
Comment 28 2012-09-04 15:15:43 PDT
Justin Novosad
Comment 29 2012-09-05 08:43:54 PDT
Justin Novosad
Comment 30 2012-09-05 08:47:42 PDT
New patch fixes build errors in ports that use JavaScriptCore. Turns out the auto-generated bindings did not support the sequence<double> IDL type. The implementation was just missing a couple template specializations.
Darin Adler
Comment 31 2012-09-05 08:56:10 PDT
Comment on attachment 162258 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=162258&action=review > Source/WebCore/bindings/js/JSDOMBinding.h:395 > + if (!jsValue.isNumber()) > + return false; > + > + indexedValue = jsValue.toNumber(exec); > + if (exec->hadException()) > + return false; This is not the right way to write it, and is unnecessarily inefficient. The toNumber() function is the general purpose way to convert any value to a number, and should not be used if the code has already checked isNumber. If this code is really supposed to reject anything that’s not a number, then it should just call asNumber() after isNumber(). If it’s supposed to work for other types of objects, then toNumber should be used without an isNumber check. The existing conversion to unsigned long above has a similar mistake, but it’s a little harder to fix correctly. The toUInt32() function does too much, but there’s no obvious alternative that does exactly the right thing.
Justin Novosad
Comment 32 2012-09-05 09:25:51 PDT
(In reply to comment #31) > (From update of attachment 162258 [details]) > View in context: https://bugs.webkit.org/attachment.cgi?id=162258&action=review > > > Source/WebCore/bindings/js/JSDOMBinding.h:395 > > + if (!jsValue.isNumber()) > > + return false; > > + > > + indexedValue = jsValue.toNumber(exec); > > + if (exec->hadException()) > > + return false; > > This is not the right way to write it, and is unnecessarily inefficient. The toNumber() function is the general purpose way to convert any value to a number, and should not be used if the code has already checked isNumber. If this code is really supposed to reject anything that’s not a number, then it should just call asNumber() after isNumber(). If it’s supposed to work for other types of objects, then toNumber should be used without an isNumber check. > > The existing conversion to unsigned long above has a similar mistake, but it’s a little harder to fix correctly. The toUInt32() function does too much, but there’s no obvious alternative that does exactly the right thing. To figure-out the right thing to do, I looked up the WebIDL spec: http://www.w3.org/TR/WebIDL/#idl-types Found this: "If the conversion cannot be performed, then the operation will not run or the attribute will not be updated. In some language bindings, type conversions could result in an exception being thrown." So I guess isNumber + asNumber would be the way to go.
Justin Novosad
Comment 33 2012-09-05 09:30:01 PDT
Ian 'Hixie' Hickson
Comment 34 2012-09-05 09:38:19 PDT
Justin, please don't refer to specs with "/TR/" in the URL, they are by definition out of date. For Web IDL, you want: http://dev.w3.org/2006/webapi/WebIDL/
Early Warning System Bot
Comment 35 2012-09-05 10:34:51 PDT
Build Bot
Comment 36 2012-09-05 10:54:47 PDT
Gyuyoung Kim
Comment 37 2012-09-05 11:00:39 PDT
Justin Novosad
Comment 38 2012-09-05 11:10:57 PDT
Build Bot
Comment 39 2012-09-05 11:45:17 PDT
Dean Jackson
Comment 40 2012-09-05 11:57:41 PDT
Comment on attachment 162291 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=162291&action=review > Source/WebCore/bindings/js/JSDOMBinding.h:388 > + static inline bool arrayNativeValue(JSC::ExecState* exec, JSC::JSValue jsValue, double& indexedValue) Remove the "exec" to avoid the unused param error.
Justin Novosad
Comment 41 2012-09-05 12:10:58 PDT
Dean Jackson
Comment 42 2012-09-05 13:12:36 PDT
Comment on attachment 162301 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=162301&action=review It's slightly weird that the lineDashOffset methods call from the webkit prefix into the unprefixed, but the setLineDash method does it the other way around. But that's not a big deal. It's also a shame we can't copy the vector directly thanks to the CGFloat -> double cast :( I wonder if we should have image tests for this? It seems important. > Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp:523 > + int copyCount = 1 + dash.size() % 2; I think this is more clear as int copyCount = (dash.size() % 2) ? 2 : 1; (but I'm not asking to change) > Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp:533 > + for (size_t i = 0; i < dash.size(); i++) { > + if (!isfinite(dash[i]) || dash[i] < 0) > + return; > + convertedDashArray[i] = static_cast<DashArrayEntry>(dash[i]); > + } > + if (copyCount == 2) { > + for (size_t src = 0, dst = dash.size(); src < dash.size(); ++src, ++dst) > + convertedDashArray[dst] = convertedDashArray[src]; > + } I'm not sure it would actually be more readable, but you could merge the content of the second loop into the first. > Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp:547 > + if (!isfinite(offset)) > + return; > + if (state().m_lineDashOffset == offset) > return; Might as well combine these into a single test. > Source/WebCore/html/canvas/CanvasRenderingContext2D.idl:79 > + void setLineDash(in sequence<double> dash); > + sequence<double> getLineDash(); > + attribute float lineDashOffset; I wonder why the spec says the dash array is a list of double when the offset is a float? > LayoutTests/fast/canvas/script-tests/canvas-lineDash-invalid.js:10 > + ctx.setLineDash([1.5, 2.5]); Could you move all these lines into a resetLineDash() method? It could probably debug() when it runs too, because I was looking at the expected output and couldn't work out why these numbers were coming up. > LayoutTests/fast/canvas/script-tests/canvas-lineDash-invalid.js:33 > +shouldBe("trySettingLineDash([1, 2, 3])", "[1, 2, 3, 1, 2, 3]"); Technically this one isn't invalid, yet it is in the invalid test.
Justin Novosad
Comment 43 2012-09-05 13:19:51 PDT
> > I wonder why the spec says the dash array is a list of double when the offset is a float? > My bad. Spec says it is a double. Good catch.
Justin Novosad
Comment 44 2012-09-05 13:41:07 PDT
(In reply to comment #43) > > > > I wonder why the spec says the dash array is a list of double when the offset is a float? > > > > My bad. Spec says it is a double. Good catch. Internally, the GraphicsContext interface uses float for the lineDash offset, even for the Cairo port, which uses double for the elements of DashArray. Given that we have no use for double precision internally, how important is it for the JS interface to expose doubles rather than floats?
Dean Jackson
Comment 45 2012-09-05 13:42:56 PDT
(In reply to comment #43) > > > > I wonder why the spec says the dash array is a list of double when the offset is a float? > > > > My bad. Spec says it is a double. Good catch. It just shows I didn't read the spec :)
Dean Jackson
Comment 46 2012-09-05 13:44:33 PDT
(In reply to comment #44) > Internally, the GraphicsContext interface uses float for the lineDash offset, even for the Cairo port, which uses double for the elements of DashArray. Given that we have no use for double precision internally, how important is it for the JS interface to expose doubles rather than floats? I'm not sure - sounds like we wouldn't lose much.
Ian 'Hixie' Hickson
Comment 47 2012-09-05 13:51:23 PDT
The JS interface actually exposes "Number"s, and Web IDL says that "double" is a better match for that than "float", and basically discourages the specs from using "float" at all. The HTML spec never uses "float".
Justin Novosad
Comment 48 2012-09-05 14:00:00 PDT
After some thinking... Even though it is useless for webkit, I think we need the interface to be double, and the context state to store the value as a double, otherwise we risk getting burned by rounding in compliance tests. ctx.lineDashOffset = someDoublePrecisionValue; if (ctx.lineDashOffset != someDoublePrecisionValue) { print("Look at that, this UA is busted!") }
Darin Adler
Comment 49 2012-09-05 14:39:33 PDT
(In reply to comment #32) > To figure-out the right thing to do, I looked up the WebIDL spec: http://www.w3.org/TR/WebIDL/#idl-types > Found this: "If the conversion cannot be performed, then the operation will not run or the attribute will not be updated. In some language bindings, type conversions could result in an exception being thrown." > > So I guess isNumber + asNumber would be the way to go. I don’t agree. Given that description, it sounds like toNumber is the way to go. That’s the function that does the conversion. Calling isNumber prevents conversion and creates failure if the value isn’t already a number. Conversion is exactly what toNumber is for. We need test cases that cover this behavior.
Dean Jackson
Comment 50 2012-09-05 16:23:11 PDT
(In reply to comment #49) > (In reply to comment #32) > > To figure-out the right thing to do, I looked up the WebIDL spec: http://www.w3.org/TR/WebIDL/#idl-types > > Found this: "If the conversion cannot be performed, then the operation will not run or the attribute will not be updated. In some language bindings, type conversions could result in an exception being thrown." > > > > So I guess isNumber + asNumber would be the way to go. > > I don’t agree. > > Given that description, it sounds like toNumber is the way to go. That’s the function that does the conversion. Calling isNumber prevents conversion and creates failure if the value isn’t already a number. Conversion is exactly what toNumber is for. > > We need test cases that cover this behavior. So you're supposed to be able to do ctx.lineDashOffset = "10"; ? That makes sense. (Similarly lineDash = ["10", 20, "30.0"];)
Dean Jackson
Comment 51 2012-09-05 16:27:07 PDT
Comment on attachment 162301 [details] Patch r- to make darin's change (and add conversion operations to the valid/invalid tests)
Justin Novosad
Comment 52 2012-09-07 07:13:35 PDT
Justin Novosad
Comment 53 2012-09-07 07:19:28 PDT
(In reply to comment #52) > Created an attachment (id=162762) [details] > Patch Improvements in the latest patch: * CanvasRenderingContext2D now uses double-precision for line dash state and interface * Code reorg in CanvasRenderingContext2D * Now using toNumber to convert double values from JS to native * Layout test validates conversion from string to number for lineDash element. * Layout test verifies rendering behavior (text-only baseline)
Darin Adler
Comment 54 2012-09-07 09:39:32 PDT
Comment on attachment 162762 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=162762&action=review This patch seems great and almost ready to go. But I am not comfortable with the mix of float and double in our canvas element implementation without any rationale or plan for moving forward. I see how it’s handy to use doubles for this new feature, but we need to look at this in context, and not in isolation. > Source/WebCore/bindings/js/JSDOMBinding.h:394 > + if (exec->hadException()) > + return false; > + > + return true; I think this reads better as: return !exec->hadException(); > Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp:516 > +static bool validateLineDash(const Vector<double>& dash) I would name this something more like: lineDashSequenceIsValid Using a verb phrase to name a function that returns a boolean with no side effects raises the question of whether there are side effects, and also makes it unclear what the boolean result of the function means. > Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp:533 > + if (dash.size() % 2) > + modifiableState().m_lineDash.append(dash); This mysterious code needs a brief "why" comment. You shouldn’t assume that the person reading the code has read the specification and so understands the need for this peculiar rule. > Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp:581 > + DashArray convertedLineDash; > + convertedLineDash.resize(state().m_lineDash.size()); The correct way to allocate a vector with an initial size is to pass it into the constructor. If you make a separate function call it’s unnecessarily less efficient. > Source/WebCore/html/canvas/CanvasRenderingContext2D.h:257 > + Vector<double> m_lineDash; > + double m_lineDashOffset; This is not good. After this patch the canvas implementation now has a mix of double and float and there is no rationale for which items are float and which are double. Until this patch it was all float. > Source/WebCore/html/canvas/CanvasRenderingContext2D.idl:-77 > - // FIXME: These attributes should also be implemented for V8. Why did you remove this FIXME? Is the legacy WebKit line dash feature something we’ll never do in V8-based builds of WebKit? If so, maybe a "why" comment is in order. > Source/WebCore/platform/graphics/DashArray.h:32 > +typedef CGFloat DashArrayEntry; I think perhaps the word Element rather than Entry would be better?
Justin Novosad
Comment 55 2012-09-07 11:14:53 PDT
(In reply to comment #54) > > Source/WebCore/html/canvas/CanvasRenderingContext2D.h:257 > > + Vector<double> m_lineDash; > > + double m_lineDashOffset; > > This is not good. After this patch the canvas implementation now has a mix of double and float and there is no rationale for which items are float and which are double. Until this patch it was all float. I am unsure about what to do here. Is it acceptable for a number to loose precision from a round trip through the API?
Justin Novosad
Comment 56 2012-09-07 12:18:14 PDT
(In reply to comment #55) > I am unsure about what to do here. Is it acceptable for a number to loose precision from a round trip through the API? I guess this question was settled long before I came along. Just realized that all the other number attributes and args are float in CanvasRenderingContext2D.idl. I'll just conform to that.
Justin Novosad
Comment 57 2012-09-07 12:47:24 PDT
kov's GTK+ EWS bot
Comment 58 2012-09-07 13:45:10 PDT
Build Bot
Comment 59 2012-09-07 13:49:32 PDT
Early Warning System Bot
Comment 60 2012-09-07 14:38:38 PDT
Gyuyoung Kim
Comment 61 2012-09-07 14:58:12 PDT
Early Warning System Bot
Comment 62 2012-09-07 14:59:23 PDT
Build Bot
Comment 63 2012-09-07 16:39:29 PDT
Justin Novosad
Comment 64 2012-09-10 07:09:09 PDT
Darin Adler
Comment 65 2012-09-10 07:49:13 PDT
Comment on attachment 163120 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=163120&action=review r=me, assuming you fix that one toDouble that should be toFloat > Source/WebCore/bindings/js/JSCanvasRenderingContext2DCustom.cpp:114 > - float elem = valueArray->getIndex(i).toFloat(exec); > + float elem = valueArray->getIndex(i).toNumber(exec); This change no longer makes sense. Should be left alone.
Justin Novosad
Comment 66 2012-09-10 08:16:57 PDT
Created attachment 163135 [details] Patch for landing
Dean Jackson
Comment 67 2012-09-10 10:41:51 PDT
Comment on attachment 163135 [details] Patch for landing Verified that Darin's suggestion was updated. Setting cq.
WebKit Review Bot
Comment 68 2012-09-10 15:21:28 PDT
Comment on attachment 163135 [details] Patch for landing Clearing flags on attachment: 163135 Committed r128116: <http://trac.webkit.org/changeset/128116>
WebKit Review Bot
Comment 69 2012-09-10 15:21:36 PDT
All reviewed patches have been landed. Closing bug.
Szilard Ledan
Comment 70 2012-09-11 00:33:35 PDT
This test fails on Qt bots. I created a bug report: #96360. Could you check it please?
Note You need to log in before you can comment on or make changes to this bug.