зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to inbound. a=merge CLOSED TREE
This commit is contained in:
Коммит
7bb9457084
|
@ -81,7 +81,7 @@ buildscript {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'org.mozilla.apilint:apilint:0.2.0'
|
||||
classpath 'org.mozilla.apilint:apilint:0.2.1'
|
||||
classpath 'com.android.tools.build:gradle:3.1.4'
|
||||
classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.8.2'
|
||||
classpath 'org.apache.commons:commons-exec:1.3'
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "mozilla/TimeStamp.h"
|
||||
#include "mozilla/dom/CharacterData.h"
|
||||
#include "mozilla/dom/DocumentType.h"
|
||||
#include "mozilla/dom/DOMOverlaysBinding.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/Event.h"
|
||||
#include "mozilla/dom/L10nUtilsBinding.h"
|
||||
|
@ -37,6 +38,7 @@
|
|||
#include "mozilla/dom/ShadowRoot.h"
|
||||
#include "mozilla/dom/SVGUseElement.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "mozilla/dom/l10n/DOMOverlays.h"
|
||||
#include "nsAttrValueOrString.h"
|
||||
#include "nsBindingManager.h"
|
||||
#include "nsCCUncollectableMarker.h"
|
||||
|
@ -2770,59 +2772,30 @@ class LocalizationHandler : public PromiseNativeHandler {
|
|||
return;
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> untranslatedElements(
|
||||
aCx, JS_NewArrayObject(aCx, mElements.Length()));
|
||||
if (!untranslatedElements) {
|
||||
mReturnValuePromise->MaybeRejectWithUndefined();
|
||||
return;
|
||||
}
|
||||
|
||||
ErrorResult rv;
|
||||
nsTArray<DOMOverlaysError> errors;
|
||||
for (size_t i = 0; i < l10nData.Length(); ++i) {
|
||||
Element* elem = mElements[i];
|
||||
nsString& content = l10nData[i].mValue;
|
||||
if (!content.IsVoid()) {
|
||||
elem->SetTextContent(content, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
mReturnValuePromise->MaybeRejectWithUndefined();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Nullable<Sequence<AttributeNameValue>>& attributes =
|
||||
l10nData[i].mAttributes;
|
||||
if (!attributes.IsNull()) {
|
||||
for (size_t j = 0; j < attributes.Value().Length(); ++j) {
|
||||
nsString& name = attributes.Value()[j].mName;
|
||||
nsString& value = attributes.Value()[j].mValue;
|
||||
RefPtr<nsAtom> nameAtom = NS_Atomize(name);
|
||||
if (!elem->AttrValueIs(kNameSpaceID_None, nameAtom, value,
|
||||
eCaseMatters)) {
|
||||
rv = elem->SetAttr(kNameSpaceID_None, nameAtom, value, true);
|
||||
if (rv.Failed()) {
|
||||
mReturnValuePromise->MaybeRejectWithUndefined();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (content.IsVoid() && attributes.IsNull()) {
|
||||
JS::Rooted<JS::Value> wrappedElem(aCx);
|
||||
if (!ToJSValue(aCx, elem, &wrappedElem)) {
|
||||
mReturnValuePromise->MaybeRejectWithUndefined();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!JS_DefineElement(aCx, untranslatedElements, i, wrappedElem,
|
||||
JSPROP_ENUMERATE)) {
|
||||
mReturnValuePromise->MaybeRejectWithUndefined();
|
||||
return;
|
||||
}
|
||||
mozilla::dom::l10n::DOMOverlays::TranslateElement(*elem, l10nData[i],
|
||||
errors, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
mReturnValuePromise->MaybeRejectWithUndefined();
|
||||
return;
|
||||
}
|
||||
}
|
||||
JS::Rooted<JS::Value> result(aCx, JS::ObjectValue(*untranslatedElements));
|
||||
mReturnValuePromise->MaybeResolveWithClone(aCx, result);
|
||||
|
||||
nsTArray<JS::Value> jsErrors;
|
||||
SequenceRooter<JS::Value> rooter(aCx, &jsErrors);
|
||||
for (auto& error : errors) {
|
||||
JS::RootedValue jsError(aCx);
|
||||
if (!ToJSValue(aCx, error, &jsError)) {
|
||||
mReturnValuePromise->MaybeRejectWithUndefined();
|
||||
return;
|
||||
}
|
||||
jsErrors.AppendElement(jsError);
|
||||
}
|
||||
|
||||
mReturnValuePromise->MaybeResolve(jsErrors);
|
||||
}
|
||||
|
||||
virtual void RejectedCallback(JSContext* aCx,
|
||||
|
|
|
@ -39,8 +39,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1363862
|
|||
{name: "accesskey", value: "V"},
|
||||
]
|
||||
},
|
||||
"key4": undefined,
|
||||
"key5": {
|
||||
"key4": {
|
||||
value: null,
|
||||
attributes: [
|
||||
{name: "value", value: "Submit Value"},
|
||||
|
@ -97,24 +96,16 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1363862
|
|||
async function testLocalization() {
|
||||
const container = document.getElementById("testContainer");
|
||||
|
||||
const untranslatedElements = await translateFragment(container);
|
||||
await translateFragment(container);
|
||||
|
||||
// We will walk through all translations and check if they
|
||||
// were correctly populated onto the DOM.
|
||||
for (const [l10nId, translation] of Object.entries(translations)) {
|
||||
const elem = document.querySelector(`[data-l10n-id=${l10nId}]`);
|
||||
|
||||
// If there is no translation then the element should be returned
|
||||
// as part of the `untranslatedElements`.
|
||||
if (translation === undefined) {
|
||||
const i = Object.keys(translations).indexOf(l10nId);
|
||||
ok(untranslatedElements[i] === elem);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (translation.value !== null) {
|
||||
ok(elem.textContent === translation.value,
|
||||
"element's textContent should be populated with the translation value");
|
||||
ok(elem.textContent === translation.value,
|
||||
"element's textContent should be populated with the translation value");
|
||||
}
|
||||
|
||||
if (translation.attributes !== null) {
|
||||
|
@ -136,7 +127,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1363862
|
|||
<label data-l10n-id="key1" />
|
||||
<label data-l10n-id="key2" data-l10n-args='{"unreadCount": 5}' />
|
||||
<label data-l10n-id="key3" />
|
||||
<label data-l10n-id="key4" />
|
||||
<html:input type="submit" data-l10n-id="key5" />
|
||||
<html:input type="submit" data-l10n-id="key4" />
|
||||
</box>
|
||||
</window>
|
||||
|
|
|
@ -239,6 +239,10 @@ DOMInterfaces = {
|
|||
'headerFile': 'mozilla/dom/DOMMatrix.h',
|
||||
},
|
||||
|
||||
'DOMOverlays': {
|
||||
'nativeType': 'mozilla::dom::l10n::DOMOverlays',
|
||||
},
|
||||
|
||||
'DOMPointReadOnly': {
|
||||
'headerFile': 'mozilla/dom/DOMPoint.h',
|
||||
},
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
dictionary DOMOverlaysError {
|
||||
short code;
|
||||
DOMString translatedElementName;
|
||||
DOMString sourceElementName;
|
||||
DOMString l10nName;
|
||||
};
|
||||
|
||||
[ChromeOnly]
|
||||
namespace DOMOverlays {
|
||||
const unsigned short ERROR_FORBIDDEN_TYPE = 1;
|
||||
const unsigned short ERROR_NAMED_ELEMENT_MISSING = 2;
|
||||
const unsigned short ERROR_NAMED_ELEMENT_TYPE_MISMATCH = 3;
|
||||
const unsigned short ERROR_UNKNOWN = 4;
|
||||
|
||||
sequence<DOMOverlaysError>? translateElement(Element element, optional L10nValue translation);
|
||||
};
|
|
@ -36,6 +36,7 @@ WEBIDL_FILES = [
|
|||
'BrowsingContext.webidl',
|
||||
'ChannelWrapper.webidl',
|
||||
'DominatorTree.webidl',
|
||||
'DOMOverlays.webidl',
|
||||
'Flex.webidl',
|
||||
'HeapSnapshot.webidl',
|
||||
'InspectorUtils.webidl',
|
||||
|
|
|
@ -22,6 +22,8 @@ class HTMLTemplateElement final : public nsGenericHTMLElement {
|
|||
// nsISupports
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
NS_IMPL_FROMNODE_HTML_WITH_TAG(HTMLTemplateElement, _template);
|
||||
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLTemplateElement,
|
||||
nsGenericHTMLElement)
|
||||
|
||||
|
|
|
@ -0,0 +1,483 @@
|
|||
#include "DOMOverlays.h"
|
||||
#include "mozilla/dom/HTMLTemplateElement.h"
|
||||
#include "mozilla/dom/HTMLInputElement.h"
|
||||
#include "HTMLSplitOnSpacesTokenizer.h"
|
||||
#include "nsHtml5StringParser.h"
|
||||
#include "nsTextNode.h"
|
||||
|
||||
using namespace mozilla::dom::l10n;
|
||||
using namespace mozilla::dom;
|
||||
using namespace mozilla;
|
||||
|
||||
bool DOMOverlays::IsAttrNameLocalizable(
|
||||
const nsAtom* nameAtom, Element* aElement,
|
||||
nsTArray<nsString>* aExplicitlyAllowed) {
|
||||
nsAutoString name;
|
||||
nameAtom->ToString(name);
|
||||
|
||||
if (aExplicitlyAllowed->Contains(name)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsAtom* elemName = aElement->NodeInfo()->NameAtom();
|
||||
|
||||
uint32_t nameSpace = aElement->NodeInfo()->NamespaceID();
|
||||
|
||||
if (nameSpace == kNameSpaceID_XHTML) {
|
||||
// Is it a globally safe attribute?
|
||||
if (nameAtom == nsGkAtoms::title || nameAtom == nsGkAtoms::aria_label ||
|
||||
nameAtom == nsGkAtoms::aria_valuetext) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Is it allowed on this element?
|
||||
if (elemName == nsGkAtoms::a) {
|
||||
return nameAtom == nsGkAtoms::download;
|
||||
}
|
||||
if (elemName == nsGkAtoms::area) {
|
||||
return nameAtom == nsGkAtoms::download || nameAtom == nsGkAtoms::alt;
|
||||
}
|
||||
if (elemName == nsGkAtoms::input) {
|
||||
// Special case for value on HTML inputs with type button, reset, submit
|
||||
if (nameAtom == nsGkAtoms::value) {
|
||||
HTMLInputElement* input = HTMLInputElement::FromNode(aElement);
|
||||
if (input) {
|
||||
uint32_t type = input->ControlType();
|
||||
if (type == NS_FORM_INPUT_SUBMIT || type == NS_FORM_INPUT_BUTTON ||
|
||||
type == NS_FORM_INPUT_RESET) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nameAtom == nsGkAtoms::alt || nameAtom == nsGkAtoms::placeholder;
|
||||
}
|
||||
if (elemName == nsGkAtoms::menuitem) {
|
||||
return nameAtom == nsGkAtoms::label;
|
||||
}
|
||||
if (elemName == nsGkAtoms::menu) {
|
||||
return nameAtom == nsGkAtoms::label;
|
||||
}
|
||||
if (elemName == nsGkAtoms::optgroup) {
|
||||
return nameAtom == nsGkAtoms::label;
|
||||
}
|
||||
if (elemName == nsGkAtoms::option) {
|
||||
return nameAtom == nsGkAtoms::label;
|
||||
}
|
||||
if (elemName == nsGkAtoms::track) {
|
||||
return nameAtom == nsGkAtoms::label;
|
||||
}
|
||||
if (elemName == nsGkAtoms::img) {
|
||||
return nameAtom == nsGkAtoms::alt;
|
||||
}
|
||||
if (elemName == nsGkAtoms::textarea) {
|
||||
return nameAtom == nsGkAtoms::placeholder;
|
||||
}
|
||||
if (elemName == nsGkAtoms::th) {
|
||||
return nameAtom == nsGkAtoms::abbr;
|
||||
}
|
||||
|
||||
} else if (nameSpace == kNameSpaceID_XUL) {
|
||||
// Is it a globally safe attribute?
|
||||
if (nameAtom == nsGkAtoms::accesskey || nameAtom == nsGkAtoms::aria_label ||
|
||||
nameAtom == nsGkAtoms::aria_valuetext || nameAtom == nsGkAtoms::label ||
|
||||
nameAtom == nsGkAtoms::title || nameAtom == nsGkAtoms::tooltiptext) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Is it allowed on this element?
|
||||
if (elemName == nsGkAtoms::description) {
|
||||
return nameAtom == nsGkAtoms::value;
|
||||
}
|
||||
if (elemName == nsGkAtoms::key) {
|
||||
return nameAtom == nsGkAtoms::key || nameAtom == nsGkAtoms::keycode;
|
||||
}
|
||||
if (elemName == nsGkAtoms::label) {
|
||||
return nameAtom == nsGkAtoms::value;
|
||||
}
|
||||
if (elemName == nsGkAtoms::textbox) {
|
||||
return nameAtom == nsGkAtoms::placeholder || nameAtom == nsGkAtoms::value;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
already_AddRefed<nsINode> DOMOverlays::CreateTextNodeFromTextContent(
|
||||
Element* aElement, ErrorResult& aRv) {
|
||||
nsAutoString content;
|
||||
aElement->GetTextContent(content, aRv);
|
||||
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return aElement->OwnerDoc()->CreateTextNode(content);
|
||||
}
|
||||
|
||||
class AttributeNameValueComparator {
|
||||
public:
|
||||
bool Equals(const AttributeNameValue& aAttribute,
|
||||
const nsAttrName* aAttrName) const {
|
||||
return aAttrName->Equals(aAttribute.mName);
|
||||
}
|
||||
};
|
||||
|
||||
void DOMOverlays::OverlayAttributes(
|
||||
const Nullable<Sequence<AttributeNameValue>>& aTranslation,
|
||||
Element* aToElement, ErrorResult& aRv) {
|
||||
nsTArray<nsString> explicitlyAllowed;
|
||||
|
||||
nsAutoString l10nAttrs;
|
||||
aToElement->GetAttr(kNameSpaceID_None, nsGkAtoms::datal10nattrs, l10nAttrs);
|
||||
|
||||
HTMLSplitOnSpacesTokenizer tokenizer(l10nAttrs, ',');
|
||||
while (tokenizer.hasMoreTokens()) {
|
||||
const nsAString& token = tokenizer.nextToken();
|
||||
if (!token.IsEmpty() && !explicitlyAllowed.Contains(token)) {
|
||||
explicitlyAllowed.AppendElement(token);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t i = aToElement->GetAttrCount();
|
||||
while (i > 0) {
|
||||
const nsAttrName* attrName = aToElement->GetAttrNameAt(i - 1);
|
||||
|
||||
if (IsAttrNameLocalizable(attrName->LocalName(), aToElement,
|
||||
&explicitlyAllowed) &&
|
||||
(aTranslation.IsNull() ||
|
||||
!aTranslation.Value().Contains(attrName,
|
||||
AttributeNameValueComparator()))) {
|
||||
nsAutoString name;
|
||||
attrName->LocalName()->ToString(name);
|
||||
aToElement->RemoveAttribute(name, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
i--;
|
||||
}
|
||||
|
||||
if (aTranslation.IsNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto& attribute : aTranslation.Value()) {
|
||||
nsString attrName = attribute.mName;
|
||||
RefPtr<nsAtom> nameAtom = NS_Atomize(attrName);
|
||||
if (IsAttrNameLocalizable(nameAtom, aToElement, &explicitlyAllowed)) {
|
||||
nsString value = attribute.mValue;
|
||||
if (!aToElement->AttrValueIs(kNameSpaceID_None, nameAtom, value,
|
||||
eCaseMatters)) {
|
||||
aToElement->SetAttr(nameAtom, value, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DOMOverlays::OverlayAttributes(Element* aFromElement, Element* aToElement,
|
||||
ErrorResult& aRv) {
|
||||
Nullable<Sequence<AttributeNameValue>> attributes;
|
||||
uint32_t attrCount = aFromElement->GetAttrCount();
|
||||
|
||||
if (attrCount == 0) {
|
||||
attributes.SetNull();
|
||||
} else {
|
||||
Sequence<AttributeNameValue> sequence;
|
||||
|
||||
uint32_t i = 0;
|
||||
while (BorrowedAttrInfo info = aFromElement->GetAttrInfoAt(i++)) {
|
||||
AttributeNameValue* attr = sequence.AppendElement(fallible);
|
||||
MOZ_ASSERT(info.mName->NamespaceEquals(kNameSpaceID_None),
|
||||
"No namespaced attributes allowed.");
|
||||
info.mName->LocalName()->ToString(attr->mName);
|
||||
info.mValue->ToString(attr->mValue);
|
||||
}
|
||||
|
||||
attributes.SetValue(sequence);
|
||||
}
|
||||
|
||||
return OverlayAttributes(attributes, aToElement, aRv);
|
||||
}
|
||||
|
||||
void DOMOverlays::ShallowPopulateUsing(Element* aFromElement,
|
||||
Element* aToElement, ErrorResult& aRv) {
|
||||
nsAutoString content;
|
||||
aFromElement->GetTextContent(content, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
||||
aToElement->SetTextContent(content, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
||||
OverlayAttributes(aFromElement, aToElement, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<nsINode> DOMOverlays::GetNodeForNamedElement(
|
||||
Element* aSourceElement, Element* aTranslatedChild,
|
||||
nsTArray<DOMOverlaysError>& aErrors, ErrorResult& aRv) {
|
||||
nsAutoString childName;
|
||||
aTranslatedChild->GetAttr(kNameSpaceID_None, nsGkAtoms::datal10nname,
|
||||
childName);
|
||||
RefPtr<Element> sourceChild = nullptr;
|
||||
|
||||
nsINodeList* childNodes = aSourceElement->ChildNodes();
|
||||
for (uint32_t i = 0; i < childNodes->Length(); i++) {
|
||||
nsINode* childNode = childNodes->Item(i);
|
||||
|
||||
if (!childNode->IsElement()) {
|
||||
continue;
|
||||
}
|
||||
Element* childElement = childNode->AsElement();
|
||||
|
||||
if (childElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::datal10nname,
|
||||
childName, eCaseMatters)) {
|
||||
sourceChild = childElement;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!sourceChild) {
|
||||
DOMOverlaysError error;
|
||||
error.mCode.Construct(DOMOverlays_Binding::ERROR_NAMED_ELEMENT_MISSING);
|
||||
error.mL10nName.Construct(childName);
|
||||
aErrors.AppendElement(error);
|
||||
return CreateTextNodeFromTextContent(aTranslatedChild, aRv);
|
||||
}
|
||||
|
||||
nsAtom* sourceChildName = sourceChild->NodeInfo()->NameAtom();
|
||||
nsAtom* translatedChildName = aTranslatedChild->NodeInfo()->NameAtom();
|
||||
if (sourceChildName != translatedChildName &&
|
||||
// Create a specific exception for img vs. image mismatches,
|
||||
// see bug 1543493
|
||||
!(translatedChildName == nsGkAtoms::img &&
|
||||
sourceChildName == nsGkAtoms::image)) {
|
||||
DOMOverlaysError error;
|
||||
error.mCode.Construct(
|
||||
DOMOverlays_Binding::ERROR_NAMED_ELEMENT_TYPE_MISMATCH);
|
||||
error.mL10nName.Construct(childName);
|
||||
error.mTranslatedElementName.Construct(
|
||||
aTranslatedChild->NodeInfo()->LocalName());
|
||||
error.mSourceElementName.Construct(sourceChild->NodeInfo()->LocalName());
|
||||
aErrors.AppendElement(error);
|
||||
return CreateTextNodeFromTextContent(aTranslatedChild, aRv);
|
||||
}
|
||||
|
||||
aSourceElement->RemoveChild(*sourceChild, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
RefPtr<nsINode> clone = sourceChild->CloneNode(false, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
ShallowPopulateUsing(aTranslatedChild, clone->AsElement(), aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
return clone.forget();
|
||||
}
|
||||
|
||||
bool DOMOverlays::IsElementAllowed(Element* aElement) {
|
||||
uint32_t nameSpace = aElement->NodeInfo()->NamespaceID();
|
||||
if (nameSpace != kNameSpaceID_XHTML) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsAtom* nameAtom = aElement->NodeInfo()->NameAtom();
|
||||
|
||||
return nameAtom == nsGkAtoms::em || nameAtom == nsGkAtoms::strong ||
|
||||
nameAtom == nsGkAtoms::small || nameAtom == nsGkAtoms::s ||
|
||||
nameAtom == nsGkAtoms::cite || nameAtom == nsGkAtoms::q ||
|
||||
nameAtom == nsGkAtoms::dfn || nameAtom == nsGkAtoms::abbr ||
|
||||
nameAtom == nsGkAtoms::data || nameAtom == nsGkAtoms::time ||
|
||||
nameAtom == nsGkAtoms::code || nameAtom == nsGkAtoms::var ||
|
||||
nameAtom == nsGkAtoms::samp || nameAtom == nsGkAtoms::kbd ||
|
||||
nameAtom == nsGkAtoms::sub || nameAtom == nsGkAtoms::sup ||
|
||||
nameAtom == nsGkAtoms::i || nameAtom == nsGkAtoms::b ||
|
||||
nameAtom == nsGkAtoms::u || nameAtom == nsGkAtoms::mark ||
|
||||
nameAtom == nsGkAtoms::bdi || nameAtom == nsGkAtoms::bdo ||
|
||||
nameAtom == nsGkAtoms::span || nameAtom == nsGkAtoms::br ||
|
||||
nameAtom == nsGkAtoms::wbr;
|
||||
}
|
||||
|
||||
already_AddRefed<Element> DOMOverlays::CreateSanitizedElement(
|
||||
Element* aElement, ErrorResult& aRv) {
|
||||
// Start with an empty element of the same type to remove nested children
|
||||
// and non-localizable attributes defined by the translation.
|
||||
|
||||
ElementCreationOptionsOrString options;
|
||||
RefPtr<Element> clone = aElement->OwnerDoc()->CreateElement(
|
||||
aElement->NodeInfo()->LocalName(), options, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ShallowPopulateUsing(aElement, clone, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
return clone.forget();
|
||||
}
|
||||
|
||||
void DOMOverlays::OverlayChildNodes(DocumentFragment* aFromFragment,
|
||||
Element* aToElement,
|
||||
nsTArray<DOMOverlaysError>& aErrors,
|
||||
ErrorResult& aRv) {
|
||||
nsINodeList* childNodes = aFromFragment->ChildNodes();
|
||||
for (uint32_t i = 0; i < childNodes->Length(); i++) {
|
||||
nsINode* childNode = childNodes->Item(i);
|
||||
|
||||
if (!childNode->IsElement()) {
|
||||
// Keep the translated text node.
|
||||
continue;
|
||||
}
|
||||
|
||||
RefPtr<Element> childElement = childNode->AsElement();
|
||||
|
||||
if (childElement->HasAttr(kNameSpaceID_None, nsGkAtoms::datal10nname)) {
|
||||
RefPtr<nsINode> sanitized =
|
||||
GetNodeForNamedElement(aToElement, childElement, aErrors, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
aFromFragment->ReplaceChild(*sanitized, *childNode, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IsElementAllowed(childElement)) {
|
||||
RefPtr<Element> sanitized = CreateSanitizedElement(childElement, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
aFromFragment->ReplaceChild(*sanitized, *childNode, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
DOMOverlaysError error;
|
||||
error.mCode.Construct(DOMOverlays_Binding::ERROR_FORBIDDEN_TYPE);
|
||||
error.mTranslatedElementName.Construct(
|
||||
childElement->NodeInfo()->LocalName());
|
||||
aErrors.AppendElement(error);
|
||||
|
||||
// If all else fails, replace the element with its text content.
|
||||
RefPtr<nsINode> textNode = CreateTextNodeFromTextContent(childElement, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
||||
aFromFragment->ReplaceChild(*textNode, *childNode, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
while (aToElement->HasChildren()) {
|
||||
aToElement->RemoveChildNode(aToElement->GetLastChild(), true);
|
||||
}
|
||||
aToElement->AppendChild(*aFromFragment, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void DOMOverlays::TranslateElement(
|
||||
const GlobalObject& aGlobal, Element& aElement,
|
||||
const L10nValue& aTranslation,
|
||||
Nullable<nsTArray<DOMOverlaysError>>& aErrors) {
|
||||
nsTArray<DOMOverlaysError> errors;
|
||||
|
||||
ErrorResult rv;
|
||||
|
||||
TranslateElement(aElement, aTranslation, errors, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
DOMOverlaysError error;
|
||||
error.mCode.Construct(DOMOverlays_Binding::ERROR_UNKNOWN);
|
||||
errors.AppendElement(error);
|
||||
}
|
||||
if (!errors.IsEmpty()) {
|
||||
aErrors.SetValue(errors);
|
||||
}
|
||||
}
|
||||
|
||||
bool DOMOverlays::ContainsMarkup(const nsAString& aStr) {
|
||||
// We use our custom ContainsMarkup rather than the
|
||||
// one from FragmentOrElement.cpp, because we don't
|
||||
// want to trigger HTML parsing on every `Preferences & Options`
|
||||
// type of string.
|
||||
const char16_t* start = aStr.BeginReading();
|
||||
const char16_t* end = aStr.EndReading();
|
||||
|
||||
while (start != end) {
|
||||
char16_t c = *start;
|
||||
if (c == char16_t('<')) {
|
||||
return true;
|
||||
}
|
||||
++start;
|
||||
|
||||
if (c == char16_t('&') && start != end) {
|
||||
c = *start;
|
||||
if (c == char16_t('#') || (c >= char16_t('0') && c <= char16_t('9')) ||
|
||||
(c >= char16_t('a') && c <= char16_t('z')) ||
|
||||
(c >= char16_t('A') && c <= char16_t('Z'))) {
|
||||
return true;
|
||||
}
|
||||
++start;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void DOMOverlays::TranslateElement(Element& aElement,
|
||||
const L10nValue& aTranslation,
|
||||
nsTArray<DOMOverlaysError>& aErrors,
|
||||
ErrorResult& aRv) {
|
||||
if (!aTranslation.mValue.IsVoid()) {
|
||||
if (!ContainsMarkup(aTranslation.mValue)) {
|
||||
// If the translation doesn't contain any markup skip the overlay logic.
|
||||
aElement.SetTextContent(aTranslation.mValue, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// Else parse the translation's HTML into a DocumentFragment,
|
||||
// sanitize it and replace the element's content.
|
||||
RefPtr<DocumentFragment> fragment =
|
||||
new DocumentFragment(aElement.OwnerDoc()->NodeInfoManager());
|
||||
nsContentUtils::ParseFragmentHTML(
|
||||
aTranslation.mValue, fragment, nsGkAtoms::_template,
|
||||
kNameSpaceID_XHTML, false, true);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
|
||||
OverlayChildNodes(fragment, &aElement, aErrors, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Even if the translation doesn't define any localizable attributes, run
|
||||
// overlayAttributes to remove any localizable attributes set by previous
|
||||
// translations.
|
||||
OverlayAttributes(aTranslation.mAttributes, &aElement, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
#ifndef mozilla_dom_l10n_DOMOverlays_h__
|
||||
#define mozilla_dom_l10n_DOMOverlays_h__
|
||||
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/L10nUtilsBinding.h"
|
||||
#include "mozilla/dom/DOMOverlaysBinding.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace l10n {
|
||||
|
||||
class DOMOverlays {
|
||||
public:
|
||||
/**
|
||||
* Translate an element.
|
||||
*
|
||||
* Translate the element's text content and attributes. Some HTML markup is
|
||||
* allowed in the translation. The element's children with the data-l10n-name
|
||||
* attribute will be treated as arguments to the translation. If the
|
||||
* translation defines the same children, their attributes and text contents
|
||||
* will be used for translating the matching source child.
|
||||
*/
|
||||
static void TranslateElement(
|
||||
const GlobalObject& aGlobal, Element& aElement,
|
||||
const L10nValue& aTranslation,
|
||||
Nullable<nsTArray<mozilla::dom::DOMOverlaysError>>& aErrors);
|
||||
static void TranslateElement(
|
||||
Element& aElement, const L10nValue& aTranslation,
|
||||
nsTArray<mozilla::dom::DOMOverlaysError>& aErrors, ErrorResult& aRv);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Check if attribute is allowed for the given element.
|
||||
*
|
||||
* This method is used by the sanitizer when the translation markup contains
|
||||
* DOM attributes, or when the translation has traits which map to DOM
|
||||
* attributes.
|
||||
*
|
||||
* `aExplicitlyAllowed` can be passed as a list of attributes explicitly
|
||||
* allowed on this element.
|
||||
*/
|
||||
static bool IsAttrNameLocalizable(const nsAtom* nameAtom, Element* aElement,
|
||||
nsTArray<nsString>* aExplicitlyAllowed);
|
||||
|
||||
/**
|
||||
* Create a text node from text content of an Element.
|
||||
*/
|
||||
static already_AddRefed<nsINode> CreateTextNodeFromTextContent(
|
||||
Element* aElement, ErrorResult& aRv);
|
||||
|
||||
/**
|
||||
* Transplant localizable attributes of an element to another element.
|
||||
*
|
||||
* Any localizable attributes already set on the target element will be
|
||||
* cleared.
|
||||
*/
|
||||
static void OverlayAttributes(
|
||||
const Nullable<Sequence<AttributeNameValue>>& aTranslation,
|
||||
Element* aToElement, ErrorResult& aRv);
|
||||
static void OverlayAttributes(Element* aFromElement, Element* aToElement,
|
||||
ErrorResult& aRv);
|
||||
|
||||
/**
|
||||
* Helper to set textContent and localizable attributes on an element.
|
||||
*/
|
||||
static void ShallowPopulateUsing(Element* aFromElement, Element* aToElement,
|
||||
ErrorResult& aRv);
|
||||
|
||||
/**
|
||||
* Sanitize a child element created by the translation.
|
||||
*
|
||||
* Try to find a corresponding child in sourceElement and use it as the base
|
||||
* for the sanitization. This will preserve functional attributes defined on
|
||||
* the child element in the source HTML.
|
||||
*/
|
||||
static already_AddRefed<nsINode> GetNodeForNamedElement(
|
||||
Element* aSourceElement, Element* aTranslatedChild,
|
||||
nsTArray<DOMOverlaysError>& aErrors, ErrorResult& aRv);
|
||||
|
||||
/**
|
||||
* Check if element is allowed in the translation.
|
||||
*
|
||||
* This method is used by the sanitizer when the translation markup contains
|
||||
* an element which is not present in the source code.
|
||||
*/
|
||||
static bool IsElementAllowed(Element* aElement);
|
||||
|
||||
/**
|
||||
* Sanitize an allowed element.
|
||||
*
|
||||
* Text-level elements allowed in translations may only use safe attributes
|
||||
* and will have any nested markup stripped to text content.
|
||||
*/
|
||||
static already_AddRefed<Element> CreateSanitizedElement(Element* aElement,
|
||||
ErrorResult& aRv);
|
||||
|
||||
/**
|
||||
* Replace child nodes of an element with child nodes of another element.
|
||||
*
|
||||
* The contents of the target element will be cleared and fully replaced with
|
||||
* sanitized contents of the source element.
|
||||
*/
|
||||
static void OverlayChildNodes(DocumentFragment* aFromFragment,
|
||||
Element* aToElement,
|
||||
nsTArray<DOMOverlaysError>& aErrors,
|
||||
ErrorResult& aRv);
|
||||
|
||||
/**
|
||||
* A helper used to test if the string contains HTML markup.
|
||||
*/
|
||||
static bool ContainsMarkup(const nsAString& aStr);
|
||||
};
|
||||
|
||||
} // namespace l10n
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
|
@ -0,0 +1,8 @@
|
|||
Classes = [
|
||||
{
|
||||
'cid': '{8d85597c-3a92-11e9-9ffc-73d225b2d53f}',
|
||||
'contract_ids': ['@mozilla.org/dom/l10n/domoverlays;1'],
|
||||
'type': 'mozilla::dom::l10n::DOMOverlays',
|
||||
'headers': ['/dom/l10n/DOMOverlays.h'],
|
||||
},
|
||||
]
|
|
@ -0,0 +1,27 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
with Files("**"):
|
||||
BUG_COMPONENT = ("Core", "Internationalization")
|
||||
|
||||
EXPORTS.mozilla.dom.l10n += [
|
||||
'DOMOverlays.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'DOMOverlays.cpp',
|
||||
]
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'/dom/base',
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
MOCHITEST_CHROME_MANIFESTS += ['tests/mochitest/chrome.ini']
|
||||
|
||||
if CONFIG['ENABLE_TESTS']:
|
||||
DIRS += ['tests/gtest']
|
|
@ -0,0 +1,81 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "mozilla/dom/l10n/DOMOverlays.h"
|
||||
#include "mozilla/dom/Document.h"
|
||||
#include "mozilla/dom/DOMOverlaysBinding.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/L10nUtilsBinding.h"
|
||||
#include "mozilla/NullPrincipal.h"
|
||||
#include "nsNetUtil.h"
|
||||
|
||||
using mozilla::NullPrincipal;
|
||||
using namespace mozilla::dom;
|
||||
using namespace mozilla::dom::l10n;
|
||||
|
||||
already_AddRefed<Document> SetUpDocument() {
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
NS_NewURI(getter_AddRefs(uri), "about:blank");
|
||||
nsCOMPtr<nsIPrincipal> principal =
|
||||
NullPrincipal::CreateWithoutOriginAttributes();
|
||||
nsCOMPtr<Document> document;
|
||||
nsresult rv = NS_NewDOMDocument(getter_AddRefs(document),
|
||||
EmptyString(), // aNamespaceURI
|
||||
EmptyString(), // aQualifiedName
|
||||
nullptr, // aDoctype
|
||||
uri, uri, principal,
|
||||
false, // aLoadedAsData
|
||||
nullptr, // aEventObject
|
||||
DocumentFlavorHTML);
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return nullptr;
|
||||
}
|
||||
return document.forget();
|
||||
}
|
||||
|
||||
/**
|
||||
* This test verifies that the basic C++ DOMOverlays API
|
||||
* works correctly.
|
||||
*/
|
||||
TEST(DOM_L10n_DOMOverlays, Initial)
|
||||
{
|
||||
mozilla::ErrorResult rv;
|
||||
|
||||
// 1. Set up an HTML document.
|
||||
nsCOMPtr<Document> doc = SetUpDocument();
|
||||
|
||||
// 2. Create a simple Element with a child.
|
||||
//
|
||||
// <div>
|
||||
// <a data-l10n-name="link" href="https://www.mozilla.org"></a>
|
||||
// </div>
|
||||
//
|
||||
RefPtr<Element> elem = doc->CreateHTMLElement(nsGkAtoms::div);
|
||||
RefPtr<Element> span = doc->CreateHTMLElement(nsGkAtoms::a);
|
||||
span->SetAttribute(NS_LITERAL_STRING("data-l10n-name"),
|
||||
NS_LITERAL_STRING("link"), rv);
|
||||
span->SetAttribute(NS_LITERAL_STRING("href"),
|
||||
NS_LITERAL_STRING("https://www.mozilla.org"), rv);
|
||||
elem->AppendChild(*span, rv);
|
||||
|
||||
// 3. Create an L10nValue with a translation for the element.
|
||||
L10nValue translation;
|
||||
translation.mValue.AssignLiteral(
|
||||
"Hello <a data-l10n-name=\"link\">World</a>.");
|
||||
|
||||
// 4. Translate the element.
|
||||
nsTArray<DOMOverlaysError> errors;
|
||||
DOMOverlays::TranslateElement(*elem, translation, errors, rv);
|
||||
|
||||
nsAutoString textContent;
|
||||
elem->GetInnerHTML(textContent, rv);
|
||||
|
||||
// 5. Verify that the innerHTML matches the expectations.
|
||||
ASSERT_STREQ(NS_ConvertUTF16toUTF8(textContent).get(),
|
||||
"Hello <a data-l10n-name=\"link\" "
|
||||
"href=\"https://www.mozilla.org\">World</a>.");
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'TestDOMOverlays.cpp',
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul-gtest'
|
|
@ -0,0 +1,5 @@
|
|||
[test_domoverlays_attributes.html]
|
||||
[test_domoverlays_functional_children.html]
|
||||
[test_domoverlays_text_children.html]
|
||||
[test_domoverlays_extra_text_markup.html]
|
||||
[test_domoverlays.xul]
|
|
@ -0,0 +1,87 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
|
||||
type="text/css"?>
|
||||
|
||||
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
xmlns:html="http://www.w3.org/1999/xhtml"
|
||||
title="Testing DocumentL10n in XUL environment">
|
||||
|
||||
<linkset>
|
||||
<html:link rel="localization" href="toolkit/about/aboutAddons.ftl"/>
|
||||
</linkset>
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
/* global DOMOverlays */
|
||||
|
||||
function elem(name) {
|
||||
return function(str) {
|
||||
const element = document.createElement(name);
|
||||
// eslint-disable-next-line no-unsanitized/property
|
||||
element.innerHTML = str;
|
||||
return element;
|
||||
};
|
||||
}
|
||||
|
||||
const { translateElement } = DOMOverlays;
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
{
|
||||
// Allowed attribute
|
||||
const element = elem("description")``;
|
||||
const translation = {
|
||||
value: null,
|
||||
attributes: [
|
||||
{name: "title", value: "FOO"},
|
||||
],
|
||||
};
|
||||
translateElement(element, translation);
|
||||
is(element.outerHTML, '<description xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" title="FOO"/>');
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
{
|
||||
// Handle HTML translation
|
||||
const element = document.getElementById("test2");
|
||||
const translation = {
|
||||
value: "This is <a data-l10n-name=\"link\">a link</a>.",
|
||||
attributes: null,
|
||||
};
|
||||
translateElement(element, translation);
|
||||
is(element.innerHTML, 'This is <html:a xmlns:html="http://www.w3.org/1999/xhtml" data-l10n-name=\"link\" href="https://www.mozilla.org\">a link</html:a>.');
|
||||
}
|
||||
|
||||
{
|
||||
// Don't handle XUL translation
|
||||
//
|
||||
// Current iteration of DOMOverlays will replace
|
||||
// XUL elements from translation with text.
|
||||
//
|
||||
// See bug 1545704 for details.
|
||||
const element = document.getElementById("test3");
|
||||
const translation = {
|
||||
value: "This is <description data-l10n-name=\"desc\">a desc</description>.",
|
||||
attributes: null,
|
||||
};
|
||||
translateElement(element, translation);
|
||||
is(element.innerHTML, 'This is a desc.');
|
||||
}
|
||||
SimpleTest.finish();
|
||||
}, {once: true});
|
||||
|
||||
]]>
|
||||
</script>
|
||||
|
||||
<description id="test2">
|
||||
<html:a data-l10n-name="link" href="https://www.mozilla.org"/>
|
||||
</description>
|
||||
|
||||
<box id="test3">
|
||||
<description data-l10n-name="desc"/>
|
||||
</box>
|
||||
</window>
|
|
@ -0,0 +1,86 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test DOMOverlays Top-level attributes</title>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
|
||||
<script type="application/javascript">
|
||||
/* global DOMOverlays */
|
||||
"use strict";
|
||||
|
||||
function elem(name) {
|
||||
return function(str) {
|
||||
const element = document.createElement(name);
|
||||
// eslint-disable-next-line no-unsanitized/property
|
||||
element.innerHTML = str;
|
||||
return element;
|
||||
};
|
||||
}
|
||||
|
||||
const { translateElement } = DOMOverlays;
|
||||
|
||||
{
|
||||
// Allowed attribute
|
||||
const element = elem("div")``;
|
||||
const translation = {
|
||||
value: null,
|
||||
attributes: [
|
||||
{name: "title", value: "FOO"},
|
||||
],
|
||||
};
|
||||
translateElement(element, translation);
|
||||
is(element.outerHTML, '<div title="FOO"></div>');
|
||||
}
|
||||
|
||||
{
|
||||
// Forbidden attribute
|
||||
const element = elem("input")``;
|
||||
const translation = {
|
||||
value: null,
|
||||
attributes: [
|
||||
{name: "disabled", value: "DISABLED"},
|
||||
],
|
||||
};
|
||||
translateElement(element, translation);
|
||||
is(element.outerHTML, "<input>");
|
||||
}
|
||||
|
||||
{
|
||||
// Attributes do not leak on first translation
|
||||
const element = elem("div")`Foo`;
|
||||
element.setAttribute("title", "Title");
|
||||
|
||||
const translation = {
|
||||
value: "FOO",
|
||||
attributes: null,
|
||||
};
|
||||
translateElement(element, translation);
|
||||
is(element.outerHTML, "<div>FOO</div>");
|
||||
}
|
||||
|
||||
{
|
||||
// Attributes do not leak on retranslation
|
||||
const element = elem("div")`Foo`;
|
||||
|
||||
const translationA = {
|
||||
value: "FOO A",
|
||||
attributes: [
|
||||
{name: "title", value: "TITLE A"},
|
||||
],
|
||||
};
|
||||
|
||||
const translationB = {
|
||||
value: "FOO B",
|
||||
attributes: null,
|
||||
};
|
||||
translateElement(element, translationA);
|
||||
is(element.outerHTML, '<div title="TITLE A">FOO A</div>');
|
||||
translateElement(element, translationB);
|
||||
is(element.outerHTML, "<div>FOO B</div>");
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,136 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test DOMOverlays Localized text markup</title>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
|
||||
<script type="application/javascript">
|
||||
/* global DOMOverlays */
|
||||
"use strict";
|
||||
|
||||
function elem(name) {
|
||||
return function(str) {
|
||||
const element = document.createElement(name);
|
||||
// eslint-disable-next-line no-unsanitized/property
|
||||
element.innerHTML = str;
|
||||
return element;
|
||||
};
|
||||
}
|
||||
|
||||
const { translateElement } = DOMOverlays;
|
||||
|
||||
// Localized text markup
|
||||
{
|
||||
// allowed element
|
||||
const element = elem("div")`Foo`;
|
||||
const translation = {
|
||||
value: "FOO <em>BAR</em> BAZ",
|
||||
attributes: null,
|
||||
};
|
||||
|
||||
translateElement(element, translation);
|
||||
is(element.innerHTML, "FOO <em>BAR</em> BAZ");
|
||||
}
|
||||
|
||||
{
|
||||
// forbidden element
|
||||
const element = elem("div")`Foo`;
|
||||
const translation = {
|
||||
value: 'FOO <img src="img.png" />',
|
||||
attributes: null,
|
||||
};
|
||||
|
||||
translateElement(element, translation);
|
||||
is(element.innerHTML, "FOO ");
|
||||
}
|
||||
|
||||
{
|
||||
// forbiden element with text
|
||||
const element = elem("div")`Foo`;
|
||||
const translation = {
|
||||
value: "FOO <a>a</a>",
|
||||
attributes: null,
|
||||
};
|
||||
|
||||
translateElement(element, translation);
|
||||
is(element.innerHTML, "FOO a");
|
||||
}
|
||||
|
||||
{
|
||||
// nested HTML is forbidden
|
||||
const element = elem("div")`Foo`;
|
||||
const translation = {
|
||||
value: "FOO <em><strong>BAR</strong></em> BAZ",
|
||||
attributes: null,
|
||||
};
|
||||
|
||||
translateElement(element, translation);
|
||||
is(element.innerHTML, "FOO <em>BAR</em> BAZ");
|
||||
}
|
||||
|
||||
// Attributes of localized text markup
|
||||
{
|
||||
// allowed attribute
|
||||
const element = elem("div")`Foo Bar`;
|
||||
const translation = {
|
||||
value: 'FOO <em title="BAR">BAR</em>',
|
||||
attributes: null,
|
||||
};
|
||||
|
||||
translateElement(element, translation);
|
||||
is(element.innerHTML,
|
||||
'FOO <em title="BAR">BAR</em>');
|
||||
}
|
||||
|
||||
{
|
||||
// forbidden attribute
|
||||
const element = elem("div")`Foo Bar`;
|
||||
const translation = {
|
||||
value: 'FOO <em class="BAR" title="BAR">BAR</em>',
|
||||
attributes: null,
|
||||
};
|
||||
|
||||
translateElement(element, translation);
|
||||
is(element.innerHTML,
|
||||
'FOO <em title="BAR">BAR</em>');
|
||||
}
|
||||
|
||||
{
|
||||
// attributes do not leak on first translation
|
||||
const element = elem("div")`
|
||||
<em title="Foo">Foo</a>`;
|
||||
const translation = {
|
||||
value: "<em>FOO</em>",
|
||||
attributes: null,
|
||||
};
|
||||
|
||||
translateElement(element, translation);
|
||||
is(element.innerHTML,
|
||||
"<em>FOO</em>");
|
||||
}
|
||||
|
||||
{
|
||||
// attributes do not leak on retranslation
|
||||
const element = elem("div")``;
|
||||
const translationA = {
|
||||
value: '<em title="FOO A">FOO A</em>',
|
||||
attributes: null,
|
||||
};
|
||||
const translationB = {
|
||||
value: "<em>FOO B</em>",
|
||||
attributes: null,
|
||||
};
|
||||
|
||||
translateElement(element, translationA);
|
||||
is(element.innerHTML,
|
||||
'<em title="FOO A">FOO A</em>');
|
||||
translateElement(element, translationB);
|
||||
is(element.innerHTML,
|
||||
"<em>FOO B</em>");
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,344 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test DOMOverlays functional children test</title>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
|
||||
<script type="application/javascript">
|
||||
/* global DOMOverlays */
|
||||
"use strict";
|
||||
|
||||
function elem(name) {
|
||||
return function(str) {
|
||||
const element = document.createElement(name);
|
||||
// eslint-disable-next-line no-unsanitized/property
|
||||
element.innerHTML = str;
|
||||
return element;
|
||||
};
|
||||
}
|
||||
|
||||
const { translateElement } = DOMOverlays;
|
||||
|
||||
// Child without name
|
||||
{
|
||||
// in source
|
||||
const element = elem("div")`
|
||||
<a>Foo</a>`;
|
||||
const translation = {
|
||||
value: "FOO",
|
||||
attributes: null,
|
||||
};
|
||||
translateElement(element, translation);
|
||||
is(element.innerHTML, "FOO");
|
||||
}
|
||||
|
||||
{
|
||||
// in translation
|
||||
const element = elem("div")`Foo`;
|
||||
const translation = {
|
||||
value: "<a>FOO</a>",
|
||||
attributes: null,
|
||||
};
|
||||
translateElement(element, translation);
|
||||
is(element.innerHTML, "FOO");
|
||||
}
|
||||
|
||||
{
|
||||
// in both
|
||||
const element = elem("div")`
|
||||
<a>Foo</a>`;
|
||||
const translation = {
|
||||
value: "<a>FOO</a>",
|
||||
attributes: null,
|
||||
};
|
||||
translateElement(element, translation);
|
||||
is(element.innerHTML, "FOO");
|
||||
}
|
||||
|
||||
// Child with name
|
||||
{
|
||||
// in source
|
||||
const element = elem("div")`
|
||||
<a data-l10n-name="foo">Foo</a>`;
|
||||
const translation = {
|
||||
value: "<a>FOO</a>",
|
||||
attributes: null,
|
||||
};
|
||||
translateElement(element, translation);
|
||||
is(element.innerHTML, "FOO");
|
||||
}
|
||||
|
||||
{
|
||||
// in translation
|
||||
const element = elem("div")`
|
||||
<a>Foo</a>`;
|
||||
const translation = {
|
||||
value: '<a data-l10n-name="foo">FOO</a>',
|
||||
attributes: null,
|
||||
};
|
||||
translateElement(element, translation);
|
||||
is(element.innerHTML, "FOO");
|
||||
}
|
||||
|
||||
{
|
||||
// in both
|
||||
const element = elem("div")`
|
||||
<a data-l10n-name="foo">Foo</a>`;
|
||||
const translation = {
|
||||
value: '<a data-l10n-name="foo">FOO</a>',
|
||||
attributes: null,
|
||||
};
|
||||
translateElement(element, translation);
|
||||
is(element.innerHTML, '<a data-l10n-name="foo">FOO</a>');
|
||||
}
|
||||
|
||||
{
|
||||
// translation without text content
|
||||
const element = elem("div")`
|
||||
<a data-l10n-name="foo">Foo</a>`;
|
||||
const translation = {
|
||||
value: '<a data-l10n-name="foo"></a>',
|
||||
attributes: null,
|
||||
};
|
||||
translateElement(element, translation);
|
||||
is(element.innerHTML, '<a data-l10n-name="foo"></a>');
|
||||
}
|
||||
|
||||
{
|
||||
// different names
|
||||
const element = elem("div")`
|
||||
<a data-l10n-name="foo">Foo</a>`;
|
||||
const translation = {
|
||||
value: '<a data-l10n-name="bar">BAR</a>',
|
||||
attributes: null,
|
||||
};
|
||||
translateElement(element, translation);
|
||||
is(element.innerHTML, "BAR");
|
||||
}
|
||||
|
||||
{
|
||||
// of different types
|
||||
const element = elem("div")`
|
||||
<a data-l10n-name="foo">Foo</a>`;
|
||||
const translation = {
|
||||
value: '<div data-l10n-name="foo">FOO</div>',
|
||||
attributes: null,
|
||||
};
|
||||
translateElement(element, translation);
|
||||
is(element.innerHTML, "FOO");
|
||||
}
|
||||
|
||||
{
|
||||
// used twice
|
||||
const element = elem("div")`
|
||||
<a data-l10n-name="foo">Foo</a>`;
|
||||
const translation = {
|
||||
value: '<a data-l10n-name="foo">FOO 1</a> <a data-l10n-name="foo">FOO 2</a>',
|
||||
attributes: null,
|
||||
};
|
||||
translateElement(element, translation);
|
||||
is(element.innerHTML, '<a data-l10n-name="foo">FOO 1</a> FOO 2');
|
||||
}
|
||||
|
||||
// Two named children
|
||||
{
|
||||
// in order
|
||||
const element = elem("div")`
|
||||
<a data-l10n-name="foo">Foo</a>
|
||||
<a data-l10n-name="bar">Bar</a>`;
|
||||
const translation = {
|
||||
value: '<a data-l10n-name="foo">FOO</a><a data-l10n-name="bar">BAR</a>',
|
||||
attributes: null,
|
||||
};
|
||||
translateElement(element, translation);
|
||||
is(element.innerHTML, '<a data-l10n-name="foo">FOO</a><a data-l10n-name="bar">BAR</a>');
|
||||
}
|
||||
|
||||
{
|
||||
// out of order
|
||||
const element = elem("div")`
|
||||
<a data-l10n-name="foo">Foo</a>
|
||||
<a data-l10n-name="bar">Bar</a>`;
|
||||
const translation = {
|
||||
value: '<a data-l10n-name="bar">BAR</a><a data-l10n-name="foo">FOO</a>',
|
||||
attributes: null,
|
||||
};
|
||||
translateElement(element, translation);
|
||||
is(element.innerHTML, '<a data-l10n-name="bar">BAR</a><a data-l10n-name="foo">FOO</a>');
|
||||
}
|
||||
|
||||
{
|
||||
// nested in source
|
||||
const element = elem("div")`
|
||||
<a data-l10n-name="foo">
|
||||
Foo 1
|
||||
<a data-l10n-name="bar">Bar</a>
|
||||
Foo 2
|
||||
</a>`;
|
||||
const translation = {
|
||||
value: '<a data-l10n-name="foo">FOO</a><a data-l10n-name="bar">BAR</a>',
|
||||
attributes: null,
|
||||
};
|
||||
translateElement(element, translation);
|
||||
is(
|
||||
element.innerHTML,
|
||||
'<a data-l10n-name="foo">FOO</a><a data-l10n-name="bar">BAR</a>'
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
// nested in translation
|
||||
const element = elem("div")`
|
||||
<div data-l10n-name="foo">Foo</div>
|
||||
<div data-l10n-name="bar">Bar</div>`;
|
||||
const translation = {
|
||||
value: '<div data-l10n-name="foo">FOO 1 <div data-l10n-name="bar">BAR</div> FOO 2</div>',
|
||||
attributes: null,
|
||||
};
|
||||
translateElement(element, translation);
|
||||
is(
|
||||
element.innerHTML,
|
||||
'<div data-l10n-name="foo">FOO 1 BAR FOO 2</div>'
|
||||
);
|
||||
}
|
||||
|
||||
// Child attributes
|
||||
{
|
||||
// functional attribute in source
|
||||
const element = elem("div")`
|
||||
<a data-l10n-name="foo" class="foo">Foo</a>`;
|
||||
const translation = {
|
||||
value: '<a data-l10n-name="foo">FOO</a>',
|
||||
attributes: null,
|
||||
};
|
||||
|
||||
translateElement(element, translation);
|
||||
is(element.innerHTML,
|
||||
'<a data-l10n-name="foo" class="foo">FOO</a>');
|
||||
}
|
||||
|
||||
{
|
||||
// functional attribute in translation
|
||||
const element = elem("div")`
|
||||
<a data-l10n-name="foo">Foo</a>`;
|
||||
const translation = {
|
||||
value: '<a data-l10n-name="foo" class="bar">FOO</a>',
|
||||
attributes: null,
|
||||
};
|
||||
|
||||
translateElement(element, translation);
|
||||
is(element.innerHTML,
|
||||
'<a data-l10n-name="foo">FOO</a>');
|
||||
}
|
||||
|
||||
{
|
||||
// functional attribute in both
|
||||
const element = elem("div")`
|
||||
<a data-l10n-name="foo" class="foo">Foo</a>`;
|
||||
const translation = {
|
||||
value: '<a data-l10n-name="foo" class="bar">FOO</a>',
|
||||
attributes: null,
|
||||
};
|
||||
|
||||
translateElement(element, translation);
|
||||
is(element.innerHTML,
|
||||
'<a data-l10n-name="foo" class="foo">FOO</a>');
|
||||
}
|
||||
|
||||
{
|
||||
// localizable attribute in source
|
||||
const element = elem("div")`
|
||||
<a data-l10n-name="foo" title="Foo">Foo</a>`;
|
||||
const translation = {
|
||||
value: '<a data-l10n-name="foo">FOO</a>',
|
||||
attributes: null,
|
||||
};
|
||||
|
||||
translateElement(element, translation);
|
||||
is(element.innerHTML,
|
||||
'<a data-l10n-name="foo">FOO</a>');
|
||||
}
|
||||
|
||||
{
|
||||
// localizable attribute in translation
|
||||
const element = elem("div")`
|
||||
<a data-l10n-name="foo">Foo</a>`;
|
||||
const translation = {
|
||||
value: '<a data-l10n-name="foo" title="FOO">FOO</a>',
|
||||
attributes: null,
|
||||
};
|
||||
|
||||
translateElement(element, translation);
|
||||
is(element.innerHTML,
|
||||
'<a data-l10n-name="foo" title="FOO">FOO</a>');
|
||||
}
|
||||
|
||||
{
|
||||
// localizable attribute in both
|
||||
const element = elem("div")`
|
||||
<a data-l10n-name="foo" title="Foo">Foo</a>`;
|
||||
const translation = {
|
||||
value: '<a data-l10n-name="foo" title="BAR">FOO</a>',
|
||||
attributes: null,
|
||||
};
|
||||
|
||||
translateElement(element, translation);
|
||||
is(element.innerHTML,
|
||||
'<a data-l10n-name="foo" title="BAR">FOO</a>');
|
||||
}
|
||||
|
||||
{
|
||||
// localizable attribute does not leak on retranslation
|
||||
const element = elem("div")`
|
||||
<a data-l10n-name="foo">Foo</a>`;
|
||||
const translationA = {
|
||||
value: '<a data-l10n-name="foo" title="FOO A">FOO A</a>',
|
||||
attributes: null,
|
||||
};
|
||||
const translationB = {
|
||||
value: '<a data-l10n-name="foo">FOO B</a>',
|
||||
attributes: null,
|
||||
};
|
||||
|
||||
translateElement(element, translationA);
|
||||
is(element.innerHTML,
|
||||
'<a data-l10n-name="foo" title="FOO A">FOO A</a>');
|
||||
translateElement(element, translationB);
|
||||
is(element.innerHTML,
|
||||
'<a data-l10n-name="foo">FOO B</a>');
|
||||
}
|
||||
|
||||
// Child attributes overrides
|
||||
{
|
||||
// the source can override child's attributes
|
||||
const element = elem("div")`
|
||||
<a data-l10n-name="foo" data-l10n-attrs="class" class="foo">Foo</a>`;
|
||||
const translation = {
|
||||
value: '<a data-l10n-name="foo" class="FOO">FOO</a>',
|
||||
attributes: null,
|
||||
};
|
||||
|
||||
translateElement(element, translation);
|
||||
is(element.innerHTML,
|
||||
'<a data-l10n-name="foo" data-l10n-attrs="class" class="FOO">FOO</a>');
|
||||
}
|
||||
|
||||
{
|
||||
// the translation cannot override child's attributes
|
||||
const element = elem("div")`
|
||||
<a data-l10n-name="foo" class="foo">Foo</a>`;
|
||||
const translation = {
|
||||
value: '<a data-l10n-name="foo" data-l10n-attrs="class" class="FOO">FOO</a>',
|
||||
attributes: null,
|
||||
};
|
||||
|
||||
translateElement(element, translation);
|
||||
is(element.innerHTML,
|
||||
'<a data-l10n-name="foo" class="foo">FOO</a>');
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,74 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test DOMOverlays Text-semantic argument elements</title>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
|
||||
<script type="application/javascript">
|
||||
/* global DOMOverlays */
|
||||
"use strict";
|
||||
|
||||
function elem(name) {
|
||||
return function(str) {
|
||||
const element = document.createElement(name);
|
||||
// eslint-disable-next-line no-unsanitized/property
|
||||
element.innerHTML = str;
|
||||
return element;
|
||||
};
|
||||
}
|
||||
|
||||
const { translateElement } = DOMOverlays;
|
||||
|
||||
{
|
||||
// without data-l10n-name
|
||||
const element = elem("div")`
|
||||
<em class="bar"></em>`;
|
||||
const translation = {
|
||||
value: '<em title="FOO">FOO</em>',
|
||||
attributes: null,
|
||||
};
|
||||
|
||||
translateElement(element, translation);
|
||||
is(
|
||||
element.innerHTML,
|
||||
'<em title="FOO">FOO</em>'
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
// mismatched types
|
||||
const element = elem("div")`
|
||||
<button data-l10n-name="foo"></button>`;
|
||||
const translation = {
|
||||
value: '<em data-l10n-name="foo" title="FOO">FOO</em>',
|
||||
attributes: null,
|
||||
};
|
||||
|
||||
translateElement(element, translation);
|
||||
is(
|
||||
element.innerHTML,
|
||||
"FOO"
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
// types and names mismatch
|
||||
const element = elem("div")`
|
||||
<em data-l10n-name="foo" class="foo"></em>`;
|
||||
const translation = {
|
||||
value: '<em data-l10n-name="foo" title="FOO">FOO</em>',
|
||||
attributes: null,
|
||||
};
|
||||
|
||||
translateElement(element, translation);
|
||||
is(
|
||||
element.innerHTML,
|
||||
'<em data-l10n-name="foo" class="foo" title="FOO">FOO</em>'
|
||||
);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
|
@ -105,6 +105,7 @@ DIRS += [
|
|||
'reporting',
|
||||
'localstorage',
|
||||
'prio',
|
||||
'l10n',
|
||||
]
|
||||
|
||||
if CONFIG['OS_ARCH'] == 'WINNT':
|
||||
|
|
|
@ -595,26 +595,6 @@ GL_APICALL void GL_APIENTRY glGetQueryObjectui64vRobustANGLE(GLuint id, GLenum p
|
|||
#define GL_PROGRAM_CACHE_ENABLED_ANGLE 0x93AC
|
||||
#endif /* GL_ANGLE_program_cache_control */
|
||||
|
||||
#ifndef GL_ANGLE_multiview
|
||||
#define GL_ANGLE_multiview 1
|
||||
// The next four enums coincide with the enums introduced by the GL_OVR_multiview extension and use the values reserved by that extension.
|
||||
#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_ANGLE 0x9630
|
||||
#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_BASE_VIEW_INDEX_ANGLE 0x9632
|
||||
#define GL_MAX_VIEWS_ANGLE 0x9631
|
||||
#define GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE 0x9633
|
||||
// The next four enums are reserved specifically for ANGLE.
|
||||
#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_VIEWPORT_OFFSETS_ANGLE 0x969B
|
||||
#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_MULTIVIEW_LAYOUT_ANGLE 0x969C
|
||||
#define GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE 0x969D
|
||||
#define GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE 0x969E
|
||||
typedef void(GL_APIENTRYP PFNGLFRAMEBUFFERTEXTUREMULTIVIEWLAYEREDANGLEPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews);
|
||||
typedef void(GL_APIENTRYP PFNGLFRAMEBUFFERTEXTUREMULTIVIEWSIDEBYSIDEANGLEPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level, GLsizei numViews, const GLint *viewportOffsets);
|
||||
#ifdef GL_GLEXT_PROTOTYPES
|
||||
GL_APICALL void GL_APIENTRY glFramebufferTextureMultiviewLayeredANGLE(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews);
|
||||
GL_APICALL void GL_APIENTRY glFramebufferTextureMultiviewSideBySideANGLE(GLenum target, GLenum attachment, GLuint texture, GLint level, GLsizei numViews, const GLint *viewportOffsets);
|
||||
#endif
|
||||
#endif /* GL_ANGLE_multiview */
|
||||
|
||||
#ifndef GL_ANGLE_texture_rectangle
|
||||
#define GL_ANGLE_texture_rectangle 1
|
||||
#define GL_MAX_RECTANGLE_TEXTURE_SIZE_ANGLE 0x84F8
|
||||
|
|
|
@ -173,6 +173,7 @@ typedef void (GL_APIENTRYP PFNGLENDQUERYEXTCONTEXTANGLEPROC)(GLeglContext ctx, G
|
|||
typedef void (GL_APIENTRYP PFNGLFINISHFENCENVCONTEXTANGLEPROC)(GLeglContext ctx, GLuint fence);
|
||||
typedef void (GL_APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEEXTCONTEXTANGLEPROC)(GLeglContext ctx, GLenum target, GLintptr offset, GLsizeiptr length);
|
||||
typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTUREEXTCONTEXTANGLEPROC)(GLeglContext ctx, GLenum target, GLenum attachment, GLuint texture, GLint level);
|
||||
typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRCONTEXTANGLEPROC)(GLeglContext ctx, GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews);
|
||||
typedef void (GL_APIENTRYP PFNGLGENFENCESNVCONTEXTANGLEPROC)(GLeglContext ctx, GLsizei n, GLuint *fences);
|
||||
typedef void (GL_APIENTRYP PFNGLGENQUERIESEXTCONTEXTANGLEPROC)(GLeglContext ctx, GLsizei n, GLuint *ids);
|
||||
typedef void (GL_APIENTRYP PFNGLGENVERTEXARRAYSOESCONTEXTANGLEPROC)(GLeglContext ctx, GLsizei n, GLuint *arrays);
|
||||
|
@ -323,8 +324,6 @@ typedef void (GL_APIENTRYP PFNGLGETSAMPLERPARAMETERIUIVROBUSTANGLECONTEXTANGLEPR
|
|||
typedef void (GL_APIENTRYP PFNGLGETQUERYOBJECTIVROBUSTANGLECONTEXTANGLEPROC)(GLeglContext ctx, GLuint id, GLenum pname, GLsizei bufSize, GLsizei * length, GLint * params);
|
||||
typedef void (GL_APIENTRYP PFNGLGETQUERYOBJECTI64VROBUSTANGLECONTEXTANGLEPROC)(GLeglContext ctx, GLuint id, GLenum pname, GLsizei bufSize, GLsizei * length, GLint64 * params);
|
||||
typedef void (GL_APIENTRYP PFNGLGETQUERYOBJECTUI64VROBUSTANGLECONTEXTANGLEPROC)(GLeglContext ctx, GLuint id, GLenum pname, GLsizei bufSize, GLsizei * length, GLuint64 * params);
|
||||
typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTUREMULTIVIEWLAYEREDANGLECONTEXTANGLEPROC)(GLeglContext ctx, GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews);
|
||||
typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTUREMULTIVIEWSIDEBYSIDEANGLECONTEXTANGLEPROC)(GLeglContext ctx, GLenum target, GLenum attachment, GLuint texture, GLint level, GLsizei numViews, const GLint * viewportOffsets);
|
||||
typedef void (GL_APIENTRYP PFNGLCOPYTEXTURE3DANGLECONTEXTANGLEPROC)(GLeglContext ctx, GLuint sourceId, GLint sourceLevel, GLenum destTarget, GLuint destId, GLint destLevel, GLint internalFormat, GLenum destType, GLboolean unpackFlipY, GLboolean unpackPremultiplyAlpha, GLboolean unpackUnmultiplyAlpha);
|
||||
typedef void (GL_APIENTRYP PFNGLCOPYSUBTEXTURE3DANGLECONTEXTANGLEPROC)(GLeglContext ctx, GLuint sourceId, GLint sourceLevel, GLenum destTarget, GLuint destId, GLint destLevel, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLint z, GLint width, GLint height, GLint depth, GLboolean unpackFlipY, GLboolean unpackPremultiplyAlpha, GLboolean unpackUnmultiplyAlpha);
|
||||
typedef void (GL_APIENTRYP PFNGLTEXSTORAGE2DMULTISAMPLEANGLECONTEXTANGLEPROC)(GLeglContext ctx, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);
|
||||
|
@ -503,6 +502,7 @@ GL_APICALL void GL_APIENTRY glEndQueryEXTContextANGLE(GLeglContext ctx, GLenum t
|
|||
GL_APICALL void GL_APIENTRY glFinishFenceNVContextANGLE(GLeglContext ctx, GLuint fence);
|
||||
GL_APICALL void GL_APIENTRY glFlushMappedBufferRangeEXTContextANGLE(GLeglContext ctx, GLenum target, GLintptr offset, GLsizeiptr length);
|
||||
GL_APICALL void GL_APIENTRY glFramebufferTextureEXTContextANGLE(GLeglContext ctx, GLenum target, GLenum attachment, GLuint texture, GLint level);
|
||||
GL_APICALL void GL_APIENTRY glFramebufferTextureMultiviewOVRContextANGLE(GLeglContext ctx, GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews);
|
||||
GL_APICALL void GL_APIENTRY glGenFencesNVContextANGLE(GLeglContext ctx, GLsizei n, GLuint *fences);
|
||||
GL_APICALL void GL_APIENTRY glGenQueriesEXTContextANGLE(GLeglContext ctx, GLsizei n, GLuint *ids);
|
||||
GL_APICALL void GL_APIENTRY glGenVertexArraysOESContextANGLE(GLeglContext ctx, GLsizei n, GLuint *arrays);
|
||||
|
@ -653,8 +653,6 @@ GL_APICALL void GL_APIENTRY glGetSamplerParameterIuivRobustANGLEContextANGLE(GLe
|
|||
GL_APICALL void GL_APIENTRY glGetQueryObjectivRobustANGLEContextANGLE(GLeglContext ctx, GLuint id, GLenum pname, GLsizei bufSize, GLsizei * length, GLint * params);
|
||||
GL_APICALL void GL_APIENTRY glGetQueryObjecti64vRobustANGLEContextANGLE(GLeglContext ctx, GLuint id, GLenum pname, GLsizei bufSize, GLsizei * length, GLint64 * params);
|
||||
GL_APICALL void GL_APIENTRY glGetQueryObjectui64vRobustANGLEContextANGLE(GLeglContext ctx, GLuint id, GLenum pname, GLsizei bufSize, GLsizei * length, GLuint64 * params);
|
||||
GL_APICALL void GL_APIENTRY glFramebufferTextureMultiviewLayeredANGLEContextANGLE(GLeglContext ctx, GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews);
|
||||
GL_APICALL void GL_APIENTRY glFramebufferTextureMultiviewSideBySideANGLEContextANGLE(GLeglContext ctx, GLenum target, GLenum attachment, GLuint texture, GLint level, GLsizei numViews, const GLint * viewportOffsets);
|
||||
GL_APICALL void GL_APIENTRY glCopyTexture3DANGLEContextANGLE(GLeglContext ctx, GLuint sourceId, GLint sourceLevel, GLenum destTarget, GLuint destId, GLint destLevel, GLint internalFormat, GLenum destType, GLboolean unpackFlipY, GLboolean unpackPremultiplyAlpha, GLboolean unpackUnmultiplyAlpha);
|
||||
GL_APICALL void GL_APIENTRY glCopySubTexture3DANGLEContextANGLE(GLeglContext ctx, GLuint sourceId, GLint sourceLevel, GLenum destTarget, GLuint destId, GLint destLevel, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLint z, GLint width, GLint height, GLint depth, GLboolean unpackFlipY, GLboolean unpackPremultiplyAlpha, GLboolean unpackUnmultiplyAlpha);
|
||||
GL_APICALL void GL_APIENTRY glTexStorage2DMultisampleANGLEContextANGLE(GLeglContext ctx, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);
|
||||
|
|
|
@ -319,7 +319,7 @@ struct ShBuiltInResources
|
|||
int EXT_shader_framebuffer_fetch;
|
||||
int NV_shader_framebuffer_fetch;
|
||||
int ARM_shader_framebuffer_fetch;
|
||||
int OVR_multiview;
|
||||
int OVR_multiview2;
|
||||
int EXT_YUV_target;
|
||||
int EXT_geometry_shader;
|
||||
int OES_texture_storage_multisample_2d_array;
|
||||
|
|
|
@ -15,11 +15,9 @@
|
|||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
// On mac, environ is not declared anywhere:
|
||||
// On BSDs (including mac), environ is not declared anywhere:
|
||||
// https://stackoverflow.com/a/31347357/912144
|
||||
#if defined(ANGLE_PLATFORM_APPLE)
|
||||
extern char **environ;
|
||||
#endif
|
||||
|
||||
namespace angle
|
||||
{
|
||||
|
|
|
@ -554,7 +554,7 @@ void CollectVariablesTraverser::visitSymbol(TIntermSymbol *symbol)
|
|||
else
|
||||
{
|
||||
ASSERT(mShaderType == GL_VERTEX_SHADER &&
|
||||
IsExtensionEnabled(mExtensionBehavior, TExtension::OVR_multiview));
|
||||
IsExtensionEnabled(mExtensionBehavior, TExtension::OVR_multiview2));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -766,7 +766,7 @@ Uniform CollectVariablesTraverser::recordUniform(const TIntermSymbol &variable)
|
|||
{
|
||||
Uniform uniform;
|
||||
setCommonVariableProperties(variable.getType(), variable.variable(), &uniform);
|
||||
uniform.binding = variable.getType().getLayoutQualifier().binding;
|
||||
uniform.binding = variable.getType().getLayoutQualifier().binding;
|
||||
uniform.imageUnitFormat =
|
||||
GetImageInternalFormatType(variable.getType().getLayoutQualifier().imageInternalFormat);
|
||||
uniform.location = variable.getType().getLayoutQualifier().location;
|
||||
|
|
|
@ -565,7 +565,7 @@ bool TCompiler::checkAndSimplifyAST(TIntermBlock *root,
|
|||
}
|
||||
|
||||
if ((compileOptions & SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW) &&
|
||||
parseContext.isExtensionEnabled(TExtension::OVR_multiview) &&
|
||||
parseContext.isExtensionEnabled(TExtension::OVR_multiview2) &&
|
||||
getShaderType() != GL_COMPUTE_SHADER)
|
||||
{
|
||||
DeclareAndInitBuiltinsForInstancedMultiview(root, mNumViews, mShaderType, compileOptions,
|
||||
|
@ -967,7 +967,7 @@ void TCompiler::setResourceString()
|
|||
<< ":EXT_shader_framebuffer_fetch:" << mResources.EXT_shader_framebuffer_fetch
|
||||
<< ":NV_shader_framebuffer_fetch:" << mResources.NV_shader_framebuffer_fetch
|
||||
<< ":ARM_shader_framebuffer_fetch:" << mResources.ARM_shader_framebuffer_fetch
|
||||
<< ":OVR_multiview:" << mResources.OVR_multiview
|
||||
<< ":OVR_multiview2:" << mResources.OVR_multiview2
|
||||
<< ":EXT_YUV_target:" << mResources.EXT_YUV_target
|
||||
<< ":EXT_geometry_shader:" << mResources.EXT_geometry_shader
|
||||
<< ":MaxVertexOutputVectors:" << mResources.MaxVertexOutputVectors
|
||||
|
@ -1094,7 +1094,7 @@ bool TCompiler::checkCallDepth()
|
|||
|
||||
for (size_t i = 0; i < mCallDag.size(); i++)
|
||||
{
|
||||
int depth = 0;
|
||||
int depth = 0;
|
||||
const CallDAG::Record &record = mCallDag.getRecordFromIndex(i);
|
||||
|
||||
for (const int &calleeIndex : record.callees)
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
OP(OES_EGL_image_external_essl3) \
|
||||
OP(OES_standard_derivatives) \
|
||||
OP(OES_texture_storage_multisample_2d_array) \
|
||||
OP(OVR_multiview) \
|
||||
OP(OVR_multiview2) \
|
||||
OP(ANGLE_multi_draw)
|
||||
|
||||
namespace sh
|
||||
|
|
|
@ -34,7 +34,7 @@ enum class TExtension
|
|||
OES_EGL_image_external_essl3,
|
||||
OES_standard_derivatives,
|
||||
OES_texture_storage_multisample_2d_array,
|
||||
OVR_multiview,
|
||||
OVR_multiview2,
|
||||
ANGLE_multi_draw,
|
||||
};
|
||||
|
||||
|
|
|
@ -61,9 +61,9 @@ void InitExtensionBehavior(const ShBuiltInResources &resources, TExtensionBehavi
|
|||
{
|
||||
extBehavior[TExtension::ARM_shader_framebuffer_fetch] = EBhUndefined;
|
||||
}
|
||||
if (resources.OVR_multiview)
|
||||
if (resources.OVR_multiview2)
|
||||
{
|
||||
extBehavior[TExtension::OVR_multiview] = EBhUndefined;
|
||||
extBehavior[TExtension::OVR_multiview2] = EBhUndefined;
|
||||
}
|
||||
if (resources.EXT_YUV_target)
|
||||
{
|
||||
|
|
|
@ -262,7 +262,7 @@ OutputHLSL::OutputHLSL(sh::GLenum shaderType,
|
|||
mUsesPointSize = false;
|
||||
mUsesInstanceID = false;
|
||||
mHasMultiviewExtensionEnabled =
|
||||
IsExtensionEnabled(mExtensionBehavior, TExtension::OVR_multiview);
|
||||
IsExtensionEnabled(mExtensionBehavior, TExtension::OVR_multiview2);
|
||||
mUsesViewID = false;
|
||||
mUsesVertexID = false;
|
||||
mUsesFragDepth = false;
|
||||
|
|
|
@ -1347,7 +1347,7 @@ void TParseContext::declarationQualifierErrorCheck(const sh::TQualifier qualifie
|
|||
|
||||
// If multiview extension is enabled, "in" qualifier is allowed in the vertex shader in previous
|
||||
// parsing steps. So it needs to be checked here.
|
||||
if (isExtensionEnabled(TExtension::OVR_multiview) && mShaderVersion < 300 &&
|
||||
if (isExtensionEnabled(TExtension::OVR_multiview2) && mShaderVersion < 300 &&
|
||||
qualifier == EvqVertexIn)
|
||||
{
|
||||
error(location, "storage qualifier supported in GLSL ES 3.00 and above only", "in");
|
||||
|
@ -3106,7 +3106,7 @@ void TParseContext::parseGlobalLayoutQualifier(const TTypeQualifierBuilder &type
|
|||
return;
|
||||
}
|
||||
}
|
||||
else if (isExtensionEnabled(TExtension::OVR_multiview) &&
|
||||
else if (isExtensionEnabled(TExtension::OVR_multiview2) &&
|
||||
typeQualifier.qualifier == EvqVertexIn)
|
||||
{
|
||||
// This error is only specified in WebGL, but tightens unspecified behavior in the native
|
||||
|
@ -4535,7 +4535,7 @@ TLayoutQualifier TParseContext::parseLayoutQualifier(const ImmutableString &qual
|
|||
}
|
||||
else if (qualifierType == "num_views" && mShaderType == GL_VERTEX_SHADER)
|
||||
{
|
||||
if (checkCanUseExtension(qualifierTypeLine, TExtension::OVR_multiview))
|
||||
if (checkCanUseExtension(qualifierTypeLine, TExtension::OVR_multiview2))
|
||||
{
|
||||
parseNumViews(intValue, intValueLine, intValueString, &qualifier.numViews);
|
||||
}
|
||||
|
@ -4597,7 +4597,7 @@ TStorageQualifierWrapper *TParseContext::parseInQualifier(const TSourceLoc &loc)
|
|||
{
|
||||
case GL_VERTEX_SHADER:
|
||||
{
|
||||
if (mShaderVersion < 300 && !isExtensionEnabled(TExtension::OVR_multiview))
|
||||
if (mShaderVersion < 300 && !isExtensionEnabled(TExtension::OVR_multiview2))
|
||||
{
|
||||
error(loc, "storage qualifier supported in GLSL ES 3.00 and above only", "in");
|
||||
}
|
||||
|
|
|
@ -199,7 +199,7 @@ void InitBuiltInResources(ShBuiltInResources *resources)
|
|||
resources->EXT_shader_framebuffer_fetch = 0;
|
||||
resources->NV_shader_framebuffer_fetch = 0;
|
||||
resources->ARM_shader_framebuffer_fetch = 0;
|
||||
resources->OVR_multiview = 0;
|
||||
resources->OVR_multiview2 = 0;
|
||||
resources->EXT_YUV_target = 0;
|
||||
resources->EXT_geometry_shader = 0;
|
||||
resources->OES_texture_storage_multisample_2d_array = 0;
|
||||
|
|
|
@ -1603,13 +1603,13 @@ constexpr const TVariable kVar_gl_ViewID_OVR(
|
|||
BuiltInId::gl_ViewID_OVR,
|
||||
BuiltInName::gl_ViewID_OVR,
|
||||
SymbolType::BuiltIn,
|
||||
TExtension::OVR_multiview,
|
||||
TExtension::OVR_multiview2,
|
||||
StaticType::Get<EbtUInt, EbpHigh, EvqViewIDOVR, 1, 1>());
|
||||
constexpr const TVariable kVar_gl_ViewID_OVRESSL1(
|
||||
BuiltInId::gl_ViewID_OVRESSL1,
|
||||
BuiltInName::gl_ViewID_OVR,
|
||||
SymbolType::BuiltIn,
|
||||
TExtension::OVR_multiview,
|
||||
TExtension::OVR_multiview2,
|
||||
StaticType::Get<EbtInt, EbpHigh, EvqViewIDOVR, 1, 1>());
|
||||
constexpr const TVariable kVar_gl_ViewportIndex(
|
||||
BuiltInId::gl_ViewportIndex,
|
||||
|
@ -16806,7 +16806,7 @@ const TSymbol *TSymbolTable::findBuiltIn(const ImmutableString &name, int shader
|
|||
}
|
||||
}
|
||||
}
|
||||
if (mResources.OVR_multiview && mShaderType != GL_COMPUTE_SHADER)
|
||||
if (mResources.OVR_multiview2 && mShaderType != GL_COMPUTE_SHADER)
|
||||
{
|
||||
switch (nameHash)
|
||||
{
|
||||
|
@ -17296,7 +17296,7 @@ const TSymbol *TSymbolTable::findBuiltIn(const ImmutableString &name, int shader
|
|||
}
|
||||
}
|
||||
}
|
||||
if (mResources.OVR_multiview && mShaderType != GL_COMPUTE_SHADER)
|
||||
if (mResources.OVR_multiview2 && mShaderType != GL_COMPUTE_SHADER)
|
||||
{
|
||||
switch (nameHash)
|
||||
{
|
||||
|
|
|
@ -132,7 +132,7 @@ void TranslatorESSL::writeExtensionBehavior(ShCompileOptions compileOptions)
|
|||
{
|
||||
if (iter->second != EBhUndefined)
|
||||
{
|
||||
const bool isMultiview = (iter->first == TExtension::OVR_multiview);
|
||||
const bool isMultiview = (iter->first == TExtension::OVR_multiview2);
|
||||
if (getResources().NV_shader_framebuffer_fetch &&
|
||||
iter->first == TExtension::EXT_shader_framebuffer_fetch)
|
||||
{
|
||||
|
@ -151,7 +151,7 @@ void TranslatorESSL::writeExtensionBehavior(ShCompileOptions compileOptions)
|
|||
{
|
||||
// Emit the NV_viewport_array2 extension in a vertex shader if the
|
||||
// SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER option is set and the
|
||||
// OVR_multiview(2) extension is requested.
|
||||
// OVR_multiview2 extension is requested.
|
||||
sink << "#extension GL_NV_viewport_array2 : require\n";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -277,12 +277,12 @@ void TranslatorGLSL::writeExtensionBehavior(TIntermNode *root, ShCompileOptions
|
|||
}
|
||||
}
|
||||
|
||||
const bool isMultiview = (iter.first == TExtension::OVR_multiview);
|
||||
const bool isMultiview = (iter.first == TExtension::OVR_multiview2);
|
||||
if (isMultiview && getShaderType() == GL_VERTEX_SHADER &&
|
||||
(compileOptions & SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER) != 0u)
|
||||
{
|
||||
// Emit the NV_viewport_array2 extension in a vertex shader if the
|
||||
// SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER option is set and the OVR_multiview(2)
|
||||
// SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER option is set and the OVR_multiview2(2)
|
||||
// extension is requested.
|
||||
sink << "#extension GL_NV_viewport_array2 : require\n";
|
||||
}
|
||||
|
|
|
@ -3895,7 +3895,7 @@ int ES2_ident_ES3_keyword_multiview_keyword(TParseContext *context, int token)
|
|||
|
||||
// not a reserved word in GLSL ES 1.00, so could be used as an identifier/type name
|
||||
// except when multiview extension is enabled
|
||||
if (context->getShaderVersion() < 300 && !context->isExtensionEnabled(TExtension::OVR_multiview))
|
||||
if (context->getShaderVersion() < 300 && !context->isExtensionEnabled(TExtension::OVR_multiview2))
|
||||
{
|
||||
yylval->lex.string = AllocatePoolCharArray(yytext, yyleng);
|
||||
return check_type(yyscanner);
|
||||
|
|
|
@ -416,12 +416,6 @@ extern void yyerror(YYLTYPE* yylloc, TParseContext* context, void *scanner, cons
|
|||
} \
|
||||
} while (0)
|
||||
|
||||
#define ES3_OR_NEWER_OR_MULTIVIEW(TOKEN, LINE, REASON) do { \
|
||||
if (context->getShaderVersion() < 300 && !context->isExtensionEnabled(TExtension::OVR_multiview)) { \
|
||||
context->error(LINE, REASON " supported in GLSL ES 3.00 and above only", TOKEN); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ES3_1_ONLY(TOKEN, LINE, REASON) do { \
|
||||
if (context->getShaderVersion() != 310) { \
|
||||
context->error(LINE, REASON " supported in GLSL ES 3.10 only", TOKEN); \
|
||||
|
@ -3740,7 +3734,7 @@ yyreduce:
|
|||
case 151:
|
||||
|
||||
{
|
||||
ES3_OR_NEWER_OR_MULTIVIEW("layout", (yylsp[-3]), "qualifier");
|
||||
ES3_OR_NEWER("layout", (yylsp[-3]), "qualifier");
|
||||
(yyval.interm.layoutQualifier) = (yyvsp[-1].interm.layoutQualifier);
|
||||
}
|
||||
|
||||
|
|
|
@ -197,7 +197,7 @@ Extensions::Extensions()
|
|||
standardDerivatives(false),
|
||||
shaderTextureLOD(false),
|
||||
fragDepth(false),
|
||||
multiview(false),
|
||||
multiview2(false),
|
||||
maxViews(1u),
|
||||
textureUsage(false),
|
||||
translatedShaderSource(false),
|
||||
|
@ -861,7 +861,7 @@ const ExtensionInfoMap &GetExtensionInfoMap()
|
|||
map["GL_OES_standard_derivatives"] = enableableExtension(&Extensions::standardDerivatives);
|
||||
map["GL_EXT_shader_texture_lod"] = enableableExtension(&Extensions::shaderTextureLOD);
|
||||
map["GL_EXT_frag_depth"] = enableableExtension(&Extensions::fragDepth);
|
||||
map["GL_ANGLE_multiview"] = enableableExtension(&Extensions::multiview);
|
||||
map["GL_OVR_multiview2"] = enableableExtension(&Extensions::multiview2);
|
||||
map["GL_ANGLE_texture_usage"] = enableableExtension(&Extensions::textureUsage);
|
||||
map["GL_ANGLE_translated_shader_source"] = esOnlyExtension(&Extensions::translatedShaderSource);
|
||||
map["GL_OES_fbo_render_mipmap"] = enableableExtension(&Extensions::fboRenderMipmap);
|
||||
|
|
|
@ -302,8 +302,8 @@ struct Extensions
|
|||
// GL_EXT_frag_depth
|
||||
bool fragDepth;
|
||||
|
||||
// ANGLE_multiview
|
||||
bool multiview;
|
||||
// OVR_multiview2
|
||||
bool multiview2;
|
||||
GLuint maxViews;
|
||||
|
||||
// GL_ANGLE_texture_usage
|
||||
|
|
|
@ -92,9 +92,9 @@ Compiler::Compiler(rx::GLImplFactory *implFactory, const State &state)
|
|||
mResources.FragmentPrecisionHigh = 1;
|
||||
mResources.EXT_frag_depth = extensions.fragDepth;
|
||||
|
||||
// OVR_multiview state
|
||||
mResources.OVR_multiview = extensions.multiview;
|
||||
mResources.MaxViewsOVR = extensions.maxViews;
|
||||
// OVR_multiview2 state
|
||||
mResources.OVR_multiview2 = extensions.multiview2;
|
||||
mResources.MaxViewsOVR = extensions.maxViews;
|
||||
|
||||
// GLSL ES 3.0 constants
|
||||
mResources.MaxVertexOutputVectors = caps.maxVertexOutputComponents / 4;
|
||||
|
|
|
@ -1561,8 +1561,8 @@ void Context::getIntegervImpl(GLenum pname, GLint *params)
|
|||
*params = mState.mExtensions.maxLabelLength;
|
||||
break;
|
||||
|
||||
// GL_ANGLE_multiview
|
||||
case GL_MAX_VIEWS_ANGLE:
|
||||
// GL_OVR_multiview2
|
||||
case GL_MAX_VIEWS_OVR:
|
||||
*params = mState.mExtensions.maxViews;
|
||||
break;
|
||||
|
||||
|
@ -3140,7 +3140,7 @@ Extensions Context::generateSupportedExtensions() const
|
|||
supportedExtensions.colorBufferFloat = false;
|
||||
supportedExtensions.eglImageExternalEssl3 = false;
|
||||
supportedExtensions.textureNorm16 = false;
|
||||
supportedExtensions.multiview = false;
|
||||
supportedExtensions.multiview2 = false;
|
||||
supportedExtensions.maxViews = 1u;
|
||||
supportedExtensions.copyTexture3d = false;
|
||||
supportedExtensions.textureMultisample = false;
|
||||
|
@ -3806,12 +3806,12 @@ void Context::framebufferTextureLayer(GLenum target,
|
|||
mState.setObjectDirty(target);
|
||||
}
|
||||
|
||||
void Context::framebufferTextureMultiviewLayered(GLenum target,
|
||||
GLenum attachment,
|
||||
GLuint texture,
|
||||
GLint level,
|
||||
GLint baseViewIndex,
|
||||
GLsizei numViews)
|
||||
void Context::framebufferTextureMultiview(GLenum target,
|
||||
GLenum attachment,
|
||||
GLuint texture,
|
||||
GLint level,
|
||||
GLint baseViewIndex,
|
||||
GLsizei numViews)
|
||||
{
|
||||
Framebuffer *framebuffer = mState.getTargetFramebuffer(target);
|
||||
ASSERT(framebuffer);
|
||||
|
@ -3831,34 +3831,8 @@ void Context::framebufferTextureMultiviewLayered(GLenum target,
|
|||
ASSERT(level == 0);
|
||||
index = ImageIndex::Make2DMultisampleArrayRange(baseViewIndex, numViews);
|
||||
}
|
||||
framebuffer->setAttachmentMultiviewLayered(this, GL_TEXTURE, attachment, index, textureObj,
|
||||
numViews, baseViewIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
framebuffer->resetAttachment(this, attachment);
|
||||
}
|
||||
|
||||
mState.setObjectDirty(target);
|
||||
}
|
||||
|
||||
void Context::framebufferTextureMultiviewSideBySide(GLenum target,
|
||||
GLenum attachment,
|
||||
GLuint texture,
|
||||
GLint level,
|
||||
GLsizei numViews,
|
||||
const GLint *viewportOffsets)
|
||||
{
|
||||
Framebuffer *framebuffer = mState.getTargetFramebuffer(target);
|
||||
ASSERT(framebuffer);
|
||||
|
||||
if (texture != 0)
|
||||
{
|
||||
Texture *textureObj = getTexture(texture);
|
||||
|
||||
ImageIndex index = ImageIndex::Make2D(level);
|
||||
framebuffer->setAttachmentMultiviewSideBySide(this, GL_TEXTURE, attachment, index,
|
||||
textureObj, numViews, viewportOffsets);
|
||||
framebuffer->setAttachmentMultiview(this, GL_TEXTURE, attachment, index, textureObj,
|
||||
numViews, baseViewIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -7577,7 +7551,7 @@ bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *nu
|
|||
return true;
|
||||
}
|
||||
|
||||
if (getExtensions().multiview && pname == GL_MAX_VIEWS_ANGLE)
|
||||
if (getExtensions().multiview2 && pname == GL_MAX_VIEWS_OVR)
|
||||
{
|
||||
*type = GL_INT;
|
||||
*numParams = 1;
|
||||
|
|
|
@ -876,18 +876,13 @@ class Context final : public egl::LabeledObject, angle::NonCopyable, public angl
|
|||
GLuint texture,
|
||||
GLint level,
|
||||
GLint layer);
|
||||
void framebufferTextureMultiviewLayered(GLenum target,
|
||||
GLenum attachment,
|
||||
GLuint texture,
|
||||
GLint level,
|
||||
GLint baseViewIndex,
|
||||
GLsizei numViews);
|
||||
void framebufferTextureMultiviewSideBySide(GLenum target,
|
||||
GLenum attachment,
|
||||
GLuint texture,
|
||||
GLint level,
|
||||
GLsizei numViews,
|
||||
const GLint *viewportOffsets);
|
||||
|
||||
void framebufferTextureMultiview(GLenum target,
|
||||
GLenum attachment,
|
||||
GLuint texture,
|
||||
GLint level,
|
||||
GLint baseViewIndex,
|
||||
GLsizei numViews);
|
||||
|
||||
void drawBuffers(GLsizei n, const GLenum *bufs);
|
||||
void readBuffer(GLenum mode);
|
||||
|
|
|
@ -49,12 +49,7 @@ bool CheckMultiviewStateMatchesForCompleteness(const FramebufferAttachment *firs
|
|||
{
|
||||
return false;
|
||||
}
|
||||
if (firstAttachment->getMultiviewLayout() != secondAttachment->getMultiviewLayout())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (firstAttachment->getMultiviewViewportOffsets() !=
|
||||
secondAttachment->getMultiviewViewportOffsets())
|
||||
if (firstAttachment->isMultiview() != secondAttachment->isMultiview())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -585,24 +580,14 @@ bool FramebufferState::hasStencil() const
|
|||
return (mStencilAttachment.isAttached() && mStencilAttachment.getStencilSize() > 0);
|
||||
}
|
||||
|
||||
const std::vector<Offset> *FramebufferState::getViewportOffsets() const
|
||||
bool FramebufferState::isMultiview() const
|
||||
{
|
||||
const FramebufferAttachment *attachment = getFirstNonNullAttachment();
|
||||
if (attachment == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
return &attachment->getMultiviewViewportOffsets();
|
||||
}
|
||||
|
||||
GLenum FramebufferState::getMultiviewLayout() const
|
||||
{
|
||||
const FramebufferAttachment *attachment = getFirstNonNullAttachment();
|
||||
if (attachment == nullptr)
|
||||
{
|
||||
return GL_NONE;
|
||||
}
|
||||
return attachment->getMultiviewLayout();
|
||||
return attachment->isMultiview();
|
||||
}
|
||||
|
||||
int FramebufferState::getBaseViewIndex() const
|
||||
|
@ -652,26 +637,20 @@ Framebuffer::Framebuffer(const Context *context, egl::Surface *surface)
|
|||
|
||||
setAttachmentImpl(context, GL_FRAMEBUFFER_DEFAULT, GL_BACK, ImageIndex(), surface,
|
||||
FramebufferAttachment::kDefaultNumViews,
|
||||
FramebufferAttachment::kDefaultBaseViewIndex,
|
||||
FramebufferAttachment::kDefaultMultiviewLayout,
|
||||
FramebufferAttachment::kDefaultViewportOffsets);
|
||||
FramebufferAttachment::kDefaultBaseViewIndex, false);
|
||||
|
||||
if (surface->getConfig()->depthSize > 0)
|
||||
{
|
||||
setAttachmentImpl(context, GL_FRAMEBUFFER_DEFAULT, GL_DEPTH, ImageIndex(), surface,
|
||||
FramebufferAttachment::kDefaultNumViews,
|
||||
FramebufferAttachment::kDefaultBaseViewIndex,
|
||||
FramebufferAttachment::kDefaultMultiviewLayout,
|
||||
FramebufferAttachment::kDefaultViewportOffsets);
|
||||
FramebufferAttachment::kDefaultBaseViewIndex, false);
|
||||
}
|
||||
|
||||
if (surface->getConfig()->stencilSize > 0)
|
||||
{
|
||||
setAttachmentImpl(context, GL_FRAMEBUFFER_DEFAULT, GL_STENCIL, ImageIndex(), surface,
|
||||
FramebufferAttachment::kDefaultNumViews,
|
||||
FramebufferAttachment::kDefaultBaseViewIndex,
|
||||
FramebufferAttachment::kDefaultMultiviewLayout,
|
||||
FramebufferAttachment::kDefaultViewportOffsets);
|
||||
FramebufferAttachment::kDefaultBaseViewIndex, false);
|
||||
}
|
||||
SetComponentTypeMask(getDrawbufferWriteType(0), 0, &mState.mDrawBufferTypeMask);
|
||||
}
|
||||
|
@ -1060,7 +1039,7 @@ GLenum Framebuffer::checkStatusWithGLFrontEnd(const Context *context)
|
|||
|
||||
if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment, &colorAttachment))
|
||||
{
|
||||
return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE;
|
||||
return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR;
|
||||
}
|
||||
|
||||
hasRenderbuffer = hasRenderbuffer || (colorAttachment.type() == GL_RENDERBUFFER);
|
||||
|
@ -1120,7 +1099,7 @@ GLenum Framebuffer::checkStatusWithGLFrontEnd(const Context *context)
|
|||
|
||||
if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment, &depthAttachment))
|
||||
{
|
||||
return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE;
|
||||
return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR;
|
||||
}
|
||||
|
||||
hasRenderbuffer = hasRenderbuffer || (depthAttachment.type() == GL_RENDERBUFFER);
|
||||
|
@ -1165,7 +1144,7 @@ GLenum Framebuffer::checkStatusWithGLFrontEnd(const Context *context)
|
|||
|
||||
if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment, &stencilAttachment))
|
||||
{
|
||||
return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE;
|
||||
return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR;
|
||||
}
|
||||
|
||||
hasRenderbuffer = hasRenderbuffer || (stencilAttachment.type() == GL_RENDERBUFFER);
|
||||
|
@ -1214,7 +1193,7 @@ GLenum Framebuffer::checkStatusWithGLFrontEnd(const Context *context)
|
|||
if (!CheckMultiviewStateMatchesForCompleteness(firstAttachment,
|
||||
&mState.mWebGLDepthStencilAttachment))
|
||||
{
|
||||
return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_ANGLE;
|
||||
return GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR;
|
||||
}
|
||||
}
|
||||
else if (mState.mStencilAttachment.isAttached() &&
|
||||
|
@ -1535,9 +1514,7 @@ void Framebuffer::setAttachment(const Context *context,
|
|||
{
|
||||
setAttachment(context, type, binding, textureIndex, resource,
|
||||
FramebufferAttachment::kDefaultNumViews,
|
||||
FramebufferAttachment::kDefaultBaseViewIndex,
|
||||
FramebufferAttachment::kDefaultMultiviewLayout,
|
||||
FramebufferAttachment::kDefaultViewportOffsets);
|
||||
FramebufferAttachment::kDefaultBaseViewIndex, false);
|
||||
}
|
||||
|
||||
void Framebuffer::setAttachment(const Context *context,
|
||||
|
@ -1547,14 +1524,13 @@ void Framebuffer::setAttachment(const Context *context,
|
|||
FramebufferAttachmentObject *resource,
|
||||
GLsizei numViews,
|
||||
GLuint baseViewIndex,
|
||||
GLenum multiviewLayout,
|
||||
const GLint *viewportOffsets)
|
||||
bool isMultiview)
|
||||
{
|
||||
// Context may be null in unit tests.
|
||||
if (!context || !context->isWebGL1())
|
||||
{
|
||||
setAttachmentImpl(context, type, binding, textureIndex, resource, numViews, baseViewIndex,
|
||||
multiviewLayout, viewportOffsets);
|
||||
isMultiview);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1564,61 +1540,42 @@ void Framebuffer::setAttachment(const Context *context,
|
|||
case GL_DEPTH_STENCIL_ATTACHMENT:
|
||||
mState.mWebGLDepthStencilAttachment.attach(context, type, binding, textureIndex,
|
||||
resource, numViews, baseViewIndex,
|
||||
multiviewLayout, viewportOffsets);
|
||||
isMultiview);
|
||||
break;
|
||||
case GL_DEPTH:
|
||||
case GL_DEPTH_ATTACHMENT:
|
||||
mState.mWebGLDepthAttachment.attach(context, type, binding, textureIndex, resource,
|
||||
numViews, baseViewIndex, multiviewLayout,
|
||||
viewportOffsets);
|
||||
numViews, baseViewIndex, isMultiview);
|
||||
break;
|
||||
case GL_STENCIL:
|
||||
case GL_STENCIL_ATTACHMENT:
|
||||
mState.mWebGLStencilAttachment.attach(context, type, binding, textureIndex, resource,
|
||||
numViews, baseViewIndex, multiviewLayout,
|
||||
viewportOffsets);
|
||||
numViews, baseViewIndex, isMultiview);
|
||||
break;
|
||||
default:
|
||||
setAttachmentImpl(context, type, binding, textureIndex, resource, numViews,
|
||||
baseViewIndex, multiviewLayout, viewportOffsets);
|
||||
baseViewIndex, isMultiview);
|
||||
return;
|
||||
}
|
||||
|
||||
commitWebGL1DepthStencilIfConsistent(context, numViews, baseViewIndex, multiviewLayout,
|
||||
viewportOffsets);
|
||||
commitWebGL1DepthStencilIfConsistent(context, numViews, baseViewIndex, isMultiview);
|
||||
}
|
||||
|
||||
void Framebuffer::setAttachmentMultiviewLayered(const Context *context,
|
||||
GLenum type,
|
||||
GLenum binding,
|
||||
const ImageIndex &textureIndex,
|
||||
FramebufferAttachmentObject *resource,
|
||||
GLsizei numViews,
|
||||
GLint baseViewIndex)
|
||||
void Framebuffer::setAttachmentMultiview(const Context *context,
|
||||
GLenum type,
|
||||
GLenum binding,
|
||||
const ImageIndex &textureIndex,
|
||||
FramebufferAttachmentObject *resource,
|
||||
GLsizei numViews,
|
||||
GLint baseViewIndex)
|
||||
{
|
||||
setAttachment(context, type, binding, textureIndex, resource, numViews, baseViewIndex,
|
||||
GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE,
|
||||
FramebufferAttachment::kDefaultViewportOffsets);
|
||||
}
|
||||
|
||||
void Framebuffer::setAttachmentMultiviewSideBySide(const Context *context,
|
||||
GLenum type,
|
||||
GLenum binding,
|
||||
const ImageIndex &textureIndex,
|
||||
FramebufferAttachmentObject *resource,
|
||||
GLsizei numViews,
|
||||
const GLint *viewportOffsets)
|
||||
{
|
||||
setAttachment(context, type, binding, textureIndex, resource, numViews,
|
||||
FramebufferAttachment::kDefaultBaseViewIndex,
|
||||
GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE, viewportOffsets);
|
||||
setAttachment(context, type, binding, textureIndex, resource, numViews, baseViewIndex, true);
|
||||
}
|
||||
|
||||
void Framebuffer::commitWebGL1DepthStencilIfConsistent(const Context *context,
|
||||
GLsizei numViews,
|
||||
GLuint baseViewIndex,
|
||||
GLenum multiviewLayout,
|
||||
const GLint *viewportOffsets)
|
||||
bool isMultiview)
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
|
@ -1656,37 +1613,35 @@ void Framebuffer::commitWebGL1DepthStencilIfConsistent(const Context *context,
|
|||
const auto &depth = mState.mWebGLDepthAttachment;
|
||||
setAttachmentImpl(context, depth.type(), GL_DEPTH_ATTACHMENT,
|
||||
getImageIndexIfTextureAttachment(depth), depth.getResource(), numViews,
|
||||
baseViewIndex, multiviewLayout, viewportOffsets);
|
||||
baseViewIndex, isMultiview);
|
||||
setAttachmentImpl(context, GL_NONE, GL_STENCIL_ATTACHMENT, ImageIndex(), nullptr, numViews,
|
||||
baseViewIndex, multiviewLayout, viewportOffsets);
|
||||
baseViewIndex, isMultiview);
|
||||
}
|
||||
else if (mState.mWebGLStencilAttachment.isAttached())
|
||||
{
|
||||
const auto &stencil = mState.mWebGLStencilAttachment;
|
||||
setAttachmentImpl(context, GL_NONE, GL_DEPTH_ATTACHMENT, ImageIndex(), nullptr, numViews,
|
||||
baseViewIndex, multiviewLayout, viewportOffsets);
|
||||
baseViewIndex, isMultiview);
|
||||
setAttachmentImpl(context, stencil.type(), GL_STENCIL_ATTACHMENT,
|
||||
getImageIndexIfTextureAttachment(stencil), stencil.getResource(),
|
||||
numViews, baseViewIndex, multiviewLayout, viewportOffsets);
|
||||
numViews, baseViewIndex, isMultiview);
|
||||
}
|
||||
else if (mState.mWebGLDepthStencilAttachment.isAttached())
|
||||
{
|
||||
const auto &depthStencil = mState.mWebGLDepthStencilAttachment;
|
||||
setAttachmentImpl(context, depthStencil.type(), GL_DEPTH_ATTACHMENT,
|
||||
getImageIndexIfTextureAttachment(depthStencil),
|
||||
depthStencil.getResource(), numViews, baseViewIndex, multiviewLayout,
|
||||
viewportOffsets);
|
||||
depthStencil.getResource(), numViews, baseViewIndex, isMultiview);
|
||||
setAttachmentImpl(context, depthStencil.type(), GL_STENCIL_ATTACHMENT,
|
||||
getImageIndexIfTextureAttachment(depthStencil),
|
||||
depthStencil.getResource(), numViews, baseViewIndex, multiviewLayout,
|
||||
viewportOffsets);
|
||||
depthStencil.getResource(), numViews, baseViewIndex, isMultiview);
|
||||
}
|
||||
else
|
||||
{
|
||||
setAttachmentImpl(context, GL_NONE, GL_DEPTH_ATTACHMENT, ImageIndex(), nullptr, numViews,
|
||||
baseViewIndex, multiviewLayout, viewportOffsets);
|
||||
baseViewIndex, isMultiview);
|
||||
setAttachmentImpl(context, GL_NONE, GL_STENCIL_ATTACHMENT, ImageIndex(), nullptr, numViews,
|
||||
baseViewIndex, multiviewLayout, viewportOffsets);
|
||||
baseViewIndex, isMultiview);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1697,8 +1652,7 @@ void Framebuffer::setAttachmentImpl(const Context *context,
|
|||
FramebufferAttachmentObject *resource,
|
||||
GLsizei numViews,
|
||||
GLuint baseViewIndex,
|
||||
GLenum multiviewLayout,
|
||||
const GLint *viewportOffsets)
|
||||
bool isMultiview)
|
||||
{
|
||||
switch (binding)
|
||||
{
|
||||
|
@ -1719,12 +1673,10 @@ void Framebuffer::setAttachmentImpl(const Context *context,
|
|||
|
||||
updateAttachment(context, &mState.mDepthAttachment, DIRTY_BIT_DEPTH_ATTACHMENT,
|
||||
&mDirtyDepthAttachmentBinding, type, binding, textureIndex,
|
||||
attachmentObj, numViews, baseViewIndex, multiviewLayout,
|
||||
viewportOffsets);
|
||||
attachmentObj, numViews, baseViewIndex, isMultiview);
|
||||
updateAttachment(context, &mState.mStencilAttachment, DIRTY_BIT_STENCIL_ATTACHMENT,
|
||||
&mDirtyStencilAttachmentBinding, type, binding, textureIndex,
|
||||
attachmentObj, numViews, baseViewIndex, multiviewLayout,
|
||||
viewportOffsets);
|
||||
attachmentObj, numViews, baseViewIndex, isMultiview);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1732,20 +1684,20 @@ void Framebuffer::setAttachmentImpl(const Context *context,
|
|||
case GL_DEPTH_ATTACHMENT:
|
||||
updateAttachment(context, &mState.mDepthAttachment, DIRTY_BIT_DEPTH_ATTACHMENT,
|
||||
&mDirtyDepthAttachmentBinding, type, binding, textureIndex, resource,
|
||||
numViews, baseViewIndex, multiviewLayout, viewportOffsets);
|
||||
numViews, baseViewIndex, isMultiview);
|
||||
break;
|
||||
|
||||
case GL_STENCIL:
|
||||
case GL_STENCIL_ATTACHMENT:
|
||||
updateAttachment(context, &mState.mStencilAttachment, DIRTY_BIT_STENCIL_ATTACHMENT,
|
||||
&mDirtyStencilAttachmentBinding, type, binding, textureIndex, resource,
|
||||
numViews, baseViewIndex, multiviewLayout, viewportOffsets);
|
||||
numViews, baseViewIndex, isMultiview);
|
||||
break;
|
||||
|
||||
case GL_BACK:
|
||||
updateAttachment(context, &mState.mColorAttachments[0], DIRTY_BIT_COLOR_ATTACHMENT_0,
|
||||
&mDirtyColorAttachmentBindings[0], type, binding, textureIndex,
|
||||
resource, numViews, baseViewIndex, multiviewLayout, viewportOffsets);
|
||||
resource, numViews, baseViewIndex, isMultiview);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -1755,8 +1707,7 @@ void Framebuffer::setAttachmentImpl(const Context *context,
|
|||
size_t dirtyBit = DIRTY_BIT_COLOR_ATTACHMENT_0 + colorIndex;
|
||||
updateAttachment(context, &mState.mColorAttachments[colorIndex], dirtyBit,
|
||||
&mDirtyColorAttachmentBindings[colorIndex], type, binding,
|
||||
textureIndex, resource, numViews, baseViewIndex, multiviewLayout,
|
||||
viewportOffsets);
|
||||
textureIndex, resource, numViews, baseViewIndex, isMultiview);
|
||||
|
||||
if (!resource)
|
||||
{
|
||||
|
@ -1789,11 +1740,10 @@ void Framebuffer::updateAttachment(const Context *context,
|
|||
FramebufferAttachmentObject *resource,
|
||||
GLsizei numViews,
|
||||
GLuint baseViewIndex,
|
||||
GLenum multiviewLayout,
|
||||
const GLint *viewportOffsets)
|
||||
bool isMultiview)
|
||||
{
|
||||
attachment->attach(context, type, binding, textureIndex, resource, numViews, baseViewIndex,
|
||||
multiviewLayout, viewportOffsets);
|
||||
isMultiview);
|
||||
mDirtyBits.set(dirtyBit);
|
||||
mState.mResourceNeedsInit.set(dirtyBit, attachment->initState() == InitState::MayNeedInit);
|
||||
onDirtyBinding->bind(resource);
|
||||
|
@ -2012,20 +1962,14 @@ GLint Framebuffer::getBaseViewIndex() const
|
|||
return mState.getBaseViewIndex();
|
||||
}
|
||||
|
||||
const std::vector<Offset> *Framebuffer::getViewportOffsets() const
|
||||
bool Framebuffer::isMultiview() const
|
||||
{
|
||||
return mState.getViewportOffsets();
|
||||
}
|
||||
|
||||
GLenum Framebuffer::getMultiviewLayout() const
|
||||
{
|
||||
return mState.getMultiviewLayout();
|
||||
return mState.isMultiview();
|
||||
}
|
||||
|
||||
bool Framebuffer::readDisallowedByMultiview() const
|
||||
{
|
||||
return (mState.getMultiviewLayout() != GL_NONE && mState.getNumViews() > 1) ||
|
||||
mState.getMultiviewLayout() == GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE;
|
||||
return (mState.isMultiview() && mState.getNumViews() > 1);
|
||||
}
|
||||
|
||||
angle::Result Framebuffer::ensureClearAttachmentsInitialized(const Context *context,
|
||||
|
|
|
@ -95,7 +95,7 @@ class FramebufferState final : angle::NonCopyable
|
|||
bool hasDepth() const;
|
||||
bool hasStencil() const;
|
||||
|
||||
GLenum getMultiviewLayout() const;
|
||||
bool isMultiview() const;
|
||||
|
||||
ANGLE_INLINE GLsizei getNumViews() const
|
||||
{
|
||||
|
@ -107,7 +107,6 @@ class FramebufferState final : angle::NonCopyable
|
|||
return attachment->getNumViews();
|
||||
}
|
||||
|
||||
const std::vector<Offset> *getViewportOffsets() const;
|
||||
GLint getBaseViewIndex() const;
|
||||
|
||||
GLuint id() const { return mId; }
|
||||
|
@ -175,20 +174,13 @@ class Framebuffer final : public angle::ObserverInterface,
|
|||
GLenum binding,
|
||||
const ImageIndex &textureIndex,
|
||||
FramebufferAttachmentObject *resource);
|
||||
void setAttachmentMultiviewLayered(const Context *context,
|
||||
GLenum type,
|
||||
GLenum binding,
|
||||
const ImageIndex &textureIndex,
|
||||
FramebufferAttachmentObject *resource,
|
||||
GLsizei numViews,
|
||||
GLint baseViewIndex);
|
||||
void setAttachmentMultiviewSideBySide(const Context *context,
|
||||
GLenum type,
|
||||
GLenum binding,
|
||||
const ImageIndex &textureIndex,
|
||||
FramebufferAttachmentObject *resource,
|
||||
GLsizei numViews,
|
||||
const GLint *viewportOffsets);
|
||||
void setAttachmentMultiview(const Context *context,
|
||||
GLenum type,
|
||||
GLenum binding,
|
||||
const ImageIndex &textureIndex,
|
||||
FramebufferAttachmentObject *resource,
|
||||
GLsizei numViews,
|
||||
GLint baseViewIndex);
|
||||
void resetAttachment(const Context *context, GLenum binding);
|
||||
|
||||
bool detachTexture(const Context *context, GLuint texture);
|
||||
|
@ -206,11 +198,10 @@ class Framebuffer final : public angle::ObserverInterface,
|
|||
const FramebufferAttachment *getFirstNonNullAttachment() const;
|
||||
|
||||
const FramebufferAttachment *getAttachment(const Context *context, GLenum attachment) const;
|
||||
GLenum getMultiviewLayout() const;
|
||||
bool isMultiview() const;
|
||||
bool readDisallowedByMultiview() const;
|
||||
GLsizei getNumViews() const;
|
||||
GLint getBaseViewIndex() const;
|
||||
const std::vector<Offset> *getViewportOffsets() const;
|
||||
|
||||
size_t getDrawbufferStateCount() const;
|
||||
GLenum getDrawBufferState(size_t drawBuffer) const;
|
||||
|
@ -379,13 +370,11 @@ class Framebuffer final : public angle::ObserverInterface,
|
|||
FramebufferAttachmentObject *resource,
|
||||
GLsizei numViews,
|
||||
GLuint baseViewIndex,
|
||||
GLenum multiviewLayout,
|
||||
const GLint *viewportOffsets);
|
||||
bool isMultiview);
|
||||
void commitWebGL1DepthStencilIfConsistent(const Context *context,
|
||||
GLsizei numViews,
|
||||
GLuint baseViewIndex,
|
||||
GLenum multiviewLayout,
|
||||
const GLint *viewportOffsets);
|
||||
bool isMultiview);
|
||||
void setAttachmentImpl(const Context *context,
|
||||
GLenum type,
|
||||
GLenum binding,
|
||||
|
@ -393,8 +382,7 @@ class Framebuffer final : public angle::ObserverInterface,
|
|||
FramebufferAttachmentObject *resource,
|
||||
GLsizei numViews,
|
||||
GLuint baseViewIndex,
|
||||
GLenum multiviewLayout,
|
||||
const GLint *viewportOffsets);
|
||||
bool isMultiview);
|
||||
void updateAttachment(const Context *context,
|
||||
FramebufferAttachment *attachment,
|
||||
size_t dirtyBit,
|
||||
|
@ -405,8 +393,7 @@ class Framebuffer final : public angle::ObserverInterface,
|
|||
FramebufferAttachmentObject *resource,
|
||||
GLsizei numViews,
|
||||
GLuint baseViewIndex,
|
||||
GLenum multiviewLayout,
|
||||
const GLint *viewportOffsets);
|
||||
bool isMultiview);
|
||||
|
||||
void markDrawAttachmentsInitialized(bool color, bool depth, bool stencil);
|
||||
void markBufferInitialized(GLenum bufferType, GLint bufferIndex);
|
||||
|
|
|
@ -22,36 +22,10 @@
|
|||
namespace gl
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
std::vector<Offset> TransformViewportOffsetArrayToVectorOfOffsets(const GLint *viewportOffsets,
|
||||
GLsizei numViews)
|
||||
{
|
||||
const size_t numViewsAsSizeT = static_cast<size_t>(numViews);
|
||||
std::vector<Offset> offsetVector;
|
||||
offsetVector.reserve(numViewsAsSizeT);
|
||||
for (size_t i = 0u; i < numViewsAsSizeT; ++i)
|
||||
{
|
||||
offsetVector.emplace_back(Offset(viewportOffsets[i * 2u], viewportOffsets[i * 2u + 1u], 0));
|
||||
}
|
||||
return offsetVector;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
////// FramebufferAttachment::Target Implementation //////
|
||||
|
||||
const GLsizei FramebufferAttachment::kDefaultNumViews = 1;
|
||||
const GLenum FramebufferAttachment::kDefaultMultiviewLayout = GL_NONE;
|
||||
const GLint FramebufferAttachment::kDefaultBaseViewIndex = 0;
|
||||
const GLint FramebufferAttachment::kDefaultViewportOffsets[2] = {0};
|
||||
|
||||
std::vector<Offset> FramebufferAttachment::GetDefaultViewportOffsetVector()
|
||||
{
|
||||
return TransformViewportOffsetArrayToVectorOfOffsets(
|
||||
FramebufferAttachment::kDefaultViewportOffsets, FramebufferAttachment::kDefaultNumViews);
|
||||
}
|
||||
const GLsizei FramebufferAttachment::kDefaultNumViews = 1;
|
||||
const GLint FramebufferAttachment::kDefaultBaseViewIndex = 0;
|
||||
|
||||
FramebufferAttachment::Target::Target() : mBinding(GL_NONE), mTextureIndex() {}
|
||||
|
||||
|
@ -76,9 +50,8 @@ FramebufferAttachment::FramebufferAttachment()
|
|||
: mType(GL_NONE),
|
||||
mResource(nullptr),
|
||||
mNumViews(kDefaultNumViews),
|
||||
mMultiviewLayout(kDefaultMultiviewLayout),
|
||||
mBaseViewIndex(kDefaultBaseViewIndex),
|
||||
mViewportOffsets(GetDefaultViewportOffsetVector())
|
||||
mIsMultiview(false),
|
||||
mBaseViewIndex(kDefaultBaseViewIndex)
|
||||
{}
|
||||
|
||||
FramebufferAttachment::FramebufferAttachment(const Context *context,
|
||||
|
@ -89,7 +62,7 @@ FramebufferAttachment::FramebufferAttachment(const Context *context,
|
|||
: mResource(nullptr)
|
||||
{
|
||||
attach(context, type, binding, textureIndex, resource, kDefaultNumViews, kDefaultBaseViewIndex,
|
||||
kDefaultMultiviewLayout, kDefaultViewportOffsets);
|
||||
false);
|
||||
}
|
||||
|
||||
FramebufferAttachment::FramebufferAttachment(FramebufferAttachment &&other)
|
||||
|
@ -104,9 +77,8 @@ FramebufferAttachment &FramebufferAttachment::operator=(FramebufferAttachment &&
|
|||
std::swap(mTarget, other.mTarget);
|
||||
std::swap(mResource, other.mResource);
|
||||
std::swap(mNumViews, other.mNumViews);
|
||||
std::swap(mMultiviewLayout, other.mMultiviewLayout);
|
||||
std::swap(mIsMultiview, other.mIsMultiview);
|
||||
std::swap(mBaseViewIndex, other.mBaseViewIndex);
|
||||
std::swap(mViewportOffsets, other.mViewportOffsets);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -123,10 +95,9 @@ void FramebufferAttachment::detach(const Context *context)
|
|||
mResource->onDetach(context);
|
||||
mResource = nullptr;
|
||||
}
|
||||
mNumViews = kDefaultNumViews;
|
||||
mMultiviewLayout = kDefaultMultiviewLayout;
|
||||
mBaseViewIndex = kDefaultBaseViewIndex;
|
||||
mViewportOffsets = GetDefaultViewportOffsetVector();
|
||||
mNumViews = kDefaultNumViews;
|
||||
mIsMultiview = false;
|
||||
mBaseViewIndex = kDefaultBaseViewIndex;
|
||||
|
||||
// not technically necessary, could omit for performance
|
||||
mTarget = Target();
|
||||
|
@ -139,8 +110,7 @@ void FramebufferAttachment::attach(const Context *context,
|
|||
FramebufferAttachmentObject *resource,
|
||||
GLsizei numViews,
|
||||
GLuint baseViewIndex,
|
||||
GLenum multiviewLayout,
|
||||
const GLint *viewportOffsets)
|
||||
bool isMultiview)
|
||||
{
|
||||
if (resource == nullptr)
|
||||
{
|
||||
|
@ -148,19 +118,11 @@ void FramebufferAttachment::attach(const Context *context,
|
|||
return;
|
||||
}
|
||||
|
||||
mType = type;
|
||||
mTarget = Target(binding, textureIndex);
|
||||
mNumViews = numViews;
|
||||
mBaseViewIndex = baseViewIndex;
|
||||
mMultiviewLayout = multiviewLayout;
|
||||
if (multiviewLayout == GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE)
|
||||
{
|
||||
mViewportOffsets = TransformViewportOffsetArrayToVectorOfOffsets(viewportOffsets, numViews);
|
||||
}
|
||||
else
|
||||
{
|
||||
mViewportOffsets = GetDefaultViewportOffsetVector();
|
||||
}
|
||||
mType = type;
|
||||
mTarget = Target(binding, textureIndex);
|
||||
mNumViews = numViews;
|
||||
mBaseViewIndex = baseViewIndex;
|
||||
mIsMultiview = isMultiview;
|
||||
resource->onAttach(context);
|
||||
|
||||
if (mResource != nullptr)
|
||||
|
@ -249,9 +211,9 @@ bool FramebufferAttachment::isLayered() const
|
|||
return mTarget.textureIndex().isLayered();
|
||||
}
|
||||
|
||||
GLenum FramebufferAttachment::getMultiviewLayout() const
|
||||
bool FramebufferAttachment::isMultiview() const
|
||||
{
|
||||
return mMultiviewLayout;
|
||||
return mIsMultiview;
|
||||
}
|
||||
|
||||
GLint FramebufferAttachment::getBaseViewIndex() const
|
||||
|
@ -259,11 +221,6 @@ GLint FramebufferAttachment::getBaseViewIndex() const
|
|||
return mBaseViewIndex;
|
||||
}
|
||||
|
||||
const std::vector<Offset> &FramebufferAttachment::getMultiviewViewportOffsets() const
|
||||
{
|
||||
return mViewportOffsets;
|
||||
}
|
||||
|
||||
Texture *FramebufferAttachment::getTexture() const
|
||||
{
|
||||
return rx::GetAs<Texture>(mResource);
|
||||
|
@ -287,8 +244,7 @@ FramebufferAttachmentObject *FramebufferAttachment::getResource() const
|
|||
bool FramebufferAttachment::operator==(const FramebufferAttachment &other) const
|
||||
{
|
||||
if (mResource != other.mResource || mType != other.mType || mNumViews != other.mNumViews ||
|
||||
mMultiviewLayout != other.mMultiviewLayout || mBaseViewIndex != other.mBaseViewIndex ||
|
||||
mViewportOffsets != other.mViewportOffsets)
|
||||
mIsMultiview != other.mIsMultiview || mBaseViewIndex != other.mBaseViewIndex)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -79,8 +79,7 @@ class FramebufferAttachment final
|
|||
FramebufferAttachmentObject *resource,
|
||||
GLsizei numViews,
|
||||
GLuint baseViewIndex,
|
||||
GLenum multiviewLayout,
|
||||
const GLint *viewportOffsets);
|
||||
bool isMultiview);
|
||||
|
||||
// Helper methods
|
||||
GLuint getRedSize() const;
|
||||
|
@ -113,9 +112,8 @@ class FramebufferAttachment final
|
|||
|
||||
GLsizei getNumViews() const { return mNumViews; }
|
||||
|
||||
GLenum getMultiviewLayout() const;
|
||||
bool isMultiview() const;
|
||||
GLint getBaseViewIndex() const;
|
||||
const std::vector<Offset> &getMultiviewViewportOffsets() const;
|
||||
|
||||
// The size of the underlying resource the attachment points to. The 'depth' value will
|
||||
// correspond to a 3D texture depth or the layer count of a 2D array texture. For Surfaces and
|
||||
|
@ -148,11 +146,8 @@ class FramebufferAttachment final
|
|||
bool operator==(const FramebufferAttachment &other) const;
|
||||
bool operator!=(const FramebufferAttachment &other) const;
|
||||
|
||||
static std::vector<Offset> GetDefaultViewportOffsetVector();
|
||||
static const GLsizei kDefaultNumViews;
|
||||
static const GLenum kDefaultMultiviewLayout;
|
||||
static const GLint kDefaultBaseViewIndex;
|
||||
static const GLint kDefaultViewportOffsets[2];
|
||||
|
||||
private:
|
||||
angle::Result getRenderTargetImpl(const Context *context,
|
||||
|
@ -184,9 +179,8 @@ class FramebufferAttachment final
|
|||
Target mTarget;
|
||||
FramebufferAttachmentObject *mResource;
|
||||
GLsizei mNumViews;
|
||||
GLenum mMultiviewLayout;
|
||||
bool mIsMultiview;
|
||||
GLint mBaseViewIndex;
|
||||
std::vector<Offset> mViewportOffsets;
|
||||
};
|
||||
|
||||
// A base class for objects that FBO Attachments may point to.
|
||||
|
|
|
@ -172,7 +172,7 @@ const std::string &VertexArray::getLabel() const
|
|||
|
||||
bool VertexArray::detachBuffer(const Context *context, GLuint bufferName)
|
||||
{
|
||||
bool isBound = context->isCurrentVertexArray(this);
|
||||
bool isBound = context->isCurrentVertexArray(this);
|
||||
bool anyBufferDetached = false;
|
||||
for (size_t bindingIndex = 0; bindingIndex < gl::MAX_VERTEX_ATTRIB_BINDINGS; ++bindingIndex)
|
||||
{
|
||||
|
|
|
@ -1077,29 +1077,14 @@ void QueryFramebufferAttachmentParameteriv(const Context *context,
|
|||
*params = attachmentObject->layer();
|
||||
break;
|
||||
|
||||
case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_ANGLE:
|
||||
case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_OVR:
|
||||
*params = attachmentObject->getNumViews();
|
||||
break;
|
||||
|
||||
case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_MULTIVIEW_LAYOUT_ANGLE:
|
||||
*params = static_cast<GLint>(attachmentObject->getMultiviewLayout());
|
||||
break;
|
||||
|
||||
case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_BASE_VIEW_INDEX_ANGLE:
|
||||
case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_BASE_VIEW_INDEX_OVR:
|
||||
*params = attachmentObject->getBaseViewIndex();
|
||||
break;
|
||||
|
||||
case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_VIEWPORT_OFFSETS_ANGLE:
|
||||
{
|
||||
const std::vector<Offset> &offsets = attachmentObject->getMultiviewViewportOffsets();
|
||||
for (size_t i = 0u; i < offsets.size(); ++i)
|
||||
{
|
||||
params[i * 2u] = offsets[i].x;
|
||||
params[i * 2u + 1u] = offsets[i].y;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case GL_FRAMEBUFFER_ATTACHMENT_LAYERED_EXT:
|
||||
*params = attachmentObject->isLayered();
|
||||
break;
|
||||
|
|
|
@ -52,7 +52,7 @@ ShaderD3D::ShaderD3D(const gl::ShaderState &data,
|
|||
{
|
||||
mAdditionalOptions |= SH_SKIP_D3D_CONSTANT_REGISTER_ZERO;
|
||||
}
|
||||
if (extensions.multiview)
|
||||
if (extensions.multiview2)
|
||||
{
|
||||
mAdditionalOptions |= SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW;
|
||||
}
|
||||
|
|
|
@ -105,18 +105,6 @@ bool UpdateDataCache(RtvDsvClearInfo<T> *dataCache,
|
|||
return cacheDirty;
|
||||
}
|
||||
|
||||
bool AllOffsetsAreNonNegative(const std::vector<gl::Offset> &viewportOffsets)
|
||||
{
|
||||
for (size_t i = 0u; i < viewportOffsets.size(); ++i)
|
||||
{
|
||||
const auto &offset = viewportOffsets[i];
|
||||
if (offset.x < 0 || offset.y < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
#define CLEARPS(Index) \
|
||||
|
@ -431,65 +419,39 @@ angle::Result Clear11::clearFramebuffer(const gl::Context *context,
|
|||
framebufferSize = colorAttachment->getSize();
|
||||
}
|
||||
|
||||
const bool isSideBySideFBO =
|
||||
(fboData.getMultiviewLayout() == GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE);
|
||||
bool needScissoredClear = false;
|
||||
std::vector<D3D11_RECT> scissorRects;
|
||||
D3D11_RECT scissorRect;
|
||||
if (clearParams.scissorEnabled)
|
||||
{
|
||||
const std::vector<gl::Offset> *viewportOffsets = fboData.getViewportOffsets();
|
||||
ASSERT(viewportOffsets != nullptr);
|
||||
ASSERT(AllOffsetsAreNonNegative(*fboData.getViewportOffsets()));
|
||||
|
||||
if (clearParams.scissor.x >= framebufferSize.width ||
|
||||
clearParams.scissor.y >= framebufferSize.height || clearParams.scissor.width == 0 ||
|
||||
clearParams.scissor.height == 0)
|
||||
{
|
||||
// The check assumes that the viewport offsets are not negative as according to the
|
||||
// ANGLE_multiview spec.
|
||||
// OVR_multiview2 spec.
|
||||
// Scissor rect is outside the renderbuffer or is an empty rect.
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
|
||||
if (isSideBySideFBO)
|
||||
if (clearParams.scissor.x + clearParams.scissor.width <= 0 ||
|
||||
clearParams.scissor.y + clearParams.scissor.height <= 0)
|
||||
{
|
||||
// We always have to do a scissor clear for side-by-side framebuffers.
|
||||
needScissoredClear = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Because the viewport offsets can generate scissor rectangles within the framebuffer's
|
||||
// bounds, we can do this check only for non-side-by-side framebuffers.
|
||||
if (clearParams.scissor.x + clearParams.scissor.width <= 0 ||
|
||||
clearParams.scissor.y + clearParams.scissor.height <= 0)
|
||||
{
|
||||
// Scissor rect is outside the renderbuffer.
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
needScissoredClear =
|
||||
clearParams.scissor.x > 0 || clearParams.scissor.y > 0 ||
|
||||
clearParams.scissor.x + clearParams.scissor.width < framebufferSize.width ||
|
||||
clearParams.scissor.y + clearParams.scissor.height < framebufferSize.height;
|
||||
// Scissor rect is outside the renderbuffer.
|
||||
return angle::Result::Continue;
|
||||
}
|
||||
needScissoredClear =
|
||||
clearParams.scissor.x > 0 || clearParams.scissor.y > 0 ||
|
||||
clearParams.scissor.x + clearParams.scissor.width < framebufferSize.width ||
|
||||
clearParams.scissor.y + clearParams.scissor.height < framebufferSize.height;
|
||||
|
||||
if (needScissoredClear)
|
||||
{
|
||||
// Apply viewport offsets to compute the final scissor rectangles. This is valid also
|
||||
// for non-side-by-side framebuffers, because the default viewport offset is {0,0}.
|
||||
const size_t numViews = viewportOffsets->size();
|
||||
scissorRects.reserve(numViews);
|
||||
for (size_t i = 0u; i < numViews; ++i)
|
||||
{
|
||||
const gl::Offset &offset = (*viewportOffsets)[i];
|
||||
D3D11_RECT rect;
|
||||
int x = clearParams.scissor.x + offset.x;
|
||||
int y = clearParams.scissor.y + offset.y;
|
||||
rect.left = x;
|
||||
rect.right = x + clearParams.scissor.width;
|
||||
rect.top = y;
|
||||
rect.bottom = y + clearParams.scissor.height;
|
||||
scissorRects.emplace_back(rect);
|
||||
}
|
||||
// Apply viewport offsets to compute the final scissor rectangles.
|
||||
// Even in multiview all layers share the same viewport and scissor.
|
||||
scissorRect.left = clearParams.scissor.x;
|
||||
scissorRect.right = scissorRect.left + clearParams.scissor.width;
|
||||
scissorRect.top = clearParams.scissor.y;
|
||||
scissorRect.bottom = scissorRect.top + clearParams.scissor.height;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -588,15 +550,10 @@ angle::Result Clear11::clearFramebuffer(const gl::Context *context,
|
|||
{
|
||||
// We shouldn't reach here if deviceContext1 is unavailable.
|
||||
ASSERT(deviceContext1);
|
||||
// There must be at least one scissor rectangle.
|
||||
ASSERT(!scissorRects.empty());
|
||||
deviceContext1->ClearView(framebufferRTV.get(), clearValues, scissorRects.data(),
|
||||
static_cast<UINT>(scissorRects.size()));
|
||||
deviceContext1->ClearView(framebufferRTV.get(), clearValues, &scissorRect, 1);
|
||||
if (mRenderer->getWorkarounds().callClearTwice)
|
||||
{
|
||||
deviceContext1->ClearView(framebufferRTV.get(), clearValues,
|
||||
scissorRects.data(),
|
||||
static_cast<UINT>(scissorRects.size()));
|
||||
deviceContext1->ClearView(framebufferRTV.get(), clearValues, &scissorRect, 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -770,8 +727,7 @@ angle::Result Clear11::clearFramebuffer(const gl::Context *context,
|
|||
const d3d11::GeometryShader *gs = nullptr;
|
||||
const d3d11::InputLayout *il = nullptr;
|
||||
const d3d11::PixelShader *ps = nullptr;
|
||||
const bool hasLayeredLayout =
|
||||
(fboData.getMultiviewLayout() == GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE);
|
||||
const bool hasLayeredLayout = (fboData.isMultiview());
|
||||
ANGLE_TRY(mShaderManager.getShadersAndLayout(context, mRenderer, clearParams.colorType, numRtvs,
|
||||
hasLayeredLayout, &il, &vs, &gs, &ps));
|
||||
|
||||
|
@ -798,26 +754,19 @@ angle::Result Clear11::clearFramebuffer(const gl::Context *context,
|
|||
// Apply render targets
|
||||
stateManager->setRenderTargets(&rtvs[0], numRtvs, dsv);
|
||||
|
||||
// If scissors are necessary to be applied, then the number of clears is the number of scissor
|
||||
// rects. If no scissors are necessary, then a single full-size clear is enough.
|
||||
size_t necessaryNumClears = needScissoredClear ? scissorRects.size() : 1u;
|
||||
for (size_t i = 0u; i < necessaryNumClears; ++i)
|
||||
if (needScissoredClear)
|
||||
{
|
||||
if (needScissoredClear)
|
||||
{
|
||||
ASSERT(i < scissorRects.size());
|
||||
stateManager->setScissorRectD3D(scissorRects[i]);
|
||||
}
|
||||
// Draw the fullscreen quad.
|
||||
if (!hasLayeredLayout || isSideBySideFBO)
|
||||
{
|
||||
deviceContext->Draw(6, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(hasLayeredLayout);
|
||||
deviceContext->DrawInstanced(6, static_cast<UINT>(fboData.getNumViews()), 0, 0);
|
||||
}
|
||||
stateManager->setScissorRectD3D(scissorRect);
|
||||
}
|
||||
// Draw the fullscreen quad.
|
||||
if (!hasLayeredLayout)
|
||||
{
|
||||
deviceContext->Draw(6, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(hasLayeredLayout);
|
||||
deviceContext->DrawInstanced(6, static_cast<UINT>(fboData.getNumViews()), 0, 0);
|
||||
}
|
||||
|
||||
return angle::Result::Continue;
|
||||
|
|
|
@ -1138,7 +1138,7 @@ void StateManager11::syncState(const gl::Context *context, const gl::State::Dirt
|
|||
invalidateProgramAtomicCounterBuffers();
|
||||
invalidateProgramShaderStorageBuffers();
|
||||
invalidateDriverUniforms();
|
||||
// If ANGLE_multiview is enabled, the attribute divisor has to be updated for each
|
||||
// If OVR_multiview2 is enabled, the attribute divisor has to be updated for each
|
||||
// binding. When using compute, there could be no vertex array.
|
||||
if (mIsMultiviewEnabled && mVertexArray11)
|
||||
{
|
||||
|
@ -1174,37 +1174,12 @@ void StateManager11::handleMultiviewDrawFramebufferChange(const gl::Context *con
|
|||
const gl::Framebuffer *drawFramebuffer = glState.getDrawFramebuffer();
|
||||
ASSERT(drawFramebuffer != nullptr);
|
||||
|
||||
// Update viewport offsets.
|
||||
const std::vector<gl::Offset> *attachmentViewportOffsets =
|
||||
drawFramebuffer->getViewportOffsets();
|
||||
const std::vector<gl::Offset> &viewportOffsets =
|
||||
attachmentViewportOffsets != nullptr
|
||||
? *attachmentViewportOffsets
|
||||
: gl::FramebufferAttachment::GetDefaultViewportOffsetVector();
|
||||
if (mViewportOffsets != viewportOffsets)
|
||||
if (drawFramebuffer->isMultiview())
|
||||
{
|
||||
mViewportOffsets = viewportOffsets;
|
||||
|
||||
// Because new viewport offsets are to be applied, we have to mark the internal viewport and
|
||||
// scissor state as dirty.
|
||||
invalidateViewport(context);
|
||||
mInternalDirtyBits.set(DIRTY_BIT_SCISSOR_STATE);
|
||||
}
|
||||
switch (drawFramebuffer->getMultiviewLayout())
|
||||
{
|
||||
case GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE:
|
||||
mShaderConstants.setMultiviewWriteToViewportIndex(1.0f);
|
||||
break;
|
||||
case GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE:
|
||||
// Because the base view index is applied as an offset to the 2D texture array when the
|
||||
// RTV is created, we just have to pass a boolean to select which code path is to be
|
||||
// used.
|
||||
mShaderConstants.setMultiviewWriteToViewportIndex(0.0f);
|
||||
break;
|
||||
default:
|
||||
// There is no need to update the value in the constant buffer if the active framebuffer
|
||||
// object does not have a multiview layout.
|
||||
break;
|
||||
// Because the base view index is applied as an offset to the 2D texture array when the
|
||||
// RTV is created, we just have to pass a boolean to select which code path is to be
|
||||
// used.
|
||||
mShaderConstants.setMultiviewWriteToViewportIndex(0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1368,19 +1343,14 @@ void StateManager11::syncScissorRectangle(const gl::Rectangle &scissor, bool ena
|
|||
|
||||
if (enabled)
|
||||
{
|
||||
std::array<D3D11_RECT, gl::IMPLEMENTATION_ANGLE_MULTIVIEW_MAX_VIEWS> rectangles;
|
||||
const UINT numRectangles = static_cast<UINT>(mViewportOffsets.size());
|
||||
for (UINT i = 0u; i < numRectangles; ++i)
|
||||
{
|
||||
D3D11_RECT &rect = rectangles[i];
|
||||
int x = scissor.x + mViewportOffsets[i].x;
|
||||
int y = modifiedScissorY + mViewportOffsets[i].y;
|
||||
rect.left = std::max(0, x);
|
||||
rect.top = std::max(0, y);
|
||||
rect.right = x + std::max(0, scissor.width);
|
||||
rect.bottom = y + std::max(0, scissor.height);
|
||||
}
|
||||
mRenderer->getDeviceContext()->RSSetScissorRects(numRectangles, rectangles.data());
|
||||
D3D11_RECT rect;
|
||||
int x = scissor.x;
|
||||
int y = modifiedScissorY;
|
||||
rect.left = std::max(0, x);
|
||||
rect.top = std::max(0, y);
|
||||
rect.right = x + std::max(0, scissor.width);
|
||||
rect.bottom = y + std::max(0, scissor.height);
|
||||
mRenderer->getDeviceContext()->RSSetScissorRects(1, &rect);
|
||||
}
|
||||
|
||||
mCurScissorRect = scissor;
|
||||
|
@ -1412,65 +1382,58 @@ void StateManager11::syncViewport(const gl::Context *context)
|
|||
}
|
||||
|
||||
const auto &viewport = glState.getViewport();
|
||||
std::array<D3D11_VIEWPORT, gl::IMPLEMENTATION_ANGLE_MULTIVIEW_MAX_VIEWS> dxViewports;
|
||||
const UINT numRectangles = static_cast<UINT>(mViewportOffsets.size());
|
||||
|
||||
int dxViewportTopLeftX = 0;
|
||||
int dxViewportTopLeftY = 0;
|
||||
int dxViewportWidth = 0;
|
||||
int dxViewportHeight = 0;
|
||||
|
||||
for (UINT i = 0u; i < numRectangles; ++i)
|
||||
dxViewportTopLeftX = gl::clamp(viewport.x, dxMinViewportBoundsX, dxMaxViewportBoundsX);
|
||||
dxViewportTopLeftY = gl::clamp(viewport.y, dxMinViewportBoundsY, dxMaxViewportBoundsY);
|
||||
dxViewportWidth = gl::clamp(viewport.width, 0, dxMaxViewportBoundsX - dxViewportTopLeftX);
|
||||
dxViewportHeight = gl::clamp(viewport.height, 0, dxMaxViewportBoundsY - dxViewportTopLeftY);
|
||||
|
||||
D3D11_VIEWPORT dxViewport;
|
||||
dxViewport.TopLeftX = static_cast<float>(dxViewportTopLeftX);
|
||||
if (mCurPresentPathFastEnabled)
|
||||
{
|
||||
dxViewportTopLeftX = gl::clamp(viewport.x + mViewportOffsets[i].x, dxMinViewportBoundsX,
|
||||
dxMaxViewportBoundsX);
|
||||
dxViewportTopLeftY = gl::clamp(viewport.y + mViewportOffsets[i].y, dxMinViewportBoundsY,
|
||||
dxMaxViewportBoundsY);
|
||||
dxViewportWidth = gl::clamp(viewport.width, 0, dxMaxViewportBoundsX - dxViewportTopLeftX);
|
||||
dxViewportHeight = gl::clamp(viewport.height, 0, dxMaxViewportBoundsY - dxViewportTopLeftY);
|
||||
|
||||
D3D11_VIEWPORT &dxViewport = dxViewports[i];
|
||||
dxViewport.TopLeftX = static_cast<float>(dxViewportTopLeftX);
|
||||
if (mCurPresentPathFastEnabled)
|
||||
{
|
||||
// When present path fast is active and we're rendering to framebuffer 0, we must invert
|
||||
// the viewport in Y-axis.
|
||||
// NOTE: We delay the inversion until right before the call to RSSetViewports, and leave
|
||||
// dxViewportTopLeftY unchanged. This allows us to calculate viewAdjust below using the
|
||||
// unaltered dxViewportTopLeftY value.
|
||||
dxViewport.TopLeftY = static_cast<float>(mCurPresentPathFastColorBufferHeight -
|
||||
dxViewportTopLeftY - dxViewportHeight);
|
||||
}
|
||||
else
|
||||
{
|
||||
dxViewport.TopLeftY = static_cast<float>(dxViewportTopLeftY);
|
||||
}
|
||||
|
||||
// The es 3.1 spec section 9.2 states that, "If there are no attachments, rendering
|
||||
// will be limited to a rectangle having a lower left of (0, 0) and an upper right of
|
||||
// (width, height), where width and height are the framebuffer object's default width
|
||||
// and height." See http://anglebug.com/1594
|
||||
// If the Framebuffer has no color attachment and the default width or height is smaller
|
||||
// than the current viewport, use the smaller of the two sizes.
|
||||
// If framebuffer default width or height is 0, the params should not set.
|
||||
if (!framebuffer->getFirstNonNullAttachment() &&
|
||||
(framebuffer->getDefaultWidth() || framebuffer->getDefaultHeight()))
|
||||
{
|
||||
dxViewport.Width =
|
||||
static_cast<GLfloat>(std::min(viewport.width, framebuffer->getDefaultWidth()));
|
||||
dxViewport.Height =
|
||||
static_cast<GLfloat>(std::min(viewport.height, framebuffer->getDefaultHeight()));
|
||||
}
|
||||
else
|
||||
{
|
||||
dxViewport.Width = static_cast<float>(dxViewportWidth);
|
||||
dxViewport.Height = static_cast<float>(dxViewportHeight);
|
||||
}
|
||||
dxViewport.MinDepth = actualZNear;
|
||||
dxViewport.MaxDepth = actualZFar;
|
||||
// When present path fast is active and we're rendering to framebuffer 0, we must invert
|
||||
// the viewport in Y-axis.
|
||||
// NOTE: We delay the inversion until right before the call to RSSetViewports, and leave
|
||||
// dxViewportTopLeftY unchanged. This allows us to calculate viewAdjust below using the
|
||||
// unaltered dxViewportTopLeftY value.
|
||||
dxViewport.TopLeftY = static_cast<float>(mCurPresentPathFastColorBufferHeight -
|
||||
dxViewportTopLeftY - dxViewportHeight);
|
||||
}
|
||||
else
|
||||
{
|
||||
dxViewport.TopLeftY = static_cast<float>(dxViewportTopLeftY);
|
||||
}
|
||||
|
||||
mRenderer->getDeviceContext()->RSSetViewports(numRectangles, dxViewports.data());
|
||||
// The es 3.1 spec section 9.2 states that, "If there are no attachments, rendering
|
||||
// will be limited to a rectangle having a lower left of (0, 0) and an upper right of
|
||||
// (width, height), where width and height are the framebuffer object's default width
|
||||
// and height." See http://anglebug.com/1594
|
||||
// If the Framebuffer has no color attachment and the default width or height is smaller
|
||||
// than the current viewport, use the smaller of the two sizes.
|
||||
// If framebuffer default width or height is 0, the params should not set.
|
||||
if (!framebuffer->getFirstNonNullAttachment() &&
|
||||
(framebuffer->getDefaultWidth() || framebuffer->getDefaultHeight()))
|
||||
{
|
||||
dxViewport.Width =
|
||||
static_cast<GLfloat>(std::min(viewport.width, framebuffer->getDefaultWidth()));
|
||||
dxViewport.Height =
|
||||
static_cast<GLfloat>(std::min(viewport.height, framebuffer->getDefaultHeight()));
|
||||
}
|
||||
else
|
||||
{
|
||||
dxViewport.Width = static_cast<float>(dxViewportWidth);
|
||||
dxViewport.Height = static_cast<float>(dxViewportHeight);
|
||||
}
|
||||
dxViewport.MinDepth = actualZNear;
|
||||
dxViewport.MaxDepth = actualZFar;
|
||||
|
||||
mRenderer->getDeviceContext()->RSSetViewports(1, &dxViewport);
|
||||
|
||||
mCurViewport = viewport;
|
||||
mCurNear = actualZNear;
|
||||
|
@ -1884,8 +1847,7 @@ angle::Result StateManager11::ensureInitialized(const gl::Context *context)
|
|||
|
||||
mShaderConstants.init(caps);
|
||||
|
||||
mIsMultiviewEnabled = extensions.multiview;
|
||||
mViewportOffsets.resize(1u);
|
||||
mIsMultiviewEnabled = extensions.multiview2;
|
||||
|
||||
ANGLE_TRY(mVertexDataManager.initialize(context));
|
||||
|
||||
|
|
|
@ -473,11 +473,6 @@ class StateManager11 final : angle::NonCopyable
|
|||
float mCurNear;
|
||||
float mCurFar;
|
||||
|
||||
// The viewport offsets are guaranteed to be updated whenever the gl::State::DirtyBits are
|
||||
// resolved and can be applied to the viewport and scissor whenever the internal viewport and
|
||||
// scissor bits are resolved.
|
||||
std::vector<gl::Offset> mViewportOffsets;
|
||||
|
||||
// Things needed in viewport state
|
||||
ShaderConstants11 mShaderConstants;
|
||||
|
||||
|
|
|
@ -1610,17 +1610,17 @@ void GenerateCaps(ID3D11Device *device,
|
|||
extensions->robustBufferAccessBehavior = true;
|
||||
extensions->blendMinMax = true;
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/direct3ddxgi/format-support-for-direct3d-11-0-feature-level-hardware
|
||||
extensions->floatBlend = true;
|
||||
extensions->framebufferBlit = GetFramebufferBlitSupport(featureLevel);
|
||||
extensions->framebufferMultisample = GetFramebufferMultisampleSupport(featureLevel);
|
||||
extensions->instancedArraysANGLE = GetInstancingSupport(featureLevel);
|
||||
extensions->instancedArraysEXT = GetInstancingSupport(featureLevel);
|
||||
extensions->packReverseRowOrder = true;
|
||||
extensions->standardDerivatives = GetDerivativeInstructionSupport(featureLevel);
|
||||
extensions->shaderTextureLOD = GetShaderTextureLODSupport(featureLevel);
|
||||
extensions->fragDepth = true;
|
||||
extensions->multiview = IsMultiviewSupported(featureLevel);
|
||||
if (extensions->multiview)
|
||||
extensions->floatBlend = true;
|
||||
extensions->framebufferBlit = GetFramebufferBlitSupport(featureLevel);
|
||||
extensions->framebufferMultisample = GetFramebufferMultisampleSupport(featureLevel);
|
||||
extensions->instancedArraysANGLE = GetInstancingSupport(featureLevel);
|
||||
extensions->instancedArraysEXT = GetInstancingSupport(featureLevel);
|
||||
extensions->packReverseRowOrder = true;
|
||||
extensions->standardDerivatives = GetDerivativeInstructionSupport(featureLevel);
|
||||
extensions->shaderTextureLOD = GetShaderTextureLODSupport(featureLevel);
|
||||
extensions->fragDepth = true;
|
||||
extensions->multiview2 = IsMultiviewSupported(featureLevel);
|
||||
if (extensions->multiview2)
|
||||
{
|
||||
extensions->maxViews =
|
||||
std::min(static_cast<GLuint>(gl::IMPLEMENTATION_ANGLE_MULTIVIEW_MAX_VIEWS),
|
||||
|
@ -1644,7 +1644,7 @@ void GenerateCaps(ID3D11Device *device,
|
|||
extensions->copyCompressedTexture = true;
|
||||
extensions->textureStorageMultisample2DArray = true;
|
||||
extensions->multiviewMultisample =
|
||||
(extensions->multiview && extensions->textureStorageMultisample2DArray);
|
||||
(extensions->multiview2 && extensions->textureStorageMultisample2DArray);
|
||||
extensions->copyTexture3d = true;
|
||||
extensions->textureBorderClamp = true;
|
||||
extensions->textureMultisample = true;
|
||||
|
|
|
@ -710,14 +710,14 @@ void GenerateCaps(IDirect3D9 *d3d9,
|
|||
extensions->robustBufferAccessBehavior = false;
|
||||
extensions->blendMinMax = true;
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/direct3ddxgi/format-support-for-direct3d-feature-level-9-1-hardware
|
||||
extensions->floatBlend = false;
|
||||
extensions->framebufferBlit = true;
|
||||
extensions->framebufferMultisample = true;
|
||||
extensions->instancedArraysANGLE = deviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0);
|
||||
extensions->floatBlend = false;
|
||||
extensions->framebufferBlit = true;
|
||||
extensions->framebufferMultisample = true;
|
||||
extensions->instancedArraysANGLE = deviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0);
|
||||
// D3D9 requires at least one attribute that has a divisor of 0, which isn't required by the EXT
|
||||
// extension
|
||||
extensions->instancedArraysEXT = false;
|
||||
extensions->packReverseRowOrder = true;
|
||||
extensions->instancedArraysEXT = false;
|
||||
extensions->packReverseRowOrder = true;
|
||||
extensions->standardDerivatives =
|
||||
(deviceCaps.PS20Caps.Caps & D3DPS20CAPS_GRADIENTINSTRUCTIONS) != 0;
|
||||
extensions->shaderTextureLOD = true;
|
||||
|
|
|
@ -1446,17 +1446,16 @@ bool ValidateBlitFramebufferParameters(Context *context,
|
|||
}
|
||||
}
|
||||
|
||||
// ANGLE_multiview, Revision 1:
|
||||
// OVR_multiview2:
|
||||
// Calling BlitFramebuffer will result in an INVALID_FRAMEBUFFER_OPERATION error if the
|
||||
// multi-view layout of the current draw framebuffer is not NONE, or if the multi-view layout of
|
||||
// the current read framebuffer is FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE or the number of
|
||||
// current draw framebuffer isMultiview() or the number of
|
||||
// views in the current read framebuffer is more than one.
|
||||
if (readFramebuffer->readDisallowedByMultiview())
|
||||
{
|
||||
context->validationError(GL_INVALID_FRAMEBUFFER_OPERATION, kBlitFromMultiview);
|
||||
return false;
|
||||
}
|
||||
if (drawFramebuffer->getMultiviewLayout() != GL_NONE)
|
||||
if (drawFramebuffer->isMultiview())
|
||||
{
|
||||
context->validationError(GL_INVALID_FRAMEBUFFER_OPERATION, kBlitToMultiview);
|
||||
return false;
|
||||
|
@ -2678,7 +2677,7 @@ const char *ValidateDrawStates(Context *context)
|
|||
return kTextureTypeConflict;
|
||||
}
|
||||
|
||||
if (extensions.multiview)
|
||||
if (extensions.multiview2)
|
||||
{
|
||||
const int programNumViews = program->usesMultiview() ? program->getNumViews() : 1;
|
||||
const int framebufferNumViews = framebuffer->getNumViews();
|
||||
|
@ -3826,11 +3825,9 @@ bool ValidateGetFramebufferAttachmentParameterivBase(Context *context,
|
|||
case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
|
||||
break;
|
||||
|
||||
case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_ANGLE:
|
||||
case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_MULTIVIEW_LAYOUT_ANGLE:
|
||||
case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_BASE_VIEW_INDEX_ANGLE:
|
||||
case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_VIEWPORT_OFFSETS_ANGLE:
|
||||
if (clientVersion < 3 || !context->getExtensions().multiview)
|
||||
case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_OVR:
|
||||
case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_BASE_VIEW_INDEX_OVR:
|
||||
if (clientVersion < 3 || !context->getExtensions().multiview2)
|
||||
{
|
||||
context->validationError(GL_INVALID_ENUM, kEnumNotSupported);
|
||||
return false;
|
||||
|
@ -4057,18 +4054,7 @@ bool ValidateGetFramebufferAttachmentParameterivBase(Context *context,
|
|||
|
||||
if (numParams)
|
||||
{
|
||||
if (pname == GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_VIEWPORT_OFFSETS_ANGLE)
|
||||
{
|
||||
// Only when the viewport offsets are queried we can have a varying number of output
|
||||
// parameters.
|
||||
const int numViews = attachmentObject ? attachmentObject->getNumViews() : 1;
|
||||
*numParams = numViews * 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
// For all other queries we can have only one output parameter.
|
||||
*numParams = 1;
|
||||
}
|
||||
*numParams = 1;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -5372,10 +5358,9 @@ bool ValidateReadPixelsBase(Context *context,
|
|||
return false;
|
||||
}
|
||||
|
||||
// ANGLE_multiview, Revision 1:
|
||||
// ReadPixels generates an INVALID_FRAMEBUFFER_OPERATION error if the multi-view layout of the
|
||||
// current read framebuffer is FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE or the number of views
|
||||
// in the current read framebuffer is more than one.
|
||||
// OVR_multiview2, Revision 1:
|
||||
// ReadPixels generates an INVALID_FRAMEBUFFER_OPERATION error if
|
||||
// the number of views in the current read framebuffer is more than one.
|
||||
if (framebuffer->readDisallowedByMultiview())
|
||||
{
|
||||
context->validationError(GL_INVALID_FRAMEBUFFER_OPERATION, kMultiviewReadFramebuffer);
|
||||
|
|
|
@ -2640,7 +2640,7 @@ bool ValidateClear(Context *context, GLbitfield mask)
|
|||
}
|
||||
}
|
||||
|
||||
if (extensions.multiview && extensions.disjointTimerQuery)
|
||||
if (extensions.multiview2 && extensions.disjointTimerQuery)
|
||||
{
|
||||
const State &state = context->getState();
|
||||
Framebuffer *framebuffer = state.getDrawFramebuffer();
|
||||
|
|
|
@ -36,7 +36,7 @@ bool ValidateFramebufferTextureMultiviewBaseANGLE(Context *context,
|
|||
GLint level,
|
||||
GLsizei numViews)
|
||||
{
|
||||
if (!context->getExtensions().multiview)
|
||||
if (!context->getExtensions().multiview2)
|
||||
{
|
||||
context->validationError(GL_INVALID_OPERATION, kMultiviewNotAvailable);
|
||||
return false;
|
||||
|
@ -3157,13 +3157,13 @@ bool ValidateMultiDrawElementsInstancedANGLE(Context *context,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool ValidateFramebufferTextureMultiviewLayeredANGLE(Context *context,
|
||||
GLenum target,
|
||||
GLenum attachment,
|
||||
GLuint texture,
|
||||
GLint level,
|
||||
GLint baseViewIndex,
|
||||
GLsizei numViews)
|
||||
bool ValidateFramebufferTextureMultiviewOVR(Context *context,
|
||||
GLenum target,
|
||||
GLenum attachment,
|
||||
GLuint texture,
|
||||
GLint level,
|
||||
GLint baseViewIndex,
|
||||
GLsizei numViews)
|
||||
{
|
||||
if (!ValidateFramebufferTextureMultiviewBaseANGLE(context, target, attachment, texture, level,
|
||||
numViews))
|
||||
|
@ -3219,53 +3219,6 @@ bool ValidateFramebufferTextureMultiviewLayeredANGLE(Context *context,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool ValidateFramebufferTextureMultiviewSideBySideANGLE(Context *context,
|
||||
GLenum target,
|
||||
GLenum attachment,
|
||||
GLuint texture,
|
||||
GLint level,
|
||||
GLsizei numViews,
|
||||
const GLint *viewportOffsets)
|
||||
{
|
||||
if (!ValidateFramebufferTextureMultiviewBaseANGLE(context, target, attachment, texture, level,
|
||||
numViews))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (texture != 0)
|
||||
{
|
||||
const GLsizei numViewportOffsetValues = numViews * 2;
|
||||
for (GLsizei i = 0; i < numViewportOffsetValues; ++i)
|
||||
{
|
||||
if (viewportOffsets[i] < 0)
|
||||
{
|
||||
context->validationError(GL_INVALID_VALUE, kNegativeOffset);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Texture *tex = context->getTexture(texture);
|
||||
ASSERT(tex);
|
||||
|
||||
switch (tex->getType())
|
||||
{
|
||||
case TextureType::_2D:
|
||||
break;
|
||||
default:
|
||||
context->validationError(GL_INVALID_OPERATION, kInvalidTextureType);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ValidateFramebufferTextureMultiviewLevelAndFormat(context, tex, level))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ValidateUniform1ui(Context *context, GLint location, GLuint v0)
|
||||
{
|
||||
return ValidateUniformES3(context, GL_UNSIGNED_INT, location, 1);
|
||||
|
|
|
@ -453,17 +453,6 @@ bool ValidateDrawIndirectBase(Context *context, PrimitiveMode mode, const void *
|
|||
return false;
|
||||
}
|
||||
|
||||
// ANGLE_multiview spec, revision 1:
|
||||
// An INVALID_OPERATION is generated by DrawArraysIndirect and DrawElementsIndirect if the
|
||||
// number of views in the draw framebuffer is greater than 1.
|
||||
const Framebuffer *drawFramebuffer = context->getState().getDrawFramebuffer();
|
||||
ASSERT(drawFramebuffer != nullptr);
|
||||
if (drawFramebuffer->getNumViews() > 1)
|
||||
{
|
||||
context->validationError(GL_INVALID_OPERATION, kMultiviewActive);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -109,22 +109,6 @@ bool ValidateMultiDrawElementsInstancedANGLE(Context *context,
|
|||
const GLsizei *instanceCounts,
|
||||
GLsizei drawcount);
|
||||
|
||||
// GL_ANGLE_multiview
|
||||
bool ValidateFramebufferTextureMultiviewLayeredANGLE(Context *context,
|
||||
GLenum target,
|
||||
GLenum attachment,
|
||||
GLuint texture,
|
||||
GLint level,
|
||||
GLint baseViewIndex,
|
||||
GLsizei numViews);
|
||||
bool ValidateFramebufferTextureMultiviewSideBySideANGLE(Context *context,
|
||||
GLenum target,
|
||||
GLenum attachment,
|
||||
GLuint texture,
|
||||
GLint level,
|
||||
GLsizei numViews,
|
||||
const GLint *viewportOffsets);
|
||||
|
||||
// GL_ANGLE_provoking_vertex
|
||||
bool ValidateProvokingVertexANGLE(Context *context, ProvokingVertex modePacked);
|
||||
|
||||
|
@ -1094,6 +1078,17 @@ bool ValidateBindVertexArrayOES(Context *context, GLuint array);
|
|||
bool ValidateDeleteVertexArraysOES(Context *context, GLsizei n, const GLuint *arrays);
|
||||
bool ValidateGenVertexArraysOES(Context *context, GLsizei n, GLuint *arrays);
|
||||
bool ValidateIsVertexArrayOES(Context *context, GLuint array);
|
||||
|
||||
// GL_OVR_multiview
|
||||
bool ValidateFramebufferTextureMultiviewOVR(Context *context,
|
||||
GLenum target,
|
||||
GLenum attachment,
|
||||
GLuint texture,
|
||||
GLint level,
|
||||
GLint baseViewIndex,
|
||||
GLsizei numViews);
|
||||
|
||||
// GL_OVR_multiview2
|
||||
} // namespace gl
|
||||
|
||||
#endif // LIBANGLE_VALIDATION_ESEXT_AUTOGEN_H_
|
||||
|
|
|
@ -180,8 +180,7 @@ enum class EntryPoint
|
|||
FramebufferTexture2DOES,
|
||||
FramebufferTextureEXT,
|
||||
FramebufferTextureLayer,
|
||||
FramebufferTextureMultiviewLayeredANGLE,
|
||||
FramebufferTextureMultiviewSideBySideANGLE,
|
||||
FramebufferTextureMultiviewOVR,
|
||||
FrontFace,
|
||||
Frustumf,
|
||||
Frustumx,
|
||||
|
|
|
@ -329,59 +329,6 @@ void GL_APIENTRY MultiDrawElementsInstancedANGLE(GLenum mode,
|
|||
}
|
||||
}
|
||||
|
||||
// GL_ANGLE_multiview
|
||||
void GL_APIENTRY FramebufferTextureMultiviewLayeredANGLE(GLenum target,
|
||||
GLenum attachment,
|
||||
GLuint texture,
|
||||
GLint level,
|
||||
GLint baseViewIndex,
|
||||
GLsizei numViews)
|
||||
{
|
||||
ANGLE_SCOPED_GLOBAL_LOCK();
|
||||
EVENT(
|
||||
"(GLenum target = 0x%X, GLenum attachment = 0x%X, GLuint texture = %u, GLint level = %d, "
|
||||
"GLint baseViewIndex = %d, GLsizei numViews = %d)",
|
||||
target, attachment, texture, level, baseViewIndex, numViews);
|
||||
|
||||
Context *context = GetValidGlobalContext();
|
||||
if (context)
|
||||
{
|
||||
if (context->skipValidation() ||
|
||||
ValidateFramebufferTextureMultiviewLayeredANGLE(context, target, attachment, texture,
|
||||
level, baseViewIndex, numViews))
|
||||
{
|
||||
context->framebufferTextureMultiviewLayered(target, attachment, texture, level,
|
||||
baseViewIndex, numViews);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GL_APIENTRY FramebufferTextureMultiviewSideBySideANGLE(GLenum target,
|
||||
GLenum attachment,
|
||||
GLuint texture,
|
||||
GLint level,
|
||||
GLsizei numViews,
|
||||
const GLint *viewportOffsets)
|
||||
{
|
||||
ANGLE_SCOPED_GLOBAL_LOCK();
|
||||
EVENT(
|
||||
"(GLenum target = 0x%X, GLenum attachment = 0x%X, GLuint texture = %u, GLint level = %d, "
|
||||
"GLsizei numViews = %d, const GLint * viewportOffsets = 0x%016" PRIxPTR ")",
|
||||
target, attachment, texture, level, numViews, (uintptr_t)viewportOffsets);
|
||||
|
||||
Context *context = GetValidGlobalContext();
|
||||
if (context)
|
||||
{
|
||||
if (context->skipValidation() ||
|
||||
ValidateFramebufferTextureMultiviewSideBySideANGLE(context, target, attachment, texture,
|
||||
level, numViews, viewportOffsets))
|
||||
{
|
||||
context->framebufferTextureMultiviewSideBySide(target, attachment, texture, level,
|
||||
numViews, viewportOffsets);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GL_ANGLE_provoking_vertex
|
||||
void GL_APIENTRY ProvokingVertexANGLE(GLenum mode)
|
||||
{
|
||||
|
@ -4779,6 +4726,35 @@ GLboolean GL_APIENTRY IsVertexArrayOES(GLuint array)
|
|||
return GetDefaultReturnValue<EntryPoint::IsVertexArrayOES, GLboolean>();
|
||||
}
|
||||
|
||||
// GL_OVR_multiview
|
||||
void GL_APIENTRY FramebufferTextureMultiviewOVR(GLenum target,
|
||||
GLenum attachment,
|
||||
GLuint texture,
|
||||
GLint level,
|
||||
GLint baseViewIndex,
|
||||
GLsizei numViews)
|
||||
{
|
||||
ANGLE_SCOPED_GLOBAL_LOCK();
|
||||
EVENT(
|
||||
"(GLenum target = 0x%X, GLenum attachment = 0x%X, GLuint texture = %u, GLint level = %d, "
|
||||
"GLint baseViewIndex = %d, GLsizei numViews = %d)",
|
||||
target, attachment, texture, level, baseViewIndex, numViews);
|
||||
|
||||
Context *context = GetValidGlobalContext();
|
||||
if (context)
|
||||
{
|
||||
if (context->skipValidation() ||
|
||||
ValidateFramebufferTextureMultiviewOVR(context, target, attachment, texture, level,
|
||||
baseViewIndex, numViews))
|
||||
{
|
||||
context->framebufferTextureMultiview(target, attachment, texture, level, baseViewIndex,
|
||||
numViews);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GL_OVR_multiview2
|
||||
|
||||
// EGL_ANGLE_explicit_context
|
||||
void GL_APIENTRY ActiveShaderProgramContextANGLE(GLeglContext ctx, GLuint pipeline, GLuint program)
|
||||
{
|
||||
|
@ -7714,6 +7690,34 @@ void GL_APIENTRY FramebufferTextureLayerContextANGLE(GLeglContext ctx,
|
|||
}
|
||||
}
|
||||
|
||||
void GL_APIENTRY FramebufferTextureMultiviewOVRContextANGLE(GLeglContext ctx,
|
||||
GLenum target,
|
||||
GLenum attachment,
|
||||
GLuint texture,
|
||||
GLint level,
|
||||
GLint baseViewIndex,
|
||||
GLsizei numViews)
|
||||
{
|
||||
ANGLE_SCOPED_GLOBAL_LOCK();
|
||||
EVENT(
|
||||
"(GLenum target = 0x%X, GLenum attachment = 0x%X, GLuint texture = %u, GLint level = %d, "
|
||||
"GLint baseViewIndex = %d, GLsizei numViews = %d)",
|
||||
target, attachment, texture, level, baseViewIndex, numViews);
|
||||
|
||||
Context *context = static_cast<gl::Context *>(ctx);
|
||||
if (context)
|
||||
{
|
||||
ASSERT(context == GetValidGlobalContext());
|
||||
if (context->skipValidation() ||
|
||||
ValidateFramebufferTextureMultiviewOVR(context, target, attachment, texture, level,
|
||||
baseViewIndex, numViews))
|
||||
{
|
||||
context->framebufferTextureMultiview(target, attachment, texture, level, baseViewIndex,
|
||||
numViews);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GL_APIENTRY FrontFaceContextANGLE(GLeglContext ctx, GLenum mode)
|
||||
{
|
||||
ANGLE_SCOPED_GLOBAL_LOCK();
|
||||
|
@ -17755,63 +17759,6 @@ void GL_APIENTRY GetQueryObjectui64vRobustANGLEContextANGLE(GLeglContext ctx,
|
|||
}
|
||||
}
|
||||
|
||||
void GL_APIENTRY FramebufferTextureMultiviewLayeredANGLEContextANGLE(GLeglContext ctx,
|
||||
GLenum target,
|
||||
GLenum attachment,
|
||||
GLuint texture,
|
||||
GLint level,
|
||||
GLint baseViewIndex,
|
||||
GLsizei numViews)
|
||||
{
|
||||
ANGLE_SCOPED_GLOBAL_LOCK();
|
||||
EVENT(
|
||||
"(GLenum target = 0x%X, GLenum attachment = 0x%X, GLuint texture = %u, GLint level = %d, "
|
||||
"GLint baseViewIndex = %d, GLsizei numViews = %d)",
|
||||
target, attachment, texture, level, baseViewIndex, numViews);
|
||||
|
||||
Context *context = static_cast<gl::Context *>(ctx);
|
||||
if (context)
|
||||
{
|
||||
ASSERT(context == GetValidGlobalContext());
|
||||
if (context->skipValidation() ||
|
||||
ValidateFramebufferTextureMultiviewLayeredANGLE(context, target, attachment, texture,
|
||||
level, baseViewIndex, numViews))
|
||||
{
|
||||
context->framebufferTextureMultiviewLayered(target, attachment, texture, level,
|
||||
baseViewIndex, numViews);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GL_APIENTRY
|
||||
FramebufferTextureMultiviewSideBySideANGLEContextANGLE(GLeglContext ctx,
|
||||
GLenum target,
|
||||
GLenum attachment,
|
||||
GLuint texture,
|
||||
GLint level,
|
||||
GLsizei numViews,
|
||||
const GLint *viewportOffsets)
|
||||
{
|
||||
ANGLE_SCOPED_GLOBAL_LOCK();
|
||||
EVENT(
|
||||
"(GLenum target = 0x%X, GLenum attachment = 0x%X, GLuint texture = %u, GLint level = %d, "
|
||||
"GLsizei numViews = %d, const GLint * viewportOffsets = 0x%016" PRIxPTR ")",
|
||||
target, attachment, texture, level, numViews, (uintptr_t)viewportOffsets);
|
||||
|
||||
Context *context = static_cast<gl::Context *>(ctx);
|
||||
if (context)
|
||||
{
|
||||
ASSERT(context == GetValidGlobalContext());
|
||||
if (context->skipValidation() ||
|
||||
ValidateFramebufferTextureMultiviewSideBySideANGLE(context, target, attachment, texture,
|
||||
level, numViews, viewportOffsets))
|
||||
{
|
||||
context->framebufferTextureMultiviewSideBySide(target, attachment, texture, level,
|
||||
numViews, viewportOffsets);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GL_APIENTRY CopyTexture3DANGLEContextANGLE(GLeglContext ctx,
|
||||
GLuint sourceId,
|
||||
GLint sourceLevel,
|
||||
|
|
|
@ -102,21 +102,6 @@ ANGLE_EXPORT void GL_APIENTRY MultiDrawElementsInstancedANGLE(GLenum mode,
|
|||
const GLsizei *instanceCounts,
|
||||
GLsizei drawcount);
|
||||
|
||||
// GL_ANGLE_multiview
|
||||
ANGLE_EXPORT void GL_APIENTRY FramebufferTextureMultiviewLayeredANGLE(GLenum target,
|
||||
GLenum attachment,
|
||||
GLuint texture,
|
||||
GLint level,
|
||||
GLint baseViewIndex,
|
||||
GLsizei numViews);
|
||||
ANGLE_EXPORT void GL_APIENTRY
|
||||
FramebufferTextureMultiviewSideBySideANGLE(GLenum target,
|
||||
GLenum attachment,
|
||||
GLuint texture,
|
||||
GLint level,
|
||||
GLsizei numViews,
|
||||
const GLint *viewportOffsets);
|
||||
|
||||
// GL_ANGLE_provoking_vertex
|
||||
ANGLE_EXPORT void GL_APIENTRY ProvokingVertexANGLE(GLenum mode);
|
||||
|
||||
|
@ -929,6 +914,16 @@ ANGLE_EXPORT void GL_APIENTRY DeleteVertexArraysOES(GLsizei n, const GLuint *arr
|
|||
ANGLE_EXPORT void GL_APIENTRY GenVertexArraysOES(GLsizei n, GLuint *arrays);
|
||||
ANGLE_EXPORT GLboolean GL_APIENTRY IsVertexArrayOES(GLuint array);
|
||||
|
||||
// GL_OVR_multiview
|
||||
ANGLE_EXPORT void GL_APIENTRY FramebufferTextureMultiviewOVR(GLenum target,
|
||||
GLenum attachment,
|
||||
GLuint texture,
|
||||
GLint level,
|
||||
GLint baseViewIndex,
|
||||
GLsizei numViews);
|
||||
|
||||
// GL_OVR_multiview2
|
||||
|
||||
// EGL_ANGLE_explicit_context
|
||||
ANGLE_EXPORT void GL_APIENTRY ActiveShaderProgramContextANGLE(GLeglContext ctx,
|
||||
GLuint pipeline,
|
||||
|
@ -1431,6 +1426,13 @@ ANGLE_EXPORT void GL_APIENTRY FramebufferTextureLayerContextANGLE(GLeglContext c
|
|||
GLuint texture,
|
||||
GLint level,
|
||||
GLint layer);
|
||||
ANGLE_EXPORT void GL_APIENTRY FramebufferTextureMultiviewOVRContextANGLE(GLeglContext ctx,
|
||||
GLenum target,
|
||||
GLenum attachment,
|
||||
GLuint texture,
|
||||
GLint level,
|
||||
GLint baseViewIndex,
|
||||
GLsizei numViews);
|
||||
ANGLE_EXPORT void GL_APIENTRY FrontFaceContextANGLE(GLeglContext ctx, GLenum mode);
|
||||
ANGLE_EXPORT void GL_APIENTRY FrustumfContextANGLE(GLeglContext ctx,
|
||||
GLfloat l,
|
||||
|
@ -3454,22 +3456,6 @@ ANGLE_EXPORT void GL_APIENTRY GetQueryObjectui64vRobustANGLEContextANGLE(GLeglCo
|
|||
GLsizei bufSize,
|
||||
GLsizei *length,
|
||||
GLuint64 *params);
|
||||
ANGLE_EXPORT void GL_APIENTRY
|
||||
FramebufferTextureMultiviewLayeredANGLEContextANGLE(GLeglContext ctx,
|
||||
GLenum target,
|
||||
GLenum attachment,
|
||||
GLuint texture,
|
||||
GLint level,
|
||||
GLint baseViewIndex,
|
||||
GLsizei numViews);
|
||||
ANGLE_EXPORT void GL_APIENTRY
|
||||
FramebufferTextureMultiviewSideBySideANGLEContextANGLE(GLeglContext ctx,
|
||||
GLenum target,
|
||||
GLenum attachment,
|
||||
GLuint texture,
|
||||
GLint level,
|
||||
GLsizei numViews,
|
||||
const GLint *viewportOffsets);
|
||||
ANGLE_EXPORT void GL_APIENTRY CopyTexture3DANGLEContextANGLE(GLeglContext ctx,
|
||||
GLuint sourceId,
|
||||
GLint sourceLevel,
|
||||
|
|
|
@ -2545,29 +2545,6 @@ void GL_APIENTRY glMultiDrawElementsInstancedANGLE(GLenum mode,
|
|||
drawcount);
|
||||
}
|
||||
|
||||
// GL_ANGLE_multiview
|
||||
void GL_APIENTRY glFramebufferTextureMultiviewLayeredANGLE(GLenum target,
|
||||
GLenum attachment,
|
||||
GLuint texture,
|
||||
GLint level,
|
||||
GLint baseViewIndex,
|
||||
GLsizei numViews)
|
||||
{
|
||||
return gl::FramebufferTextureMultiviewLayeredANGLE(target, attachment, texture, level,
|
||||
baseViewIndex, numViews);
|
||||
}
|
||||
|
||||
void GL_APIENTRY glFramebufferTextureMultiviewSideBySideANGLE(GLenum target,
|
||||
GLenum attachment,
|
||||
GLuint texture,
|
||||
GLint level,
|
||||
GLsizei numViews,
|
||||
const GLint *viewportOffsets)
|
||||
{
|
||||
return gl::FramebufferTextureMultiviewSideBySideANGLE(target, attachment, texture, level,
|
||||
numViews, viewportOffsets);
|
||||
}
|
||||
|
||||
// GL_ANGLE_provoking_vertex
|
||||
void GL_APIENTRY glProvokingVertexANGLE(GLenum mode)
|
||||
{
|
||||
|
@ -4192,6 +4169,20 @@ GLboolean GL_APIENTRY glIsVertexArrayOES(GLuint array)
|
|||
return gl::IsVertexArrayOES(array);
|
||||
}
|
||||
|
||||
// GL_OVR_multiview
|
||||
void GL_APIENTRY glFramebufferTextureMultiviewOVR(GLenum target,
|
||||
GLenum attachment,
|
||||
GLuint texture,
|
||||
GLint level,
|
||||
GLint baseViewIndex,
|
||||
GLsizei numViews)
|
||||
{
|
||||
return gl::FramebufferTextureMultiviewOVR(target, attachment, texture, level, baseViewIndex,
|
||||
numViews);
|
||||
}
|
||||
|
||||
// GL_OVR_multiview2
|
||||
|
||||
// EGL_ANGLE_explicit_context
|
||||
void GL_APIENTRY glActiveShaderProgramContextANGLE(GLeglContext ctx,
|
||||
GLuint pipeline,
|
||||
|
@ -5248,6 +5239,18 @@ void GL_APIENTRY glFramebufferTextureLayerContextANGLE(GLeglContext ctx,
|
|||
return gl::FramebufferTextureLayerContextANGLE(ctx, target, attachment, texture, level, layer);
|
||||
}
|
||||
|
||||
void GL_APIENTRY glFramebufferTextureMultiviewOVRContextANGLE(GLeglContext ctx,
|
||||
GLenum target,
|
||||
GLenum attachment,
|
||||
GLuint texture,
|
||||
GLint level,
|
||||
GLint baseViewIndex,
|
||||
GLsizei numViews)
|
||||
{
|
||||
return gl::FramebufferTextureMultiviewOVRContextANGLE(ctx, target, attachment, texture, level,
|
||||
baseViewIndex, numViews);
|
||||
}
|
||||
|
||||
void GL_APIENTRY glFrontFaceContextANGLE(GLeglContext ctx, GLenum mode)
|
||||
{
|
||||
return gl::FrontFaceContextANGLE(ctx, mode);
|
||||
|
@ -9062,31 +9065,6 @@ void GL_APIENTRY glGetQueryObjectui64vRobustANGLEContextANGLE(GLeglContext ctx,
|
|||
return gl::GetQueryObjectui64vRobustANGLEContextANGLE(ctx, id, pname, bufSize, length, params);
|
||||
}
|
||||
|
||||
void GL_APIENTRY glFramebufferTextureMultiviewLayeredANGLEContextANGLE(GLeglContext ctx,
|
||||
GLenum target,
|
||||
GLenum attachment,
|
||||
GLuint texture,
|
||||
GLint level,
|
||||
GLint baseViewIndex,
|
||||
GLsizei numViews)
|
||||
{
|
||||
return gl::FramebufferTextureMultiviewLayeredANGLEContextANGLE(ctx, target, attachment, texture,
|
||||
level, baseViewIndex, numViews);
|
||||
}
|
||||
|
||||
void GL_APIENTRY
|
||||
glFramebufferTextureMultiviewSideBySideANGLEContextANGLE(GLeglContext ctx,
|
||||
GLenum target,
|
||||
GLenum attachment,
|
||||
GLuint texture,
|
||||
GLint level,
|
||||
GLsizei numViews,
|
||||
const GLint *viewportOffsets)
|
||||
{
|
||||
return gl::FramebufferTextureMultiviewSideBySideANGLEContextANGLE(
|
||||
ctx, target, attachment, texture, level, numViews, viewportOffsets);
|
||||
}
|
||||
|
||||
void GL_APIENTRY glCopyTexture3DANGLEContextANGLE(GLeglContext ctx,
|
||||
GLuint sourceId,
|
||||
GLint sourceLevel,
|
||||
|
|
|
@ -436,10 +436,6 @@ EXPORTS
|
|||
glMultiDrawElementsANGLE
|
||||
glMultiDrawElementsInstancedANGLE
|
||||
|
||||
; GL_ANGLE_multiview
|
||||
glFramebufferTextureMultiviewLayeredANGLE
|
||||
glFramebufferTextureMultiviewSideBySideANGLE
|
||||
|
||||
; GL_ANGLE_provoking_vertex
|
||||
glProvokingVertexANGLE
|
||||
|
||||
|
@ -724,6 +720,11 @@ EXPORTS
|
|||
glGenVertexArraysOES
|
||||
glIsVertexArrayOES
|
||||
|
||||
; GL_OVR_multiview
|
||||
glFramebufferTextureMultiviewOVR
|
||||
|
||||
; GL_OVR_multiview2
|
||||
|
||||
; EGL_ANGLE_explicit_context
|
||||
glActiveShaderProgramContextANGLE
|
||||
glActiveTextureContextANGLE
|
||||
|
@ -889,8 +890,7 @@ EXPORTS
|
|||
glFramebufferTexture2DOESContextANGLE
|
||||
glFramebufferTextureEXTContextANGLE
|
||||
glFramebufferTextureLayerContextANGLE
|
||||
glFramebufferTextureMultiviewLayeredANGLEContextANGLE
|
||||
glFramebufferTextureMultiviewSideBySideANGLEContextANGLE
|
||||
glFramebufferTextureMultiviewOVRContextANGLE
|
||||
glFrontFaceContextANGLE
|
||||
glFrustumfContextANGLE
|
||||
glFrustumxContextANGLE
|
||||
|
|
|
@ -440,13 +440,9 @@ ProcEntry g_procTable[] = {
|
|||
{"glFramebufferTextureEXTContextANGLE", P(gl::FramebufferTextureEXTContextANGLE)},
|
||||
{"glFramebufferTextureLayer", P(gl::FramebufferTextureLayer)},
|
||||
{"glFramebufferTextureLayerContextANGLE", P(gl::FramebufferTextureLayerContextANGLE)},
|
||||
{"glFramebufferTextureMultiviewLayeredANGLE", P(gl::FramebufferTextureMultiviewLayeredANGLE)},
|
||||
{"glFramebufferTextureMultiviewLayeredANGLEContextANGLE",
|
||||
P(gl::FramebufferTextureMultiviewLayeredANGLEContextANGLE)},
|
||||
{"glFramebufferTextureMultiviewSideBySideANGLE",
|
||||
P(gl::FramebufferTextureMultiviewSideBySideANGLE)},
|
||||
{"glFramebufferTextureMultiviewSideBySideANGLEContextANGLE",
|
||||
P(gl::FramebufferTextureMultiviewSideBySideANGLEContextANGLE)},
|
||||
{"glFramebufferTextureMultiviewOVR", P(gl::FramebufferTextureMultiviewOVR)},
|
||||
{"glFramebufferTextureMultiviewOVRContextANGLE",
|
||||
P(gl::FramebufferTextureMultiviewOVRContextANGLE)},
|
||||
{"glFrontFace", P(gl::FrontFace)},
|
||||
{"glFrontFaceContextANGLE", P(gl::FrontFaceContextANGLE)},
|
||||
{"glFrustumf", P(gl::Frustumf)},
|
||||
|
@ -1374,5 +1370,5 @@ ProcEntry g_procTable[] = {
|
|||
{"glWeightPointerOES", P(gl::WeightPointerOES)},
|
||||
{"glWeightPointerOESContextANGLE", P(gl::WeightPointerOESContextANGLE)}};
|
||||
|
||||
size_t g_numProcs = 1290;
|
||||
size_t g_numProcs = 1288;
|
||||
} // namespace egl
|
||||
|
|
|
@ -1,3 +1,30 @@
|
|||
commit f2915830eaf4b2970c37d4baecf0dc8030c85dba
|
||||
Author: Jan Beich <jbeich@FreeBSD.org>
|
||||
Date: Tue Apr 23 16:25:18 2019 -0700
|
||||
|
||||
`environ` needs to be declared for (at least) FreeBSD.
|
||||
|
||||
Declaring it unconditionally seems to build fine on all other platforms.
|
||||
|
||||
Change-Id: I4c587d6ec47989f0d22588aca8883c4ef68f91c8
|
||||
|
||||
commit 95eb4bfbc4a349b6c1274527dc3245212e5075e5
|
||||
Author: Mingyu Hu <mihu@microsoft.com>
|
||||
Date: Tue Mar 12 14:27:40 2019 -0700
|
||||
|
||||
GL_ANGLE_multiview has been renamed to GL_OVR_multiview2.
|
||||
|
||||
changes include:
|
||||
1) GL_OVR_multiview to GL_OVR_multiview2 extension directive change
|
||||
2) Removal of all references to side by side. We no longer support multiple views in a single 2DTexture. Only 2DTextureArray's are supported
|
||||
3) WebGL 2 (ES3) is required for multiview
|
||||
|
||||
Bug: angleproject:3341
|
||||
Change-Id: Ie0c1d21d7610f8feebdb2e4d01c6947f57e69328
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1552023
|
||||
Commit-Queue: Rafael Cintron <rafael.cintron@microsoft.com>
|
||||
Reviewed-by: Geoff Lang <geofflang@chromium.org>
|
||||
|
||||
commit 11fe1e4ce42be6e5136621b15ec163e0bbc0b7be
|
||||
Author: Jamie Madill <jmadill@chromium.org>
|
||||
Date: Fri Apr 12 10:36:00 2019 -0400
|
||||
|
|
|
@ -11,7 +11,7 @@ DEFINES['DYNAMIC_ANNOTATIONS_ENABLED'] = '1'
|
|||
#DEFINES['FULL_SAFE_BROWSING'] = True
|
||||
DEFINES['NOMINMAX'] = True
|
||||
#DEFINES['NO_TCMALLOC'] = True
|
||||
DEFINES['NTDDI_VERSION'] = '0x0A000003'
|
||||
DEFINES['NTDDI_VERSION'] = 'NTDDI_WIN10_RS2'
|
||||
#DEFINES['PSAPI_VERSION'] = '2'
|
||||
#DEFINES['SAFE_BROWSING_CSD'] = True
|
||||
#DEFINES['SAFE_BROWSING_DB_LOCAL'] = True
|
||||
|
@ -45,7 +45,6 @@ LOCAL_INCLUDES += [
|
|||
|
||||
#CXXFLAGS += [
|
||||
# '/bigobj',
|
||||
# '/d2FastFail',
|
||||
# '/D__DATE__=',
|
||||
# '/D__TIME__=',
|
||||
# '/D__TIMESTAMP__=',
|
||||
|
|
|
@ -11,7 +11,7 @@ DEFINES['DYNAMIC_ANNOTATIONS_ENABLED'] = '1'
|
|||
DEFINES['GPU_INFO_USE_SETUPAPI'] = True
|
||||
DEFINES['NOMINMAX'] = True
|
||||
#DEFINES['NO_TCMALLOC'] = True
|
||||
DEFINES['NTDDI_VERSION'] = '0x0A000003'
|
||||
DEFINES['NTDDI_VERSION'] = 'NTDDI_WIN10_RS2'
|
||||
#DEFINES['PSAPI_VERSION'] = '2'
|
||||
#DEFINES['SAFE_BROWSING_CSD'] = True
|
||||
#DEFINES['SAFE_BROWSING_DB_LOCAL'] = True
|
||||
|
@ -45,7 +45,6 @@ LOCAL_INCLUDES += [
|
|||
|
||||
#CXXFLAGS += [
|
||||
# '/bigobj',
|
||||
# '/d2FastFail',
|
||||
# '/D__DATE__=',
|
||||
# '/D__TIME__=',
|
||||
# '/D__TIMESTAMP__=',
|
||||
|
|
|
@ -10,7 +10,7 @@ DEFINES['DYNAMIC_ANNOTATIONS_ENABLED'] = '1'
|
|||
#DEFINES['FULL_SAFE_BROWSING'] = True
|
||||
DEFINES['NOMINMAX'] = True
|
||||
#DEFINES['NO_TCMALLOC'] = True
|
||||
DEFINES['NTDDI_VERSION'] = '0x0A000003'
|
||||
DEFINES['NTDDI_VERSION'] = 'NTDDI_WIN10_RS2'
|
||||
#DEFINES['PSAPI_VERSION'] = '2'
|
||||
#DEFINES['SAFE_BROWSING_CSD'] = True
|
||||
#DEFINES['SAFE_BROWSING_DB_LOCAL'] = True
|
||||
|
@ -44,7 +44,6 @@ LOCAL_INCLUDES += [
|
|||
|
||||
#CXXFLAGS += [
|
||||
# '/bigobj',
|
||||
# '/d2FastFail',
|
||||
# '/D__DATE__=',
|
||||
# '/D__TIME__=',
|
||||
# '/D__TIMESTAMP__=',
|
||||
|
|
|
@ -16,7 +16,7 @@ DEFINES['DYNAMIC_ANNOTATIONS_ENABLED'] = '1'
|
|||
DEFINES['LIBANGLE_IMPLEMENTATION'] = True
|
||||
DEFINES['NOMINMAX'] = True
|
||||
#DEFINES['NO_TCMALLOC'] = True
|
||||
DEFINES['NTDDI_VERSION'] = '0x0A000003'
|
||||
DEFINES['NTDDI_VERSION'] = 'NTDDI_WIN10_RS2'
|
||||
#DEFINES['PSAPI_VERSION'] = '2'
|
||||
#DEFINES['SAFE_BROWSING_CSD'] = True
|
||||
#DEFINES['SAFE_BROWSING_DB_LOCAL'] = True
|
||||
|
@ -50,7 +50,6 @@ LOCAL_INCLUDES += [
|
|||
|
||||
#CXXFLAGS += [
|
||||
# '/bigobj',
|
||||
# '/d2FastFail',
|
||||
# '/D__DATE__=',
|
||||
# '/D__TIME__=',
|
||||
# '/D__TIMESTAMP__=',
|
||||
|
|
|
@ -20,7 +20,7 @@ DEFINES['GL_GLEXT_PROTOTYPES'] = True
|
|||
DEFINES['LIBEGL_IMPLEMENTATION'] = True
|
||||
DEFINES['NOMINMAX'] = True
|
||||
#DEFINES['NO_TCMALLOC'] = True
|
||||
DEFINES['NTDDI_VERSION'] = '0x0A000003'
|
||||
DEFINES['NTDDI_VERSION'] = 'NTDDI_WIN10_RS2'
|
||||
#DEFINES['PSAPI_VERSION'] = '2'
|
||||
#DEFINES['SAFE_BROWSING_CSD'] = True
|
||||
#DEFINES['SAFE_BROWSING_DB_LOCAL'] = True
|
||||
|
@ -53,7 +53,6 @@ LOCAL_INCLUDES += [
|
|||
|
||||
#CXXFLAGS += [
|
||||
# '/bigobj',
|
||||
# '/d2FastFail',
|
||||
# '/D__DATE__=',
|
||||
# '/D__TIME__=',
|
||||
# '/D__TIMESTAMP__=',
|
||||
|
@ -165,7 +164,6 @@ OS_LIBS += [
|
|||
#LDFLAGS += [
|
||||
# '/DEBUG',
|
||||
# '/DYNAMICBASE',
|
||||
# '/fastfail',
|
||||
# '/FIXED:NO',
|
||||
# '/ignore:4199',
|
||||
# '/ignore:4221',
|
||||
|
|
|
@ -21,7 +21,7 @@ DEFINES['LIBANGLE_IMPLEMENTATION'] = True
|
|||
DEFINES['LIBGLESV2_IMPLEMENTATION'] = True
|
||||
DEFINES['NOMINMAX'] = True
|
||||
#DEFINES['NO_TCMALLOC'] = True
|
||||
DEFINES['NTDDI_VERSION'] = '0x0A000003'
|
||||
DEFINES['NTDDI_VERSION'] = 'NTDDI_WIN10_RS2'
|
||||
#DEFINES['PSAPI_VERSION'] = '2'
|
||||
#DEFINES['SAFE_BROWSING_CSD'] = True
|
||||
#DEFINES['SAFE_BROWSING_DB_LOCAL'] = True
|
||||
|
@ -55,7 +55,6 @@ LOCAL_INCLUDES += [
|
|||
|
||||
#CXXFLAGS += [
|
||||
# '/bigobj',
|
||||
# '/d2FastFail',
|
||||
# '/D__DATE__=',
|
||||
# '/D__TIME__=',
|
||||
# '/D__TIMESTAMP__=',
|
||||
|
@ -173,7 +172,6 @@ OS_LIBS += [
|
|||
#LDFLAGS += [
|
||||
# '/DEBUG',
|
||||
# '/DYNAMICBASE',
|
||||
# '/fastfail',
|
||||
# '/FIXED:NO',
|
||||
# '/ignore:4199',
|
||||
# '/ignore:4221',
|
||||
|
|
|
@ -10,7 +10,7 @@ DEFINES['DYNAMIC_ANNOTATIONS_ENABLED'] = '1'
|
|||
#DEFINES['FULL_SAFE_BROWSING'] = True
|
||||
DEFINES['NOMINMAX'] = True
|
||||
#DEFINES['NO_TCMALLOC'] = True
|
||||
DEFINES['NTDDI_VERSION'] = '0x0A000003'
|
||||
DEFINES['NTDDI_VERSION'] = 'NTDDI_WIN10_RS2'
|
||||
#DEFINES['PSAPI_VERSION'] = '2'
|
||||
#DEFINES['SAFE_BROWSING_CSD'] = True
|
||||
#DEFINES['SAFE_BROWSING_DB_LOCAL'] = True
|
||||
|
@ -44,7 +44,6 @@ LOCAL_INCLUDES += [
|
|||
|
||||
#CXXFLAGS += [
|
||||
# '/bigobj',
|
||||
# '/d2FastFail',
|
||||
# '/D__DATE__=',
|
||||
# '/D__TIME__=',
|
||||
# '/D__TIMESTAMP__=',
|
||||
|
|
|
@ -13,7 +13,7 @@ DEFINES['DYNAMIC_ANNOTATIONS_ENABLED'] = '1'
|
|||
#DEFINES['FULL_SAFE_BROWSING'] = True
|
||||
DEFINES['NOMINMAX'] = True
|
||||
#DEFINES['NO_TCMALLOC'] = True
|
||||
DEFINES['NTDDI_VERSION'] = '0x0A000003'
|
||||
DEFINES['NTDDI_VERSION'] = 'NTDDI_WIN10_RS2'
|
||||
#DEFINES['PSAPI_VERSION'] = '2'
|
||||
#DEFINES['SAFE_BROWSING_CSD'] = True
|
||||
#DEFINES['SAFE_BROWSING_DB_LOCAL'] = True
|
||||
|
@ -47,7 +47,6 @@ LOCAL_INCLUDES += [
|
|||
|
||||
#CXXFLAGS += [
|
||||
# '/bigobj',
|
||||
# '/d2FastFail',
|
||||
# '/D__DATE__=',
|
||||
# '/D__TIME__=',
|
||||
# '/D__TIMESTAMP__=',
|
||||
|
|
|
@ -440,6 +440,8 @@ class SurfaceTextureHost : public TextureHost {
|
|||
const wr::LayoutRect& aClip, wr::ImageRendering aFilter,
|
||||
const Range<wr::ImageKey>& aImageKeys) override;
|
||||
|
||||
bool SupportsWrNativeTexture() override { return true; }
|
||||
|
||||
protected:
|
||||
bool EnsureAttached();
|
||||
|
||||
|
|
|
@ -15,405 +15,51 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* fluent-dom@fa25466f (October 12, 2018) */
|
||||
/* Based on fluent-dom@fa25466f (October 12, 2018) */
|
||||
/* global DOMOverlays */
|
||||
|
||||
const { Localization } =
|
||||
ChromeUtils.import("resource://gre/modules/Localization.jsm");
|
||||
const { Services } =
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
// Match the opening angle bracket (<) in HTML tags, and HTML entities like
|
||||
// &, &, &.
|
||||
const reOverlay = /<|&#?\w+;/;
|
||||
|
||||
/**
|
||||
* Elements allowed in translations even if they are not present in the source
|
||||
* HTML. They are text-level elements as defined by the HTML5 spec:
|
||||
* https://www.w3.org/TR/html5/text-level-semantics.html with the exception of:
|
||||
*
|
||||
* - a - because we don't allow href on it anyways,
|
||||
* - ruby, rt, rp - because we don't allow nested elements to be inserted.
|
||||
*/
|
||||
const TEXT_LEVEL_ELEMENTS = {
|
||||
"http://www.w3.org/1999/xhtml": [
|
||||
"em", "strong", "small", "s", "cite", "q", "dfn", "abbr", "data",
|
||||
"time", "code", "var", "samp", "kbd", "sub", "sup", "i", "b", "u",
|
||||
"mark", "bdi", "bdo", "span", "br", "wbr",
|
||||
],
|
||||
};
|
||||
|
||||
const LOCALIZABLE_ATTRIBUTES = {
|
||||
"http://www.w3.org/1999/xhtml": {
|
||||
global: ["title", "aria-label", "aria-valuetext", "aria-moz-hint"],
|
||||
a: ["download"],
|
||||
area: ["download", "alt"],
|
||||
// value is special-cased in isAttrNameLocalizable
|
||||
input: ["alt", "placeholder"],
|
||||
menuitem: ["label"],
|
||||
menu: ["label"],
|
||||
optgroup: ["label"],
|
||||
option: ["label"],
|
||||
track: ["label"],
|
||||
img: ["alt"],
|
||||
textarea: ["placeholder"],
|
||||
th: ["abbr"],
|
||||
},
|
||||
"http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul": {
|
||||
global: [
|
||||
"accesskey", "aria-label", "aria-valuetext", "aria-moz-hint", "label",
|
||||
"title", "tooltiptext"],
|
||||
description: ["value"],
|
||||
key: ["key", "keycode"],
|
||||
label: ["value"],
|
||||
textbox: ["placeholder", "value"],
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Translate an element.
|
||||
*
|
||||
* Translate the element's text content and attributes. Some HTML markup is
|
||||
* allowed in the translation. The element's children with the data-l10n-name
|
||||
* attribute will be treated as arguments to the translation. If the
|
||||
* translation defines the same children, their attributes and text contents
|
||||
* will be used for translating the matching source child.
|
||||
*
|
||||
* @param {Element} element
|
||||
* @param {Object} translation
|
||||
* @private
|
||||
*/
|
||||
function translateElement(element, translation) {
|
||||
const {value} = translation;
|
||||
|
||||
if (typeof value === "string") {
|
||||
if (!reOverlay.test(value)) {
|
||||
// If the translation doesn't contain any markup skip the overlay logic.
|
||||
element.textContent = value;
|
||||
} else {
|
||||
// Else parse the translation's HTML using an inert template element,
|
||||
// sanitize it and replace the element's content.
|
||||
const templateElement = element.ownerDocument.createElementNS(
|
||||
"http://www.w3.org/1999/xhtml", "template"
|
||||
);
|
||||
// eslint-disable-next-line no-unsanitized/property
|
||||
templateElement.innerHTML = value;
|
||||
overlayChildNodes(templateElement.content, element);
|
||||
}
|
||||
}
|
||||
|
||||
// Even if the translation doesn't define any localizable attributes, run
|
||||
// overlayAttributes to remove any localizable attributes set by previous
|
||||
// translations.
|
||||
overlayAttributes(translation, element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace child nodes of an element with child nodes of another element.
|
||||
*
|
||||
* The contents of the target element will be cleared and fully replaced with
|
||||
* sanitized contents of the source element.
|
||||
*
|
||||
* @param {DocumentFragment} fromFragment - The source of children to overlay.
|
||||
* @param {Element} toElement - The target of the overlay.
|
||||
* @private
|
||||
*/
|
||||
function overlayChildNodes(fromFragment, toElement) {
|
||||
for (const childNode of fromFragment.childNodes) {
|
||||
if (childNode.nodeType === childNode.TEXT_NODE) {
|
||||
// Keep the translated text node.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (childNode.hasAttribute("data-l10n-name")) {
|
||||
const sanitized = namedChildFrom(toElement, childNode);
|
||||
fromFragment.replaceChild(sanitized, childNode);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isElementAllowed(childNode)) {
|
||||
const sanitized = allowedChild(childNode);
|
||||
fromFragment.replaceChild(sanitized, childNode);
|
||||
continue;
|
||||
}
|
||||
|
||||
console.warn(
|
||||
`An element of forbidden type "${childNode.localName}" was found in ` +
|
||||
"the translation. Only safe text-level elements and elements with " +
|
||||
"data-l10n-name are allowed."
|
||||
);
|
||||
|
||||
// If all else fails, replace the element with its text content.
|
||||
fromFragment.replaceChild(textNode(childNode), childNode);
|
||||
}
|
||||
|
||||
toElement.textContent = "";
|
||||
toElement.appendChild(fromFragment);
|
||||
}
|
||||
|
||||
function hasAttribute(attributes, name) {
|
||||
if (!attributes) {
|
||||
return false;
|
||||
}
|
||||
for (let attr of attributes) {
|
||||
if (attr.name === name) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transplant localizable attributes of an element to another element.
|
||||
*
|
||||
* Any localizable attributes already set on the target element will be
|
||||
* cleared.
|
||||
*
|
||||
* @param {Element|Object} fromElement - The source of child nodes to overlay.
|
||||
* @param {Element} toElement - The target of the overlay.
|
||||
* @private
|
||||
*/
|
||||
function overlayAttributes(fromElement, toElement) {
|
||||
const explicitlyAllowed = toElement.hasAttribute("data-l10n-attrs")
|
||||
? toElement.getAttribute("data-l10n-attrs")
|
||||
.split(",").map(i => i.trim())
|
||||
: null;
|
||||
|
||||
// Remove existing localizable attributes if they
|
||||
// will not be used in the new translation.
|
||||
for (const attr of Array.from(toElement.attributes)) {
|
||||
if (isAttrNameLocalizable(attr.name, toElement, explicitlyAllowed)
|
||||
&& !hasAttribute(fromElement.attributes, attr.name)) {
|
||||
toElement.removeAttribute(attr.name);
|
||||
}
|
||||
}
|
||||
|
||||
// fromElement might be a {value, attributes} object as returned by
|
||||
// Localization.messageFromBundle. In which case attributes may be null to
|
||||
// save GC cycles.
|
||||
if (!fromElement.attributes) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set localizable attributes.
|
||||
for (const attr of Array.from(fromElement.attributes)) {
|
||||
if (isAttrNameLocalizable(attr.name, toElement, explicitlyAllowed)
|
||||
&& toElement.getAttribute(attr.name) !== attr.value) {
|
||||
toElement.setAttribute(attr.name, attr.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize a child element created by the translation.
|
||||
*
|
||||
* Try to find a corresponding child in sourceElement and use it as the base
|
||||
* for the sanitization. This will preserve functional attribtues defined on
|
||||
* the child element in the source HTML.
|
||||
*
|
||||
* @param {Element} sourceElement - The source for data-l10n-name lookups.
|
||||
* @param {Element} translatedChild - The translated child to be sanitized.
|
||||
* @returns {Element}
|
||||
* @private
|
||||
*/
|
||||
function namedChildFrom(sourceElement, translatedChild) {
|
||||
const childName = translatedChild.getAttribute("data-l10n-name");
|
||||
const sourceChild = sourceElement.querySelector(
|
||||
`[data-l10n-name="${childName}"]`
|
||||
);
|
||||
|
||||
if (!sourceChild) {
|
||||
console.warn(
|
||||
`An element named "${childName}" wasn't found in the source.`
|
||||
);
|
||||
return textNode(translatedChild);
|
||||
}
|
||||
|
||||
if (sourceChild.localName !== translatedChild.localName &&
|
||||
// Create a specific exception for img vs. image mismatches,
|
||||
// see bug 1543493
|
||||
!(translatedChild.localName == "img" &&
|
||||
sourceChild.localName == "image")) {
|
||||
console.warn(
|
||||
`An element named "${childName}" was found in the translation ` +
|
||||
`but its type ${translatedChild.localName} didn't match the ` +
|
||||
`element found in the source (${sourceChild.localName}).`
|
||||
);
|
||||
return textNode(translatedChild);
|
||||
}
|
||||
|
||||
// Remove it from sourceElement so that the translation cannot use
|
||||
// the same reference name again.
|
||||
sourceElement.removeChild(sourceChild);
|
||||
// We can't currently guarantee that a translation won't remove
|
||||
// sourceChild from the element completely, which could break the app if
|
||||
// it relies on an event handler attached to the sourceChild. Let's make
|
||||
// this limitation explicit for now by breaking the identitiy of the
|
||||
// sourceChild by cloning it. This will destroy all event handlers
|
||||
// attached to sourceChild via addEventListener and via on<name>
|
||||
// properties.
|
||||
const clone = sourceChild.cloneNode(false);
|
||||
return shallowPopulateUsing(translatedChild, clone);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize an allowed element.
|
||||
*
|
||||
* Text-level elements allowed in translations may only use safe attributes
|
||||
* and will have any nested markup stripped to text content.
|
||||
*
|
||||
* @param {Element} element - The element to be sanitized.
|
||||
* @returns {Element}
|
||||
* @private
|
||||
*/
|
||||
function allowedChild(element) {
|
||||
// Start with an empty element of the same type to remove nested children
|
||||
// and non-localizable attributes defined by the translation.
|
||||
const clone = element.ownerDocument.createElement(element.localName);
|
||||
return shallowPopulateUsing(element, clone);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an element to a text node.
|
||||
*
|
||||
* @param {Element} element - The element to be sanitized.
|
||||
* @returns {Node}
|
||||
* @private
|
||||
*/
|
||||
function textNode(element) {
|
||||
return element.ownerDocument.createTextNode(element.textContent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if element is allowed in the translation.
|
||||
*
|
||||
* This method is used by the sanitizer when the translation markup contains
|
||||
* an element which is not present in the source code.
|
||||
*
|
||||
* @param {Element} element
|
||||
* @returns {boolean}
|
||||
* @private
|
||||
*/
|
||||
function isElementAllowed(element) {
|
||||
const allowed = TEXT_LEVEL_ELEMENTS[element.namespaceURI];
|
||||
return allowed && allowed.includes(element.localName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if attribute is allowed for the given element.
|
||||
*
|
||||
* This method is used by the sanitizer when the translation markup contains
|
||||
* DOM attributes, or when the translation has traits which map to DOM
|
||||
* attributes.
|
||||
*
|
||||
* `explicitlyAllowed` can be passed as a list of attributes explicitly
|
||||
* allowed on this element.
|
||||
*
|
||||
* @param {string} name
|
||||
* @param {Element} element
|
||||
* @param {Array} explicitlyAllowed
|
||||
* @returns {boolean}
|
||||
* @private
|
||||
*/
|
||||
function isAttrNameLocalizable(name, element, explicitlyAllowed = null) {
|
||||
if (explicitlyAllowed && explicitlyAllowed.includes(name)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const allowed = LOCALIZABLE_ATTRIBUTES[element.namespaceURI];
|
||||
if (!allowed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const attrName = name.toLowerCase();
|
||||
const elemName = element.localName;
|
||||
|
||||
// Is it a globally safe attribute?
|
||||
if (allowed.global.includes(attrName)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Are there no allowed attributes for this element?
|
||||
if (!allowed[elemName]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Is it allowed on this element?
|
||||
if (allowed[elemName].includes(attrName)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Special case for value on HTML inputs with type button, reset, submit
|
||||
if (element.namespaceURI === "http://www.w3.org/1999/xhtml" &&
|
||||
elemName === "input" && attrName === "value") {
|
||||
const type = element.type.toLowerCase();
|
||||
if (type === "submit" || type === "button" || type === "reset") {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to set textContent and localizable attributes on an element.
|
||||
*
|
||||
* @param {Element} fromElement
|
||||
* @param {Element} toElement
|
||||
* @returns {Element}
|
||||
* @private
|
||||
*/
|
||||
function shallowPopulateUsing(fromElement, toElement) {
|
||||
toElement.textContent = fromElement.textContent;
|
||||
overlayAttributes(fromElement, toElement);
|
||||
return toElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitizes a translation before passing them to Node.localize API.
|
||||
*
|
||||
* It returns `false` if the translation contains DOM Overlays and should
|
||||
* not go into Node.localize.
|
||||
*
|
||||
* Note: There's a third item of work that JS DOM Overlays do - removal
|
||||
* of attributes from the previous translation.
|
||||
* This is not trivial to implement for Node.localize scenario, so
|
||||
* at the moment it is not supported.
|
||||
*
|
||||
* @param {{
|
||||
* localName: string,
|
||||
* namespaceURI: string,
|
||||
* type: string || null
|
||||
* l10nId: string,
|
||||
* l10nArgs: Array<Object> || null,
|
||||
* l10nAttrs: string ||null,
|
||||
* }} l10nItems
|
||||
* @param {{value: string, attrs: Object}} translations
|
||||
* @returns boolean
|
||||
* @private
|
||||
*/
|
||||
function sanitizeTranslationForNodeLocalize(l10nItem, translation) {
|
||||
if (reOverlay.test(translation.value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (translation.attributes) {
|
||||
const explicitlyAllowed = l10nItem.l10nAttrs === null ? null :
|
||||
l10nItem.l10nAttrs.split(",").map(i => i.trim());
|
||||
for (const [j, {name}] of translation.attributes.entries()) {
|
||||
if (!isAttrNameLocalizable(name, l10nItem, explicitlyAllowed)) {
|
||||
translation.attributes.splice(j, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const L10NID_ATTR_NAME = "data-l10n-id";
|
||||
const L10NARGS_ATTR_NAME = "data-l10n-args";
|
||||
|
||||
const L10N_ELEMENT_QUERY = `[${L10NID_ATTR_NAME}]`;
|
||||
|
||||
function reportDOMOverlayErrors(errors) {
|
||||
for (let error of errors) {
|
||||
switch (error.code) {
|
||||
case DOMOverlays.ERROR_FORBIDDEN_TYPE: {
|
||||
console.warn(
|
||||
`An element of forbidden type "${error.translatedElementName}" was found in ` +
|
||||
"the translation. Only safe text-level elements and elements with " +
|
||||
"data-l10n-name are allowed."
|
||||
);
|
||||
break;
|
||||
}
|
||||
case DOMOverlays.ERROR_NAMED_ELEMENT_MISSING: {
|
||||
console.warn(
|
||||
`An element named "${error.l10nName}" wasn't found in the source.`
|
||||
);
|
||||
break;
|
||||
}
|
||||
case DOMOverlays.ERROR_NAMED_ELEMENT_TYPE_MISMATCH: {
|
||||
console.warn(
|
||||
`An element named "${error.l10nName}" was found in the translation ` +
|
||||
`but its type ${error.translatedElementName} didn't match the ` +
|
||||
`element found in the source (${error.sourceElementName}).`
|
||||
);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
console.warn(`Unknown error ${error.code} happend while translation an element.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The `DOMLocalization` class is responsible for fetching resources and
|
||||
* formatting translations.
|
||||
|
@ -720,31 +366,11 @@ class DOMLocalization extends Localization {
|
|||
|
||||
// A sparse array which will store translations separated out from
|
||||
// all translations that is needed for DOM Overlay.
|
||||
const overlayTranslations = [];
|
||||
|
||||
const getTranslationsForItems = async l10nItems => {
|
||||
const keys = l10nItems.map(
|
||||
l10nItem => ({id: l10nItem.l10nId, args: l10nItem.l10nArgs}));
|
||||
const translations = await this.formatMessages(keys);
|
||||
|
||||
// Here we want to separate out elements that require DOM Overlays.
|
||||
// Those elements will have to be translated using our JS
|
||||
// implementation, while everything else is going to use the fast-path.
|
||||
for (const [i, translation] of translations.entries()) {
|
||||
if (translation === undefined) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const hasOnlyText =
|
||||
sanitizeTranslationForNodeLocalize(l10nItems[i], translation);
|
||||
if (!hasOnlyText) {
|
||||
// Removing from translations to make Node.localize skip it.
|
||||
// We will translate it below using JS DOM Overlays.
|
||||
overlayTranslations[i] = translations[i];
|
||||
translations[i] = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
// We pause translation observing here because Node.localize
|
||||
// will translate the whole DOM next, using the `translations`.
|
||||
//
|
||||
|
@ -755,12 +381,9 @@ class DOMLocalization extends Localization {
|
|||
};
|
||||
|
||||
return frag.localize(getTranslationsForItems.bind(this))
|
||||
.then(untranslatedElements => {
|
||||
for (let i = 0; i < overlayTranslations.length; i++) {
|
||||
if (overlayTranslations[i] !== undefined &&
|
||||
untranslatedElements[i] !== undefined) {
|
||||
translateElement(untranslatedElements[i], overlayTranslations[i]);
|
||||
}
|
||||
.then((errors) => {
|
||||
if (errors) {
|
||||
reportDOMOverlayErrors(errors);
|
||||
}
|
||||
this.resumeObserving();
|
||||
})
|
||||
|
@ -811,11 +434,18 @@ class DOMLocalization extends Localization {
|
|||
applyTranslations(elements, translations) {
|
||||
this.pauseObserving();
|
||||
|
||||
const errors = [];
|
||||
for (let i = 0; i < elements.length; i++) {
|
||||
if (translations[i] !== undefined) {
|
||||
translateElement(elements[i], translations[i]);
|
||||
const translationErrors = DOMOverlays.translateElement(elements[i], translations[i]);
|
||||
if (translationErrors) {
|
||||
errors.push(...translationErrors);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (errors.length) {
|
||||
reportDOMOverlayErrors(errors);
|
||||
}
|
||||
|
||||
this.resumeObserving();
|
||||
}
|
||||
|
|
|
@ -35,9 +35,7 @@ key2 = Value for <a>Key 2<a/>.
|
|||
const elem2 = document.querySelector("#elem2");
|
||||
|
||||
ok(elem1.textContent.includes("Value for"));
|
||||
// This is a limitation of us using Node.localize API
|
||||
// Documenting it here to make sure we notice when we fix it
|
||||
is(elem1.getAttribute("title"), "Old Translation");
|
||||
ok(!elem1.hasAttribute("title"));
|
||||
|
||||
ok(elem2.textContent.includes("Value for"));
|
||||
ok(!elem2.hasAttribute("title"));
|
||||
|
|
|
@ -50,7 +50,6 @@ import java.lang.RuntimeException;
|
|||
import java.lang.String;
|
||||
import java.lang.Throwable;
|
||||
import java.lang.Void;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.net.InetAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.AbstractSequentialList;
|
||||
|
@ -515,9 +514,6 @@ package org.mozilla.geckoview {
|
|||
method @AnyThread default public int getCurrentIndex();
|
||||
}
|
||||
|
||||
public static interface GeckoSession.HistoryDelegate.VisitFlags implements Annotation {
|
||||
}
|
||||
|
||||
public static interface GeckoSession.MediaDelegate {
|
||||
method @UiThread default public void onMediaAdd(@NonNull GeckoSession, @NonNull MediaElement);
|
||||
method @UiThread default public void onMediaRemove(@NonNull GeckoSession, @NonNull MediaElement);
|
||||
|
@ -544,9 +540,6 @@ package org.mozilla.geckoview {
|
|||
field @NonNull public final String uri;
|
||||
}
|
||||
|
||||
public static interface GeckoSession.NavigationDelegate.TargetWindow implements Annotation {
|
||||
}
|
||||
|
||||
public static interface GeckoSession.PermissionDelegate {
|
||||
method @UiThread default public void onAndroidPermissionsRequest(@NonNull GeckoSession, @Nullable String[], @NonNull GeckoSession.PermissionDelegate.Callback);
|
||||
method @UiThread default public void onContentPermissionRequest(@NonNull GeckoSession, @Nullable String, int, @NonNull GeckoSession.PermissionDelegate.Callback);
|
||||
|
@ -585,9 +578,6 @@ package org.mozilla.geckoview {
|
|||
field public final int type;
|
||||
}
|
||||
|
||||
public static interface GeckoSession.PermissionDelegate.Permission implements Annotation {
|
||||
}
|
||||
|
||||
public static interface GeckoSession.ProgressDelegate {
|
||||
method @UiThread default public void onPageStart(@NonNull GeckoSession, @NonNull String);
|
||||
method @UiThread default public void onPageStop(@NonNull GeckoSession, boolean);
|
||||
|
@ -694,17 +684,11 @@ package org.mozilla.geckoview {
|
|||
method @UiThread default public void confirm(@Nullable GeckoSession.PromptDelegate.Choice[]);
|
||||
}
|
||||
|
||||
public static interface GeckoSession.PromptDelegate.DatetimeType implements Annotation {
|
||||
}
|
||||
|
||||
public static interface GeckoSession.PromptDelegate.FileCallback implements GeckoSession.PromptDelegate.AlertCallback {
|
||||
method @UiThread default public void confirm(@Nullable Context, @Nullable Uri);
|
||||
method @UiThread default public void confirm(@Nullable Context, @Nullable Uri[]);
|
||||
}
|
||||
|
||||
public static interface GeckoSession.PromptDelegate.FileType implements Annotation {
|
||||
}
|
||||
|
||||
public static interface GeckoSession.PromptDelegate.TextCallback implements GeckoSession.PromptDelegate.AlertCallback {
|
||||
method @UiThread default public void confirm(@Nullable String);
|
||||
}
|
||||
|
@ -734,15 +718,6 @@ package org.mozilla.geckoview {
|
|||
field public static final int HIDE_REASON_NO_SELECTION = 0;
|
||||
}
|
||||
|
||||
public static interface GeckoSession.SelectionActionDelegate.Action implements Annotation {
|
||||
}
|
||||
|
||||
public static interface GeckoSession.SelectionActionDelegate.Flag implements Annotation {
|
||||
}
|
||||
|
||||
public static interface GeckoSession.SelectionActionDelegate.HideReason implements Annotation {
|
||||
}
|
||||
|
||||
public static class GeckoSession.SelectionActionDelegate.Selection {
|
||||
ctor protected Selection();
|
||||
field @Nullable public final RectF clientRect;
|
||||
|
@ -778,12 +753,6 @@ package org.mozilla.geckoview {
|
|||
field public static final int RESTART_REASON_FOCUS = 0;
|
||||
}
|
||||
|
||||
public static interface GeckoSession.TextInputDelegate.AutoFillNotification implements Annotation {
|
||||
}
|
||||
|
||||
public static interface GeckoSession.TextInputDelegate.RestartReason implements Annotation {
|
||||
}
|
||||
|
||||
@AnyThread public static class GeckoSession.WebResponseInfo {
|
||||
ctor protected WebResponseInfo();
|
||||
field @Nullable public final long contentLength;
|
||||
|
@ -884,9 +853,6 @@ package org.mozilla.geckoview {
|
|||
field public static final int FETCH_FLAGS_NO_REDIRECTS = 2;
|
||||
}
|
||||
|
||||
public static interface GeckoWebExecutor.FetchFlags implements Annotation {
|
||||
}
|
||||
|
||||
@AnyThread public class MediaElement {
|
||||
method @Nullable public MediaElement.Delegate getDelegate();
|
||||
method public void pause();
|
||||
|
@ -1053,14 +1019,20 @@ package org.mozilla.geckoview {
|
|||
}
|
||||
|
||||
public class WebExtension {
|
||||
ctor public WebExtension(@NonNull String, @NonNull String, boolean);
|
||||
ctor public WebExtension(@NonNull String, @NonNull String, long);
|
||||
ctor public WebExtension(@NonNull String);
|
||||
method @UiThread public void setMessageDelegate(@Nullable WebExtension.MessageDelegate, @NonNull String);
|
||||
field public final boolean allowContentMessaging;
|
||||
field public final long flags;
|
||||
field @NonNull public final String id;
|
||||
field @NonNull public final String location;
|
||||
}
|
||||
|
||||
public static class WebExtension.Flags {
|
||||
ctor protected Flags();
|
||||
field public static final long ALLOW_CONTENT_MESSAGING = 1L;
|
||||
field public static final long NONE = 0L;
|
||||
}
|
||||
|
||||
@UiThread public static interface WebExtension.MessageDelegate {
|
||||
method @Nullable default public void onConnect(@NonNull WebExtension.Port);
|
||||
method @Nullable default public GeckoResult<Object> onMessage(@NonNull Object, @NonNull WebExtension.MessageSender);
|
||||
|
@ -1126,9 +1098,6 @@ package org.mozilla.geckoview {
|
|||
method @NonNull public WebRequest.Builder referrer(@Nullable String);
|
||||
}
|
||||
|
||||
public static interface WebRequest.CacheMode implements Annotation {
|
||||
}
|
||||
|
||||
@AnyThread public class WebRequestError extends Exception {
|
||||
ctor public WebRequestError(int, int);
|
||||
field public static final int ERROR_CATEGORY_CONTENT = 4;
|
||||
|
@ -1168,12 +1137,6 @@ package org.mozilla.geckoview {
|
|||
field public final int code;
|
||||
}
|
||||
|
||||
public static interface WebRequestError.Error implements Annotation {
|
||||
}
|
||||
|
||||
public static interface WebRequestError.ErrorCategory implements Annotation {
|
||||
}
|
||||
|
||||
@AnyThread public class WebResponse extends WebMessage {
|
||||
ctor protected WebResponse(@NonNull WebResponse.Builder);
|
||||
field @Nullable public final InputStream body;
|
||||
|
|
|
@ -85,7 +85,7 @@ class WebExecutorTest {
|
|||
return fetch(request, GeckoWebExecutor.FETCH_FLAGS_NONE)
|
||||
}
|
||||
|
||||
private fun fetch(request: WebRequest, @GeckoWebExecutor.FetchFlags flags: Int): WebResponse {
|
||||
private fun fetch(request: WebRequest, flags: Int): WebResponse {
|
||||
return executor.fetch(request, flags).poll(env.defaultTimeoutMillis)!!
|
||||
}
|
||||
|
||||
|
|
|
@ -110,20 +110,30 @@ class WebExtensionTest : BaseSessionTest() {
|
|||
}
|
||||
}
|
||||
|
||||
val messaging = WebExtension(if (background) MESSAGING_BACKGROUND else MESSAGING_CONTENT,
|
||||
"{${UUID.randomUUID()}}", !background)
|
||||
if (background) {
|
||||
messaging.setMessageDelegate(messageDelegate, "browser")
|
||||
} else {
|
||||
sessionRule.session.setMessageDelegate(messageDelegate, "browser");
|
||||
}
|
||||
|
||||
val messaging = createWebExtension(background, messageDelegate)
|
||||
sessionRule.waitForResult(sessionRule.runtime.registerWebExtension(messaging))
|
||||
sessionRule.waitForResult(messageResult)
|
||||
|
||||
sessionRule.waitForResult(sessionRule.runtime.unregisterWebExtension(messaging))
|
||||
}
|
||||
|
||||
private fun createWebExtension(background: Boolean,
|
||||
messageDelegate: WebExtension.MessageDelegate): WebExtension {
|
||||
val webExtension: WebExtension
|
||||
val uuid = "{${UUID.randomUUID()}}"
|
||||
|
||||
if (background) {
|
||||
webExtension = WebExtension(MESSAGING_BACKGROUND, uuid, WebExtension.Flags.NONE)
|
||||
webExtension.setMessageDelegate(messageDelegate, "browser")
|
||||
} else {
|
||||
webExtension = WebExtension(MESSAGING_CONTENT, uuid,
|
||||
WebExtension.Flags.ALLOW_CONTENT_MESSAGING)
|
||||
sessionRule.session.setMessageDelegate(messageDelegate, "browser");
|
||||
}
|
||||
|
||||
return webExtension
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithDevToolsAPI
|
||||
fun contentMessaging() {
|
||||
|
@ -192,13 +202,7 @@ class WebExtensionTest : BaseSessionTest() {
|
|||
}
|
||||
}
|
||||
|
||||
val messaging = WebExtension(if (background) MESSAGING_BACKGROUND else MESSAGING_CONTENT,
|
||||
"{${UUID.randomUUID()}}", !background)
|
||||
if (background) {
|
||||
messaging.setMessageDelegate(messageDelegate, "browser")
|
||||
} else {
|
||||
sessionRule.session.setMessageDelegate(messageDelegate, "browser");
|
||||
}
|
||||
val messaging = createWebExtension(background, messageDelegate)
|
||||
|
||||
sessionRule.waitForResult(sessionRule.runtime.registerWebExtension(messaging))
|
||||
sessionRule.waitForResult(result)
|
||||
|
@ -280,13 +284,7 @@ class WebExtensionTest : BaseSessionTest() {
|
|||
}
|
||||
}
|
||||
|
||||
messaging = WebExtension(if (background) MESSAGING_BACKGROUND else MESSAGING_CONTENT,
|
||||
"{${UUID.randomUUID()}}", !background)
|
||||
if (background) {
|
||||
messaging.setMessageDelegate(messageDelegate, "browser")
|
||||
} else {
|
||||
sessionRule.session.setMessageDelegate(messageDelegate, "browser");
|
||||
}
|
||||
messaging = createWebExtension(background, messageDelegate)
|
||||
|
||||
sessionRule.waitForResult(sessionRule.runtime.registerWebExtension(messaging))
|
||||
sessionRule.waitForResult(result)
|
||||
|
@ -366,13 +364,7 @@ class WebExtensionTest : BaseSessionTest() {
|
|||
}
|
||||
}
|
||||
|
||||
messaging = WebExtension(if (background) MESSAGING_BACKGROUND else MESSAGING_CONTENT,
|
||||
"{${UUID.randomUUID()}}", !background)
|
||||
if (background) {
|
||||
messaging.setMessageDelegate(messageDelegate, "browser")
|
||||
} else {
|
||||
sessionRule.session.setMessageDelegate(messageDelegate, "browser");
|
||||
}
|
||||
messaging = createWebExtension(background, messageDelegate)
|
||||
|
||||
sessionRule.waitForResult(sessionRule.runtime.registerWebExtension(messaging))
|
||||
sessionRule.waitForResult(result)
|
||||
|
@ -441,7 +433,7 @@ class WebExtensionTest : BaseSessionTest() {
|
|||
}
|
||||
|
||||
messaging = WebExtension("resource://android/assets/web_extensions/messaging-iframe/",
|
||||
"{${UUID.randomUUID()}}", true)
|
||||
"{${UUID.randomUUID()}}", WebExtension.Flags.ALLOW_CONTENT_MESSAGING)
|
||||
sessionRule.session.setMessageDelegate(messageDelegate, "browser");
|
||||
|
||||
sessionRule.waitForResult(sessionRule.runtime.registerWebExtension(messaging))
|
||||
|
|
|
@ -1473,7 +1473,7 @@ import android.view.inputmethod.EditorInfo;
|
|||
}
|
||||
}
|
||||
|
||||
private void icRestartInput(@GeckoSession.TextInputDelegate.RestartReason final int reason,
|
||||
private void icRestartInput(@GeckoSession.RestartReason final int reason,
|
||||
final boolean toggleSoftInput) {
|
||||
if (DEBUG) {
|
||||
assertOnIcThread();
|
||||
|
|
|
@ -340,7 +340,8 @@ public final class GeckoRuntime implements Parcelable {
|
|||
final GeckoBundle bundle = new GeckoBundle(3);
|
||||
bundle.putString("locationUri", webExtension.location);
|
||||
bundle.putString("id", webExtension.id);
|
||||
bundle.putBoolean("allowContentMessaging", webExtension.allowContentMessaging);
|
||||
bundle.putBoolean("allowContentMessaging",
|
||||
(webExtension.flags & WebExtension.Flags.ALLOW_CONTENT_MESSAGING) > 0);
|
||||
|
||||
mWebExtensionDispatcher.registerWebExtension(webExtension);
|
||||
|
||||
|
|
|
@ -401,7 +401,7 @@ public class GeckoSession implements Parcelable {
|
|||
*
|
||||
* Note: To receive messages from content scripts, the WebExtension needs
|
||||
* to explicitely allow it in {@link WebExtension#WebExtension} by setting
|
||||
* {@link WebExtension#allowContentMessaging} to <code>true</code>.
|
||||
* {@link WebExtension.Flags#ALLOW_CONTENT_MESSAGING}.
|
||||
*
|
||||
* @param delegate {@link WebExtension.MessageDelegate} that will receive
|
||||
* messages from this session.
|
||||
|
@ -807,7 +807,7 @@ public class GeckoSession implements Parcelable {
|
|||
final SelectionActionDelegate.Selection selection =
|
||||
new SelectionActionDelegate.Selection(message);
|
||||
|
||||
final @SelectionActionDelegate.Action String[] actions = message.getStringArray("actions");
|
||||
final @SelectionActionDelegateAction String[] actions = message.getStringArray("actions");
|
||||
final int seqNo = message.getInt("seqNo");
|
||||
final GeckoResponse<String> response = new GeckoResponse<String>() {
|
||||
@Override
|
||||
|
@ -3155,11 +3155,6 @@ public class GeckoSession implements Parcelable {
|
|||
}
|
||||
|
||||
public interface SelectionActionDelegate {
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef(flag = true, value = {FLAG_IS_COLLAPSED,
|
||||
FLAG_IS_EDITABLE})
|
||||
/* package */ @interface Flag {}
|
||||
|
||||
/**
|
||||
* The selection is collapsed at a single position.
|
||||
*/
|
||||
|
@ -3174,18 +3169,6 @@ public class GeckoSession implements Parcelable {
|
|||
*/
|
||||
final int FLAG_IS_PASSWORD = 4;
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@StringDef({ACTION_HIDE,
|
||||
ACTION_CUT,
|
||||
ACTION_COPY,
|
||||
ACTION_DELETE,
|
||||
ACTION_PASTE,
|
||||
ACTION_SELECT_ALL,
|
||||
ACTION_UNSELECT,
|
||||
ACTION_COLLAPSE_TO_START,
|
||||
ACTION_COLLAPSE_TO_END})
|
||||
/* package */ @interface Action {}
|
||||
|
||||
/**
|
||||
* Hide selection actions and cause {@link #onHideAction} to be called.
|
||||
*/
|
||||
|
@ -3235,7 +3218,7 @@ public class GeckoSession implements Parcelable {
|
|||
* Flags describing the current selection, as a bitwise combination
|
||||
* of the {@link #FLAG_IS_COLLAPSED FLAG_*} constants.
|
||||
*/
|
||||
public final @Flag int flags;
|
||||
public final @SelectionActionDelegateFlag int flags;
|
||||
|
||||
/**
|
||||
* Text content of the current selection. An empty string indicates the selection
|
||||
|
@ -3305,16 +3288,9 @@ public class GeckoSession implements Parcelable {
|
|||
*/
|
||||
@UiThread
|
||||
default void onShowActionRequest(@NonNull GeckoSession session, @NonNull Selection selection,
|
||||
@NonNull @Action String[] actions,
|
||||
@NonNull @SelectionActionDelegateAction String[] actions,
|
||||
@NonNull GeckoResponse<String> response) {}
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({HIDE_REASON_NO_SELECTION,
|
||||
HIDE_REASON_INVISIBLE_SELECTION,
|
||||
HIDE_REASON_ACTIVE_SELECTION,
|
||||
HIDE_REASON_ACTIVE_SCROLL})
|
||||
/* package */ @interface HideReason {}
|
||||
|
||||
/**
|
||||
* Actions are no longer available due to the user clearing the selection.
|
||||
*/
|
||||
|
@ -3347,9 +3323,37 @@ public class GeckoSession implements Parcelable {
|
|||
* {@link #HIDE_REASON_NO_SELECTION HIDE_REASON_*} constants.
|
||||
*/
|
||||
@UiThread
|
||||
default void onHideAction(@NonNull GeckoSession session, @HideReason int reason) {}
|
||||
default void onHideAction(@NonNull GeckoSession session,
|
||||
@SelectionActionDelegateHideReason int reason) {}
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@StringDef({
|
||||
SelectionActionDelegate.ACTION_HIDE,
|
||||
SelectionActionDelegate.ACTION_CUT,
|
||||
SelectionActionDelegate.ACTION_COPY,
|
||||
SelectionActionDelegate.ACTION_DELETE,
|
||||
SelectionActionDelegate.ACTION_PASTE,
|
||||
SelectionActionDelegate.ACTION_SELECT_ALL,
|
||||
SelectionActionDelegate.ACTION_UNSELECT,
|
||||
SelectionActionDelegate.ACTION_COLLAPSE_TO_START,
|
||||
SelectionActionDelegate.ACTION_COLLAPSE_TO_END})
|
||||
/* package */ @interface SelectionActionDelegateAction {}
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef(flag = true, value = {
|
||||
SelectionActionDelegate.FLAG_IS_COLLAPSED,
|
||||
SelectionActionDelegate.FLAG_IS_EDITABLE})
|
||||
/* package */ @interface SelectionActionDelegateFlag {}
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({
|
||||
SelectionActionDelegate.HIDE_REASON_NO_SELECTION,
|
||||
SelectionActionDelegate.HIDE_REASON_INVISIBLE_SELECTION,
|
||||
SelectionActionDelegate.HIDE_REASON_ACTIVE_SELECTION,
|
||||
SelectionActionDelegate.HIDE_REASON_ACTIVE_SCROLL})
|
||||
/* package */ @interface SelectionActionDelegateHideReason {}
|
||||
|
||||
public interface NavigationDelegate {
|
||||
/**
|
||||
* A view has started loading content from the network.
|
||||
|
@ -3375,9 +3379,6 @@ public class GeckoSession implements Parcelable {
|
|||
@UiThread
|
||||
default void onCanGoForward(@NonNull GeckoSession session, boolean canGoForward) {}
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({TARGET_WINDOW_NONE, TARGET_WINDOW_CURRENT, TARGET_WINDOW_NEW})
|
||||
/* package */ @interface TargetWindow {}
|
||||
public static final int TARGET_WINDOW_NONE = 0;
|
||||
public static final int TARGET_WINDOW_CURRENT = 1;
|
||||
public static final int TARGET_WINDOW_NEW = 2;
|
||||
|
@ -3499,6 +3500,11 @@ public class GeckoSession implements Parcelable {
|
|||
}
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({NavigationDelegate.TARGET_WINDOW_NONE, NavigationDelegate.TARGET_WINDOW_CURRENT,
|
||||
NavigationDelegate.TARGET_WINDOW_NEW})
|
||||
/* package */ @interface TargetWindow {}
|
||||
|
||||
/**
|
||||
* GeckoSession applications implement this interface to handle prompts triggered by
|
||||
* content in the GeckoSession, such as alerts, authentication dialogs, and select list
|
||||
|
@ -3943,11 +3949,6 @@ public class GeckoSession implements Parcelable {
|
|||
callback.dismiss();
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({DATETIME_TYPE_DATE, DATETIME_TYPE_MONTH, DATETIME_TYPE_WEEK,
|
||||
DATETIME_TYPE_TIME, DATETIME_TYPE_DATETIME_LOCAL})
|
||||
/* package */ @interface DatetimeType {}
|
||||
|
||||
/**
|
||||
* Prompt for year, month, and day.
|
||||
*/
|
||||
|
@ -4017,9 +4018,6 @@ public class GeckoSession implements Parcelable {
|
|||
default void confirm(@Nullable Context context, @Nullable Uri[] uris) {}
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({FILE_TYPE_SINGLE, FILE_TYPE_MULTIPLE})
|
||||
/* package */ @interface FileType {}
|
||||
static final int FILE_TYPE_SINGLE = 1;
|
||||
static final int FILE_TYPE_MULTIPLE = 2;
|
||||
|
||||
|
@ -4059,6 +4057,16 @@ public class GeckoSession implements Parcelable {
|
|||
}
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({PromptDelegate.FILE_TYPE_SINGLE, PromptDelegate.FILE_TYPE_MULTIPLE})
|
||||
/* package */ @interface FileType {}
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({PromptDelegate.DATETIME_TYPE_DATE, PromptDelegate.DATETIME_TYPE_MONTH,
|
||||
PromptDelegate.DATETIME_TYPE_WEEK, PromptDelegate.DATETIME_TYPE_TIME,
|
||||
PromptDelegate.DATETIME_TYPE_DATETIME_LOCAL})
|
||||
/* package */ @interface DatetimeType {}
|
||||
|
||||
/**
|
||||
* GeckoSession applications implement this interface to handle content scroll
|
||||
* events.
|
||||
|
@ -4248,10 +4256,6 @@ public class GeckoSession implements Parcelable {
|
|||
* further requests from being presented to the user.
|
||||
**/
|
||||
public interface PermissionDelegate {
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({PERMISSION_GEOLOCATION, PERMISSION_DESKTOP_NOTIFICATION})
|
||||
/* package */ @interface Permission {}
|
||||
|
||||
/**
|
||||
* Permission for using the geolocation API.
|
||||
* See: https://developer.mozilla.org/en-US/docs/Web/API/Geolocation
|
||||
|
@ -4525,16 +4529,17 @@ public class GeckoSession implements Parcelable {
|
|||
}
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({PermissionDelegate.PERMISSION_GEOLOCATION,
|
||||
PermissionDelegate.PERMISSION_DESKTOP_NOTIFICATION})
|
||||
/* package */ @interface Permission {}
|
||||
|
||||
/**
|
||||
* Interface that SessionTextInput uses for performing operations such as opening and closing
|
||||
* the software keyboard. If the delegate is not set, these operations are forwarded to the
|
||||
* system {@link android.view.inputmethod.InputMethodManager} automatically.
|
||||
*/
|
||||
public interface TextInputDelegate {
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({RESTART_REASON_FOCUS, RESTART_REASON_BLUR, RESTART_REASON_CONTENT_CHANGE})
|
||||
/* package */ @interface RestartReason {}
|
||||
|
||||
/** Restarting input due to an input field gaining focus. */
|
||||
int RESTART_REASON_FOCUS = 0;
|
||||
/** Restarting input due to an input field losing focus. */
|
||||
|
@ -4622,13 +4627,6 @@ public class GeckoSession implements Parcelable {
|
|||
default void updateCursorAnchorInfo(@NonNull GeckoSession session,
|
||||
@NonNull CursorAnchorInfo info) {}
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({AUTO_FILL_NOTIFY_STARTED, AUTO_FILL_NOTIFY_COMMITTED, AUTO_FILL_NOTIFY_CANCELED,
|
||||
AUTO_FILL_NOTIFY_VIEW_ADDED, AUTO_FILL_NOTIFY_VIEW_REMOVED,
|
||||
AUTO_FILL_NOTIFY_VIEW_UPDATED, AUTO_FILL_NOTIFY_VIEW_ENTERED,
|
||||
AUTO_FILL_NOTIFY_VIEW_EXITED})
|
||||
/* package */ @interface AutoFillNotification {}
|
||||
|
||||
/** An auto-fill session has started, usually as a result of loading a page. */
|
||||
int AUTO_FILL_NOTIFY_STARTED = 0;
|
||||
/** An auto-fill session has been committed, usually as a result of submitting a form. */
|
||||
|
@ -4665,6 +4663,23 @@ public class GeckoSession implements Parcelable {
|
|||
int virtualId) {}
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({TextInputDelegate.RESTART_REASON_FOCUS, TextInputDelegate.RESTART_REASON_BLUR,
|
||||
TextInputDelegate.RESTART_REASON_CONTENT_CHANGE})
|
||||
/* package */ @interface RestartReason {}
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({
|
||||
TextInputDelegate.AUTO_FILL_NOTIFY_STARTED,
|
||||
TextInputDelegate.AUTO_FILL_NOTIFY_COMMITTED,
|
||||
TextInputDelegate.AUTO_FILL_NOTIFY_CANCELED,
|
||||
TextInputDelegate.AUTO_FILL_NOTIFY_VIEW_ADDED,
|
||||
TextInputDelegate.AUTO_FILL_NOTIFY_VIEW_REMOVED,
|
||||
TextInputDelegate.AUTO_FILL_NOTIFY_VIEW_UPDATED,
|
||||
TextInputDelegate.AUTO_FILL_NOTIFY_VIEW_ENTERED,
|
||||
TextInputDelegate.AUTO_FILL_NOTIFY_VIEW_EXITED})
|
||||
/* package */ @interface AutoFillNotification {}
|
||||
|
||||
/* package */ void onSurfaceChanged(final Surface surface, final int x, final int y, final int width,
|
||||
final int height) {
|
||||
ThreadUtils.assertOnUiThread();
|
||||
|
@ -4967,14 +4982,6 @@ public class GeckoSession implements Parcelable {
|
|||
}
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef(flag = true,
|
||||
value = { VISIT_TOP_LEVEL,
|
||||
VISIT_REDIRECT_TEMPORARY, VISIT_REDIRECT_PERMANENT,
|
||||
VISIT_REDIRECT_SOURCE, VISIT_REDIRECT_SOURCE_PERMANENT,
|
||||
VISIT_UNRECOVERABLE_ERROR })
|
||||
/* package */ @interface VisitFlags {}
|
||||
|
||||
// These flags are similar to those in `IHistory::LoadFlags`, but we use
|
||||
// different values to decouple GeckoView from Gecko changes. These
|
||||
// should be kept in sync with `GeckoViewHistory::GeckoViewVisitFlags`.
|
||||
|
@ -5001,7 +5008,7 @@ public class GeckoSession implements Parcelable {
|
|||
* redirects and reloads.
|
||||
* @param flags Additional flags for this visit, including redirect and
|
||||
* error statuses. This is a bitmask of one or more
|
||||
* {@link VisitFlags}, OR-ed together.
|
||||
* {@link #VISIT_TOP_LEVEL VISIT_*} flags, OR-ed together.
|
||||
* @return A {@link GeckoResult} completed with a boolean indicating
|
||||
* whether to highlight links for the new URL as visited
|
||||
* ({@code true}) or unvisited ({@code false}).
|
||||
|
@ -5034,4 +5041,16 @@ public class GeckoSession implements Parcelable {
|
|||
@UiThread
|
||||
default void onHistoryStateChange(@NonNull GeckoSession session, @NonNull HistoryList historyList) {}
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef(flag = true,
|
||||
value = {
|
||||
HistoryDelegate.VISIT_TOP_LEVEL,
|
||||
HistoryDelegate.VISIT_REDIRECT_TEMPORARY,
|
||||
HistoryDelegate.VISIT_REDIRECT_PERMANENT,
|
||||
HistoryDelegate.VISIT_REDIRECT_SOURCE,
|
||||
HistoryDelegate.VISIT_REDIRECT_SOURCE_PERMANENT,
|
||||
HistoryDelegate.VISIT_UNRECOVERABLE_ERROR
|
||||
})
|
||||
/* package */ @interface VisitFlags {}
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ public class GeckoWebExecutor {
|
|||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({FETCH_FLAGS_NONE, FETCH_FLAGS_ANONYMOUS, FETCH_FLAGS_NO_REDIRECTS})
|
||||
public @interface FetchFlags {};
|
||||
/* package */ @interface FetchFlags {};
|
||||
|
||||
/**
|
||||
* No special treatment.
|
||||
|
@ -100,7 +100,7 @@ public class GeckoWebExecutor {
|
|||
* Send the given {@link WebRequest} with specified flags.
|
||||
*
|
||||
* @param request A {@link WebRequest} instance
|
||||
* @param flags The specified flags. One or more of {@link FetchFlags}.
|
||||
* @param flags The specified flags. One or more of the {@link #FETCH_FLAGS_NONE FETCH_*} flags.
|
||||
* @return A {@link GeckoResult} which will be completed with a {@link WebResponse}. If the
|
||||
* request fails to complete, the {@link GeckoResult} will be completed exceptionally
|
||||
* with a {@link WebRequestError}.
|
||||
|
|
|
@ -276,7 +276,7 @@ public final class SessionTextInput {
|
|||
|
||||
@Override
|
||||
public void notifyAutoFill(@NonNull final GeckoSession session,
|
||||
@AutoFillNotification final int notification,
|
||||
@GeckoSession.AutoFillNotification final int notification,
|
||||
final int virtualId) {
|
||||
ThreadUtils.assertOnUiThread();
|
||||
final View view = session.getTextInput().getView();
|
||||
|
|
|
@ -11,6 +11,8 @@ import org.json.JSONObject;
|
|||
import org.mozilla.gecko.EventDispatcher;
|
||||
import org.mozilla.gecko.util.GeckoBundle;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
@ -39,9 +41,9 @@ public class WebExtension {
|
|||
*/
|
||||
public final @NonNull String id;
|
||||
/**
|
||||
* Whether content scripts can send messages to the browser or not.
|
||||
* {@link Flags} for this WebExtension.
|
||||
*/
|
||||
public final boolean allowContentMessaging;
|
||||
public final @WebExtensionFlags long flags;
|
||||
/**
|
||||
* Delegates that handle messaging between this WebExtension and the app.
|
||||
*/
|
||||
|
@ -49,6 +51,27 @@ public class WebExtension {
|
|||
|
||||
private final static String LOGTAG = "WebExtension";
|
||||
|
||||
public static class Flags {
|
||||
/*
|
||||
* Default flags for this WebExtension.
|
||||
*/
|
||||
public static final long NONE = 0;
|
||||
/**
|
||||
* Set this flag if you want to enable content scripts messaging.
|
||||
* To listen to such messages you can use
|
||||
* {@link WebExtension#setMessageDelegate}.
|
||||
*/
|
||||
public static final long ALLOW_CONTENT_MESSAGING = 1 << 0;
|
||||
|
||||
// Do not instantiate this class.
|
||||
protected Flags() {}
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef(flag = true,
|
||||
value = { Flags.NONE, Flags.ALLOW_CONTENT_MESSAGING })
|
||||
/* package */ @interface WebExtensionFlags {}
|
||||
|
||||
/**
|
||||
* Builds a WebExtension instance that can be loaded in GeckoView using
|
||||
* {@link GeckoRuntime#registerWebExtension}
|
||||
|
@ -95,15 +118,13 @@ public class WebExtension {
|
|||
* WebExtensions/WebExtensions_and_the_Add-on_ID
|
||||
* </a>
|
||||
* </ul>
|
||||
* @param allowContentMessaging Whether content scripts are allowed to send
|
||||
* messages to the browser or not. To listen to such messages you can
|
||||
* use {@link #setMessageDelegate(MessageDelegate, String)}.
|
||||
* @param flags {@link Flags} for this WebExtension.
|
||||
*/
|
||||
public WebExtension(final @NonNull String location, final @NonNull String id,
|
||||
final boolean allowContentMessaging) {
|
||||
final @WebExtensionFlags long flags) {
|
||||
this.location = location;
|
||||
this.id = id;
|
||||
this.allowContentMessaging = allowContentMessaging;
|
||||
this.flags = flags;
|
||||
this.messageDelegates = new HashMap<>();
|
||||
}
|
||||
|
||||
|
@ -120,7 +141,7 @@ public class WebExtension {
|
|||
* a <code>file:</code> URL to a <code>.xpi</code> file.
|
||||
*/
|
||||
public WebExtension(final @NonNull String location) {
|
||||
this(location, "{" + UUID.randomUUID().toString() + "}", false);
|
||||
this(location, "{" + UUID.randomUUID().toString() + "}", Flags.NONE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -144,7 +144,7 @@ import java.util.Map;
|
|||
private WebExtension.MessageDelegate getDelegate(
|
||||
final String nativeApp, final WebExtension.MessageSender sender,
|
||||
final EventCallback callback) {
|
||||
if (!sender.webExtension.allowContentMessaging &&
|
||||
if ((sender.webExtension.flags & WebExtension.Flags.ALLOW_CONTENT_MESSAGING) == 0 &&
|
||||
sender.environmentType == WebExtension.MessageSender.ENV_TYPE_CONTENT_SCRIPT) {
|
||||
callback.sendError("This NativeApp can't receive messages from Content Scripts.");
|
||||
return null;
|
||||
|
|
|
@ -53,7 +53,7 @@ public class WebRequest extends WebMessage {
|
|||
@IntDef({CACHE_MODE_DEFAULT, CACHE_MODE_NO_STORE,
|
||||
CACHE_MODE_RELOAD, CACHE_MODE_NO_CACHE,
|
||||
CACHE_MODE_FORCE_CACHE, CACHE_MODE_ONLY_IF_CACHED})
|
||||
public @interface CacheMode {};
|
||||
/* package */ @interface CacheMode {};
|
||||
|
||||
/**
|
||||
* Default cache mode. Normal caching rules apply.
|
||||
|
@ -183,7 +183,7 @@ public class WebRequest extends WebMessage {
|
|||
/**
|
||||
* Set the cache mode.
|
||||
*
|
||||
* @param mode One of {@link CacheMode}.
|
||||
* @param mode One of the {@link #CACHE_MODE_DEFAULT CACHE_*} flags.
|
||||
* @return This Builder instance.
|
||||
*/
|
||||
public @NonNull Builder cacheMode(final @CacheMode int mode) {
|
||||
|
|
|
@ -26,7 +26,7 @@ public class WebRequestError extends Exception {
|
|||
ERROR_CATEGORY_NETWORK, ERROR_CATEGORY_CONTENT,
|
||||
ERROR_CATEGORY_URI, ERROR_CATEGORY_PROXY,
|
||||
ERROR_CATEGORY_SAFEBROWSING})
|
||||
public @interface ErrorCategory {}
|
||||
/* package */ @interface ErrorCategory {}
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({ERROR_UNKNOWN, ERROR_SECURITY_SSL, ERROR_SECURITY_BAD_CERT,
|
||||
|
@ -41,7 +41,7 @@ public class WebRequestError extends Exception {
|
|||
ERROR_PROXY_CONNECTION_REFUSED, ERROR_FILE_NOT_FOUND,
|
||||
ERROR_FILE_ACCESS_DENIED, ERROR_INVALID_CONTENT_ENCODING,
|
||||
ERROR_UNSAFE_CONTENT_TYPE, ERROR_CORRUPTED_CONTENT})
|
||||
public @interface Error {}
|
||||
/* package */ @interface Error {}
|
||||
|
||||
/**
|
||||
* This is normally used for error codes that don't
|
||||
|
|
|
@ -304,4 +304,4 @@ exclude: true
|
|||
[65.24]: ../CrashReporter.html#sendCrashReport-android.content.Context-android.os.Bundle-java.lang.String-
|
||||
[65.25]: ../GeckoResult.html
|
||||
|
||||
[api-version]: 3b910c2e6b3df9bd9926cf4e54b37a5a08bdb64a
|
||||
[api-version]: 3fbf9d92418d270558cefad65cfe00599aeae263
|
||||
|
|
|
@ -409,6 +409,8 @@ android-x86_64-opt-tests:
|
|||
# geckoview-junit perma-fail on opt and debug; bug 1521195
|
||||
# - geckoview-junit
|
||||
- mochitest
|
||||
- web-platform-tests
|
||||
- web-platform-tests-reftests
|
||||
|
||||
android-x86_64-tests:
|
||||
- gtest
|
||||
|
|
|
@ -25,6 +25,10 @@ job-defaults:
|
|||
default:
|
||||
- web_platform_tests/prod_config.py
|
||||
- remove_executables.py
|
||||
target:
|
||||
by-test-platform:
|
||||
android-em-7.0-x86_64/opt: geckoview-androidTest.apk
|
||||
default: null
|
||||
|
||||
web-platform-tests:
|
||||
description: "Web platform test run"
|
||||
|
@ -32,7 +36,7 @@ web-platform-tests:
|
|||
treeherder-symbol: W(wpt)
|
||||
chunks:
|
||||
by-test-platform:
|
||||
android.*: 36
|
||||
android.*: 18
|
||||
linux.*/debug: 18
|
||||
macosx64.*/opt: 8
|
||||
macosx64/debug: 16
|
||||
|
@ -57,6 +61,7 @@ web-platform-tests:
|
|||
default: built-projects
|
||||
tier:
|
||||
by-test-platform:
|
||||
android-em-7.0-x86_64/opt: 3
|
||||
android.*: 2
|
||||
linux64-asan/opt: 2
|
||||
windows10-aarch64.*: 2
|
||||
|
@ -100,10 +105,7 @@ web-platform-tests-reftests:
|
|||
name: web-platform-tests-reftests
|
||||
schedules-component: web-platform-tests-reftests
|
||||
treeherder-symbol: W(Wr)
|
||||
chunks:
|
||||
by-test-platform:
|
||||
android.*: 12
|
||||
default: 6
|
||||
chunks: 6
|
||||
e10s:
|
||||
by-test-platform:
|
||||
linux32/debug: both
|
||||
|
@ -115,6 +117,7 @@ web-platform-tests-reftests:
|
|||
default: built-projects
|
||||
tier:
|
||||
by-test-platform:
|
||||
android-em-7.0-x86_64/opt: 3
|
||||
android.*: 2
|
||||
linux64-asan/opt: 2
|
||||
windows10-aarch64.*: 2
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
[
|
||||
{
|
||||
"size": 445663957,
|
||||
"visibility": "public",
|
||||
"digest": "d1846b9184ac70e95345cf4226607706bbac72b648cf6583f01aa3950bc2be3b7476263377601f986203dae87af406f11eaf9569ed3e48eb8ce90c02c93704b1",
|
||||
"algorithm": "sha512",
|
||||
"filename": "AVDs-x86-android-7.0-build-2019-01-22.tar.gz",
|
||||
"unpack": true
|
||||
"visibility": "public",
|
||||
"filename": "AVDs-x86-android-7.0-build-2019-04-23.tar.gz",
|
||||
"unpack": true,
|
||||
"digest": "3cc03789aabfc692c76e5ae4ebefa7a5628f386df3c9778af2485a49b2401d4ad66301be6c3d116ff7d3ee747e00ce6332381216f55a7253b6b5b600d059baa2",
|
||||
"size": 445250935
|
||||
}
|
||||
]
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
[
|
||||
{
|
||||
"size": 445663957,
|
||||
"visibility": "public",
|
||||
"digest": "d1846b9184ac70e95345cf4226607706bbac72b648cf6583f01aa3950bc2be3b7476263377601f986203dae87af406f11eaf9569ed3e48eb8ce90c02c93704b1",
|
||||
"algorithm": "sha512",
|
||||
"filename": "AVDs-x86-android-7.0-build-2019-01-22.tar.gz",
|
||||
"unpack": true
|
||||
"visibility": "public",
|
||||
"filename": "AVDs-x86-android-7.0-build-2019-04-23.tar.gz",
|
||||
"unpack": true,
|
||||
"digest": "3cc03789aabfc692c76e5ae4ebefa7a5628f386df3c9778af2485a49b2401d4ad66301be6c3d116ff7d3ee747e00ce6332381216f55a7253b6b5b600d059baa2",
|
||||
"size": 445250935
|
||||
}
|
||||
]
|
||||
|
|
|
@ -4,6 +4,6 @@
|
|||
if debug: true
|
||||
[@font-face fonts should work even if they are not used in the page]
|
||||
expected:
|
||||
if (os == "android"): PASS
|
||||
if os == "android" and not e10s: PASS
|
||||
FAIL
|
||||
|
||||
|
|
|
@ -4,5 +4,5 @@
|
|||
if (os == "linux"): FAIL
|
||||
if (os == "win"): FAIL
|
||||
if (os == "mac"): FAIL
|
||||
if (os == "android"): FAIL
|
||||
if os == "android" and not e10s: FAIL
|
||||
|
||||
|
|
|
@ -4,5 +4,5 @@
|
|||
if (os == "win"): FAIL
|
||||
if (os == "mac"): FAIL
|
||||
if (os == "linux"): FAIL
|
||||
if (os == "android"): FAIL
|
||||
if os == "android" and not e10s: FAIL
|
||||
|
||||
|
|
|
@ -4,5 +4,5 @@
|
|||
if (os == "linux"): FAIL
|
||||
if (os == "win"): FAIL
|
||||
if (os == "mac"): FAIL
|
||||
if (os == "android"): FAIL
|
||||
if os == "android" and not e10s: FAIL
|
||||
|
||||
|
|
|
@ -4,5 +4,5 @@
|
|||
if (os == "linux"): FAIL
|
||||
if (os == "win"): FAIL
|
||||
if (os == "mac"): FAIL
|
||||
if (os == "android"): FAIL
|
||||
if os == "android" and not e10s: FAIL
|
||||
|
||||
|
|
|
@ -4,5 +4,5 @@
|
|||
if (os == "win"): FAIL
|
||||
if (os == "mac"): FAIL
|
||||
if (os == "linux"): FAIL
|
||||
if (os == "android"): FAIL
|
||||
if os == "android" and not e10s: FAIL
|
||||
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче