diff options
4 files changed, 162 insertions, 0 deletions
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-hit-regions-fallback-element-test.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-hit-regions-fallback-element-test.html new file mode 100644 index 0000000..17e59e8 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-hit-regions-fallback-element-test.html @@ -0,0 +1,91 @@ +<!DOCTYPE html> +<title>HitRegion Canvas Fallback Element Test</title> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script src="./resources/test-helpers.js"></script> +<canvas width="400" height="400"> + <a id="a"></a> + <a id="a_with_image"><img></a> + <button id="button"></button> + <input id="checkbox" type="checkbox"> + <input id="radio" type="radio"> + <input id="input_button" type="button"> + <input id="input_image_button" type="image"> + <select id="empty_select"></select> + <select id="select_size_greater_than_1" size="2"></select> + <select id="select_multiple" multiple="multiple"></select> + <select> + <option id="option_with_select"></option> + </select> + <select multiple="multiple"> + <option id="option_with_select_multiple"></option> + </select> + <select size="2"> + <option id="option_with_select_size_greater_than_1"></option> + </select> + <p id="p"></p> + <p id="p_with_tabindex" tabindex="0"></p> + <table> + <caption></caption> + <thead><tr><th></th></tr></thead> + <tfoot><tr><td></td></tr></tfoot> + <tbody><tr><td></td></tr></tbody> + </table> +</canvas> +<button id="button_is_not_descendant_of_canvas"></button> +<style> + +body { + margin : 0px; + padding : 0px; +} + +</style> +<script> + +function canvas_fallback_test(element, expected) { + test(function() { + var canvas = document.querySelector('canvas'); + var context = canvas.getContext('2d'); + + context.clearRect(0, 0, 400, 400); + context.rect(0, 0, 100, 100); + if (expected) { + assert_throws(expected, function() { + context.addHitRegion({ control : element }); + }); + } else { + context.addHitRegion({ control : element }); + } + }, element.id); +} + +const NotSupportedError = { name : 'NotSupportedError' }; + +canvas_fallback_test(document.getElementById('button_is_not_descendant_of_canvas'), NotSupportedError); +canvas_fallback_test(document.querySelector('canvas'), NotSupportedError); +canvas_fallback_test(document.getElementById('a')); +canvas_fallback_test(document.getElementById('a_with_image'), NotSupportedError); +canvas_fallback_test(document.getElementById('button')); +canvas_fallback_test(document.getElementById('checkbox')); +canvas_fallback_test(document.getElementById('radio')); +canvas_fallback_test(document.getElementById('input_button')); +canvas_fallback_test(document.getElementById('input_image_button'), NotSupportedError); +canvas_fallback_test(document.getElementById('empty_select'), NotSupportedError); +canvas_fallback_test(document.getElementById('select_size_greater_than_1')); +canvas_fallback_test(document.getElementById('select_multiple')); +canvas_fallback_test(document.getElementById('option_with_select'), NotSupportedError); +canvas_fallback_test(document.getElementById('option_with_select_multiple')); +canvas_fallback_test(document.getElementById('option_with_select_size_greater_than_1')); +canvas_fallback_test(document.getElementById('p'), NotSupportedError); +canvas_fallback_test(document.getElementById('p_with_tabindex')); +canvas_fallback_test(document.querySelector('canvas table')); +canvas_fallback_test(document.querySelector('canvas tr')); +canvas_fallback_test(document.querySelector('canvas th')); +canvas_fallback_test(document.querySelector('canvas td')); +canvas_fallback_test(document.querySelector('canvas thead')); +canvas_fallback_test(document.querySelector('canvas tfoot')); +canvas_fallback_test(document.querySelector('canvas tbody')); +canvas_fallback_test(document.querySelector('canvas caption')); + +</script> diff --git a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp index a7f4745..40f436f 100644 --- a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp @@ -31,12 +31,18 @@ #include "bindings/core/v8/ExceptionState.h" #include "bindings/core/v8/ScriptController.h" #include "core/HTMLNames.h" +#include "core/InputTypeNames.h" #include "core/dom/Document.h" +#include "core/dom/Element.h" +#include "core/dom/ElementTraversal.h" #include "core/dom/ExceptionCode.h" #include "core/fileapi/File.h" #include "core/frame/ImageBitmap.h" #include "core/frame/LocalFrame.h" #include "core/frame/Settings.h" +#include "core/html/HTMLImageElement.h" +#include "core/html/HTMLInputElement.h" +#include "core/html/HTMLSelectElement.h" #include "core/html/ImageData.h" #include "core/html/canvas/CanvasAsyncBlobCreator.h" #include "core/html/canvas/CanvasContextCreationAttributes.h" @@ -1020,4 +1026,62 @@ bool HTMLCanvasElement::isOpaque() const return m_context && !m_context->hasAlpha(); } +bool HTMLCanvasElement::isSupportedInteractiveCanvasFallback(const Element& element) +{ + if (!element.isDescendantOf(this)) + return false; + + // An element is a supported interactive canvas fallback element if it is one of the following: + // https://html.spec.whatwg.org/multipage/scripting.html#supported-interactive-canvas-fallback-element + + // An a element that represents a hyperlink and that does not have any img descendants. + if (isHTMLAnchorElement(element)) + return !Traversal<HTMLImageElement>::firstWithin(element); + + // A button element + if (isHTMLButtonElement(element)) + return true; + + // An input element whose type attribute is in one of the Checkbox or Radio Button states. + // An input element that is a button but its type attribute is not in the Image Button state. + if (isHTMLInputElement(element)) { + const HTMLInputElement& inputElement = toHTMLInputElement(element); + if (inputElement.type() == InputTypeNames::checkbox + || inputElement.type() == InputTypeNames::radio + || inputElement.isTextButton()) + return true; + } + + // A select element with a multiple attribute or a display size greater than 1. + if (isHTMLSelectElement(element)) { + const HTMLSelectElement& selectElement = toHTMLSelectElement(element); + if (selectElement.multiple() || selectElement.size() > 1) + return true; + } + + // An option element that is in a list of options of a select element with a multiple attribute or a display size greater than 1. + if (isHTMLOptionElement(element) && element.parentNode() && isHTMLSelectElement(*element.parentNode())) { + const HTMLSelectElement& selectElement = toHTMLSelectElement(*element.parentNode()); + if (selectElement.multiple() || selectElement.size() > 1) + return true; + } + + // An element that would not be interactive content except for having the tabindex attribute specified. + if (element.fastHasAttribute(HTMLNames::tabindexAttr)) + return true; + + // A non-interactive table, caption, thead, tbody, tfoot, tr, td, or th element. + if (isHTMLTableElement(element) + || element.hasTagName(HTMLNames::captionTag) + || element.hasTagName(HTMLNames::theadTag) + || element.hasTagName(HTMLNames::tbodyTag) + || element.hasTagName(HTMLNames::tfootTag) + || element.hasTagName(HTMLNames::trTag) + || element.hasTagName(HTMLNames::tdTag) + || element.hasTagName(HTMLNames::thTag)) + return true; + + return false; +} + } // namespace blink diff --git a/third_party/WebKit/Source/core/html/HTMLCanvasElement.h b/third_party/WebKit/Source/core/html/HTMLCanvasElement.h index da30a88..5d7d9d9 100644 --- a/third_party/WebKit/Source/core/html/HTMLCanvasElement.h +++ b/third_party/WebKit/Source/core/html/HTMLCanvasElement.h @@ -181,6 +181,8 @@ public: void notifyListenersCanvasChanged(); + bool isSupportedInteractiveCanvasFallback(const Element&); + protected: void didMoveToNewDocument(Document& oldDocument) override; diff --git a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp index bd7f158..7fe1240 100644 --- a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp +++ b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp @@ -2234,6 +2234,11 @@ void CanvasRenderingContext2D::addHitRegion(const HitRegionOptions& options, Exc return; } + if (options.control() && !canvas()->isSupportedInteractiveCanvasFallback(*options.control())) { + exceptionState.throwDOMException(NotSupportedError, "The control is neither null nor a supported interactive canvas fallback element."); + return; + } + Path hitRegionPath = options.hasPath() ? options.path()->path() : m_path; SkCanvas* c = drawingCanvas(); |