Commit 4b28d4cc authored by bashi@chromium.org's avatar bashi@chromium.org

IDL: ArrayBuffer and ArrayBufferView support for union types

(ArrayBuffer or ArrayBufferView) is a common union type usage. For example,
CSS font loading[1] and fetch API[2] use it. Implement and use them for
FontFace constructor.

Change for FontFace is covered by fast/css/fontface-arraybuffer.html

This CL also fixed two minor bugs:
- Collect union types from constructors (we didn't before)
- We need to use 'implemented_as' for forward class declarations, instead of
  'name'.

[1] http://dev.w3.org/csswg/css-font-loading/#fontface-interface
[2] https://fetch.spec.whatwg.org/#body-mixin

BUG=240176

Review URL: https://codereview.chromium.org/699713003

git-svn-id: svn://svn.chromium.org/blink/trunk@184824 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 457c51e5
......@@ -143,6 +143,10 @@ def collect_union_types_from_definitions(definitions):
this_union_types.update(union_types_from(operation.arguments))
if operation.idl_type.is_union_type:
this_union_types.add(operation.idl_type)
for constructor in interface.constructors:
this_union_types.update(union_types_from(constructor.arguments))
for constructor in interface.custom_constructors:
this_union_types.update(union_types_from(constructor.arguments))
for callback_function in definitions.callback_functions.itervalues():
this_union_types.update(union_types_from(callback_function.arguments))
if callback_function.idl_type.is_union_type:
......
......@@ -30,6 +30,8 @@ def container_context(union_type, interfaces_info):
# These variables refer to member contexts if the given union type has
# corresponding types. They are used for V8 -> impl conversion.
array_buffer_type = None
array_buffer_view_type = None
boolean_type = None
dictionary_type = None
interface_types = []
......@@ -38,7 +40,15 @@ def container_context(union_type, interfaces_info):
for member in union_type.member_types:
context = member_context(member, interfaces_info)
members.append(context)
if member.is_interface_type:
if member.base_type == 'ArrayBuffer':
if array_buffer_type:
raise Exception('%s is ambiguous.' % union_type.name)
array_buffer_type = context
elif member.base_type == 'ArrayBufferView':
if array_buffer_view_type:
raise Exception('%s is ambiguous.' % union_type.name)
array_buffer_view_type = context
elif member.is_interface_type:
interface_types.append(context)
elif member.is_dictionary:
if dictionary_type:
......@@ -60,6 +70,8 @@ def container_context(union_type, interfaces_info):
raise Exception('%s is not supported as an union member.' % member.name)
return {
'array_buffer_type': array_buffer_type,
'array_buffer_view_type': array_buffer_view_type,
'boolean_type': boolean_type,
'cpp_class': union_type.name,
'dictionary_type': dictionary_type,
......@@ -76,7 +88,7 @@ def member_context(member, interfaces_info):
interface_info = interfaces_info.get(member.name, None)
if interface_info:
cpp_includes.update(interface_info.get('dependencies_include_paths', []))
header_forward_decls.add(member.name)
header_forward_decls.add(member.implemented_as)
return {
'cpp_name': v8_utilities.uncapitalize(member.name),
'cpp_type': member.cpp_type_args(used_in_cpp_sequence=True),
......
......@@ -7,6 +7,13 @@
#include "config.h"
#include "{{header_filename}}"
{% macro assign_and_return_if_hasinstance(member) %}
if (V8{{member.type_name}}::hasInstance(v8Value, isolate)) {
{{member.cpp_local_type}} cppValue = V8{{member.type_name}}::toImpl(v8::Handle<v8::Object>::Cast(v8Value));
impl.set{{member.type_name}}(cppValue);
return;
}
{% endmacro %}
{% for filename in cpp_includes %}
#include "{{filename}}"
{% endfor %}
......@@ -56,13 +63,20 @@ void V8{{container.cpp_class}}::toImpl(v8::Isolate* isolate, v8::Handle<v8::Valu
FIXME: Implement all necessary steps #}
{# 3. Platform objects (interfaces) #}
{% for interface in container.interface_types %}
if (V8{{interface.type_name}}::hasInstance(v8Value, isolate)) {
{{interface.cpp_local_type}} cppValue = V8{{interface.type_name}}::toImpl(v8::Handle<v8::Object>::Cast(v8Value));
impl.set{{interface.type_name}}(cppValue);
return;
}
{{assign_and_return_if_hasinstance(interface) | indent}}
{% endfor %}
{# 8. ArrayBuffer #}
{% if container.array_buffer_type %}
{{assign_and_return_if_hasinstance(container.array_buffer_type) | indent}}
{% endif %}
{# 9., 10. ArrayBufferView #}
{# FIXME: Individual typed arrays (e.g. Uint8Array) aren't supported yet. #}
{% if container.array_buffer_view_type %}
{{assign_and_return_if_hasinstance(container.array_buffer_view_type) | indent}}
{% endif %}
{% if container.dictionary_type %}
{# 12. Dictionaries #}
{# FIXME: This should also check "object but not Date or RegExp". Add checks
......
......@@ -355,6 +355,7 @@ interface TestObject {
(boolean or DOMString or unrestricted double) booleanOrDOMStringOrUnrestrictedDoubleMethod();
(TestInterface or long) testInterfaceOrLongMethod();
void voidMethodDOMStringOrDouble((DOMString or double) arg);
void voidMethodDOMStringOrArrayBufferOrArrayBufferView((DOMString or ArrayBuffer or ArrayBufferView) arg);
// Currently only used on interface type arguments
void voidMethodTestInterfaceEmptyOrNullArg(TestInterfaceEmpty? nullableTestInterfaceEmptyArg);
// Callback interface types
......
......@@ -7,6 +7,8 @@
#include "config.h"
#include "bindings/core/v8/UnionTypesCore.h"
#include "bindings/core/v8/V8ArrayBuffer.h"
#include "bindings/core/v8/V8ArrayBufferView.h"
#include "bindings/core/v8/V8Node.h"
#include "bindings/core/v8/V8NodeList.h"
#include "bindings/core/v8/V8TestDictionary.h"
......@@ -184,6 +186,94 @@ v8::Handle<v8::Value> toV8(NodeOrNodeList& impl, v8::Handle<v8::Object> creation
return v8::Handle<v8::Value>();
}
StringOrArrayBufferOrArrayBufferView::StringOrArrayBufferOrArrayBufferView()
: m_type(SpecificTypeNone)
{
}
String StringOrArrayBufferOrArrayBufferView::getAsString()
{
ASSERT(isString());
return m_string;
}
void StringOrArrayBufferOrArrayBufferView::setString(String value)
{
ASSERT(isNull());
m_string = value;
m_type = SpecificTypeString;
}
PassRefPtr<TestArrayBuffer> StringOrArrayBufferOrArrayBufferView::getAsArrayBuffer()
{
ASSERT(isArrayBuffer());
return m_arrayBuffer;
}
void StringOrArrayBufferOrArrayBufferView::setArrayBuffer(PassRefPtr<TestArrayBuffer> value)
{
ASSERT(isNull());
m_arrayBuffer = value;
m_type = SpecificTypeArrayBuffer;
}
PassRefPtr<TestArrayBufferView> StringOrArrayBufferOrArrayBufferView::getAsArrayBufferView()
{
ASSERT(isArrayBufferView());
return m_arrayBufferView;
}
void StringOrArrayBufferOrArrayBufferView::setArrayBufferView(PassRefPtr<TestArrayBufferView> value)
{
ASSERT(isNull());
m_arrayBufferView = value;
m_type = SpecificTypeArrayBufferView;
}
void V8StringOrArrayBufferOrArrayBufferView::toImpl(v8::Isolate* isolate, v8::Handle<v8::Value> v8Value, StringOrArrayBufferOrArrayBufferView& impl, ExceptionState& exceptionState)
{
if (v8Value.IsEmpty())
return;
if (V8ArrayBuffer::hasInstance(v8Value, isolate)) {
RefPtr<TestArrayBuffer> cppValue = V8ArrayBuffer::toImpl(v8::Handle<v8::Object>::Cast(v8Value));
impl.setArrayBuffer(cppValue);
return;
}
if (V8ArrayBufferView::hasInstance(v8Value, isolate)) {
RefPtr<TestArrayBufferView> cppValue = V8ArrayBufferView::toImpl(v8::Handle<v8::Object>::Cast(v8Value));
impl.setArrayBufferView(cppValue);
return;
}
{
TOSTRING_VOID_EXCEPTIONSTATE(V8StringResource<>, cppValue, v8Value, exceptionState);
impl.setString(cppValue);
return;
}
exceptionState.throwTypeError("Not a valid union member.");
}
v8::Handle<v8::Value> toV8(StringOrArrayBufferOrArrayBufferView& impl, v8::Handle<v8::Object> creationContext, v8::Isolate* isolate)
{
if (impl.isNull())
return v8::Null(isolate);
if (impl.isString())
return v8String(isolate, impl.getAsString());
if (impl.isArrayBuffer())
return toV8(impl.getAsArrayBuffer(), creationContext, isolate);
if (impl.isArrayBufferView())
return toV8(impl.getAsArrayBufferView(), creationContext, isolate);
ASSERT_NOT_REACHED();
return v8::Handle<v8::Value>();
}
StringOrDouble::StringOrDouble()
: m_type(SpecificTypeNone)
{
......
......@@ -15,10 +15,12 @@ namespace blink {
class Node;
class NodeList;
class TestArrayBuffer;
class TestArrayBufferView;
class TestDictionary;
class TestInterface;
class TestInterfaceEmpty;
class TestInterfaceGarbageCollected;
class TestInterfaceImplementation;
class TestInterfaceWillBeGarbageCollected;
class BooleanOrStringOrUnrestrictedDouble final {
......@@ -107,6 +109,51 @@ inline void v8SetReturnValue(const CallbackInfo& callbackInfo, NodeOrNodeList& i
v8SetReturnValue(callbackInfo, toV8(impl, callbackInfo.Holder(), callbackInfo.GetIsolate()));
}
class StringOrArrayBufferOrArrayBufferView final {
ALLOW_ONLY_INLINE_ALLOCATION();
public:
StringOrArrayBufferOrArrayBufferView();
bool isNull() const { return m_type == SpecificTypeNone; }
bool isString() const { return m_type == SpecificTypeString; }
String getAsString();
void setString(String);
bool isArrayBuffer() const { return m_type == SpecificTypeArrayBuffer; }
PassRefPtr<TestArrayBuffer> getAsArrayBuffer();
void setArrayBuffer(PassRefPtr<TestArrayBuffer>);
bool isArrayBufferView() const { return m_type == SpecificTypeArrayBufferView; }
PassRefPtr<TestArrayBufferView> getAsArrayBufferView();
void setArrayBufferView(PassRefPtr<TestArrayBufferView>);
private:
enum SpecificTypes {
SpecificTypeNone,
SpecificTypeString,
SpecificTypeArrayBuffer,
SpecificTypeArrayBufferView,
};
SpecificTypes m_type;
String m_string;
RefPtr<TestArrayBuffer> m_arrayBuffer;
RefPtr<TestArrayBufferView> m_arrayBufferView;
};
class V8StringOrArrayBufferOrArrayBufferView final {
public:
static void toImpl(v8::Isolate*, v8::Handle<v8::Value>, StringOrArrayBufferOrArrayBufferView&, ExceptionState&);
};
v8::Handle<v8::Value> toV8(StringOrArrayBufferOrArrayBufferView&, v8::Handle<v8::Object>, v8::Isolate*);
template <class CallbackInfo>
inline void v8SetReturnValue(const CallbackInfo& callbackInfo, StringOrArrayBufferOrArrayBufferView& impl)
{
v8SetReturnValue(callbackInfo, toV8(impl, callbackInfo.Holder(), callbackInfo.GetIsolate()));
}
class StringOrDouble final {
ALLOW_ONLY_INLINE_ALLOCATION();
public:
......
......@@ -6415,6 +6415,29 @@ static void voidMethodDOMStringOrDoubleMethodCallback(const v8::FunctionCallback
TRACE_EVENT_SET_SAMPLING_STATE("v8", "V8Execution");
}
static void voidMethodDOMStringOrArrayBufferOrArrayBufferViewMethod(const v8::FunctionCallbackInfo<v8::Value>& info)
{
ExceptionState exceptionState(ExceptionState::ExecutionContext, "voidMethodDOMStringOrArrayBufferOrArrayBufferView", "TestObject", info.Holder(), info.GetIsolate());
if (UNLIKELY(info.Length() < 1)) {
setMinimumArityTypeError(exceptionState, 1, info.Length());
exceptionState.throwIfNeeded();
return;
}
TestObject* impl = V8TestObject::toImpl(info.Holder());
StringOrArrayBufferOrArrayBufferView arg;
{
TONATIVE_VOID_EXCEPTIONSTATE_ARGINTERNAL(V8StringOrArrayBufferOrArrayBufferView::toImpl(info.GetIsolate(), info[0], arg, exceptionState), exceptionState);
}
impl->voidMethodDOMStringOrArrayBufferOrArrayBufferView(arg);
}
static void voidMethodDOMStringOrArrayBufferOrArrayBufferViewMethodCallback(const v8::FunctionCallbackInfo<v8::Value>& info)
{
TRACE_EVENT_SET_SAMPLING_STATE("blink", "DOMMethod");
TestObjectV8Internal::voidMethodDOMStringOrArrayBufferOrArrayBufferViewMethod(info);
TRACE_EVENT_SET_SAMPLING_STATE("v8", "V8Execution");
}
static void voidMethodTestInterfaceEmptyOrNullArgMethod(const v8::FunctionCallbackInfo<v8::Value>& info)
{
if (UNLIKELY(info.Length() < 1)) {
......@@ -10392,6 +10415,7 @@ static const V8DOMConfiguration::MethodConfiguration V8TestObjectMethods[] = {
{"booleanOrDOMStringOrUnrestrictedDoubleMethod", TestObjectV8Internal::booleanOrDOMStringOrUnrestrictedDoubleMethodMethodCallback, 0, 0, V8DOMConfiguration::ExposedToAllScripts},
{"testInterfaceOrLongMethod", TestObjectV8Internal::testInterfaceOrLongMethodMethodCallback, 0, 0, V8DOMConfiguration::ExposedToAllScripts},
{"voidMethodDOMStringOrDouble", TestObjectV8Internal::voidMethodDOMStringOrDoubleMethodCallback, 0, 1, V8DOMConfiguration::ExposedToAllScripts},
{"voidMethodDOMStringOrArrayBufferOrArrayBufferView", TestObjectV8Internal::voidMethodDOMStringOrArrayBufferOrArrayBufferViewMethodCallback, 0, 1, V8DOMConfiguration::ExposedToAllScripts},
{"voidMethodTestInterfaceEmptyOrNullArg", TestObjectV8Internal::voidMethodTestInterfaceEmptyOrNullArgMethodCallback, 0, 1, V8DOMConfiguration::ExposedToAllScripts},
{"voidMethodTestCallbackInterfaceArg", TestObjectV8Internal::voidMethodTestCallbackInterfaceArgMethodCallback, 0, 1, V8DOMConfiguration::ExposedToAllScripts},
{"voidMethodOptionalTestCallbackInterfaceArg", TestObjectV8Internal::voidMethodOptionalTestCallbackInterfaceArgMethodCallback, 0, 0, V8DOMConfiguration::ExposedToAllScripts},
......
......@@ -33,6 +33,7 @@
#include "bindings/core/v8/ExceptionState.h"
#include "bindings/core/v8/ScriptState.h"
#include "bindings/core/v8/UnionTypesCore.h"
#include "core/CSSValueKeywords.h"
#include "core/css/BinaryDataFontFaceSource.h"
#include "core/css/CSSFontFace.h"
......@@ -68,6 +69,18 @@ static PassRefPtrWillBeRawPtr<CSSValue> parseCSSValue(const Document* document,
return CSSParser::parseSingleValue(propertyID, s, context);
}
PassRefPtrWillBeRawPtr<FontFace> FontFace::create(ExecutionContext* context, const AtomicString& family, StringOrArrayBufferOrArrayBufferView& source, const FontFaceDescriptors& descriptors)
{
if (source.isString())
return create(context, family, source.getAsString(), descriptors);
if (source.isArrayBuffer())
return create(context, family, source.getAsArrayBuffer(), descriptors);
if (source.isArrayBufferView())
return create(context, family, source.getAsArrayBufferView(), descriptors);
ASSERT_NOT_REACHED();
return nullptr;
}
PassRefPtrWillBeRawPtr<FontFace> FontFace::create(ExecutionContext* context, const AtomicString& family, const String& source, const FontFaceDescriptors& descriptors)
{
RefPtrWillBeRawPtr<FontFace> fontFace = adoptRefWillBeNoop(new FontFace(context, family, descriptors));
......
......@@ -53,6 +53,7 @@ class Dictionary;
class Document;
class ExceptionState;
class FontFaceDescriptors;
class StringOrArrayBufferOrArrayBufferView;
class StylePropertySet;
class StyleRuleFontFace;
......@@ -61,9 +62,7 @@ class FontFace : public RefCountedWillBeGarbageCollectedFinalized<FontFace>, pub
public:
enum LoadStatus { Unloaded, Loading, Loaded, Error };
static PassRefPtrWillBeRawPtr<FontFace> create(ExecutionContext*, const AtomicString& family, PassRefPtr<DOMArrayBuffer> source, const FontFaceDescriptors&);
static PassRefPtrWillBeRawPtr<FontFace> create(ExecutionContext*, const AtomicString& family, PassRefPtr<DOMArrayBufferView>, const FontFaceDescriptors&);
static PassRefPtrWillBeRawPtr<FontFace> create(ExecutionContext*, const AtomicString& family, const String& source, const FontFaceDescriptors&);
static PassRefPtrWillBeRawPtr<FontFace> create(ExecutionContext*, const AtomicString& family, StringOrArrayBufferOrArrayBufferView&, const FontFaceDescriptors&);
static PassRefPtrWillBeRawPtr<FontFace> create(Document*, const StyleRuleFontFace*);
~FontFace();
......@@ -114,6 +113,10 @@ public:
virtual bool hasPendingActivity() const override;
private:
static PassRefPtrWillBeRawPtr<FontFace> create(ExecutionContext*, const AtomicString& family, PassRefPtr<DOMArrayBuffer> source, const FontFaceDescriptors&);
static PassRefPtrWillBeRawPtr<FontFace> create(ExecutionContext*, const AtomicString& family, PassRefPtr<DOMArrayBufferView>, const FontFaceDescriptors&);
static PassRefPtrWillBeRawPtr<FontFace> create(ExecutionContext*, const AtomicString& family, const String& source, const FontFaceDescriptors&);
explicit FontFace(ExecutionContext*);
FontFace(ExecutionContext*, const AtomicString& family, const FontFaceDescriptors&);
......
......@@ -39,10 +39,8 @@ enum FontFaceLoadStatus {
[
ActiveDOMObject,
// FIXME: should be union type http://crbug.com/240176
Constructor(DOMString family, DOMString source, optional FontFaceDescriptors descriptors),
Constructor(DOMString family, ArrayBuffer source, optional FontFaceDescriptors descriptors),
Constructor(DOMString family, ArrayBufferView source, optional FontFaceDescriptors descriptors),
// FIXME: This should be (DOMString or BinaryData), where BinaryData is typedef of (ArrayBuffer or ArrayBufferView)
Constructor(DOMString family, (DOMString or ArrayBuffer or ArrayBufferView) source, optional FontFaceDescriptors descriptors),
ConstructorCallWith=ExecutionContext,
WillBeGarbageCollected,
] interface FontFace {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment