mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge inbound to m-c. a=merge
This commit is contained in:
commit
ced0ea44b5
@ -255,8 +255,8 @@ nsAccUtils::TableFor(Accessible* aRow)
|
|||||||
tableRole = table->Role();
|
tableRole = table->Role();
|
||||||
}
|
}
|
||||||
|
|
||||||
return tableRole == roles::TABLE || tableRole == roles::TREE_TABLE ?
|
return (tableRole == roles::TABLE || tableRole == roles::TREE_TABLE ||
|
||||||
table : nullptr;
|
tableRole == roles::MATHML_TABLE) ? table : nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -823,6 +823,8 @@ ConvertToNSArray(nsTArray<Accessible*>& aArray)
|
|||||||
return @"AXMathSubscriptSuperscript";
|
return @"AXMathSubscriptSuperscript";
|
||||||
|
|
||||||
case roles::MATHML_ROW:
|
case roles::MATHML_ROW:
|
||||||
|
case roles::MATHML_STYLE:
|
||||||
|
case roles::MATHML_ERROR:
|
||||||
return @"AXMathRow";
|
return @"AXMathRow";
|
||||||
|
|
||||||
case roles::MATHML_UNDER:
|
case roles::MATHML_UNDER:
|
||||||
|
@ -23,42 +23,42 @@ AUTOMATION_UPLOAD_OUTPUT = $(DIST)/automation-upload.txt
|
|||||||
|
|
||||||
# Helper variables to convert from MOZ_AUTOMATION_* variables to the
|
# Helper variables to convert from MOZ_AUTOMATION_* variables to the
|
||||||
# corresponding the make target
|
# corresponding the make target
|
||||||
tier_BUILD_SYMBOLS = buildsymbols
|
tier_MOZ_AUTOMATION_BUILD_SYMBOLS = buildsymbols
|
||||||
tier_L10N_CHECK = l10n-check
|
tier_MOZ_AUTOMATION_L10N_CHECK = l10n-check
|
||||||
tier_PRETTY_L10N_CHECK = pretty-l10n-check
|
tier_MOZ_AUTOMATION_PRETTY_L10N_CHECK = pretty-l10n-check
|
||||||
tier_INSTALLER = installer
|
tier_MOZ_AUTOMATION_INSTALLER = installer
|
||||||
tier_PRETTY_INSTALLER = pretty-installer
|
tier_MOZ_AUTOMATION_PRETTY_INSTALLER = pretty-installer
|
||||||
tier_PACKAGE = package
|
tier_MOZ_AUTOMATION_PACKAGE = package
|
||||||
tier_PRETTY_PACKAGE = pretty-package
|
tier_MOZ_AUTOMATION_PRETTY_PACKAGE = pretty-package
|
||||||
tier_PACKAGE_TESTS = package-tests
|
tier_MOZ_AUTOMATION_PACKAGE_TESTS = package-tests
|
||||||
tier_PRETTY_PACKAGE_TESTS = pretty-package-tests
|
tier_MOZ_AUTOMATION_PRETTY_PACKAGE_TESTS = pretty-package-tests
|
||||||
tier_UPDATE_PACKAGING = update-packaging
|
tier_MOZ_AUTOMATION_UPDATE_PACKAGING = update-packaging
|
||||||
tier_PRETTY_UPDATE_PACKAGING = pretty-update-packaging
|
tier_MOZ_AUTOMATION_PRETTY_UPDATE_PACKAGING = pretty-update-packaging
|
||||||
tier_UPLOAD_SYMBOLS = uploadsymbols
|
tier_MOZ_AUTOMATION_UPLOAD_SYMBOLS = uploadsymbols
|
||||||
tier_UPLOAD = upload
|
tier_MOZ_AUTOMATION_UPLOAD = upload
|
||||||
tier_SDK = sdk
|
tier_MOZ_AUTOMATION_SDK = sdk
|
||||||
|
|
||||||
# Automation build steps. Everything in MOZ_AUTOMATION_TIERS also gets used in
|
# Automation build steps. Everything in MOZ_AUTOMATION_TIERS also gets used in
|
||||||
# TIERS for mach display. As such, the MOZ_AUTOMATION_TIERS are roughly sorted
|
# TIERS for mach display. As such, the MOZ_AUTOMATION_TIERS are roughly sorted
|
||||||
# here in the order that they will be executed (since mach doesn't know of the
|
# here in the order that they will be executed (since mach doesn't know of the
|
||||||
# dependencies between them).
|
# dependencies between them).
|
||||||
moz_automation_symbols = \
|
moz_automation_symbols = \
|
||||||
PACKAGE_TESTS \
|
MOZ_AUTOMATION_PACKAGE_TESTS \
|
||||||
PRETTY_PACKAGE_TESTS \
|
MOZ_AUTOMATION_PRETTY_PACKAGE_TESTS \
|
||||||
BUILD_SYMBOLS \
|
MOZ_AUTOMATION_BUILD_SYMBOLS \
|
||||||
UPLOAD_SYMBOLS \
|
MOZ_AUTOMATION_UPLOAD_SYMBOLS \
|
||||||
PACKAGE \
|
MOZ_AUTOMATION_PACKAGE \
|
||||||
PRETTY_PACKAGE \
|
MOZ_AUTOMATION_PRETTY_PACKAGE \
|
||||||
INSTALLER \
|
MOZ_AUTOMATION_INSTALLER \
|
||||||
PRETTY_INSTALLER \
|
MOZ_AUTOMATION_PRETTY_INSTALLER \
|
||||||
UPDATE_PACKAGING \
|
MOZ_AUTOMATION_UPDATE_PACKAGING \
|
||||||
PRETTY_UPDATE_PACKAGING \
|
MOZ_AUTOMATION_PRETTY_UPDATE_PACKAGING \
|
||||||
L10N_CHECK \
|
MOZ_AUTOMATION_L10N_CHECK \
|
||||||
PRETTY_L10N_CHECK \
|
MOZ_AUTOMATION_PRETTY_L10N_CHECK \
|
||||||
UPLOAD \
|
MOZ_AUTOMATION_UPLOAD \
|
||||||
SDK \
|
MOZ_AUTOMATION_SDK \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
MOZ_AUTOMATION_TIERS := $(foreach sym,$(moz_automation_symbols),$(if $(filter 1,$(MOZ_AUTOMATION_$(sym))),$(tier_$(sym))))
|
MOZ_AUTOMATION_TIERS := $(foreach sym,$(moz_automation_symbols),$(if $(filter 1,$($(sym))),$(tier_$(sym))))
|
||||||
|
|
||||||
# Dependencies between automation build steps
|
# Dependencies between automation build steps
|
||||||
automation/uploadsymbols: automation/buildsymbols
|
automation/uploadsymbols: automation/buildsymbols
|
||||||
@ -119,10 +119,14 @@ AUTOMATION_EXTRA_CMDLINE-pretty-package-tests = -j1
|
|||||||
# However, the target automation/buildsymbols will still be executed in this
|
# However, the target automation/buildsymbols will still be executed in this
|
||||||
# case because it is a prerequisite of automation/upload.
|
# case because it is a prerequisite of automation/upload.
|
||||||
define automation_commands
|
define automation_commands
|
||||||
$(call BUILDSTATUS,TIER_START $1)
|
|
||||||
@$(MAKE) $1 $(AUTOMATION_EXTRA_CMDLINE-$1)
|
@$(MAKE) $1 $(AUTOMATION_EXTRA_CMDLINE-$1)
|
||||||
$(call BUILDSTATUS,TIER_FINISH $1)
|
$(call BUILDSTATUS,TIER_FINISH $1)
|
||||||
endef
|
endef
|
||||||
|
|
||||||
automation/%:
|
# The tier start message is in a separate target so make doesn't buffer it
|
||||||
|
# until the step completes with output syncing enabled.
|
||||||
|
automation-start/%:
|
||||||
|
$(if $(filter $*,$(MOZ_AUTOMATION_TIERS)),$(call BUILDSTATUS,TIER_START $*))
|
||||||
|
|
||||||
|
automation/%: automation-start/%
|
||||||
$(if $(filter $*,$(MOZ_AUTOMATION_TIERS)),$(call automation_commands,$*))
|
$(if $(filter $*,$(MOZ_AUTOMATION_TIERS)),$(call automation_commands,$*))
|
||||||
|
@ -499,7 +499,14 @@ function runTest() {
|
|||||||
var chromeDoc = SpecialPowers.wrap(document);
|
var chromeDoc = SpecialPowers.wrap(document);
|
||||||
ok(chromeDoc.documentURI.indexOf("pushStateTest") > -1);
|
ok(chromeDoc.documentURI.indexOf("pushStateTest") > -1);
|
||||||
|
|
||||||
|
SimpleTest.executeSoon(function() { gen.next(); });
|
||||||
|
|
||||||
|
yield undefined;
|
||||||
|
|
||||||
history.back();
|
history.back();
|
||||||
|
SimpleTest.executeSoon(function() { gen.next(); });
|
||||||
|
|
||||||
|
yield undefined;
|
||||||
|
|
||||||
SimpleTest.finish();
|
SimpleTest.finish();
|
||||||
SpecialPowers.removePermission("systemXHR", document);
|
SpecialPowers.removePermission("systemXHR", document);
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include "mozilla/IMEStateManager.h"
|
#include "mozilla/IMEStateManager.h"
|
||||||
#include "mozilla/TextEvents.h"
|
#include "mozilla/TextEvents.h"
|
||||||
#include "mozilla/dom/Element.h"
|
#include "mozilla/dom/Element.h"
|
||||||
|
#include "mozilla/dom/Selection.h"
|
||||||
#include "nsCaret.h"
|
#include "nsCaret.h"
|
||||||
#include "nsCOMPtr.h"
|
#include "nsCOMPtr.h"
|
||||||
#include "nsContentUtils.h"
|
#include "nsContentUtils.h"
|
||||||
@ -19,8 +20,6 @@
|
|||||||
#include "nsIPresShell.h"
|
#include "nsIPresShell.h"
|
||||||
#include "nsISelection.h"
|
#include "nsISelection.h"
|
||||||
#include "nsISelectionController.h"
|
#include "nsISelectionController.h"
|
||||||
#include "nsISelectionPrivate.h"
|
|
||||||
#include "nsIDOMRange.h"
|
|
||||||
#include "nsIFrame.h"
|
#include "nsIFrame.h"
|
||||||
#include "nsIObjectFrame.h"
|
#include "nsIObjectFrame.h"
|
||||||
#include "nsLayoutUtils.h"
|
#include "nsLayoutUtils.h"
|
||||||
@ -75,16 +74,19 @@ ContentEventHandler::InitCommon()
|
|||||||
nsresult rv = InitBasic();
|
nsresult rv = InitBasic();
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
nsCOMPtr<nsISelection> sel;
|
||||||
nsCopySupport::GetSelectionForCopy(mPresShell->GetDocument(),
|
nsCopySupport::GetSelectionForCopy(mPresShell->GetDocument(),
|
||||||
getter_AddRefs(mSelection));
|
getter_AddRefs(sel));
|
||||||
|
mSelection = static_cast<Selection*>(sel.get());
|
||||||
nsCOMPtr<nsIDOMRange> firstRange;
|
if (NS_WARN_IF(!mSelection)) {
|
||||||
rv = mSelection->GetRangeAt(0, getter_AddRefs(firstRange));
|
|
||||||
// This shell doesn't support selection.
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
return NS_ERROR_NOT_AVAILABLE;
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
}
|
}
|
||||||
mFirstSelectedRange = static_cast<nsRange*>(firstRange.get());
|
|
||||||
|
// This shell doesn't support selection.
|
||||||
|
if (NS_WARN_IF(!mSelection->RangeCount())) {
|
||||||
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
|
}
|
||||||
|
mFirstSelectedRange = mSelection->GetRangeAt(0);
|
||||||
|
|
||||||
nsINode* startNode = mFirstSelectedRange->GetStartParent();
|
nsINode* startNode = mFirstSelectedRange->GetStartParent();
|
||||||
NS_ENSURE_TRUE(startNode, NS_ERROR_FAILURE);
|
NS_ENSURE_TRUE(startNode, NS_ERROR_FAILURE);
|
||||||
@ -114,15 +116,16 @@ ContentEventHandler::Init(WidgetQueryContentEvent* aEvent)
|
|||||||
|
|
||||||
aEvent->mReply.mContentsRoot = mRootContent.get();
|
aEvent->mReply.mContentsRoot = mRootContent.get();
|
||||||
|
|
||||||
bool isCollapsed;
|
aEvent->mReply.mHasSelection = !mSelection->IsCollapsed();
|
||||||
rv = mSelection->GetIsCollapsed(&isCollapsed);
|
|
||||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_NOT_AVAILABLE);
|
|
||||||
aEvent->mReply.mHasSelection = !isCollapsed;
|
|
||||||
|
|
||||||
nsRect r;
|
nsRect r;
|
||||||
nsIFrame* frame = nsCaret::GetGeometry(mSelection, &r);
|
nsIFrame* frame = nsCaret::GetGeometry(mSelection, &r);
|
||||||
NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
|
if (!frame) {
|
||||||
|
frame = mRootContent->GetPrimaryFrame();
|
||||||
|
if (NS_WARN_IF(!frame)) {
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
aEvent->mReply.mFocusedWidget = frame->GetNearestWidget();
|
aEvent->mReply.mFocusedWidget = frame->GetNearestWidget();
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
@ -750,7 +753,7 @@ ContentEventHandler::SetRangeFromFlatTextOffset(nsRange* aRange,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
rv = aRange->SetEnd(mRootContent, int32_t(mRootContent->GetChildCount()));
|
rv = aRange->SetEnd(mRootContent, int32_t(mRootContent->GetChildCount()));
|
||||||
NS_ASSERTION(NS_SUCCEEDED(rv), "nsIDOMRange::SetEnd failed");
|
NS_ASSERTION(NS_SUCCEEDED(rv), "nsRange::SetEnd failed");
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -806,21 +809,17 @@ ContentEventHandler::OnQuerySelectedText(WidgetQueryContentEvent* aEvent)
|
|||||||
&aEvent->mReply.mOffset, lineBreakType);
|
&aEvent->mReply.mOffset, lineBreakType);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
nsCOMPtr<nsIDOMNode> anchorDomNode, focusDomNode;
|
nsCOMPtr<nsINode> anchorNode = mSelection->GetAnchorNode();
|
||||||
rv = mSelection->GetAnchorNode(getter_AddRefs(anchorDomNode));
|
nsCOMPtr<nsINode> focusNode = mSelection->GetFocusNode();
|
||||||
NS_ENSURE_TRUE(anchorDomNode, NS_ERROR_FAILURE);
|
if (NS_WARN_IF(!anchorNode) || NS_WARN_IF(!focusNode)) {
|
||||||
rv = mSelection->GetFocusNode(getter_AddRefs(focusDomNode));
|
return NS_ERROR_FAILURE;
|
||||||
NS_ENSURE_TRUE(focusDomNode, NS_ERROR_FAILURE);
|
}
|
||||||
|
|
||||||
int32_t anchorOffset, focusOffset;
|
int32_t anchorOffset = static_cast<int32_t>(mSelection->AnchorOffset());
|
||||||
rv = mSelection->GetAnchorOffset(&anchorOffset);
|
int32_t focusOffset = static_cast<int32_t>(mSelection->FocusOffset());
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
if (NS_WARN_IF(anchorOffset < 0) || NS_WARN_IF(focusOffset < 0)) {
|
||||||
rv = mSelection->GetFocusOffset(&focusOffset);
|
return NS_ERROR_FAILURE;
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsINode> anchorNode(do_QueryInterface(anchorDomNode));
|
|
||||||
nsCOMPtr<nsINode> focusNode(do_QueryInterface(focusDomNode));
|
|
||||||
NS_ENSURE_TRUE(anchorNode && focusNode, NS_ERROR_UNEXPECTED);
|
|
||||||
|
|
||||||
int16_t compare = nsContentUtils::ComparePoints(anchorNode, anchorOffset,
|
int16_t compare = nsContentUtils::ComparePoints(anchorNode, anchorOffset,
|
||||||
focusNode, focusOffset);
|
focusNode, focusOffset);
|
||||||
@ -1032,32 +1031,29 @@ ContentEventHandler::OnQueryCaretRect(WidgetQueryContentEvent* aEvent)
|
|||||||
|
|
||||||
LineBreakType lineBreakType = GetLineBreakType(aEvent);
|
LineBreakType lineBreakType = GetLineBreakType(aEvent);
|
||||||
|
|
||||||
|
nsRect caretRect;
|
||||||
|
|
||||||
// When the selection is collapsed and the queried offset is current caret
|
// When the selection is collapsed and the queried offset is current caret
|
||||||
// position, we should return the "real" caret rect.
|
// position, we should return the "real" caret rect.
|
||||||
bool selectionIsCollapsed;
|
if (mSelection->IsCollapsed()) {
|
||||||
rv = mSelection->GetIsCollapsed(&selectionIsCollapsed);
|
nsIFrame* caretFrame = nsCaret::GetGeometry(mSelection, &caretRect);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
if (caretFrame) {
|
||||||
|
uint32_t offset;
|
||||||
nsRect caretRect;
|
rv = GetFlatTextOffsetOfRange(mRootContent, mFirstSelectedRange, &offset,
|
||||||
nsIFrame* caretFrame = nsCaret::GetGeometry(mSelection, &caretRect);
|
lineBreakType);
|
||||||
|
|
||||||
if (selectionIsCollapsed) {
|
|
||||||
uint32_t offset;
|
|
||||||
rv = GetFlatTextOffsetOfRange(mRootContent, mFirstSelectedRange, &offset,
|
|
||||||
lineBreakType);
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
if (offset == aEvent->mInput.mOffset) {
|
|
||||||
if (!caretFrame) {
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
rv = ConvertToRootViewRelativeOffset(caretFrame, caretRect);
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
aEvent->mReply.mRect = LayoutDevicePixel::FromUntyped(
|
if (offset == aEvent->mInput.mOffset) {
|
||||||
caretRect.ToOutsidePixels(caretFrame->PresContext()->AppUnitsPerDevPixel()));
|
rv = ConvertToRootViewRelativeOffset(caretFrame, caretRect);
|
||||||
aEvent->mReply.mWritingMode = caretFrame->GetWritingMode();
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
aEvent->mReply.mOffset = aEvent->mInput.mOffset;
|
nscoord appUnitsPerDevPixel =
|
||||||
aEvent->mSucceeded = true;
|
caretFrame->PresContext()->AppUnitsPerDevPixel();
|
||||||
return NS_OK;
|
aEvent->mReply.mRect = LayoutDevicePixel::FromUntyped(
|
||||||
|
caretRect.ToOutsidePixels(appUnitsPerDevPixel));
|
||||||
|
aEvent->mReply.mWritingMode = caretFrame->GetWritingMode();
|
||||||
|
aEvent->mReply.mOffset = aEvent->mInput.mOffset;
|
||||||
|
aEvent->mSucceeded = true;
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1527,9 +1523,11 @@ ContentEventHandler::OnSelectionEvent(WidgetSelectionEvent* aEvent)
|
|||||||
// Get selection to manipulate
|
// Get selection to manipulate
|
||||||
// XXX why do we need to get them from ISM? This method should work fine
|
// XXX why do we need to get them from ISM? This method should work fine
|
||||||
// without ISM.
|
// without ISM.
|
||||||
|
nsCOMPtr<nsISelection> sel;
|
||||||
nsresult rv =
|
nsresult rv =
|
||||||
IMEStateManager::GetFocusSelectionAndRoot(getter_AddRefs(mSelection),
|
IMEStateManager::GetFocusSelectionAndRoot(getter_AddRefs(sel),
|
||||||
getter_AddRefs(mRootContent));
|
getter_AddRefs(mRootContent));
|
||||||
|
mSelection = static_cast<Selection*>(sel.get());
|
||||||
if (rv != NS_ERROR_NOT_AVAILABLE) {
|
if (rv != NS_ERROR_NOT_AVAILABLE) {
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
} else {
|
} else {
|
||||||
@ -1550,36 +1548,35 @@ ContentEventHandler::OnSelectionEvent(WidgetSelectionEvent* aEvent)
|
|||||||
int32_t endNodeOffset = range->EndOffset();
|
int32_t endNodeOffset = range->EndOffset();
|
||||||
AdjustRangeForSelection(mRootContent, &startNode, &startNodeOffset);
|
AdjustRangeForSelection(mRootContent, &startNode, &startNodeOffset);
|
||||||
AdjustRangeForSelection(mRootContent, &endNode, &endNodeOffset);
|
AdjustRangeForSelection(mRootContent, &endNode, &endNodeOffset);
|
||||||
|
if (NS_WARN_IF(!startNode) || NS_WARN_IF(!endNode) ||
|
||||||
|
NS_WARN_IF(startNodeOffset < 0) || NS_WARN_IF(endNodeOffset < 0)) {
|
||||||
|
return NS_ERROR_UNEXPECTED;
|
||||||
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIDOMNode> startDomNode(do_QueryInterface(startNode));
|
mSelection->StartBatchChanges();
|
||||||
nsCOMPtr<nsIDOMNode> endDomNode(do_QueryInterface(endNode));
|
|
||||||
NS_ENSURE_TRUE(startDomNode && endDomNode, NS_ERROR_UNEXPECTED);
|
|
||||||
|
|
||||||
nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryInterface(mSelection));
|
|
||||||
selPrivate->StartBatchChanges();
|
|
||||||
|
|
||||||
// Clear selection first before setting
|
// Clear selection first before setting
|
||||||
rv = mSelection->RemoveAllRanges();
|
rv = mSelection->RemoveAllRanges();
|
||||||
// Need to call EndBatchChanges at the end even if call failed
|
// Need to call EndBatchChanges at the end even if call failed
|
||||||
if (NS_SUCCEEDED(rv)) {
|
if (NS_SUCCEEDED(rv)) {
|
||||||
if (aEvent->mReversed) {
|
if (aEvent->mReversed) {
|
||||||
rv = mSelection->Collapse(endDomNode, endNodeOffset);
|
rv = mSelection->Collapse(endNode, endNodeOffset);
|
||||||
} else {
|
} else {
|
||||||
rv = mSelection->Collapse(startDomNode, startNodeOffset);
|
rv = mSelection->Collapse(startNode, startNodeOffset);
|
||||||
}
|
}
|
||||||
if (NS_SUCCEEDED(rv) &&
|
if (NS_SUCCEEDED(rv) &&
|
||||||
(startDomNode != endDomNode || startNodeOffset != endNodeOffset)) {
|
(startNode != endNode || startNodeOffset != endNodeOffset)) {
|
||||||
if (aEvent->mReversed) {
|
if (aEvent->mReversed) {
|
||||||
rv = mSelection->Extend(startDomNode, startNodeOffset);
|
rv = mSelection->Extend(startNode, startNodeOffset);
|
||||||
} else {
|
} else {
|
||||||
rv = mSelection->Extend(endDomNode, endNodeOffset);
|
rv = mSelection->Extend(endNode, endNodeOffset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
selPrivate->EndBatchChanges();
|
mSelection->EndBatchChanges();
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
selPrivate->ScrollIntoViewInternal(
|
mSelection->ScrollIntoViewInternal(
|
||||||
nsISelectionController::SELECTION_FOCUS_REGION,
|
nsISelectionController::SELECTION_FOCUS_REGION,
|
||||||
false, nsIPresShell::ScrollAxis(), nsIPresShell::ScrollAxis());
|
false, nsIPresShell::ScrollAxis(), nsIPresShell::ScrollAxis());
|
||||||
aEvent->mSucceeded = true;
|
aEvent->mSucceeded = true;
|
||||||
|
@ -8,8 +8,8 @@
|
|||||||
#define mozilla_ContentEventHandler_h_
|
#define mozilla_ContentEventHandler_h_
|
||||||
|
|
||||||
#include "mozilla/EventForwards.h"
|
#include "mozilla/EventForwards.h"
|
||||||
|
#include "mozilla/dom/Selection.h"
|
||||||
#include "nsCOMPtr.h"
|
#include "nsCOMPtr.h"
|
||||||
#include "nsISelection.h"
|
|
||||||
#include "nsRange.h"
|
#include "nsRange.h"
|
||||||
|
|
||||||
class nsPresContext;
|
class nsPresContext;
|
||||||
@ -35,6 +35,8 @@ enum LineBreakType
|
|||||||
class MOZ_STACK_CLASS ContentEventHandler
|
class MOZ_STACK_CLASS ContentEventHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
typedef dom::Selection Selection;
|
||||||
|
|
||||||
explicit ContentEventHandler(nsPresContext* aPresContext);
|
explicit ContentEventHandler(nsPresContext* aPresContext);
|
||||||
|
|
||||||
// NS_QUERY_SELECTED_TEXT event handler
|
// NS_QUERY_SELECTED_TEXT event handler
|
||||||
@ -62,7 +64,7 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
nsPresContext* mPresContext;
|
nsPresContext* mPresContext;
|
||||||
nsCOMPtr<nsIPresShell> mPresShell;
|
nsCOMPtr<nsIPresShell> mPresShell;
|
||||||
nsCOMPtr<nsISelection> mSelection;
|
nsRefPtr<Selection> mSelection;
|
||||||
nsRefPtr<nsRange> mFirstSelectedRange;
|
nsRefPtr<nsRange> mFirstSelectedRange;
|
||||||
nsCOMPtr<nsIContent> mRootContent;
|
nsCOMPtr<nsIContent> mRootContent;
|
||||||
|
|
||||||
|
@ -3385,7 +3385,7 @@ EventStateManager::RemoteQueryContentEvent(WidgetEvent* aEvent)
|
|||||||
TabParent*
|
TabParent*
|
||||||
EventStateManager::GetCrossProcessTarget()
|
EventStateManager::GetCrossProcessTarget()
|
||||||
{
|
{
|
||||||
return TabParent::GetIMETabParent();
|
return IMEStateManager::GetActiveTabParent();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@ -3396,7 +3396,7 @@ EventStateManager::IsTargetCrossProcess(WidgetGUIEvent* aEvent)
|
|||||||
nsIContent *focusedContent = GetFocusedContent();
|
nsIContent *focusedContent = GetFocusedContent();
|
||||||
if (focusedContent && focusedContent->IsEditable())
|
if (focusedContent && focusedContent->IsEditable())
|
||||||
return false;
|
return false;
|
||||||
return TabParent::GetIMETabParent() != nullptr;
|
return IMEStateManager::GetActiveTabParent() != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include "mozilla/Services.h"
|
#include "mozilla/Services.h"
|
||||||
#include "mozilla/TextComposition.h"
|
#include "mozilla/TextComposition.h"
|
||||||
#include "mozilla/TextEvents.h"
|
#include "mozilla/TextEvents.h"
|
||||||
|
#include "mozilla/unused.h"
|
||||||
#include "mozilla/dom/HTMLFormElement.h"
|
#include "mozilla/dom/HTMLFormElement.h"
|
||||||
#include "mozilla/dom/TabParent.h"
|
#include "mozilla/dom/TabParent.h"
|
||||||
|
|
||||||
@ -180,19 +181,17 @@ GetNotifyIMEMessageName(IMEMessage aMessage)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nsIContent* IMEStateManager::sContent = nullptr;
|
StaticRefPtr<nsIContent> IMEStateManager::sContent;
|
||||||
nsPresContext* IMEStateManager::sPresContext = nullptr;
|
nsPresContext* IMEStateManager::sPresContext = nullptr;
|
||||||
StaticRefPtr<nsIWidget> IMEStateManager::sFocusedIMEWidget;
|
StaticRefPtr<nsIWidget> IMEStateManager::sFocusedIMEWidget;
|
||||||
|
StaticRefPtr<TabParent> IMEStateManager::sActiveTabParent;
|
||||||
|
StaticRefPtr<IMEContentObserver> IMEStateManager::sActiveIMEContentObserver;
|
||||||
|
TextCompositionArray* IMEStateManager::sTextCompositions = nullptr;
|
||||||
bool IMEStateManager::sInstalledMenuKeyboardListener = false;
|
bool IMEStateManager::sInstalledMenuKeyboardListener = false;
|
||||||
bool IMEStateManager::sIsGettingNewIMEState = false;
|
bool IMEStateManager::sIsGettingNewIMEState = false;
|
||||||
bool IMEStateManager::sCheckForIMEUnawareWebApps = false;
|
bool IMEStateManager::sCheckForIMEUnawareWebApps = false;
|
||||||
bool IMEStateManager::sRemoteHasFocus = false;
|
bool IMEStateManager::sRemoteHasFocus = false;
|
||||||
|
|
||||||
// sActiveIMEContentObserver points to the currently active IMEContentObserver.
|
|
||||||
// sActiveIMEContentObserver is null if there is no focused editor.
|
|
||||||
IMEContentObserver* IMEStateManager::sActiveIMEContentObserver = nullptr;
|
|
||||||
TextCompositionArray* IMEStateManager::sTextCompositions = nullptr;
|
|
||||||
|
|
||||||
// static
|
// static
|
||||||
void
|
void
|
||||||
IMEStateManager::Init()
|
IMEStateManager::Init()
|
||||||
@ -221,6 +220,43 @@ IMEStateManager::Shutdown()
|
|||||||
sTextCompositions = nullptr;
|
sTextCompositions = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
void
|
||||||
|
IMEStateManager::OnTabParentDestroying(TabParent* aTabParent)
|
||||||
|
{
|
||||||
|
if (sActiveTabParent != aTabParent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
MOZ_LOG(sISMLog, LogLevel::Info,
|
||||||
|
("ISM: IMEStateManager::OnTabParentDestroying(aTabParent=0x%p), "
|
||||||
|
"The active TabParent is being destroyed", aTabParent));
|
||||||
|
|
||||||
|
// The active remote process might have crashed.
|
||||||
|
sActiveTabParent = nullptr;
|
||||||
|
|
||||||
|
// TODO: Need to cancel composition without TextComposition and make
|
||||||
|
// disable IME.
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
void
|
||||||
|
IMEStateManager::StopIMEStateManagement()
|
||||||
|
{
|
||||||
|
MOZ_LOG(sISMLog, LogLevel::Info,
|
||||||
|
("ISM: IMEStateManager::StopIMEStateManagement()"));
|
||||||
|
|
||||||
|
// NOTE: Don't set input context from here since this has already lost
|
||||||
|
// the rights to change input context.
|
||||||
|
|
||||||
|
if (sTextCompositions && sPresContext) {
|
||||||
|
NotifyIME(REQUEST_TO_COMMIT_COMPOSITION, sPresContext);
|
||||||
|
}
|
||||||
|
sPresContext = nullptr;
|
||||||
|
sContent = nullptr;
|
||||||
|
sActiveTabParent = nullptr;
|
||||||
|
DestroyIMEContentObserver();
|
||||||
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
nsresult
|
nsresult
|
||||||
IMEStateManager::OnDestroyPresContext(nsPresContext* aPresContext)
|
IMEStateManager::OnDestroyPresContext(nsPresContext* aPresContext)
|
||||||
@ -255,7 +291,7 @@ IMEStateManager::OnDestroyPresContext(nsPresContext* aPresContext)
|
|||||||
MOZ_LOG(sISMLog, LogLevel::Info,
|
MOZ_LOG(sISMLog, LogLevel::Info,
|
||||||
("ISM: IMEStateManager::OnDestroyPresContext(aPresContext=0x%p), "
|
("ISM: IMEStateManager::OnDestroyPresContext(aPresContext=0x%p), "
|
||||||
"sPresContext=0x%p, sContent=0x%p, sTextCompositions=0x%p",
|
"sPresContext=0x%p, sContent=0x%p, sTextCompositions=0x%p",
|
||||||
aPresContext, sPresContext, sContent, sTextCompositions));
|
aPresContext, sPresContext, sContent.get(), sTextCompositions));
|
||||||
|
|
||||||
DestroyIMEContentObserver();
|
DestroyIMEContentObserver();
|
||||||
|
|
||||||
@ -266,8 +302,9 @@ IMEStateManager::OnDestroyPresContext(nsPresContext* aPresContext)
|
|||||||
InputContextAction::LOST_FOCUS);
|
InputContextAction::LOST_FOCUS);
|
||||||
SetIMEState(newState, nullptr, widget, action);
|
SetIMEState(newState, nullptr, widget, action);
|
||||||
}
|
}
|
||||||
NS_IF_RELEASE(sContent);
|
sContent = nullptr;
|
||||||
sPresContext = nullptr;
|
sPresContext = nullptr;
|
||||||
|
sActiveTabParent = nullptr;
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -310,7 +347,7 @@ IMEStateManager::OnRemoveContent(nsPresContext* aPresContext,
|
|||||||
MOZ_LOG(sISMLog, LogLevel::Info,
|
MOZ_LOG(sISMLog, LogLevel::Info,
|
||||||
("ISM: IMEStateManager::OnRemoveContent(aPresContext=0x%p, "
|
("ISM: IMEStateManager::OnRemoveContent(aPresContext=0x%p, "
|
||||||
"aContent=0x%p), sPresContext=0x%p, sContent=0x%p, sTextCompositions=0x%p",
|
"aContent=0x%p), sPresContext=0x%p, sContent=0x%p, sTextCompositions=0x%p",
|
||||||
aPresContext, aContent, sPresContext, sContent, sTextCompositions));
|
aPresContext, aContent, sPresContext, sContent.get(), sTextCompositions));
|
||||||
|
|
||||||
DestroyIMEContentObserver();
|
DestroyIMEContentObserver();
|
||||||
|
|
||||||
@ -323,8 +360,9 @@ IMEStateManager::OnRemoveContent(nsPresContext* aPresContext,
|
|||||||
SetIMEState(newState, nullptr, widget, action);
|
SetIMEState(newState, nullptr, widget, action);
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IF_RELEASE(sContent);
|
sContent = nullptr;
|
||||||
sPresContext = nullptr;
|
sPresContext = nullptr;
|
||||||
|
sActiveTabParent = nullptr;
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
@ -350,16 +388,23 @@ IMEStateManager::OnChangeFocusInternal(nsPresContext* aPresContext,
|
|||||||
nsIContent* aContent,
|
nsIContent* aContent,
|
||||||
InputContextAction aAction)
|
InputContextAction aAction)
|
||||||
{
|
{
|
||||||
|
nsRefPtr<TabParent> newTabParent = TabParent::GetFrom(aContent);
|
||||||
|
|
||||||
MOZ_LOG(sISMLog, LogLevel::Info,
|
MOZ_LOG(sISMLog, LogLevel::Info,
|
||||||
("ISM: IMEStateManager::OnChangeFocusInternal(aPresContext=0x%p, "
|
("ISM: IMEStateManager::OnChangeFocusInternal(aPresContext=0x%p, "
|
||||||
"aContent=0x%p, aAction={ mCause=%s, mFocusChange=%s }), "
|
"aContent=0x%p (TabParent=0x%p), aAction={ mCause=%s, mFocusChange=%s }), "
|
||||||
"sPresContext=0x%p, sContent=0x%p, sActiveIMEContentObserver=0x%p",
|
"sPresContext=0x%p, sContent=0x%p, sActiveTabParent=0x%p, "
|
||||||
aPresContext, aContent, GetActionCauseName(aAction.mCause),
|
"sActiveIMEContentObserver=0x%p, sInstalledMenuKeyboardListener=%s",
|
||||||
|
aPresContext, aContent, newTabParent.get(),
|
||||||
|
GetActionCauseName(aAction.mCause),
|
||||||
GetActionFocusChangeName(aAction.mFocusChange),
|
GetActionFocusChangeName(aAction.mFocusChange),
|
||||||
sPresContext, sContent, sActiveIMEContentObserver));
|
sPresContext, sContent.get(), sActiveTabParent.get(),
|
||||||
|
sActiveIMEContentObserver.get(),
|
||||||
|
GetBoolName(sInstalledMenuKeyboardListener)));
|
||||||
|
|
||||||
bool focusActuallyChanging =
|
bool focusActuallyChanging =
|
||||||
(sContent != aContent || sPresContext != aPresContext);
|
(sContent != aContent || sPresContext != aPresContext ||
|
||||||
|
sActiveTabParent != newTabParent);
|
||||||
|
|
||||||
nsCOMPtr<nsIWidget> oldWidget =
|
nsCOMPtr<nsIWidget> oldWidget =
|
||||||
sPresContext ? sPresContext->GetRootWidget() : nullptr;
|
sPresContext ? sPresContext->GetRootWidget() : nullptr;
|
||||||
@ -384,6 +429,18 @@ IMEStateManager::OnChangeFocusInternal(nsPresContext* aPresContext,
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsIContentParent* currentContentParent =
|
||||||
|
sActiveTabParent ? sActiveTabParent->Manager() : nullptr;
|
||||||
|
nsIContentParent* newContentParent =
|
||||||
|
newTabParent ? newTabParent->Manager() : nullptr;
|
||||||
|
if (sActiveTabParent && currentContentParent != newContentParent) {
|
||||||
|
MOZ_LOG(sISMLog, LogLevel::Debug,
|
||||||
|
("ISM: IMEStateManager::OnChangeFocusInternal(), notifying previous "
|
||||||
|
"focused child process of parent process or another child process "
|
||||||
|
"getting focus"));
|
||||||
|
unused << sActiveTabParent->SendStopIMEStateManagement();
|
||||||
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIWidget> widget =
|
nsCOMPtr<nsIWidget> widget =
|
||||||
(sPresContext == aPresContext) ? oldWidget.get() :
|
(sPresContext == aPresContext) ? oldWidget.get() :
|
||||||
aPresContext->GetRootWidget();
|
aPresContext->GetRootWidget();
|
||||||
@ -394,61 +451,85 @@ IMEStateManager::OnChangeFocusInternal(nsPresContext* aPresContext,
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
IMEState newState = GetNewIMEState(aPresContext, aContent);
|
// If a child process has focus, we should disable IME state until the child
|
||||||
|
// process actually gets focus because if user types keys before that they
|
||||||
|
// are handled by IME.
|
||||||
|
IMEState newState =
|
||||||
|
newTabParent ? IMEState(IMEState::DISABLED) :
|
||||||
|
GetNewIMEState(aPresContext, aContent);
|
||||||
|
bool setIMEState = true;
|
||||||
|
|
||||||
// In e10s, remote content may have IME focus. The main process (i.e. this process)
|
if (newTabParent) {
|
||||||
// would attempt to set state to DISABLED if, for example, the user clicks
|
if (aAction.mFocusChange == InputContextAction::MENU_GOT_PSEUDO_FOCUS ||
|
||||||
// some other remote content. The content process would later re-ENABLE IME, meaning
|
aAction.mFocusChange == InputContextAction::MENU_LOST_PSEUDO_FOCUS) {
|
||||||
// that all state-changes were unnecessary.
|
// XXX When menu keyboard listener is being uninstalled, IME state needs
|
||||||
// Here we filter the common case where the main process knows that the remote
|
// to be restored by the child process asynchronously. Therefore,
|
||||||
// process controls IME focus. The DISABLED->re-ENABLED progression can
|
// some key events which are fired immediately after closing menu
|
||||||
// still happen since remote content may be concurrently communicating its claim
|
// may not be handled by IME.
|
||||||
// on focus to the main process... but this cannot cause bugs like missed keypresses.
|
unused << newTabParent->
|
||||||
// (It just means a lot of needless IPC.)
|
SendMenuKeyboardListenerInstalled(sInstalledMenuKeyboardListener);
|
||||||
if ((newState.mEnabled == IMEState::DISABLED) && TabParent::GetIMETabParent()) {
|
setIMEState = sInstalledMenuKeyboardListener;
|
||||||
MOZ_LOG(sISMLog, LogLevel::Debug,
|
} else if (focusActuallyChanging) {
|
||||||
("ISM: IMEStateManager::OnChangeFocusInternal(), "
|
InputContext context = widget->GetInputContext();
|
||||||
"Parent process cancels to set DISABLED state because the content process "
|
if (context.mIMEState.mEnabled == IMEState::DISABLED) {
|
||||||
"has IME focus and has already sets IME state"));
|
setIMEState = false;
|
||||||
MOZ_ASSERT(XRE_IsParentProcess(),
|
MOZ_LOG(sISMLog, LogLevel::Debug,
|
||||||
"TabParent::GetIMETabParent() should never return non-null value "
|
("ISM: IMEStateManager::OnChangeFocusInternal(), doesn't set IME "
|
||||||
"in the content process");
|
"state because focused element (or document) is in a child process "
|
||||||
return NS_OK;
|
"and the IME state is already disabled"));
|
||||||
}
|
} else {
|
||||||
|
MOZ_LOG(sISMLog, LogLevel::Debug,
|
||||||
if (!focusActuallyChanging) {
|
("ISM: IMEStateManager::OnChangeFocusInternal(), will disable IME "
|
||||||
// actual focus isn't changing, but if IME enabled state is changing,
|
"until new focused element (or document) in the child process "
|
||||||
// we should do it.
|
"will get focus actually"));
|
||||||
InputContext context = widget->GetInputContext();
|
}
|
||||||
if (context.mIMEState.mEnabled == newState.mEnabled) {
|
} else {
|
||||||
|
// When focus is NOT changed actually, we shouldn't set IME state since
|
||||||
|
// that means that the window is being activated and the child process
|
||||||
|
// may have composition. Then, we shouldn't commit the composition with
|
||||||
|
// making IME state disabled.
|
||||||
|
setIMEState = false;
|
||||||
MOZ_LOG(sISMLog, LogLevel::Debug,
|
MOZ_LOG(sISMLog, LogLevel::Debug,
|
||||||
("ISM: IMEStateManager::OnChangeFocusInternal(), "
|
("ISM: IMEStateManager::OnChangeFocusInternal(), doesn't set IME "
|
||||||
"neither focus nor IME state is changing"));
|
"state because focused element (or document) is already in the child "
|
||||||
return NS_OK;
|
"process"));
|
||||||
}
|
}
|
||||||
aAction.mFocusChange = InputContextAction::FOCUS_NOT_CHANGED;
|
|
||||||
|
|
||||||
// Even if focus isn't changing actually, we should commit current
|
|
||||||
// composition here since the IME state is changing.
|
|
||||||
if (sPresContext && oldWidget && !focusActuallyChanging) {
|
|
||||||
NotifyIME(REQUEST_TO_COMMIT_COMPOSITION, oldWidget);
|
|
||||||
}
|
|
||||||
} else if (aAction.mFocusChange == InputContextAction::FOCUS_NOT_CHANGED) {
|
|
||||||
// If aContent isn't null or aContent is null but editable, somebody gets
|
|
||||||
// focus.
|
|
||||||
bool gotFocus = aContent || (newState.mEnabled == IMEState::ENABLED);
|
|
||||||
aAction.mFocusChange =
|
|
||||||
gotFocus ? InputContextAction::GOT_FOCUS : InputContextAction::LOST_FOCUS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update IME state for new focus widget
|
if (setIMEState) {
|
||||||
SetIMEState(newState, aContent, widget, aAction);
|
if (!focusActuallyChanging) {
|
||||||
|
// actual focus isn't changing, but if IME enabled state is changing,
|
||||||
|
// we should do it.
|
||||||
|
InputContext context = widget->GetInputContext();
|
||||||
|
if (context.mIMEState.mEnabled == newState.mEnabled) {
|
||||||
|
MOZ_LOG(sISMLog, LogLevel::Debug,
|
||||||
|
("ISM: IMEStateManager::OnChangeFocusInternal(), "
|
||||||
|
"neither focus nor IME state is changing"));
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
aAction.mFocusChange = InputContextAction::FOCUS_NOT_CHANGED;
|
||||||
|
|
||||||
|
// Even if focus isn't changing actually, we should commit current
|
||||||
|
// composition here since the IME state is changing.
|
||||||
|
if (sPresContext && oldWidget && !focusActuallyChanging) {
|
||||||
|
NotifyIME(REQUEST_TO_COMMIT_COMPOSITION, oldWidget);
|
||||||
|
}
|
||||||
|
} else if (aAction.mFocusChange == InputContextAction::FOCUS_NOT_CHANGED) {
|
||||||
|
// If aContent isn't null or aContent is null but editable, somebody gets
|
||||||
|
// focus.
|
||||||
|
bool gotFocus = aContent || (newState.mEnabled == IMEState::ENABLED);
|
||||||
|
aAction.mFocusChange =
|
||||||
|
gotFocus ? InputContextAction::GOT_FOCUS :
|
||||||
|
InputContextAction::LOST_FOCUS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update IME state for new focus widget
|
||||||
|
SetIMEState(newState, aContent, widget, aAction);
|
||||||
|
}
|
||||||
|
|
||||||
|
sActiveTabParent = newTabParent;
|
||||||
sPresContext = aPresContext;
|
sPresContext = aPresContext;
|
||||||
if (sContent != aContent) {
|
sContent = aContent;
|
||||||
NS_IF_RELEASE(sContent);
|
|
||||||
NS_IF_ADDREF(sContent = aContent);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't call CreateIMEContentObserver() here, it should be called from
|
// Don't call CreateIMEContentObserver() here, it should be called from
|
||||||
// focus event handler of editor.
|
// focus event handler of editor.
|
||||||
@ -482,7 +563,7 @@ IMEStateManager::OnMouseButtonEventInEditor(nsPresContext* aPresContext,
|
|||||||
MOZ_LOG(sISMLog, LogLevel::Info,
|
MOZ_LOG(sISMLog, LogLevel::Info,
|
||||||
("ISM: IMEStateManager::OnMouseButtonEventInEditor(aPresContext=0x%p, "
|
("ISM: IMEStateManager::OnMouseButtonEventInEditor(aPresContext=0x%p, "
|
||||||
"aContent=0x%p, aMouseEvent=0x%p), sPresContext=0x%p, sContent=0x%p",
|
"aContent=0x%p, aMouseEvent=0x%p), sPresContext=0x%p, sContent=0x%p",
|
||||||
aPresContext, aContent, aMouseEvent, sPresContext, sContent));
|
aPresContext, aContent, aMouseEvent, sPresContext, sContent.get()));
|
||||||
|
|
||||||
if (sPresContext != aPresContext || sContent != aContent) {
|
if (sPresContext != aPresContext || sContent != aContent) {
|
||||||
MOZ_LOG(sISMLog, LogLevel::Debug,
|
MOZ_LOG(sISMLog, LogLevel::Debug,
|
||||||
@ -539,7 +620,7 @@ IMEStateManager::OnClickInEditor(nsPresContext* aPresContext,
|
|||||||
MOZ_LOG(sISMLog, LogLevel::Info,
|
MOZ_LOG(sISMLog, LogLevel::Info,
|
||||||
("ISM: IMEStateManager::OnClickInEditor(aPresContext=0x%p, aContent=0x%p, "
|
("ISM: IMEStateManager::OnClickInEditor(aPresContext=0x%p, aContent=0x%p, "
|
||||||
"aMouseEvent=0x%p), sPresContext=0x%p, sContent=0x%p",
|
"aMouseEvent=0x%p), sPresContext=0x%p, sContent=0x%p",
|
||||||
aPresContext, aContent, aMouseEvent, sPresContext, sContent));
|
aPresContext, aContent, aMouseEvent, sPresContext, sContent.get()));
|
||||||
|
|
||||||
if (sPresContext != aPresContext || sContent != aContent) {
|
if (sPresContext != aPresContext || sContent != aContent) {
|
||||||
MOZ_LOG(sISMLog, LogLevel::Debug,
|
MOZ_LOG(sISMLog, LogLevel::Debug,
|
||||||
@ -597,8 +678,8 @@ IMEStateManager::OnFocusInEditor(nsPresContext* aPresContext,
|
|||||||
("ISM: IMEStateManager::OnFocusInEditor(aPresContext=0x%p, aContent=0x%p, "
|
("ISM: IMEStateManager::OnFocusInEditor(aPresContext=0x%p, aContent=0x%p, "
|
||||||
"aEditor=0x%p), sPresContext=0x%p, sContent=0x%p, "
|
"aEditor=0x%p), sPresContext=0x%p, sContent=0x%p, "
|
||||||
"sActiveIMEContentObserver=0x%p",
|
"sActiveIMEContentObserver=0x%p",
|
||||||
aPresContext, aContent, aEditor, sPresContext, sContent,
|
aPresContext, aContent, aEditor, sPresContext, sContent.get(),
|
||||||
sActiveIMEContentObserver));
|
sActiveIMEContentObserver.get()));
|
||||||
|
|
||||||
if (sPresContext != aPresContext || sContent != aContent) {
|
if (sPresContext != aPresContext || sContent != aContent) {
|
||||||
MOZ_LOG(sISMLog, LogLevel::Debug,
|
MOZ_LOG(sISMLog, LogLevel::Debug,
|
||||||
@ -669,7 +750,7 @@ IMEStateManager::UpdateIMEState(const IMEState& aNewIMEState,
|
|||||||
"sIsGettingNewIMEState=%s",
|
"sIsGettingNewIMEState=%s",
|
||||||
GetIMEStateEnabledName(aNewIMEState.mEnabled),
|
GetIMEStateEnabledName(aNewIMEState.mEnabled),
|
||||||
GetIMEStateSetOpenName(aNewIMEState.mOpen), aContent, aEditor,
|
GetIMEStateSetOpenName(aNewIMEState.mOpen), aContent, aEditor,
|
||||||
sPresContext, sContent, sActiveIMEContentObserver,
|
sPresContext, sContent.get(), sActiveIMEContentObserver.get(),
|
||||||
GetBoolName(sIsGettingNewIMEState)));
|
GetBoolName(sIsGettingNewIMEState)));
|
||||||
|
|
||||||
if (sIsGettingNewIMEState) {
|
if (sIsGettingNewIMEState) {
|
||||||
@ -842,6 +923,55 @@ MayBeIMEUnawareWebApp(nsINode* aNode)
|
|||||||
return haveKeyEventsListener;
|
return haveKeyEventsListener;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
void
|
||||||
|
IMEStateManager::SetInputContextForChildProcess(
|
||||||
|
TabParent* aTabParent,
|
||||||
|
const InputContext& aInputContext,
|
||||||
|
const InputContextAction& aAction)
|
||||||
|
{
|
||||||
|
MOZ_LOG(sISMLog, LogLevel::Info,
|
||||||
|
("ISM: IMEStateManager::SetInputContextForChildProcess(aTabParent=0x%p, "
|
||||||
|
"aInputContext={ mIMEState={ mEnabled=%s, mOpen=%s }, "
|
||||||
|
"mHTMLInputType=\"%s\", mHTMLInputInputmode=\"%s\", mActionHint=\"%s\" }, "
|
||||||
|
"aAction={ mCause=%s, mAction=%s }, aTabParent=0x%p), sPresContext=0x%p, "
|
||||||
|
"sActiveTabParent=0x%p",
|
||||||
|
aTabParent, GetIMEStateEnabledName(aInputContext.mIMEState.mEnabled),
|
||||||
|
GetIMEStateSetOpenName(aInputContext.mIMEState.mOpen),
|
||||||
|
NS_ConvertUTF16toUTF8(aInputContext.mHTMLInputType).get(),
|
||||||
|
NS_ConvertUTF16toUTF8(aInputContext.mHTMLInputInputmode).get(),
|
||||||
|
NS_ConvertUTF16toUTF8(aInputContext.mActionHint).get(),
|
||||||
|
GetActionCauseName(aAction.mCause),
|
||||||
|
GetActionFocusChangeName(aAction.mFocusChange),
|
||||||
|
sPresContext, sActiveTabParent.get()));
|
||||||
|
|
||||||
|
if (NS_WARN_IF(aTabParent != sActiveTabParent)) {
|
||||||
|
MOZ_LOG(sISMLog, LogLevel::Error,
|
||||||
|
("ISM: IMEStateManager::SetInputContextForChildProcess(), FAILED, "
|
||||||
|
"because non-focused tab parent tries to set input context"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NS_WARN_IF(!sPresContext)) {
|
||||||
|
MOZ_LOG(sISMLog, LogLevel::Error,
|
||||||
|
("ISM: IMEStateManager::SetInputContextForChildProcess(), FAILED, "
|
||||||
|
"due to no focused presContext"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIWidget> widget = sPresContext->GetRootWidget();
|
||||||
|
if (NS_WARN_IF(!widget)) {
|
||||||
|
MOZ_LOG(sISMLog, LogLevel::Error,
|
||||||
|
("ISM: IMEStateManager::SetInputContextForChildProcess(), FAILED, "
|
||||||
|
"due to no widget in the focused presContext"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MOZ_ASSERT(aInputContext.mOrigin == InputContext::ORIGIN_CONTENT);
|
||||||
|
|
||||||
|
SetInputContext(widget, aInputContext, aAction);
|
||||||
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
void
|
void
|
||||||
IMEStateManager::SetIMEState(const IMEState& aState,
|
IMEStateManager::SetIMEState(const IMEState& aState,
|
||||||
@ -851,9 +981,11 @@ IMEStateManager::SetIMEState(const IMEState& aState,
|
|||||||
{
|
{
|
||||||
MOZ_LOG(sISMLog, LogLevel::Info,
|
MOZ_LOG(sISMLog, LogLevel::Info,
|
||||||
("ISM: IMEStateManager::SetIMEState(aState={ mEnabled=%s, mOpen=%s }, "
|
("ISM: IMEStateManager::SetIMEState(aState={ mEnabled=%s, mOpen=%s }, "
|
||||||
"aContent=0x%p, aWidget=0x%p, aAction={ mCause=%s, mFocusChange=%s })",
|
"aContent=0x%p (TabParent=0x%p), aWidget=0x%p, aAction={ mCause=%s, "
|
||||||
|
"mFocusChange=%s })",
|
||||||
GetIMEStateEnabledName(aState.mEnabled),
|
GetIMEStateEnabledName(aState.mEnabled),
|
||||||
GetIMEStateSetOpenName(aState.mOpen), aContent, aWidget,
|
GetIMEStateSetOpenName(aState.mOpen), aContent,
|
||||||
|
TabParent::GetFrom(aContent), aWidget,
|
||||||
GetActionCauseName(aAction.mCause),
|
GetActionCauseName(aAction.mCause),
|
||||||
GetActionFocusChangeName(aAction.mFocusChange)));
|
GetActionFocusChangeName(aAction.mFocusChange)));
|
||||||
|
|
||||||
@ -936,27 +1068,41 @@ IMEStateManager::SetIMEState(const IMEState& aState,
|
|||||||
aAction.mCause = InputContextAction::CAUSE_UNKNOWN_CHROME;
|
aAction.mCause = InputContextAction::CAUSE_UNKNOWN_CHROME;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SetInputContext(aWidget, context, aAction);
|
||||||
|
}
|
||||||
|
|
||||||
MOZ_LOG(sISMLog, LogLevel::Debug,
|
// static
|
||||||
("ISM: IMEStateManager::SetIMEState(), "
|
void
|
||||||
"calling nsIWidget::SetInputContext(context={ mIMEState={ mEnabled=%s, "
|
IMEStateManager::SetInputContext(nsIWidget* aWidget,
|
||||||
"mOpen=%s }, mHTMLInputType=\"%s\", mHTMLInputInputmode=\"%s\", "
|
const InputContext& aInputContext,
|
||||||
"mActionHint=\"%s\" }, aAction={ mCause=%s, mAction=%s })",
|
const InputContextAction& aAction)
|
||||||
GetIMEStateEnabledName(context.mIMEState.mEnabled),
|
{
|
||||||
GetIMEStateSetOpenName(context.mIMEState.mOpen),
|
MOZ_LOG(sISMLog, LogLevel::Info,
|
||||||
NS_ConvertUTF16toUTF8(context.mHTMLInputType).get(),
|
("ISM: IMEStateManager::SetInputContext(aWidget=0x%p, aInputContext={ "
|
||||||
NS_ConvertUTF16toUTF8(context.mHTMLInputInputmode).get(),
|
"mIMEState={ mEnabled=%s, mOpen=%s }, mHTMLInputType=\"%s\", "
|
||||||
NS_ConvertUTF16toUTF8(context.mActionHint).get(),
|
"mHTMLInputInputmode=\"%s\", mActionHint=\"%s\" }, "
|
||||||
|
"aAction={ mCause=%s, mAction=%s }), sActiveTabParent=0x%p",
|
||||||
|
aWidget,
|
||||||
|
GetIMEStateEnabledName(aInputContext.mIMEState.mEnabled),
|
||||||
|
GetIMEStateSetOpenName(aInputContext.mIMEState.mOpen),
|
||||||
|
NS_ConvertUTF16toUTF8(aInputContext.mHTMLInputType).get(),
|
||||||
|
NS_ConvertUTF16toUTF8(aInputContext.mHTMLInputInputmode).get(),
|
||||||
|
NS_ConvertUTF16toUTF8(aInputContext.mActionHint).get(),
|
||||||
GetActionCauseName(aAction.mCause),
|
GetActionCauseName(aAction.mCause),
|
||||||
GetActionFocusChangeName(aAction.mFocusChange)));
|
GetActionFocusChangeName(aAction.mFocusChange),
|
||||||
|
sActiveTabParent.get()));
|
||||||
|
|
||||||
aWidget->SetInputContext(context, aAction);
|
MOZ_RELEASE_ASSERT(aWidget);
|
||||||
if (oldContext.mIMEState.mEnabled == context.mIMEState.mEnabled) {
|
|
||||||
|
InputContext oldContext = aWidget->GetInputContext();
|
||||||
|
|
||||||
|
aWidget->SetInputContext(aInputContext, aAction);
|
||||||
|
if (oldContext.mIMEState.mEnabled == aInputContext.mIMEState.mEnabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsContentUtils::AddScriptRunner(
|
nsContentUtils::AddScriptRunner(
|
||||||
new IMEEnabledStateChangedEvent(context.mIMEState.mEnabled));
|
new IMEEnabledStateChangedEvent(aInputContext.mIMEState.mEnabled));
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
@ -1334,7 +1480,7 @@ IMEStateManager::DestroyIMEContentObserver()
|
|||||||
MOZ_LOG(sISMLog, LogLevel::Info,
|
MOZ_LOG(sISMLog, LogLevel::Info,
|
||||||
("ISM: IMEStateManager::DestroyIMEContentObserver(), "
|
("ISM: IMEStateManager::DestroyIMEContentObserver(), "
|
||||||
"sActiveIMEContentObserver=0x%p",
|
"sActiveIMEContentObserver=0x%p",
|
||||||
sActiveIMEContentObserver));
|
sActiveIMEContentObserver.get()));
|
||||||
|
|
||||||
if (!sActiveIMEContentObserver) {
|
if (!sActiveIMEContentObserver) {
|
||||||
MOZ_LOG(sISMLog, LogLevel::Debug,
|
MOZ_LOG(sISMLog, LogLevel::Debug,
|
||||||
@ -1345,8 +1491,8 @@ IMEStateManager::DestroyIMEContentObserver()
|
|||||||
MOZ_LOG(sISMLog, LogLevel::Debug,
|
MOZ_LOG(sISMLog, LogLevel::Debug,
|
||||||
("ISM: IMEStateManager::DestroyIMEContentObserver(), destroying "
|
("ISM: IMEStateManager::DestroyIMEContentObserver(), destroying "
|
||||||
"the active IMEContentObserver..."));
|
"the active IMEContentObserver..."));
|
||||||
nsRefPtr<IMEContentObserver> tsm;
|
nsRefPtr<IMEContentObserver> tsm = sActiveIMEContentObserver.get();
|
||||||
tsm.swap(sActiveIMEContentObserver);
|
sActiveIMEContentObserver = nullptr;
|
||||||
tsm->Destroy();
|
tsm->Destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1358,7 +1504,7 @@ IMEStateManager::CreateIMEContentObserver(nsIEditor* aEditor)
|
|||||||
("ISM: IMEStateManager::CreateIMEContentObserver(aEditor=0x%p), "
|
("ISM: IMEStateManager::CreateIMEContentObserver(aEditor=0x%p), "
|
||||||
"sPresContext=0x%p, sContent=0x%p, sActiveIMEContentObserver=0x%p, "
|
"sPresContext=0x%p, sContent=0x%p, sActiveIMEContentObserver=0x%p, "
|
||||||
"sActiveIMEContentObserver->IsManaging(sPresContext, sContent)=%s",
|
"sActiveIMEContentObserver->IsManaging(sPresContext, sContent)=%s",
|
||||||
aEditor, sPresContext, sContent, sActiveIMEContentObserver,
|
aEditor, sPresContext, sContent.get(), sActiveIMEContentObserver.get(),
|
||||||
GetBoolName(sActiveIMEContentObserver ?
|
GetBoolName(sActiveIMEContentObserver ?
|
||||||
sActiveIMEContentObserver->IsManaging(sPresContext, sContent) : false)));
|
sActiveIMEContentObserver->IsManaging(sPresContext, sContent) : false)));
|
||||||
|
|
||||||
@ -1390,7 +1536,6 @@ IMEStateManager::CreateIMEContentObserver(nsIEditor* aEditor)
|
|||||||
("ISM: IMEStateManager::CreateIMEContentObserver() is creating an "
|
("ISM: IMEStateManager::CreateIMEContentObserver() is creating an "
|
||||||
"IMEContentObserver instance..."));
|
"IMEContentObserver instance..."));
|
||||||
sActiveIMEContentObserver = new IMEContentObserver();
|
sActiveIMEContentObserver = new IMEContentObserver();
|
||||||
NS_ADDREF(sActiveIMEContentObserver);
|
|
||||||
|
|
||||||
// IMEContentObserver::Init() might create another IMEContentObserver
|
// IMEContentObserver::Init() might create another IMEContentObserver
|
||||||
// instance. So, sActiveIMEContentObserver would be replaced with new one.
|
// instance. So, sActiveIMEContentObserver would be replaced with new one.
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include "mozilla/EventForwards.h"
|
#include "mozilla/EventForwards.h"
|
||||||
#include "mozilla/StaticPtr.h"
|
#include "mozilla/StaticPtr.h"
|
||||||
|
#include "mozilla/dom/TabParent.h"
|
||||||
#include "nsIWidget.h"
|
#include "nsIWidget.h"
|
||||||
|
|
||||||
class nsIContent;
|
class nsIContent;
|
||||||
@ -33,6 +34,7 @@ class TextComposition;
|
|||||||
|
|
||||||
class IMEStateManager
|
class IMEStateManager
|
||||||
{
|
{
|
||||||
|
typedef dom::TabParent TabParent;
|
||||||
typedef widget::IMEMessage IMEMessage;
|
typedef widget::IMEMessage IMEMessage;
|
||||||
typedef widget::IMENotification IMENotification;
|
typedef widget::IMENotification IMENotification;
|
||||||
typedef widget::IMEState IMEState;
|
typedef widget::IMEState IMEState;
|
||||||
@ -43,6 +45,39 @@ public:
|
|||||||
static void Init();
|
static void Init();
|
||||||
static void Shutdown();
|
static void Shutdown();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GetActiveTabParent() returns a pointer to a TabParent instance which is
|
||||||
|
* managed by the focused content (sContent). If the focused content isn't
|
||||||
|
* managing another process, this returns nullptr.
|
||||||
|
*/
|
||||||
|
static TabParent* GetActiveTabParent()
|
||||||
|
{
|
||||||
|
// If menu has pseudo focus, we should ignore active child process.
|
||||||
|
if (sInstalledMenuKeyboardListener) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return sActiveTabParent.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OnTabParentDestroying() is called when aTabParent is being destroyed.
|
||||||
|
*/
|
||||||
|
static void OnTabParentDestroying(TabParent* aTabParent);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SetIMEContextForChildProcess() is called when aTabParent receives
|
||||||
|
* SetInputContext() from the remote process.
|
||||||
|
*/
|
||||||
|
static void SetInputContextForChildProcess(TabParent* aTabParent,
|
||||||
|
const InputContext& aInputContext,
|
||||||
|
const InputContextAction& aAction);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* StopIMEStateManagement() is called when the process should stop managing
|
||||||
|
* IME state.
|
||||||
|
*/
|
||||||
|
static void StopIMEStateManagement();
|
||||||
|
|
||||||
static nsresult OnDestroyPresContext(nsPresContext* aPresContext);
|
static nsresult OnDestroyPresContext(nsPresContext* aPresContext);
|
||||||
static nsresult OnRemoveContent(nsPresContext* aPresContext,
|
static nsresult OnRemoveContent(nsPresContext* aPresContext,
|
||||||
nsIContent* aContent);
|
nsIContent* aContent);
|
||||||
@ -163,6 +198,9 @@ protected:
|
|||||||
nsIContent* aContent,
|
nsIContent* aContent,
|
||||||
nsIWidget* aWidget,
|
nsIWidget* aWidget,
|
||||||
InputContextAction aAction);
|
InputContextAction aAction);
|
||||||
|
static void SetInputContext(nsIWidget* aWidget,
|
||||||
|
const InputContext& aInputContext,
|
||||||
|
const InputContextAction& aAction);
|
||||||
static IMEState GetNewIMEState(nsPresContext* aPresContext,
|
static IMEState GetNewIMEState(nsPresContext* aPresContext,
|
||||||
nsIContent* aContent);
|
nsIContent* aContent);
|
||||||
|
|
||||||
@ -174,9 +212,20 @@ protected:
|
|||||||
|
|
||||||
static bool IsIMEObserverNeeded(const IMEState& aState);
|
static bool IsIMEObserverNeeded(const IMEState& aState);
|
||||||
|
|
||||||
static nsIContent* sContent;
|
static StaticRefPtr<nsIContent> sContent;
|
||||||
static nsPresContext* sPresContext;
|
static nsPresContext* sPresContext;
|
||||||
static StaticRefPtr<nsIWidget> sFocusedIMEWidget;
|
static StaticRefPtr<nsIWidget> sFocusedIMEWidget;
|
||||||
|
static StaticRefPtr<TabParent> sActiveTabParent;
|
||||||
|
// sActiveIMEContentObserver points to the currently active
|
||||||
|
// IMEContentObserver. This is null if there is no focused editor.
|
||||||
|
static StaticRefPtr<IMEContentObserver> sActiveIMEContentObserver;
|
||||||
|
|
||||||
|
// All active compositions in the process are stored by this array.
|
||||||
|
// When you get an item of this array and use it, please be careful.
|
||||||
|
// The instances in this array can be destroyed automatically if you do
|
||||||
|
// something to cause committing or canceling the composition.
|
||||||
|
static TextCompositionArray* sTextCompositions;
|
||||||
|
|
||||||
static bool sInstalledMenuKeyboardListener;
|
static bool sInstalledMenuKeyboardListener;
|
||||||
static bool sIsGettingNewIMEState;
|
static bool sIsGettingNewIMEState;
|
||||||
static bool sCheckForIMEUnawareWebApps;
|
static bool sCheckForIMEUnawareWebApps;
|
||||||
@ -197,14 +246,6 @@ protected:
|
|||||||
private:
|
private:
|
||||||
bool mOldValue;
|
bool mOldValue;
|
||||||
};
|
};
|
||||||
|
|
||||||
static IMEContentObserver* sActiveIMEContentObserver;
|
|
||||||
|
|
||||||
// All active compositions in the process are stored by this array.
|
|
||||||
// When you get an item of this array and use it, please be careful.
|
|
||||||
// The instances in this array can be destroyed automatically if you do
|
|
||||||
// something to cause committing or canceling the composition.
|
|
||||||
static TextCompositionArray* sTextCompositions;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
@ -435,7 +435,14 @@ const kEventConstructors = {
|
|||||||
return new SpeechRecognitionEvent(aName, aProps);
|
return new SpeechRecognitionEvent(aName, aProps);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
SpeechSynthesisErrorEvent: { create: function (aName, aProps) {
|
||||||
|
aProps.error = "synthesis-unavailable";
|
||||||
|
aProps.utterance = new SpeechSynthesisUtterance("Hello World");
|
||||||
|
return new SpeechSynthesisErrorEvent(aName, aProps);
|
||||||
|
},
|
||||||
|
},
|
||||||
SpeechSynthesisEvent: { create: function (aName, aProps) {
|
SpeechSynthesisEvent: { create: function (aName, aProps) {
|
||||||
|
aProps.utterance = new SpeechSynthesisUtterance("Hello World");
|
||||||
return new SpeechSynthesisEvent(aName, aProps);
|
return new SpeechSynthesisEvent(aName, aProps);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -576,6 +576,18 @@ child:
|
|||||||
|
|
||||||
ParentActivated(bool aActivated);
|
ParentActivated(bool aActivated);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* StopIMEStateManagement() is called when the process loses focus and
|
||||||
|
* should stop managing IME state.
|
||||||
|
*/
|
||||||
|
StopIMEStateManagement();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MenuKeyboardListenerInstalled() is called when menu keyboard listener
|
||||||
|
* is installed in the parent process.
|
||||||
|
*/
|
||||||
|
MenuKeyboardListenerInstalled(bool aInstalled);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see nsIDOMWindowUtils sendMouseEvent.
|
* @see nsIDOMWindowUtils sendMouseEvent.
|
||||||
*/
|
*/
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include "mozilla/dom/workers/ServiceWorkerManager.h"
|
#include "mozilla/dom/workers/ServiceWorkerManager.h"
|
||||||
#include "mozilla/dom/indexedDB/PIndexedDBPermissionRequestChild.h"
|
#include "mozilla/dom/indexedDB/PIndexedDBPermissionRequestChild.h"
|
||||||
#include "mozilla/plugins/PluginWidgetChild.h"
|
#include "mozilla/plugins/PluginWidgetChild.h"
|
||||||
|
#include "mozilla/IMEStateManager.h"
|
||||||
#include "mozilla/ipc/DocumentRendererChild.h"
|
#include "mozilla/ipc/DocumentRendererChild.h"
|
||||||
#include "mozilla/ipc/FileDescriptorUtils.h"
|
#include "mozilla/ipc/FileDescriptorUtils.h"
|
||||||
#include "mozilla/layers/APZCCallbackHelper.h"
|
#include "mozilla/layers/APZCCallbackHelper.h"
|
||||||
@ -2199,6 +2200,20 @@ bool TabChild::RecvParentActivated(const bool& aActivated)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
TabChild::RecvStopIMEStateManagement()
|
||||||
|
{
|
||||||
|
IMEStateManager::StopIMEStateManagement();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
TabChild::RecvMenuKeyboardListenerInstalled(const bool& aInstalled)
|
||||||
|
{
|
||||||
|
IMEStateManager::OnInstalledMenuKeyboardListener(aInstalled);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
TabChild::RecvMouseEvent(const nsString& aType,
|
TabChild::RecvMouseEvent(const nsString& aType,
|
||||||
const float& aX,
|
const float& aX,
|
||||||
|
@ -529,6 +529,10 @@ protected:
|
|||||||
|
|
||||||
virtual bool RecvParentActivated(const bool& aActivated) override;
|
virtual bool RecvParentActivated(const bool& aActivated) override;
|
||||||
|
|
||||||
|
virtual bool RecvStopIMEStateManagement() override;
|
||||||
|
virtual bool RecvMenuKeyboardListenerInstalled(
|
||||||
|
const bool& aInstalled) override;
|
||||||
|
|
||||||
#ifdef MOZ_WIDGET_GONK
|
#ifdef MOZ_WIDGET_GONK
|
||||||
void MaybeRequestPreinitCamera();
|
void MaybeRequestPreinitCamera();
|
||||||
#endif
|
#endif
|
||||||
|
@ -248,7 +248,6 @@ private:
|
|||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
|
|
||||||
TabParent *TabParent::mIMETabParent = nullptr;
|
|
||||||
TabParent::LayerToTabParentTable* TabParent::sLayerToTabParentTable = nullptr;
|
TabParent::LayerToTabParentTable* TabParent::sLayerToTabParentTable = nullptr;
|
||||||
|
|
||||||
NS_IMPL_ISUPPORTS(TabParent,
|
NS_IMPL_ISUPPORTS(TabParent,
|
||||||
@ -481,9 +480,8 @@ TabParent::Recv__delete__()
|
|||||||
void
|
void
|
||||||
TabParent::ActorDestroy(ActorDestroyReason why)
|
TabParent::ActorDestroy(ActorDestroyReason why)
|
||||||
{
|
{
|
||||||
if (mIMETabParent == this) {
|
IMEStateManager::OnTabParentDestroying(this);
|
||||||
mIMETabParent = nullptr;
|
|
||||||
}
|
|
||||||
nsRefPtr<nsFrameLoader> frameLoader = GetFrameLoader(true);
|
nsRefPtr<nsFrameLoader> frameLoader = GetFrameLoader(true);
|
||||||
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
|
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
|
||||||
if (frameLoader) {
|
if (frameLoader) {
|
||||||
@ -1934,7 +1932,6 @@ TabParent::RecvNotifyIMEFocus(const bool& aFocus,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
mIMETabParent = aFocus ? this : nullptr;
|
|
||||||
IMENotification notification(aFocus ? NOTIFY_IME_OF_FOCUS :
|
IMENotification notification(aFocus ? NOTIFY_IME_OF_FOCUS :
|
||||||
NOTIFY_IME_OF_BLUR);
|
NOTIFY_IME_OF_BLUR);
|
||||||
mContentCache.AssignContent(aContentCache, ¬ification);
|
mContentCache.AssignContent(aContentCache, ¬ification);
|
||||||
@ -2388,26 +2385,6 @@ TabParent::RecvSetInputContext(const int32_t& aIMEEnabled,
|
|||||||
const int32_t& aCause,
|
const int32_t& aCause,
|
||||||
const int32_t& aFocusChange)
|
const int32_t& aFocusChange)
|
||||||
{
|
{
|
||||||
nsCOMPtr<nsIWidget> widget = GetWidget();
|
|
||||||
if (!widget || !AllowContentIME()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
InputContext oldContext = widget->GetInputContext();
|
|
||||||
|
|
||||||
// Ignore if current widget IME setting is not DISABLED and didn't come
|
|
||||||
// from remote content. Chrome content may have taken over.
|
|
||||||
if (oldContext.mIMEState.mEnabled != IMEState::DISABLED &&
|
|
||||||
oldContext.IsOriginMainProcess()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// mIMETabParent (which is actually static) tracks which if any TabParent has IMEFocus
|
|
||||||
// When the input mode is set to anything but IMEState::DISABLED,
|
|
||||||
// mIMETabParent should be set to this
|
|
||||||
mIMETabParent =
|
|
||||||
aIMEEnabled != static_cast<int32_t>(IMEState::DISABLED) ? this : nullptr;
|
|
||||||
|
|
||||||
InputContext context;
|
InputContext context;
|
||||||
context.mIMEState.mEnabled = static_cast<IMEState::Enabled>(aIMEEnabled);
|
context.mIMEState.mEnabled = static_cast<IMEState::Enabled>(aIMEEnabled);
|
||||||
context.mIMEState.mOpen = static_cast<IMEState::Open>(aIMEOpen);
|
context.mIMEState.mOpen = static_cast<IMEState::Open>(aIMEOpen);
|
||||||
@ -2419,15 +2396,8 @@ TabParent::RecvSetInputContext(const int32_t& aIMEEnabled,
|
|||||||
InputContextAction action(
|
InputContextAction action(
|
||||||
static_cast<InputContextAction::Cause>(aCause),
|
static_cast<InputContextAction::Cause>(aCause),
|
||||||
static_cast<InputContextAction::FocusChange>(aFocusChange));
|
static_cast<InputContextAction::FocusChange>(aFocusChange));
|
||||||
widget->SetInputContext(context, action);
|
|
||||||
|
|
||||||
nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
|
IMEStateManager::SetInputContextForChildProcess(this, context, action);
|
||||||
if (!observerService)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
nsAutoString state;
|
|
||||||
state.AppendInt(aIMEEnabled);
|
|
||||||
observerService->NotifyObservers(nullptr, "ime-enabled-state-changed", state.get());
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -2617,19 +2587,6 @@ TabParent::RecvGetRenderFrameInfo(PRenderFrameParent* aRenderFrame,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
TabParent::AllowContentIME()
|
|
||||||
{
|
|
||||||
nsFocusManager* fm = nsFocusManager::GetFocusManager();
|
|
||||||
NS_ENSURE_TRUE(fm, false);
|
|
||||||
|
|
||||||
nsCOMPtr<nsIContent> focusedContent = fm->GetFocusedContent();
|
|
||||||
if (focusedContent && focusedContent->IsEditable())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
already_AddRefed<nsFrameLoader>
|
already_AddRefed<nsFrameLoader>
|
||||||
TabParent::GetFrameLoader(bool aUseCachedFrameLoaderAfterDestroy) const
|
TabParent::GetFrameLoader(bool aUseCachedFrameLoaderAfterDestroy) const
|
||||||
{
|
{
|
||||||
|
@ -366,7 +366,6 @@ public:
|
|||||||
NS_DECL_NSIAUTHPROMPTPROVIDER
|
NS_DECL_NSIAUTHPROMPTPROVIDER
|
||||||
NS_DECL_NSISECUREBROWSERUI
|
NS_DECL_NSISECUREBROWSERUI
|
||||||
|
|
||||||
static TabParent *GetIMETabParent() { return mIMETabParent; }
|
|
||||||
bool HandleQueryContentEvent(mozilla::WidgetQueryContentEvent& aEvent);
|
bool HandleQueryContentEvent(mozilla::WidgetQueryContentEvent& aEvent);
|
||||||
bool SendCompositionEvent(mozilla::WidgetCompositionEvent& event);
|
bool SendCompositionEvent(mozilla::WidgetCompositionEvent& event);
|
||||||
bool SendSelectionEvent(mozilla::WidgetSelectionEvent& event);
|
bool SendSelectionEvent(mozilla::WidgetSelectionEvent& event);
|
||||||
@ -447,8 +446,6 @@ protected:
|
|||||||
Element* mFrameElement;
|
Element* mFrameElement;
|
||||||
nsCOMPtr<nsIBrowserDOMWindow> mBrowserDOMWindow;
|
nsCOMPtr<nsIBrowserDOMWindow> mBrowserDOMWindow;
|
||||||
|
|
||||||
bool AllowContentIME();
|
|
||||||
|
|
||||||
virtual PRenderFrameParent* AllocPRenderFrameParent() override;
|
virtual PRenderFrameParent* AllocPRenderFrameParent() override;
|
||||||
virtual bool DeallocPRenderFrameParent(PRenderFrameParent* aFrame) override;
|
virtual bool DeallocPRenderFrameParent(PRenderFrameParent* aFrame) override;
|
||||||
|
|
||||||
@ -467,8 +464,6 @@ protected:
|
|||||||
|
|
||||||
void SetHasContentOpener(bool aHasContentOpener);
|
void SetHasContentOpener(bool aHasContentOpener);
|
||||||
|
|
||||||
// IME
|
|
||||||
static TabParent *mIMETabParent;
|
|
||||||
ContentCacheInParent mContentCache;
|
ContentCacheInParent mContentCache;
|
||||||
|
|
||||||
nsIntRect mRect;
|
nsIntRect mRect;
|
||||||
|
@ -225,7 +225,9 @@ SpeechSynthesis::GetVoices(nsTArray< nsRefPtr<SpeechSynthesisVoice> >& aResult)
|
|||||||
uint32_t voiceCount = 0;
|
uint32_t voiceCount = 0;
|
||||||
|
|
||||||
nsresult rv = nsSynthVoiceRegistry::GetInstance()->GetVoiceCount(&voiceCount);
|
nsresult rv = nsSynthVoiceRegistry::GetInstance()->GetVoiceCount(&voiceCount);
|
||||||
NS_ENSURE_SUCCESS_VOID(rv);
|
if(NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (uint32_t i = 0; i < voiceCount; i++) {
|
for (uint32_t i = 0; i < voiceCount; i++) {
|
||||||
nsAutoString uri;
|
nsAutoString uri;
|
||||||
|
@ -162,6 +162,7 @@ SpeechSynthesisUtterance::DispatchSpeechSynthesisEvent(const nsAString& aEventTy
|
|||||||
SpeechSynthesisEventInit init;
|
SpeechSynthesisEventInit init;
|
||||||
init.mBubbles = false;
|
init.mBubbles = false;
|
||||||
init.mCancelable = false;
|
init.mCancelable = false;
|
||||||
|
init.mUtterance = this;
|
||||||
init.mCharIndex = aCharIndex;
|
init.mCharIndex = aCharIndex;
|
||||||
init.mElapsedTime = aElapsedTime;
|
init.mElapsedTime = aElapsedTime;
|
||||||
init.mName = aName;
|
init.mName = aName;
|
||||||
|
@ -123,7 +123,9 @@ nsresult
|
|||||||
SpeechTaskParent::DispatchStartImpl(const nsAString& aUri)
|
SpeechTaskParent::DispatchStartImpl(const nsAString& aUri)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mActor);
|
MOZ_ASSERT(mActor);
|
||||||
NS_ENSURE_TRUE(mActor->SendOnStart(nsString(aUri)), NS_ERROR_FAILURE);
|
if(NS_WARN_IF(!(mActor->SendOnStart(nsString(aUri))))) {
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
@ -134,8 +136,9 @@ SpeechTaskParent::DispatchEndImpl(float aElapsedTime, uint32_t aCharIndex)
|
|||||||
MOZ_ASSERT(mActor);
|
MOZ_ASSERT(mActor);
|
||||||
SpeechSynthesisRequestParent* actor = mActor;
|
SpeechSynthesisRequestParent* actor = mActor;
|
||||||
mActor = nullptr;
|
mActor = nullptr;
|
||||||
NS_ENSURE_TRUE(actor->Send__delete__(actor, false, aElapsedTime, aCharIndex),
|
if(NS_WARN_IF(!(actor->Send__delete__(actor, false, aElapsedTime, aCharIndex)))) {
|
||||||
NS_ERROR_FAILURE);
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
@ -144,7 +147,9 @@ nsresult
|
|||||||
SpeechTaskParent::DispatchPauseImpl(float aElapsedTime, uint32_t aCharIndex)
|
SpeechTaskParent::DispatchPauseImpl(float aElapsedTime, uint32_t aCharIndex)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mActor);
|
MOZ_ASSERT(mActor);
|
||||||
NS_ENSURE_TRUE(mActor->SendOnPause(aElapsedTime, aCharIndex), NS_ERROR_FAILURE);
|
if(NS_WARN_IF(!(mActor->SendOnPause(aElapsedTime, aCharIndex)))) {
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
@ -153,7 +158,9 @@ nsresult
|
|||||||
SpeechTaskParent::DispatchResumeImpl(float aElapsedTime, uint32_t aCharIndex)
|
SpeechTaskParent::DispatchResumeImpl(float aElapsedTime, uint32_t aCharIndex)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mActor);
|
MOZ_ASSERT(mActor);
|
||||||
NS_ENSURE_TRUE(mActor->SendOnResume(aElapsedTime, aCharIndex), NS_ERROR_FAILURE);
|
if(NS_WARN_IF(!(mActor->SendOnResume(aElapsedTime, aCharIndex)))) {
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
@ -164,8 +171,9 @@ SpeechTaskParent::DispatchErrorImpl(float aElapsedTime, uint32_t aCharIndex)
|
|||||||
MOZ_ASSERT(mActor);
|
MOZ_ASSERT(mActor);
|
||||||
SpeechSynthesisRequestParent* actor = mActor;
|
SpeechSynthesisRequestParent* actor = mActor;
|
||||||
mActor = nullptr;
|
mActor = nullptr;
|
||||||
NS_ENSURE_TRUE(actor->Send__delete__(actor, true, aElapsedTime, aCharIndex),
|
if(NS_WARN_IF(!(actor->Send__delete__(actor, true, aElapsedTime, aCharIndex)))) {
|
||||||
NS_ERROR_FAILURE);
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
@ -175,8 +183,9 @@ SpeechTaskParent::DispatchBoundaryImpl(const nsAString& aName,
|
|||||||
float aElapsedTime, uint32_t aCharIndex)
|
float aElapsedTime, uint32_t aCharIndex)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mActor);
|
MOZ_ASSERT(mActor);
|
||||||
NS_ENSURE_TRUE(mActor->SendOnBoundary(nsString(aName), aElapsedTime, aCharIndex),
|
if(NS_WARN_IF(!(mActor->SendOnBoundary(nsString(aName), aElapsedTime, aCharIndex)))) {
|
||||||
NS_ERROR_FAILURE);
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
@ -186,8 +195,9 @@ SpeechTaskParent::DispatchMarkImpl(const nsAString& aName,
|
|||||||
float aElapsedTime, uint32_t aCharIndex)
|
float aElapsedTime, uint32_t aCharIndex)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mActor);
|
MOZ_ASSERT(mActor);
|
||||||
NS_ENSURE_TRUE(mActor->SendOnMark(nsString(aName), aElapsedTime, aCharIndex),
|
if(NS_WARN_IF(!(mActor->SendOnMark(nsString(aName), aElapsedTime, aCharIndex)))) {
|
||||||
NS_ERROR_FAILURE);
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
@ -165,7 +165,9 @@ nsSpeechTask::Setup(nsISpeechTaskCallback* aCallback,
|
|||||||
mStream->AddListener(new SynthStreamListener(this));
|
mStream->AddListener(new SynthStreamListener(this));
|
||||||
|
|
||||||
// XXX: Support more than one channel
|
// XXX: Support more than one channel
|
||||||
NS_ENSURE_TRUE(aChannels == 1, NS_ERROR_FAILURE);
|
if(NS_WARN_IF(!(aChannels == 1))) {
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
mChannels = aChannels;
|
mChannels = aChannels;
|
||||||
|
|
||||||
@ -197,10 +199,18 @@ nsSpeechTask::SendAudio(JS::Handle<JS::Value> aData, JS::Handle<JS::Value> aLand
|
|||||||
{
|
{
|
||||||
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
|
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
|
||||||
|
|
||||||
NS_ENSURE_TRUE(mStream, NS_ERROR_NOT_AVAILABLE);
|
if(NS_WARN_IF(!(mStream))) {
|
||||||
NS_ENSURE_FALSE(mStream->IsDestroyed(), NS_ERROR_NOT_AVAILABLE);
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
NS_ENSURE_TRUE(mChannels, NS_ERROR_FAILURE);
|
}
|
||||||
NS_ENSURE_TRUE(aData.isObject(), NS_ERROR_INVALID_ARG);
|
if(NS_WARN_IF(mStream->IsDestroyed())) {
|
||||||
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
|
}
|
||||||
|
if(NS_WARN_IF(!(mChannels))) {
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
if(NS_WARN_IF(!(aData.isObject()))) {
|
||||||
|
return NS_ERROR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
if (mIndirectAudio) {
|
if (mIndirectAudio) {
|
||||||
NS_WARNING("Can't call SendAudio from an indirect audio speech service.");
|
NS_WARNING("Can't call SendAudio from an indirect audio speech service.");
|
||||||
@ -239,9 +249,15 @@ nsSpeechTask::SendAudioNative(int16_t* aData, uint32_t aDataLen)
|
|||||||
{
|
{
|
||||||
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
|
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
|
||||||
|
|
||||||
NS_ENSURE_TRUE(mStream, NS_ERROR_NOT_AVAILABLE);
|
if(NS_WARN_IF(!(mStream))) {
|
||||||
NS_ENSURE_FALSE(mStream->IsDestroyed(), NS_ERROR_NOT_AVAILABLE);
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
NS_ENSURE_TRUE(mChannels, NS_ERROR_FAILURE);
|
}
|
||||||
|
if(NS_WARN_IF(mStream->IsDestroyed())) {
|
||||||
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
|
}
|
||||||
|
if(NS_WARN_IF(!(mChannels))) {
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
if (mIndirectAudio) {
|
if (mIndirectAudio) {
|
||||||
NS_WARNING("Can't call SendAudio from an indirect audio speech service.");
|
NS_WARNING("Can't call SendAudio from an indirect audio speech service.");
|
||||||
@ -293,8 +309,9 @@ nsSpeechTask::DispatchStartImpl(const nsAString& aUri)
|
|||||||
LOG(LogLevel::Debug, ("nsSpeechTask::DispatchStart"));
|
LOG(LogLevel::Debug, ("nsSpeechTask::DispatchStart"));
|
||||||
|
|
||||||
MOZ_ASSERT(mUtterance);
|
MOZ_ASSERT(mUtterance);
|
||||||
NS_ENSURE_TRUE(mUtterance->mState == SpeechSynthesisUtterance::STATE_PENDING,
|
if(NS_WARN_IF(!(mUtterance->mState == SpeechSynthesisUtterance::STATE_PENDING))) {
|
||||||
NS_ERROR_NOT_AVAILABLE);
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
|
}
|
||||||
|
|
||||||
mUtterance->mState = SpeechSynthesisUtterance::STATE_SPEAKING;
|
mUtterance->mState = SpeechSynthesisUtterance::STATE_SPEAKING;
|
||||||
mUtterance->mChosenVoiceURI = aUri;
|
mUtterance->mChosenVoiceURI = aUri;
|
||||||
@ -321,8 +338,9 @@ nsSpeechTask::DispatchEndImpl(float aElapsedTime, uint32_t aCharIndex)
|
|||||||
LOG(LogLevel::Debug, ("nsSpeechTask::DispatchEnd\n"));
|
LOG(LogLevel::Debug, ("nsSpeechTask::DispatchEnd\n"));
|
||||||
|
|
||||||
MOZ_ASSERT(mUtterance);
|
MOZ_ASSERT(mUtterance);
|
||||||
NS_ENSURE_FALSE(mUtterance->mState == SpeechSynthesisUtterance::STATE_ENDED,
|
if(NS_WARN_IF(mUtterance->mState == SpeechSynthesisUtterance::STATE_ENDED)) {
|
||||||
NS_ERROR_NOT_AVAILABLE);
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
|
}
|
||||||
|
|
||||||
// XXX: This should not be here, but it prevents a crash in MSG.
|
// XXX: This should not be here, but it prevents a crash in MSG.
|
||||||
if (mStream) {
|
if (mStream) {
|
||||||
@ -363,9 +381,12 @@ nsSpeechTask::DispatchPauseImpl(float aElapsedTime, uint32_t aCharIndex)
|
|||||||
{
|
{
|
||||||
LOG(LogLevel::Debug, ("nsSpeechTask::DispatchPause"));
|
LOG(LogLevel::Debug, ("nsSpeechTask::DispatchPause"));
|
||||||
MOZ_ASSERT(mUtterance);
|
MOZ_ASSERT(mUtterance);
|
||||||
NS_ENSURE_FALSE(mUtterance->mPaused, NS_ERROR_NOT_AVAILABLE);
|
if(NS_WARN_IF(mUtterance->mPaused)) {
|
||||||
NS_ENSURE_FALSE(mUtterance->mState == SpeechSynthesisUtterance::STATE_ENDED,
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
NS_ERROR_NOT_AVAILABLE);
|
}
|
||||||
|
if(NS_WARN_IF(mUtterance->mState == SpeechSynthesisUtterance::STATE_ENDED)) {
|
||||||
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
|
}
|
||||||
|
|
||||||
mUtterance->mPaused = true;
|
mUtterance->mPaused = true;
|
||||||
mUtterance->DispatchSpeechSynthesisEvent(NS_LITERAL_STRING("pause"),
|
mUtterance->DispatchSpeechSynthesisEvent(NS_LITERAL_STRING("pause"),
|
||||||
@ -390,9 +411,12 @@ nsSpeechTask::DispatchResumeImpl(float aElapsedTime, uint32_t aCharIndex)
|
|||||||
{
|
{
|
||||||
LOG(LogLevel::Debug, ("nsSpeechTask::DispatchResume"));
|
LOG(LogLevel::Debug, ("nsSpeechTask::DispatchResume"));
|
||||||
MOZ_ASSERT(mUtterance);
|
MOZ_ASSERT(mUtterance);
|
||||||
NS_ENSURE_TRUE(mUtterance->mPaused, NS_ERROR_NOT_AVAILABLE);
|
if(NS_WARN_IF(!(mUtterance->mPaused))) {
|
||||||
NS_ENSURE_FALSE(mUtterance->mState == SpeechSynthesisUtterance::STATE_ENDED,
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
NS_ERROR_NOT_AVAILABLE);
|
}
|
||||||
|
if(NS_WARN_IF(mUtterance->mState == SpeechSynthesisUtterance::STATE_ENDED)) {
|
||||||
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
|
}
|
||||||
|
|
||||||
mUtterance->mPaused = false;
|
mUtterance->mPaused = false;
|
||||||
mUtterance->DispatchSpeechSynthesisEvent(NS_LITERAL_STRING("resume"),
|
mUtterance->DispatchSpeechSynthesisEvent(NS_LITERAL_STRING("resume"),
|
||||||
@ -416,8 +440,9 @@ nsresult
|
|||||||
nsSpeechTask::DispatchErrorImpl(float aElapsedTime, uint32_t aCharIndex)
|
nsSpeechTask::DispatchErrorImpl(float aElapsedTime, uint32_t aCharIndex)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mUtterance);
|
MOZ_ASSERT(mUtterance);
|
||||||
NS_ENSURE_FALSE(mUtterance->mState == SpeechSynthesisUtterance::STATE_ENDED,
|
if(NS_WARN_IF(mUtterance->mState == SpeechSynthesisUtterance::STATE_ENDED)) {
|
||||||
NS_ERROR_NOT_AVAILABLE);
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
|
}
|
||||||
|
|
||||||
mUtterance->mState = SpeechSynthesisUtterance::STATE_ENDED;
|
mUtterance->mState = SpeechSynthesisUtterance::STATE_ENDED;
|
||||||
mUtterance->DispatchSpeechSynthesisEvent(NS_LITERAL_STRING("error"),
|
mUtterance->DispatchSpeechSynthesisEvent(NS_LITERAL_STRING("error"),
|
||||||
@ -443,8 +468,9 @@ nsSpeechTask::DispatchBoundaryImpl(const nsAString& aName,
|
|||||||
float aElapsedTime, uint32_t aCharIndex)
|
float aElapsedTime, uint32_t aCharIndex)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mUtterance);
|
MOZ_ASSERT(mUtterance);
|
||||||
NS_ENSURE_TRUE(mUtterance->mState == SpeechSynthesisUtterance::STATE_SPEAKING,
|
if(NS_WARN_IF(!(mUtterance->mState == SpeechSynthesisUtterance::STATE_SPEAKING))) {
|
||||||
NS_ERROR_NOT_AVAILABLE);
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
|
}
|
||||||
|
|
||||||
mUtterance->DispatchSpeechSynthesisEvent(NS_LITERAL_STRING("boundary"),
|
mUtterance->DispatchSpeechSynthesisEvent(NS_LITERAL_STRING("boundary"),
|
||||||
aCharIndex, aElapsedTime,
|
aCharIndex, aElapsedTime,
|
||||||
@ -469,8 +495,9 @@ nsSpeechTask::DispatchMarkImpl(const nsAString& aName,
|
|||||||
float aElapsedTime, uint32_t aCharIndex)
|
float aElapsedTime, uint32_t aCharIndex)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mUtterance);
|
MOZ_ASSERT(mUtterance);
|
||||||
NS_ENSURE_TRUE(mUtterance->mState == SpeechSynthesisUtterance::STATE_SPEAKING,
|
if(NS_WARN_IF(!(mUtterance->mState == SpeechSynthesisUtterance::STATE_SPEAKING))) {
|
||||||
NS_ERROR_NOT_AVAILABLE);
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
|
}
|
||||||
|
|
||||||
mUtterance->DispatchSpeechSynthesisEvent(NS_LITERAL_STRING("mark"),
|
mUtterance->DispatchSpeechSynthesisEvent(NS_LITERAL_STRING("mark"),
|
||||||
aCharIndex, aElapsedTime,
|
aCharIndex, aElapsedTime,
|
||||||
|
@ -236,8 +236,9 @@ nsSynthVoiceRegistry::AddVoice(nsISpeechService* aService,
|
|||||||
NS_ConvertUTF16toUTF8(aLang).get(),
|
NS_ConvertUTF16toUTF8(aLang).get(),
|
||||||
aLocalService ? "true" : "false"));
|
aLocalService ? "true" : "false"));
|
||||||
|
|
||||||
NS_ENSURE_FALSE(XRE_GetProcessType() == GeckoProcessType_Content,
|
if(NS_WARN_IF(XRE_GetProcessType() == GeckoProcessType_Content)) {
|
||||||
NS_ERROR_NOT_AVAILABLE);
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
|
}
|
||||||
|
|
||||||
return AddVoiceImpl(aService, aUri, aName, aLang,
|
return AddVoiceImpl(aService, aUri, aName, aLang,
|
||||||
aLocalService);
|
aLocalService);
|
||||||
@ -255,8 +256,12 @@ nsSynthVoiceRegistry::RemoveVoice(nsISpeechService* aService,
|
|||||||
bool found = false;
|
bool found = false;
|
||||||
VoiceData* retval = mUriVoiceMap.GetWeak(aUri, &found);
|
VoiceData* retval = mUriVoiceMap.GetWeak(aUri, &found);
|
||||||
|
|
||||||
NS_ENSURE_TRUE(found, NS_ERROR_NOT_AVAILABLE);
|
if(NS_WARN_IF(!(found))) {
|
||||||
NS_ENSURE_TRUE(aService == retval->mService, NS_ERROR_INVALID_ARG);
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
|
}
|
||||||
|
if(NS_WARN_IF(!(aService == retval->mService))) {
|
||||||
|
return NS_ERROR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
mVoices.RemoveElement(retval);
|
mVoices.RemoveElement(retval);
|
||||||
mDefaultVoices.RemoveElement(retval);
|
mDefaultVoices.RemoveElement(retval);
|
||||||
@ -277,7 +282,9 @@ nsSynthVoiceRegistry::SetDefaultVoice(const nsAString& aUri,
|
|||||||
{
|
{
|
||||||
bool found = false;
|
bool found = false;
|
||||||
VoiceData* retval = mUriVoiceMap.GetWeak(aUri, &found);
|
VoiceData* retval = mUriVoiceMap.GetWeak(aUri, &found);
|
||||||
NS_ENSURE_TRUE(found, NS_ERROR_NOT_AVAILABLE);
|
if(NS_WARN_IF(!(found))) {
|
||||||
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
|
}
|
||||||
|
|
||||||
mDefaultVoices.RemoveElement(retval);
|
mDefaultVoices.RemoveElement(retval);
|
||||||
|
|
||||||
@ -312,7 +319,9 @@ nsSynthVoiceRegistry::GetVoiceCount(uint32_t* aRetval)
|
|||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsSynthVoiceRegistry::GetVoice(uint32_t aIndex, nsAString& aRetval)
|
nsSynthVoiceRegistry::GetVoice(uint32_t aIndex, nsAString& aRetval)
|
||||||
{
|
{
|
||||||
NS_ENSURE_TRUE(aIndex < mVoices.Length(), NS_ERROR_INVALID_ARG);
|
if(NS_WARN_IF(!(aIndex < mVoices.Length()))) {
|
||||||
|
return NS_ERROR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
aRetval = mVoices[aIndex]->mUri;
|
aRetval = mVoices[aIndex]->mUri;
|
||||||
|
|
||||||
@ -324,7 +333,9 @@ nsSynthVoiceRegistry::IsDefaultVoice(const nsAString& aUri, bool* aRetval)
|
|||||||
{
|
{
|
||||||
bool found;
|
bool found;
|
||||||
VoiceData* voice = mUriVoiceMap.GetWeak(aUri, &found);
|
VoiceData* voice = mUriVoiceMap.GetWeak(aUri, &found);
|
||||||
NS_ENSURE_TRUE(found, NS_ERROR_NOT_AVAILABLE);
|
if(NS_WARN_IF(!(found))) {
|
||||||
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
|
}
|
||||||
|
|
||||||
for (int32_t i = mDefaultVoices.Length(); i > 0; ) {
|
for (int32_t i = mDefaultVoices.Length(); i > 0; ) {
|
||||||
VoiceData* defaultVoice = mDefaultVoices[--i];
|
VoiceData* defaultVoice = mDefaultVoices[--i];
|
||||||
@ -344,7 +355,9 @@ nsSynthVoiceRegistry::IsLocalVoice(const nsAString& aUri, bool* aRetval)
|
|||||||
{
|
{
|
||||||
bool found;
|
bool found;
|
||||||
VoiceData* voice = mUriVoiceMap.GetWeak(aUri, &found);
|
VoiceData* voice = mUriVoiceMap.GetWeak(aUri, &found);
|
||||||
NS_ENSURE_TRUE(found, NS_ERROR_NOT_AVAILABLE);
|
if(NS_WARN_IF(!(found))) {
|
||||||
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
|
}
|
||||||
|
|
||||||
*aRetval = voice->mIsLocal;
|
*aRetval = voice->mIsLocal;
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
@ -355,7 +368,9 @@ nsSynthVoiceRegistry::GetVoiceLang(const nsAString& aUri, nsAString& aRetval)
|
|||||||
{
|
{
|
||||||
bool found;
|
bool found;
|
||||||
VoiceData* voice = mUriVoiceMap.GetWeak(aUri, &found);
|
VoiceData* voice = mUriVoiceMap.GetWeak(aUri, &found);
|
||||||
NS_ENSURE_TRUE(found, NS_ERROR_NOT_AVAILABLE);
|
if(NS_WARN_IF(!(found))) {
|
||||||
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
|
}
|
||||||
|
|
||||||
aRetval = voice->mLang;
|
aRetval = voice->mLang;
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
@ -366,7 +381,9 @@ nsSynthVoiceRegistry::GetVoiceName(const nsAString& aUri, nsAString& aRetval)
|
|||||||
{
|
{
|
||||||
bool found;
|
bool found;
|
||||||
VoiceData* voice = mUriVoiceMap.GetWeak(aUri, &found);
|
VoiceData* voice = mUriVoiceMap.GetWeak(aUri, &found);
|
||||||
NS_ENSURE_TRUE(found, NS_ERROR_NOT_AVAILABLE);
|
if(NS_WARN_IF(!(found))) {
|
||||||
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
|
}
|
||||||
|
|
||||||
aRetval = voice->mName;
|
aRetval = voice->mName;
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
@ -381,7 +398,9 @@ nsSynthVoiceRegistry::AddVoiceImpl(nsISpeechService* aService,
|
|||||||
{
|
{
|
||||||
bool found = false;
|
bool found = false;
|
||||||
mUriVoiceMap.GetWeak(aUri, &found);
|
mUriVoiceMap.GetWeak(aUri, &found);
|
||||||
NS_ENSURE_FALSE(found, NS_ERROR_INVALID_ARG);
|
if(NS_WARN_IF(found)) {
|
||||||
|
return NS_ERROR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
nsRefPtr<VoiceData> voice = new VoiceData(aService, aUri, aName, aLang,
|
nsRefPtr<VoiceData> voice = new VoiceData(aService, aUri, aName, aLang,
|
||||||
aLocalService);
|
aLocalService);
|
||||||
@ -477,11 +496,15 @@ nsSynthVoiceRegistry::FindBestMatch(const nsAString& aUri,
|
|||||||
// Try UI language.
|
// Try UI language.
|
||||||
nsresult rv;
|
nsresult rv;
|
||||||
nsCOMPtr<nsILocaleService> localeService = do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv);
|
nsCOMPtr<nsILocaleService> localeService = do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv);
|
||||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
nsAutoString uiLang;
|
nsAutoString uiLang;
|
||||||
rv = localeService->GetLocaleComponentForUserAgent(uiLang);
|
rv = localeService->GetLocaleComponentForUserAgent(uiLang);
|
||||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
if (FindVoiceByLang(uiLang, &retval)) {
|
if (FindVoiceByLang(uiLang, &retval)) {
|
||||||
LOG(LogLevel::Debug,
|
LOG(LogLevel::Debug,
|
||||||
|
@ -451,7 +451,9 @@ nsPicoService::Observe(nsISupports* aSubject, const char* aTopic,
|
|||||||
const char16_t* aData)
|
const char16_t* aData)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
NS_ENSURE_TRUE(!strcmp(aTopic, "profile-after-change"), NS_ERROR_UNEXPECTED);
|
if(NS_WARN_IF(!(!strcmp(aTopic, "profile-after-change")))) {
|
||||||
|
return NS_ERROR_UNEXPECTED;
|
||||||
|
}
|
||||||
|
|
||||||
if (!Preferences::GetBool("media.webspeech.synth.enabled") ||
|
if (!Preferences::GetBool("media.webspeech.synth.enabled") ||
|
||||||
Preferences::GetBool("media.webspeech.synth.test")) {
|
Preferences::GetBool("media.webspeech.synth.test")) {
|
||||||
@ -470,12 +472,16 @@ nsPicoService::Speak(const nsAString& aText, const nsAString& aUri,
|
|||||||
float aVolume, float aRate, float aPitch,
|
float aVolume, float aRate, float aPitch,
|
||||||
nsISpeechTask* aTask)
|
nsISpeechTask* aTask)
|
||||||
{
|
{
|
||||||
NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_AVAILABLE);
|
if(NS_WARN_IF(!(mInitialized))) {
|
||||||
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
|
}
|
||||||
|
|
||||||
MonitorAutoLock autoLock(mVoicesMonitor);
|
MonitorAutoLock autoLock(mVoicesMonitor);
|
||||||
bool found = false;
|
bool found = false;
|
||||||
PicoVoice* voice = mVoices.GetWeak(aUri, &found);
|
PicoVoice* voice = mVoices.GetWeak(aUri, &found);
|
||||||
NS_ENSURE_TRUE(found, NS_ERROR_NOT_AVAILABLE);
|
if(NS_WARN_IF(!(found))) {
|
||||||
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
|
}
|
||||||
|
|
||||||
mCurrentTask = aTask;
|
mCurrentTask = aTask;
|
||||||
nsRefPtr<PicoCallbackRunnable> cb = new PicoCallbackRunnable(aText, voice, aRate, aPitch, aTask, this);
|
nsRefPtr<PicoCallbackRunnable> cb = new PicoCallbackRunnable(aText, voice, aRate, aPitch, aTask, this);
|
||||||
|
@ -27,6 +27,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=525444
|
|||||||
|
|
||||||
ok(SpeechSynthesis, "SpeechSynthesis exists in global scope");
|
ok(SpeechSynthesis, "SpeechSynthesis exists in global scope");
|
||||||
ok(SpeechSynthesisVoice, "SpeechSynthesisVoice exists in global scope");
|
ok(SpeechSynthesisVoice, "SpeechSynthesisVoice exists in global scope");
|
||||||
|
ok(SpeechSynthesisErrorEvent, "SpeechSynthesisErrorEvent exists in global scope");
|
||||||
ok(SpeechSynthesisEvent, "SpeechSynthesisEvent exists in global scope");
|
ok(SpeechSynthesisEvent, "SpeechSynthesisEvent exists in global scope");
|
||||||
|
|
||||||
// SpeechSynthesisUtterance is the only type that has a constructor
|
// SpeechSynthesisUtterance is the only type that has a constructor
|
||||||
|
@ -311,7 +311,9 @@ nsFakeSynthServices::Observe(nsISupports* aSubject, const char* aTopic,
|
|||||||
const char16_t* aData)
|
const char16_t* aData)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
NS_ENSURE_TRUE(!strcmp(aTopic, "profile-after-change"), NS_ERROR_UNEXPECTED);
|
if(NS_WARN_IF(!(!strcmp(aTopic, "profile-after-change")))) {
|
||||||
|
return NS_ERROR_UNEXPECTED;
|
||||||
|
}
|
||||||
|
|
||||||
if (Preferences::GetBool("media.webspeech.synth.test")) {
|
if (Preferences::GetBool("media.webspeech.synth.test")) {
|
||||||
Init();
|
Init();
|
||||||
|
@ -964,6 +964,8 @@ var interfaceNamesInGlobalScope =
|
|||||||
{name: "SourceBuffer", linux: false, release: false},
|
{name: "SourceBuffer", linux: false, release: false},
|
||||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||||
{name: "SourceBufferList", linux: false, release: false},
|
{name: "SourceBufferList", linux: false, release: false},
|
||||||
|
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||||
|
{name: "SpeechSynthesisErrorEvent", b2g: true},
|
||||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||||
{name: "SpeechSynthesisEvent", b2g: true},
|
{name: "SpeechSynthesisEvent", b2g: true},
|
||||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||||
|
36
dom/webidl/SpeechSynthesisErrorEvent.webidl
Normal file
36
dom/webidl/SpeechSynthesisErrorEvent.webidl
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/* -*- Mode: IDL; 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/.
|
||||||
|
*
|
||||||
|
* The origin of this IDL file is
|
||||||
|
* http://dvcs.w3.org/hg/speech-api/raw-file/tip/speechapi.html
|
||||||
|
*
|
||||||
|
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
|
||||||
|
* liability, trademark and document use rules apply.
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum SpeechSynthesisErrorCode {
|
||||||
|
"canceled",
|
||||||
|
"interrupted",
|
||||||
|
"audio-busy",
|
||||||
|
"audio-hardware",
|
||||||
|
"network",
|
||||||
|
"synthesis-unavailable",
|
||||||
|
"synthesis-failed",
|
||||||
|
"language-unavailable",
|
||||||
|
"voice-unavailable",
|
||||||
|
"text-too-long",
|
||||||
|
"invalid-argument",
|
||||||
|
};
|
||||||
|
|
||||||
|
[Constructor(DOMString type, optional SpeechSynthesisErrorEventInit eventInitDict),
|
||||||
|
Pref="media.webspeech.synth.enabled"]
|
||||||
|
interface SpeechSynthesisErrorEvent : SpeechSynthesisEvent {
|
||||||
|
readonly attribute SpeechSynthesisErrorCode error;
|
||||||
|
};
|
||||||
|
|
||||||
|
dictionary SpeechSynthesisErrorEventInit : SpeechSynthesisEventInit
|
||||||
|
{
|
||||||
|
required SpeechSynthesisErrorCode error;
|
||||||
|
};
|
@ -14,6 +14,7 @@
|
|||||||
Pref="media.webspeech.synth.enabled"]
|
Pref="media.webspeech.synth.enabled"]
|
||||||
interface SpeechSynthesisEvent : Event
|
interface SpeechSynthesisEvent : Event
|
||||||
{
|
{
|
||||||
|
readonly attribute SpeechSynthesisUtterance utterance;
|
||||||
readonly attribute unsigned long charIndex;
|
readonly attribute unsigned long charIndex;
|
||||||
readonly attribute float elapsedTime;
|
readonly attribute float elapsedTime;
|
||||||
readonly attribute DOMString? name;
|
readonly attribute DOMString? name;
|
||||||
@ -21,6 +22,7 @@ interface SpeechSynthesisEvent : Event
|
|||||||
|
|
||||||
dictionary SpeechSynthesisEventInit : EventInit
|
dictionary SpeechSynthesisEventInit : EventInit
|
||||||
{
|
{
|
||||||
|
required SpeechSynthesisUtterance utterance;
|
||||||
unsigned long charIndex = 0;
|
unsigned long charIndex = 0;
|
||||||
float elapsedTime = 0;
|
float elapsedTime = 0;
|
||||||
DOMString name = "";
|
DOMString name = "";
|
||||||
|
@ -611,6 +611,7 @@ if CONFIG['MOZ_WEBSPEECH']:
|
|||||||
'SpeechRecognitionResult.webidl',
|
'SpeechRecognitionResult.webidl',
|
||||||
'SpeechRecognitionResultList.webidl',
|
'SpeechRecognitionResultList.webidl',
|
||||||
'SpeechSynthesis.webidl',
|
'SpeechSynthesis.webidl',
|
||||||
|
'SpeechSynthesisErrorEvent.webidl',
|
||||||
'SpeechSynthesisEvent.webidl',
|
'SpeechSynthesisEvent.webidl',
|
||||||
'SpeechSynthesisUtterance.webidl',
|
'SpeechSynthesisUtterance.webidl',
|
||||||
'SpeechSynthesisVoice.webidl',
|
'SpeechSynthesisVoice.webidl',
|
||||||
@ -788,6 +789,7 @@ GENERATED_EVENTS_WEBIDL_FILES = [
|
|||||||
if CONFIG['MOZ_WEBSPEECH']:
|
if CONFIG['MOZ_WEBSPEECH']:
|
||||||
GENERATED_EVENTS_WEBIDL_FILES += [
|
GENERATED_EVENTS_WEBIDL_FILES += [
|
||||||
'SpeechRecognitionEvent.webidl',
|
'SpeechRecognitionEvent.webidl',
|
||||||
|
'SpeechSynthesisErrorEvent.webidl',
|
||||||
'SpeechSynthesisEvent.webidl',
|
'SpeechSynthesisEvent.webidl',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -60,11 +60,6 @@ static inline int floor_div(int a, int b)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// An abstract implementation of a tile buffer. This code covers the logic of
|
|
||||||
// moving and reusing tiles and leaves the validation up to the implementor. To
|
|
||||||
// avoid the overhead of virtual dispatch, we employ the curiously recurring
|
|
||||||
// template pattern.
|
|
||||||
//
|
|
||||||
// Tiles are aligned to a grid with one of the grid points at (0,0) and other
|
// Tiles are aligned to a grid with one of the grid points at (0,0) and other
|
||||||
// grid points spaced evenly in the x- and y-directions by GetTileSize()
|
// grid points spaced evenly in the x- and y-directions by GetTileSize()
|
||||||
// multiplied by mResolution. GetScaledTileSize() provides convenience for
|
// multiplied by mResolution. GetScaledTileSize() provides convenience for
|
||||||
@ -82,30 +77,6 @@ static inline int floor_div(int a, int b)
|
|||||||
// the tile type should be a reference or some other type with an efficient
|
// the tile type should be a reference or some other type with an efficient
|
||||||
// copy constructor.
|
// copy constructor.
|
||||||
//
|
//
|
||||||
// It is required that the derived class specify the base class as a friend. It
|
|
||||||
// must also implement the following public method:
|
|
||||||
//
|
|
||||||
// Tile GetPlaceholderTile() const;
|
|
||||||
//
|
|
||||||
// Returns a temporary placeholder tile used as a marker. This placeholder tile
|
|
||||||
// must never be returned by validateTile and must be == to every instance
|
|
||||||
// of a placeholder tile.
|
|
||||||
//
|
|
||||||
// Additionally, it must implement the following protected methods:
|
|
||||||
//
|
|
||||||
// Tile ValidateTile(Tile aTile, const nsIntPoint& aTileOrigin,
|
|
||||||
// const nsIntRegion& aDirtyRect);
|
|
||||||
//
|
|
||||||
// Validates the dirtyRect. The returned Tile will replace the tile.
|
|
||||||
//
|
|
||||||
// void ReleaseTile(Tile aTile);
|
|
||||||
//
|
|
||||||
// Destroys the given tile.
|
|
||||||
//
|
|
||||||
// void SwapTiles(Tile& aTileA, Tile& aTileB);
|
|
||||||
//
|
|
||||||
// Swaps two tiles.
|
|
||||||
//
|
|
||||||
// The contents of the tile buffer will be rendered at the resolution specified
|
// The contents of the tile buffer will be rendered at the resolution specified
|
||||||
// in mResolution, which can be altered with SetResolution. The resolution
|
// in mResolution, which can be altered with SetResolution. The resolution
|
||||||
// should always be a factor of the tile length, to avoid tiles covering
|
// should always be a factor of the tile length, to avoid tiles covering
|
||||||
@ -146,12 +117,23 @@ struct TilesPlacement {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HasTile(TileIntPoint aPosition) {
|
bool HasTile(TileIntPoint aPosition) const {
|
||||||
return aPosition.x >= mFirst.x && aPosition.x < mFirst.x + mSize.width &&
|
return aPosition.x >= mFirst.x && aPosition.x < mFirst.x + mSize.width &&
|
||||||
aPosition.y >= mFirst.y && aPosition.y < mFirst.y + mSize.height;
|
aPosition.y >= mFirst.y && aPosition.y < mFirst.y + mSize.height;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Given a position i, this function returns the position inside the current tile.
|
||||||
|
inline int GetTileStart(int i, int aTileLength) {
|
||||||
|
return (i >= 0) ? (i % aTileLength)
|
||||||
|
: ((aTileLength - (-i % aTileLength)) %
|
||||||
|
aTileLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rounds the given coordinate down to the nearest tile boundary.
|
||||||
|
inline int RoundDownToTileEdge(int aX, int aTileLength) { return aX - GetTileStart(aX, aTileLength); }
|
||||||
|
|
||||||
template<typename Derived, typename Tile>
|
template<typename Derived, typename Tile>
|
||||||
class TiledLayerBuffer
|
class TiledLayerBuffer
|
||||||
{
|
{
|
||||||
@ -165,21 +147,6 @@ public:
|
|||||||
|
|
||||||
~TiledLayerBuffer() {}
|
~TiledLayerBuffer() {}
|
||||||
|
|
||||||
// Given a tile origin aligned to a multiple of GetScaledTileSize,
|
|
||||||
// return the tile that describes that region.
|
|
||||||
// NOTE: To get the valid area of that tile you must intersect
|
|
||||||
// (aTileOrigin.x, aTileOrigin.y,
|
|
||||||
// GetScaledTileSize().width, GetScaledTileSize().height)
|
|
||||||
// and GetValidRegion() to get the area of the tile that is valid.
|
|
||||||
Tile& GetTile(const gfx::IntPoint& aTileOrigin);
|
|
||||||
// Given a tile x, y relative to the top left of the layer, this function
|
|
||||||
// will return the tile for
|
|
||||||
// (x*GetScaledTileSize().width, y*GetScaledTileSize().height,
|
|
||||||
// GetScaledTileSize().width, GetScaledTileSize().height)
|
|
||||||
Tile& GetTile(int x, int y);
|
|
||||||
|
|
||||||
Tile& GetTile(size_t i) { return mRetainedTiles[i]; }
|
|
||||||
|
|
||||||
gfx::IntPoint GetTileOffset(TileIntPoint aPosition) const {
|
gfx::IntPoint GetTileOffset(TileIntPoint aPosition) const {
|
||||||
gfx::IntSize scaledTileSize = GetScaledTileSize();
|
gfx::IntSize scaledTileSize = GetScaledTileSize();
|
||||||
return gfx::IntPoint(aPosition.x * scaledTileSize.width,
|
return gfx::IntPoint(aPosition.x * scaledTileSize.width,
|
||||||
@ -188,48 +155,18 @@ public:
|
|||||||
|
|
||||||
const TilesPlacement& GetPlacement() const { return mTiles; }
|
const TilesPlacement& GetPlacement() const { return mTiles; }
|
||||||
|
|
||||||
int TileIndex(const gfx::IntPoint& aTileOrigin) const;
|
|
||||||
int TileIndex(int x, int y) const { return x * mTiles.mSize.height + y; }
|
|
||||||
|
|
||||||
bool HasTile(int index) const { return index >= 0 && index < (int)mRetainedTiles.Length(); }
|
|
||||||
bool HasTile(const gfx::IntPoint& aTileOrigin) const;
|
|
||||||
bool HasTile(int x, int y) const {
|
|
||||||
return x >= 0 && x < mTiles.mSize.width && y >= 0 && y < mTiles.mSize.height;
|
|
||||||
}
|
|
||||||
|
|
||||||
const gfx::IntSize& GetTileSize() const { return mTileSize; }
|
const gfx::IntSize& GetTileSize() const { return mTileSize; }
|
||||||
|
|
||||||
gfx::IntSize GetScaledTileSize() const { return RoundedToInt(gfx::Size(mTileSize) / mResolution); }
|
gfx::IntSize GetScaledTileSize() const { return RoundedToInt(gfx::Size(mTileSize) / mResolution); }
|
||||||
|
|
||||||
unsigned int GetTileCount() const { return mRetainedTiles.Length(); }
|
unsigned int GetTileCount() const { return mRetainedTiles.Length(); }
|
||||||
|
|
||||||
|
Tile& GetTile(size_t i) { return mRetainedTiles[i]; }
|
||||||
|
|
||||||
const nsIntRegion& GetValidRegion() const { return mValidRegion; }
|
const nsIntRegion& GetValidRegion() const { return mValidRegion; }
|
||||||
const nsIntRegion& GetPaintedRegion() const { return mPaintedRegion; }
|
const nsIntRegion& GetPaintedRegion() const { return mPaintedRegion; }
|
||||||
void ClearPaintedRegion() { mPaintedRegion.SetEmpty(); }
|
void ClearPaintedRegion() { mPaintedRegion.SetEmpty(); }
|
||||||
|
|
||||||
void ResetPaintedAndValidState() {
|
|
||||||
mPaintedRegion.SetEmpty();
|
|
||||||
mValidRegion.SetEmpty();
|
|
||||||
mTiles.mSize.width = 0;
|
|
||||||
mTiles.mSize.height = 0;
|
|
||||||
for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
|
|
||||||
if (!mRetainedTiles[i].IsPlaceholderTile()) {
|
|
||||||
AsDerived().ReleaseTile(mRetainedTiles[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mRetainedTiles.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Given a position i, this function returns the position inside the current tile.
|
|
||||||
int GetTileStart(int i, int aTileLength) const {
|
|
||||||
return (i >= 0) ? (i % aTileLength)
|
|
||||||
: ((aTileLength - (-i % aTileLength)) %
|
|
||||||
aTileLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rounds the given coordinate down to the nearest tile boundary.
|
|
||||||
int RoundDownToTileEdge(int aX, int aTileLength) const { return aX - GetTileStart(aX, aTileLength); }
|
|
||||||
|
|
||||||
// Get and set draw scaling. mResolution affects the resolution at which the
|
// Get and set draw scaling. mResolution affects the resolution at which the
|
||||||
// contents of the buffer are drawn. mResolution has no effect on the
|
// contents of the buffer are drawn. mResolution has no effect on the
|
||||||
// coordinate space of the valid region, but does affect the size of an
|
// coordinate space of the valid region, but does affect the size of an
|
||||||
@ -238,22 +175,9 @@ public:
|
|||||||
float GetResolution() const { return mResolution; }
|
float GetResolution() const { return mResolution; }
|
||||||
bool IsLowPrecision() const { return mResolution < 1; }
|
bool IsLowPrecision() const { return mResolution < 1; }
|
||||||
|
|
||||||
typedef Tile* Iterator;
|
|
||||||
Iterator TilesBegin() { return mRetainedTiles.Elements(); }
|
|
||||||
Iterator TilesEnd() { return mRetainedTiles.Elements() + mRetainedTiles.Length(); }
|
|
||||||
|
|
||||||
void Dump(std::stringstream& aStream, const char* aPrefix, bool aDumpHtml);
|
void Dump(std::stringstream& aStream, const char* aPrefix, bool aDumpHtml);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// The implementor should call Update() to change
|
|
||||||
// the new valid region. This implementation will call
|
|
||||||
// validateTile on each tile that is dirty, which is left
|
|
||||||
// to the implementor.
|
|
||||||
void Update(const nsIntRegion& aNewValidRegion, const nsIntRegion& aPaintRegion);
|
|
||||||
|
|
||||||
// Return a reference to this tile in GetTile when the requested tile offset
|
|
||||||
// does not exist.
|
|
||||||
Tile mPlaceHolderTile;
|
|
||||||
|
|
||||||
nsIntRegion mValidRegion;
|
nsIntRegion mValidRegion;
|
||||||
nsIntRegion mPaintedRegion;
|
nsIntRegion mPaintedRegion;
|
||||||
@ -270,411 +194,25 @@ protected:
|
|||||||
TilesPlacement mTiles;
|
TilesPlacement mTiles;
|
||||||
float mResolution;
|
float mResolution;
|
||||||
gfx::IntSize mTileSize;
|
gfx::IntSize mTileSize;
|
||||||
|
|
||||||
private:
|
|
||||||
const Derived& AsDerived() const { return *static_cast<const Derived*>(this); }
|
|
||||||
Derived& AsDerived() { return *static_cast<Derived*>(this); }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class ClientTiledLayerBuffer;
|
|
||||||
class SurfaceDescriptorTiles;
|
|
||||||
class ISurfaceAllocator;
|
|
||||||
|
|
||||||
// Shadow layers may implement this interface in order to be notified when a
|
|
||||||
// tiled layer buffer is updated.
|
|
||||||
class TiledLayerComposer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Update the current retained layer with the updated layer data.
|
|
||||||
* It is expected that the tiles described by aTiledDescriptor are all in the
|
|
||||||
* ReadLock state, so that the locks can be adopted when recreating a
|
|
||||||
* ClientTiledLayerBuffer locally. This lock will be retained until the buffer
|
|
||||||
* has completed uploading.
|
|
||||||
*
|
|
||||||
* Returns false if a deserialization error happened, in which case we will
|
|
||||||
* have to kill the child process.
|
|
||||||
*/
|
|
||||||
virtual bool UseTiledLayerBuffer(ISurfaceAllocator* aAllocator,
|
|
||||||
const SurfaceDescriptorTiles& aTiledDescriptor) = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If some part of the buffer is being rendered at a lower precision, this
|
|
||||||
* returns that region. If it is not, an empty region will be returned.
|
|
||||||
*/
|
|
||||||
virtual const nsIntRegion& GetValidLowPrecisionRegion() const = 0;
|
|
||||||
|
|
||||||
virtual const nsIntRegion& GetValidRegion() const = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename Derived, typename Tile> bool
|
|
||||||
TiledLayerBuffer<Derived, Tile>::HasTile(const gfx::IntPoint& aTileOrigin) const {
|
|
||||||
gfx::IntSize scaledTileSize = GetScaledTileSize();
|
|
||||||
return HasTile(floor_div(aTileOrigin.x, scaledTileSize.width) - mTiles.mFirst.x,
|
|
||||||
floor_div(aTileOrigin.y, scaledTileSize.height) - mTiles.mFirst.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Derived, typename Tile> Tile&
|
|
||||||
TiledLayerBuffer<Derived, Tile>::GetTile(const nsIntPoint& aTileOrigin)
|
|
||||||
{
|
|
||||||
if (HasTile(aTileOrigin)) {
|
|
||||||
return mRetainedTiles[TileIndex(aTileOrigin)];
|
|
||||||
}
|
|
||||||
return mPlaceHolderTile;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Derived, typename Tile> int
|
|
||||||
TiledLayerBuffer<Derived, Tile>::TileIndex(const gfx::IntPoint& aTileOrigin) const
|
|
||||||
{
|
|
||||||
// Find the tile x/y of the first tile and the target tile relative to the (0, 0)
|
|
||||||
// origin, the difference is the tile x/y relative to the start of the tile buffer.
|
|
||||||
gfx::IntSize scaledTileSize = GetScaledTileSize();
|
|
||||||
return TileIndex(floor_div(aTileOrigin.x, scaledTileSize.width) - mTiles.mFirst.x,
|
|
||||||
floor_div(aTileOrigin.y, scaledTileSize.height) - mTiles.mFirst.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Derived, typename Tile> Tile&
|
|
||||||
TiledLayerBuffer<Derived, Tile>::GetTile(int x, int y)
|
|
||||||
{
|
|
||||||
if (HasTile(x, y)) {
|
|
||||||
return mRetainedTiles[TileIndex(x, y)];
|
|
||||||
}
|
|
||||||
return mPlaceHolderTile;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Derived, typename Tile> void
|
template<typename Derived, typename Tile> void
|
||||||
TiledLayerBuffer<Derived, Tile>::Dump(std::stringstream& aStream,
|
TiledLayerBuffer<Derived, Tile>::Dump(std::stringstream& aStream,
|
||||||
const char* aPrefix,
|
const char* aPrefix,
|
||||||
bool aDumpHtml)
|
bool aDumpHtml)
|
||||||
{
|
{
|
||||||
gfx::IntRect visibleRect = GetValidRegion().GetBounds();
|
for (size_t i = 0; i < mRetainedTiles.Length(); ++i) {
|
||||||
gfx::IntSize scaledTileSize = GetScaledTileSize();
|
const TileIntPoint tilePosition = mTiles.TilePosition(i);
|
||||||
for (int32_t x = visibleRect.x; x < visibleRect.x + visibleRect.width;) {
|
gfx::IntPoint tileOffset = GetTileOffset(tilePosition);
|
||||||
int32_t tileStartX = GetTileStart(x, scaledTileSize.width);
|
|
||||||
int32_t w = scaledTileSize.width - tileStartX;
|
|
||||||
|
|
||||||
for (int32_t y = visibleRect.y; y < visibleRect.y + visibleRect.height;) {
|
aStream << "\n" << aPrefix << "Tile (x=" <<
|
||||||
int32_t tileStartY = GetTileStart(y, scaledTileSize.height);
|
tileOffset.x << ", y=" << tileOffset.y << "): ";
|
||||||
nsIntPoint tileOrigin = nsIntPoint(RoundDownToTileEdge(x, scaledTileSize.width),
|
if (!mRetainedTiles[i].IsPlaceholderTile()) {
|
||||||
RoundDownToTileEdge(y, scaledTileSize.height));
|
mRetainedTiles[i].DumpTexture(aStream);
|
||||||
Tile& tileTexture = GetTile(tileOrigin);
|
|
||||||
int32_t h = scaledTileSize.height - tileStartY;
|
|
||||||
|
|
||||||
aStream << "\n" << aPrefix << "Tile (x=" <<
|
|
||||||
RoundDownToTileEdge(x, scaledTileSize.width) << ", y=" <<
|
|
||||||
RoundDownToTileEdge(y, scaledTileSize.height) << "): ";
|
|
||||||
if (!tileTexture.IsPlaceholderTile()) {
|
|
||||||
tileTexture.DumpTexture(aStream);
|
|
||||||
} else {
|
|
||||||
aStream << "empty tile";
|
|
||||||
}
|
|
||||||
y += h;
|
|
||||||
}
|
|
||||||
x += w;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Derived, typename Tile> void
|
|
||||||
TiledLayerBuffer<Derived, Tile>::Update(const nsIntRegion& newValidRegion,
|
|
||||||
const nsIntRegion& aPaintRegion)
|
|
||||||
{
|
|
||||||
gfx::IntSize scaledTileSize = GetScaledTileSize();
|
|
||||||
|
|
||||||
nsTArray<Tile> newRetainedTiles;
|
|
||||||
nsTArray<Tile>& oldRetainedTiles = mRetainedTiles;
|
|
||||||
const gfx::IntRect oldBound = mValidRegion.GetBounds();
|
|
||||||
const gfx::IntRect newBound = newValidRegion.GetBounds();
|
|
||||||
const nsIntPoint oldBufferOrigin(RoundDownToTileEdge(oldBound.x, scaledTileSize.width),
|
|
||||||
RoundDownToTileEdge(oldBound.y, scaledTileSize.height));
|
|
||||||
const nsIntPoint newBufferOrigin(RoundDownToTileEdge(newBound.x, scaledTileSize.width),
|
|
||||||
RoundDownToTileEdge(newBound.y, scaledTileSize.height));
|
|
||||||
|
|
||||||
// This is the reason we break the style guide with newValidRegion instead
|
|
||||||
// of aNewValidRegion - so that the names match better and code easier to read
|
|
||||||
const nsIntRegion& oldValidRegion = mValidRegion;
|
|
||||||
const int oldRetainedHeight = mTiles.mSize.height;
|
|
||||||
|
|
||||||
#ifdef GFX_TILEDLAYER_RETAINING_LOG
|
|
||||||
{ // scope ss
|
|
||||||
std::stringstream ss;
|
|
||||||
ss << "TiledLayerBuffer " << this << " starting update"
|
|
||||||
<< " on bounds ";
|
|
||||||
AppendToString(ss, newBound);
|
|
||||||
ss << " with mResolution=" << mResolution << "\n";
|
|
||||||
for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
|
|
||||||
ss << "mRetainedTiles[" << i << "] = ";
|
|
||||||
mRetainedTiles[i].Dump(ss);
|
|
||||||
ss << "\n";
|
|
||||||
}
|
|
||||||
print_stderr(ss);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Pass 1: Recycle valid content from the old buffer
|
|
||||||
// Recycle tiles from the old buffer that contain valid regions.
|
|
||||||
// Insert placeholders tiles if we have no valid area for that tile
|
|
||||||
// which we will allocate in pass 2.
|
|
||||||
// TODO: Add a tile pool to reduce new allocation
|
|
||||||
int tileX = 0;
|
|
||||||
int tileY = 0;
|
|
||||||
int tilesMissing = 0;
|
|
||||||
// Iterate over the new drawing bounds in steps of tiles.
|
|
||||||
for (int32_t x = newBound.x; x < newBound.XMost(); tileX++) {
|
|
||||||
// Compute tileRect(x,y,width,height) in layer space coordinate
|
|
||||||
// giving us the rect of the tile that hits the newBounds.
|
|
||||||
int width = scaledTileSize.width - GetTileStart(x, scaledTileSize.width);
|
|
||||||
if (x + width > newBound.XMost()) {
|
|
||||||
width = newBound.x + newBound.width - x;
|
|
||||||
}
|
|
||||||
|
|
||||||
tileY = 0;
|
|
||||||
for (int32_t y = newBound.y; y < newBound.YMost(); tileY++) {
|
|
||||||
int height = scaledTileSize.height - GetTileStart(y, scaledTileSize.height);
|
|
||||||
if (y + height > newBound.y + newBound.height) {
|
|
||||||
height = newBound.y + newBound.height - y;
|
|
||||||
}
|
|
||||||
|
|
||||||
const gfx::IntRect tileRect(x,y,width,height);
|
|
||||||
if (oldValidRegion.Intersects(tileRect) && newValidRegion.Intersects(tileRect)) {
|
|
||||||
// This old tiles contains some valid area so move it to the new tile
|
|
||||||
// buffer. Replace the tile in the old buffer with a placeholder
|
|
||||||
// to leave the old buffer index unaffected.
|
|
||||||
int tileX = floor_div(x - oldBufferOrigin.x, scaledTileSize.width);
|
|
||||||
int tileY = floor_div(y - oldBufferOrigin.y, scaledTileSize.height);
|
|
||||||
int index = tileX * oldRetainedHeight + tileY;
|
|
||||||
|
|
||||||
// The tile may have been removed, skip over it in this case.
|
|
||||||
if (oldRetainedTiles.
|
|
||||||
SafeElementAt(index, AsDerived().GetPlaceholderTile()).IsPlaceholderTile()) {
|
|
||||||
newRetainedTiles.AppendElement(AsDerived().GetPlaceholderTile());
|
|
||||||
} else {
|
|
||||||
Tile tileWithPartialValidContent = oldRetainedTiles[index];
|
|
||||||
newRetainedTiles.AppendElement(tileWithPartialValidContent);
|
|
||||||
oldRetainedTiles[index] = AsDerived().GetPlaceholderTile();
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// This tile is either:
|
|
||||||
// 1) Outside the new valid region and will simply be an empty
|
|
||||||
// placeholder forever.
|
|
||||||
// 2) The old buffer didn't have any data for this tile. We postpone
|
|
||||||
// the allocation of this tile after we've reused any tile with
|
|
||||||
// valid content because then we know we can safely recycle
|
|
||||||
// with taking from a tile that has recyclable content.
|
|
||||||
newRetainedTiles.AppendElement(AsDerived().GetPlaceholderTile());
|
|
||||||
|
|
||||||
if (aPaintRegion.Intersects(tileRect)) {
|
|
||||||
tilesMissing++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
y += height;
|
|
||||||
}
|
|
||||||
|
|
||||||
x += width;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Keep track of the number of horizontal/vertical tiles
|
|
||||||
// in the buffer so that we can easily look up a tile.
|
|
||||||
mTiles.mSize.width = tileX;
|
|
||||||
mTiles.mSize.height = tileY;
|
|
||||||
|
|
||||||
#ifdef GFX_TILEDLAYER_RETAINING_LOG
|
|
||||||
{ // scope ss
|
|
||||||
std::stringstream ss;
|
|
||||||
ss << "TiledLayerBuffer " << this << " finished pass 1 of update;"
|
|
||||||
<< " tilesMissing=" << tilesMissing << "\n";
|
|
||||||
for (size_t i = 0; i < oldRetainedTiles.Length(); i++) {
|
|
||||||
ss << "oldRetainedTiles[" << i << "] = ";
|
|
||||||
oldRetainedTiles[i].Dump(ss);
|
|
||||||
ss << "\n";
|
|
||||||
}
|
|
||||||
print_stderr(ss);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
// Pass 1.5: Release excess tiles in oldRetainedTiles
|
|
||||||
// Tiles in oldRetainedTiles that aren't in newRetainedTiles will be recycled
|
|
||||||
// before creating new ones, but there could still be excess unnecessary
|
|
||||||
// tiles. As tiles may not have a fixed memory cost (for example, due to
|
|
||||||
// double-buffering), we should release these excess tiles first.
|
|
||||||
int oldTileCount = 0;
|
|
||||||
for (size_t i = 0; i < oldRetainedTiles.Length(); i++) {
|
|
||||||
Tile oldTile = oldRetainedTiles[i];
|
|
||||||
if (oldTile.IsPlaceholderTile()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (oldTileCount >= tilesMissing) {
|
|
||||||
oldRetainedTiles[i] = AsDerived().GetPlaceholderTile();
|
|
||||||
AsDerived().ReleaseTile(oldTile);
|
|
||||||
} else {
|
} else {
|
||||||
oldTileCount ++;
|
aStream << "empty tile";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!newValidRegion.Contains(aPaintRegion)) {
|
|
||||||
gfxCriticalError() << "Painting outside visible:"
|
|
||||||
<< " paint " << aPaintRegion.ToString().get()
|
|
||||||
<< " old valid " << oldValidRegion.ToString().get()
|
|
||||||
<< " new valid " << newValidRegion.ToString().get();
|
|
||||||
}
|
|
||||||
#ifdef DEBUG
|
|
||||||
nsIntRegion oldAndPainted(oldValidRegion);
|
|
||||||
oldAndPainted.Or(oldAndPainted, aPaintRegion);
|
|
||||||
if (!oldAndPainted.Contains(newValidRegion)) {
|
|
||||||
gfxCriticalError() << "Not fully painted:"
|
|
||||||
<< " paint " << aPaintRegion.ToString().get()
|
|
||||||
<< " old valid " << oldValidRegion.ToString().get()
|
|
||||||
<< " old painted " << oldAndPainted.ToString().get()
|
|
||||||
<< " new valid " << newValidRegion.ToString().get();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
nsIntRegion regionToPaint(aPaintRegion);
|
|
||||||
|
|
||||||
#ifdef GFX_TILEDLAYER_RETAINING_LOG
|
|
||||||
{ // scope ss
|
|
||||||
std::stringstream ss;
|
|
||||||
ss << "TiledLayerBuffer " << this << " finished pass 1.5 of update\n";
|
|
||||||
for (size_t i = 0; i < oldRetainedTiles.Length(); i++) {
|
|
||||||
ss << "oldRetainedTiles[" << i << "] = ";
|
|
||||||
oldRetainedTiles[i].Dump(ss);
|
|
||||||
ss << "\n";
|
|
||||||
}
|
|
||||||
for (size_t i = 0; i < newRetainedTiles.Length(); i++) {
|
|
||||||
ss << "newRetainedTiles[" << i << "] = ";
|
|
||||||
newRetainedTiles[i].Dump(ss);
|
|
||||||
ss << "\n";
|
|
||||||
}
|
|
||||||
print_stderr(ss);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Pass 2: Validate
|
|
||||||
// We know at this point that any tile in the new buffer that had valid content
|
|
||||||
// from the previous buffer is placed correctly in the new buffer.
|
|
||||||
// We know that any tile in the old buffer that isn't a place holder is
|
|
||||||
// of no use and can be recycled.
|
|
||||||
// We also know that any place holder tile in the new buffer must be
|
|
||||||
// allocated.
|
|
||||||
tileX = 0;
|
|
||||||
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
|
|
||||||
printf_stderr("Update %i, %i, %i, %i\n", newBound.x, newBound.y, newBound.width, newBound.height);
|
|
||||||
#endif
|
|
||||||
for (int x = newBound.x; x < newBound.x + newBound.width; tileX++) {
|
|
||||||
// Compute tileRect(x,y,width,height) in layer space coordinate
|
|
||||||
// giving us the rect of the tile that hits the newBounds.
|
|
||||||
int tileStartX = RoundDownToTileEdge(x, scaledTileSize.width);
|
|
||||||
int width = scaledTileSize.width - GetTileStart(x, scaledTileSize.width);
|
|
||||||
if (x + width > newBound.XMost())
|
|
||||||
width = newBound.XMost() - x;
|
|
||||||
|
|
||||||
tileY = 0;
|
|
||||||
for (int y = newBound.y; y < newBound.y + newBound.height; tileY++) {
|
|
||||||
int tileStartY = RoundDownToTileEdge(y, scaledTileSize.height);
|
|
||||||
int height = scaledTileSize.height - GetTileStart(y, scaledTileSize.height);
|
|
||||||
if (y + height > newBound.YMost()) {
|
|
||||||
height = newBound.YMost() - y;
|
|
||||||
}
|
|
||||||
|
|
||||||
const gfx::IntRect tileRect(x, y, width, height);
|
|
||||||
|
|
||||||
nsIntRegion tileDrawRegion;
|
|
||||||
tileDrawRegion.And(tileRect, regionToPaint);
|
|
||||||
|
|
||||||
if (tileDrawRegion.IsEmpty()) {
|
|
||||||
// We have a tile but it doesn't hit the draw region
|
|
||||||
// because we can reuse all of the content from the
|
|
||||||
// previous buffer.
|
|
||||||
#ifdef DEBUG
|
|
||||||
int currTileX = floor_div(x - newBufferOrigin.x, scaledTileSize.width);
|
|
||||||
int currTileY = floor_div(y - newBufferOrigin.y, scaledTileSize.height);
|
|
||||||
int index = TileIndex(currTileX, currTileY);
|
|
||||||
// If allocating a tile failed we can run into this assertion.
|
|
||||||
// Rendering is going to be glitchy but we don't want to crash.
|
|
||||||
NS_ASSERTION(!newValidRegion.Intersects(tileRect) ||
|
|
||||||
!newRetainedTiles.
|
|
||||||
SafeElementAt(index, AsDerived().GetPlaceholderTile()).IsPlaceholderTile(),
|
|
||||||
"Unexpected placeholder tile");
|
|
||||||
|
|
||||||
#endif
|
|
||||||
y += height;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
int tileX = floor_div(x - newBufferOrigin.x, scaledTileSize.width);
|
|
||||||
int tileY = floor_div(y - newBufferOrigin.y, scaledTileSize.height);
|
|
||||||
int index = TileIndex(tileX, tileY);
|
|
||||||
MOZ_ASSERT(index >= 0 &&
|
|
||||||
static_cast<unsigned>(index) < newRetainedTiles.Length(),
|
|
||||||
"index out of range");
|
|
||||||
|
|
||||||
Tile newTile = newRetainedTiles[index];
|
|
||||||
|
|
||||||
// Try to reuse a tile from the old retained tiles that had no partially
|
|
||||||
// valid content.
|
|
||||||
while (newTile.IsPlaceholderTile() && oldRetainedTiles.Length() > 0) {
|
|
||||||
AsDerived().SwapTiles(newTile, oldRetainedTiles[oldRetainedTiles.Length()-1]);
|
|
||||||
oldRetainedTiles.RemoveElementAt(oldRetainedTiles.Length()-1);
|
|
||||||
if (!newTile.IsPlaceholderTile()) {
|
|
||||||
oldTileCount--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We've done our best effort to recycle a tile but it can be null
|
|
||||||
// in which case it's up to the derived class's ValidateTile()
|
|
||||||
// implementation to allocate a new tile before drawing
|
|
||||||
nsIntPoint tileOrigin(tileStartX, tileStartY);
|
|
||||||
newTile = AsDerived().ValidateTile(newTile, nsIntPoint(tileStartX, tileStartY),
|
|
||||||
tileDrawRegion);
|
|
||||||
NS_ASSERTION(!newTile.IsPlaceholderTile(), "Unexpected placeholder tile - failed to allocate?");
|
|
||||||
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
|
|
||||||
printf_stderr("Store Validate tile %i, %i -> %i\n", tileStartX, tileStartY, index);
|
|
||||||
#endif
|
|
||||||
newRetainedTiles[index] = newTile;
|
|
||||||
|
|
||||||
y += height;
|
|
||||||
}
|
|
||||||
|
|
||||||
x += width;
|
|
||||||
}
|
|
||||||
|
|
||||||
AsDerived().PostValidate(aPaintRegion);
|
|
||||||
for (unsigned int i = 0; i < newRetainedTiles.Length(); ++i) {
|
|
||||||
AsDerived().UnlockTile(newRetainedTiles[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef GFX_TILEDLAYER_RETAINING_LOG
|
|
||||||
{ // scope ss
|
|
||||||
std::stringstream ss;
|
|
||||||
ss << "TiledLayerBuffer " << this << " finished pass 2 of update;"
|
|
||||||
<< " oldTileCount=" << oldTileCount << "\n";
|
|
||||||
for (size_t i = 0; i < oldRetainedTiles.Length(); i++) {
|
|
||||||
ss << "oldRetainedTiles[" << i << "] = ";
|
|
||||||
oldRetainedTiles[i].Dump(ss);
|
|
||||||
ss << "\n";
|
|
||||||
}
|
|
||||||
for (size_t i = 0; i < newRetainedTiles.Length(); i++) {
|
|
||||||
ss << "newRetainedTiles[" << i << "] = ";
|
|
||||||
newRetainedTiles[i].Dump(ss);
|
|
||||||
ss << "\n";
|
|
||||||
}
|
|
||||||
print_stderr(ss);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// At this point, oldTileCount should be zero
|
|
||||||
MOZ_ASSERT(oldTileCount == 0, "Failed to release old tiles");
|
|
||||||
|
|
||||||
mRetainedTiles = newRetainedTiles;
|
|
||||||
mValidRegion = newValidRegion;
|
|
||||||
|
|
||||||
mTiles.mFirst.x = floor_div(mValidRegion.GetBounds().x, scaledTileSize.width);
|
|
||||||
mTiles.mFirst.y = floor_div(mValidRegion.GetBounds().y, scaledTileSize.height);
|
|
||||||
|
|
||||||
mPaintedRegion.Or(mPaintedRegion, aPaintRegion);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // layers
|
} // layers
|
||||||
|
@ -1100,6 +1100,71 @@ ClientTiledLayerBuffer::UnlockTile(TileClient aTile)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ClientTiledLayerBuffer::Update(const nsIntRegion& newValidRegion,
|
||||||
|
const nsIntRegion& aPaintRegion)
|
||||||
|
{
|
||||||
|
const IntSize scaledTileSize = GetScaledTileSize();
|
||||||
|
const gfx::IntRect newBounds = newValidRegion.GetBounds();
|
||||||
|
|
||||||
|
const TilesPlacement oldTiles = mTiles;
|
||||||
|
const TilesPlacement newTiles(floor_div(newBounds.x, scaledTileSize.width),
|
||||||
|
floor_div(newBounds.y, scaledTileSize.height),
|
||||||
|
floor_div(GetTileStart(newBounds.x, scaledTileSize.width)
|
||||||
|
+ newBounds.width, scaledTileSize.width) + 1,
|
||||||
|
floor_div(GetTileStart(newBounds.y, scaledTileSize.height)
|
||||||
|
+ newBounds.height, scaledTileSize.height) + 1);
|
||||||
|
|
||||||
|
const size_t oldTileCount = mRetainedTiles.Length();
|
||||||
|
const size_t newTileCount = newTiles.mSize.width * newTiles.mSize.height;
|
||||||
|
|
||||||
|
nsTArray<TileClient> oldRetainedTiles;
|
||||||
|
mRetainedTiles.SwapElements(oldRetainedTiles);
|
||||||
|
mRetainedTiles.SetLength(newTileCount);
|
||||||
|
|
||||||
|
for (size_t oldIndex = 0; oldIndex < oldTileCount; oldIndex++) {
|
||||||
|
const TileIntPoint tilePosition = oldTiles.TilePosition(oldIndex);
|
||||||
|
const size_t newIndex = newTiles.TileIndex(tilePosition);
|
||||||
|
// First, get the already existing tiles to the right place in the new array.
|
||||||
|
// Leave placeholders (default constructor) where there was no tile.
|
||||||
|
if (newTiles.HasTile(tilePosition)) {
|
||||||
|
mRetainedTiles[newIndex] = oldRetainedTiles[oldIndex];
|
||||||
|
} else {
|
||||||
|
// release tiles that we are not going to reuse before allocating new ones
|
||||||
|
// to avoid allocating unnecessarily.
|
||||||
|
oldRetainedTiles[oldIndex].Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
oldRetainedTiles.Clear();
|
||||||
|
|
||||||
|
for (size_t i = 0; i < newTileCount; ++i) {
|
||||||
|
const TileIntPoint tilePosition = newTiles.TilePosition(i);
|
||||||
|
|
||||||
|
IntPoint tileOffset = GetTileOffset(tilePosition);
|
||||||
|
nsIntRegion tileDrawRegion = IntRect(tileOffset, scaledTileSize);
|
||||||
|
tileDrawRegion.AndWith(aPaintRegion);
|
||||||
|
|
||||||
|
if (tileDrawRegion.IsEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
TileClient tile = mRetainedTiles[i];
|
||||||
|
tile = ValidateTile(tile, GetTileOffset(tilePosition),
|
||||||
|
tileDrawRegion);
|
||||||
|
|
||||||
|
mRetainedTiles[i] = tile;
|
||||||
|
}
|
||||||
|
|
||||||
|
PostValidate(aPaintRegion);
|
||||||
|
for (size_t i = 0; i < mRetainedTiles.Length(); ++i) {
|
||||||
|
UnlockTile(mRetainedTiles[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
mTiles = newTiles;
|
||||||
|
mValidRegion = newValidRegion;
|
||||||
|
mPaintedRegion.OrWith(aPaintRegion);
|
||||||
|
}
|
||||||
|
|
||||||
TileClient
|
TileClient
|
||||||
ClientTiledLayerBuffer::ValidateTile(TileClient aTile,
|
ClientTiledLayerBuffer::ValidateTile(TileClient aTile,
|
||||||
const nsIntPoint& aTileOrigin,
|
const nsIntPoint& aTileOrigin,
|
||||||
|
@ -419,6 +419,8 @@ public:
|
|||||||
LayerManager::DrawPaintedLayerCallback aCallback,
|
LayerManager::DrawPaintedLayerCallback aCallback,
|
||||||
void* aCallbackData);
|
void* aCallbackData);
|
||||||
|
|
||||||
|
void Update(const nsIntRegion& aNewValidRegion, const nsIntRegion& aPaintRegion);
|
||||||
|
|
||||||
void ReadLock();
|
void ReadLock();
|
||||||
|
|
||||||
void Release();
|
void Release();
|
||||||
@ -453,6 +455,19 @@ public:
|
|||||||
mResolution = aResolution;
|
mResolution = aResolution;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ResetPaintedAndValidState() {
|
||||||
|
mPaintedRegion.SetEmpty();
|
||||||
|
mValidRegion.SetEmpty();
|
||||||
|
mTiles.mSize.width = 0;
|
||||||
|
mTiles.mSize.height = 0;
|
||||||
|
for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
|
||||||
|
if (!mRetainedTiles[i].IsPlaceholderTile()) {
|
||||||
|
mRetainedTiles[i].Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mRetainedTiles.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
TileClient ValidateTile(TileClient aTile,
|
TileClient ValidateTile(TileClient aTile,
|
||||||
const nsIntPoint& aTileRect,
|
const nsIntPoint& aTileRect,
|
||||||
@ -462,10 +477,6 @@ protected:
|
|||||||
|
|
||||||
void UnlockTile(TileClient aTile);
|
void UnlockTile(TileClient aTile);
|
||||||
|
|
||||||
void ReleaseTile(TileClient aTile) { aTile.Release(); }
|
|
||||||
|
|
||||||
void SwapTiles(TileClient& aTileA, TileClient& aTileB) { std::swap(aTileA, aTileB); }
|
|
||||||
|
|
||||||
TileClient GetPlaceholderTile() const { return TileClient(); }
|
TileClient GetPlaceholderTile() const { return TileClient(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -39,7 +39,7 @@ namespace layers {
|
|||||||
class Layer;
|
class Layer;
|
||||||
class Compositor;
|
class Compositor;
|
||||||
class ThebesBufferData;
|
class ThebesBufferData;
|
||||||
class TiledLayerComposer;
|
class TiledContentHost;
|
||||||
class CompositableParentManager;
|
class CompositableParentManager;
|
||||||
class PCompositableParent;
|
class PCompositableParent;
|
||||||
struct EffectChain;
|
struct EffectChain;
|
||||||
@ -132,7 +132,7 @@ public:
|
|||||||
Layer* GetLayer() const { return mLayer; }
|
Layer* GetLayer() const { return mLayer; }
|
||||||
void SetLayer(Layer* aLayer) { mLayer = aLayer; }
|
void SetLayer(Layer* aLayer) { mLayer = aLayer; }
|
||||||
|
|
||||||
virtual TiledLayerComposer* AsTiledLayerComposer() { return nullptr; }
|
virtual TiledContentHost* AsTiledContentHost() { return nullptr; }
|
||||||
|
|
||||||
typedef uint32_t AttachFlags;
|
typedef uint32_t AttachFlags;
|
||||||
static const AttachFlags NO_FLAGS = 0;
|
static const AttachFlags NO_FLAGS = 0;
|
||||||
|
@ -40,7 +40,6 @@ class Matrix4x4;
|
|||||||
namespace layers {
|
namespace layers {
|
||||||
class Compositor;
|
class Compositor;
|
||||||
class ThebesBufferData;
|
class ThebesBufferData;
|
||||||
class TiledLayerComposer;
|
|
||||||
struct EffectChain;
|
struct EffectChain;
|
||||||
|
|
||||||
struct TexturedEffect;
|
struct TexturedEffect;
|
||||||
@ -54,10 +53,6 @@ struct TexturedEffect;
|
|||||||
class ContentHost : public CompositableHost
|
class ContentHost : public CompositableHost
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// Subclasses should implement this method if they support being used as a
|
|
||||||
// tiling.
|
|
||||||
virtual TiledLayerComposer* AsTiledLayerComposer() { return nullptr; }
|
|
||||||
|
|
||||||
virtual bool UpdateThebes(const ThebesBufferData& aData,
|
virtual bool UpdateThebes(const ThebesBufferData& aData,
|
||||||
const nsIntRegion& aUpdated,
|
const nsIntRegion& aUpdated,
|
||||||
const nsIntRegion& aOldValidRegionBack,
|
const nsIntRegion& aOldValidRegionBack,
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
#include "LayerScope.h" // for LayerScope Tool
|
#include "LayerScope.h" // for LayerScope Tool
|
||||||
#include "protobuf/LayerScopePacket.pb.h" // for protobuf (LayerScope)
|
#include "protobuf/LayerScopePacket.pb.h" // for protobuf (LayerScope)
|
||||||
#include "PaintedLayerComposite.h" // for PaintedLayerComposite
|
#include "PaintedLayerComposite.h" // for PaintedLayerComposite
|
||||||
#include "TiledLayerBuffer.h" // for TiledLayerComposer
|
#include "TiledContentHost.h"
|
||||||
#include "Units.h" // for ScreenIntRect
|
#include "Units.h" // for ScreenIntRect
|
||||||
#include "UnitTransforms.h" // for ViewAs
|
#include "UnitTransforms.h" // for ViewAs
|
||||||
#include "gfx2DGlue.h" // for ToMatrix4x4
|
#include "gfx2DGlue.h" // for ToMatrix4x4
|
||||||
@ -1016,10 +1016,10 @@ LayerManagerComposite::ComputeRenderIntegrityInternal(Layer* aLayer,
|
|||||||
SubtractTransformedRegion(aScreenRegion, incompleteRegion, transformToScreen);
|
SubtractTransformedRegion(aScreenRegion, incompleteRegion, transformToScreen);
|
||||||
|
|
||||||
// See if there's any incomplete low-precision rendering
|
// See if there's any incomplete low-precision rendering
|
||||||
TiledLayerComposer* composer = nullptr;
|
TiledContentHost* composer = nullptr;
|
||||||
LayerComposite* shadow = aLayer->AsLayerComposite();
|
LayerComposite* shadow = aLayer->AsLayerComposite();
|
||||||
if (shadow) {
|
if (shadow) {
|
||||||
composer = shadow->GetTiledLayerComposer();
|
composer = shadow->GetCompositableHost()->AsTiledContentHost();
|
||||||
if (composer) {
|
if (composer) {
|
||||||
incompleteRegion.Sub(incompleteRegion, composer->GetValidLowPrecisionRegion());
|
incompleteRegion.Sub(incompleteRegion, composer->GetValidLowPrecisionRegion());
|
||||||
if (!incompleteRegion.IsEmpty()) {
|
if (!incompleteRegion.IsEmpty()) {
|
||||||
@ -1338,7 +1338,8 @@ LayerManagerComposite::AsyncPanZoomEnabled() const
|
|||||||
|
|
||||||
nsIntRegion
|
nsIntRegion
|
||||||
LayerComposite::GetFullyRenderedRegion() {
|
LayerComposite::GetFullyRenderedRegion() {
|
||||||
if (TiledLayerComposer* tiled = GetTiledLayerComposer()) {
|
if (TiledContentHost* tiled = GetCompositableHost() ? GetCompositableHost()->AsTiledContentHost()
|
||||||
|
: nullptr) {
|
||||||
nsIntRegion shadowVisibleRegion = GetShadowVisibleRegion();
|
nsIntRegion shadowVisibleRegion = GetShadowVisibleRegion();
|
||||||
// Discard the region which hasn't been drawn yet when doing
|
// Discard the region which hasn't been drawn yet when doing
|
||||||
// progressive drawing. Note that if the shadow visible region
|
// progressive drawing. Note that if the shadow visible region
|
||||||
|
@ -56,7 +56,6 @@ class ImageLayerComposite;
|
|||||||
class LayerComposite;
|
class LayerComposite;
|
||||||
class RefLayerComposite;
|
class RefLayerComposite;
|
||||||
class PaintedLayerComposite;
|
class PaintedLayerComposite;
|
||||||
class TiledLayerComposer;
|
|
||||||
class TextRenderer;
|
class TextRenderer;
|
||||||
class CompositingRenderTarget;
|
class CompositingRenderTarget;
|
||||||
struct FPSState;
|
struct FPSState;
|
||||||
@ -379,8 +378,6 @@ public:
|
|||||||
|
|
||||||
virtual void CleanupResources() = 0;
|
virtual void CleanupResources() = 0;
|
||||||
|
|
||||||
virtual TiledLayerComposer* GetTiledLayerComposer() { return nullptr; }
|
|
||||||
|
|
||||||
virtual void DestroyFrontBuffer() { }
|
virtual void DestroyFrontBuffer() { }
|
||||||
|
|
||||||
void AddBlendModeEffect(EffectChain& aEffectChain);
|
void AddBlendModeEffect(EffectChain& aEffectChain);
|
||||||
|
@ -29,8 +29,6 @@
|
|||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace layers {
|
namespace layers {
|
||||||
|
|
||||||
class TiledLayerComposer;
|
|
||||||
|
|
||||||
PaintedLayerComposite::PaintedLayerComposite(LayerManagerComposite *aManager)
|
PaintedLayerComposite::PaintedLayerComposite(LayerManagerComposite *aManager)
|
||||||
: PaintedLayer(aManager, nullptr)
|
: PaintedLayer(aManager, nullptr)
|
||||||
, LayerComposite(aManager)
|
, LayerComposite(aManager)
|
||||||
@ -91,16 +89,6 @@ PaintedLayerComposite::SetLayerManager(LayerManagerComposite* aManager)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TiledLayerComposer*
|
|
||||||
PaintedLayerComposite::GetTiledLayerComposer()
|
|
||||||
{
|
|
||||||
if (!mBuffer) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
MOZ_ASSERT(mBuffer->IsAttached());
|
|
||||||
return mBuffer->AsTiledLayerComposer();
|
|
||||||
}
|
|
||||||
|
|
||||||
LayerRenderState
|
LayerRenderState
|
||||||
PaintedLayerComposite::GetRenderState()
|
PaintedLayerComposite::GetRenderState()
|
||||||
{
|
{
|
||||||
|
@ -28,7 +28,6 @@ namespace layers {
|
|||||||
|
|
||||||
class CompositableHost;
|
class CompositableHost;
|
||||||
class ContentHost;
|
class ContentHost;
|
||||||
class TiledLayerComposer;
|
|
||||||
|
|
||||||
class PaintedLayerComposite : public PaintedLayer,
|
class PaintedLayerComposite : public PaintedLayer,
|
||||||
public LayerComposite
|
public LayerComposite
|
||||||
@ -52,8 +51,6 @@ public:
|
|||||||
|
|
||||||
virtual void SetLayerManager(LayerManagerComposite* aManager) override;
|
virtual void SetLayerManager(LayerManagerComposite* aManager) override;
|
||||||
|
|
||||||
virtual TiledLayerComposer* GetTiledLayerComposer() override;
|
|
||||||
|
|
||||||
virtual void RenderLayer(const gfx::IntRect& aClipRect) override;
|
virtual void RenderLayer(const gfx::IntRect& aClipRect) override;
|
||||||
|
|
||||||
virtual void CleanupResources() override;
|
virtual void CleanupResources() override;
|
||||||
|
@ -498,9 +498,9 @@ TiledContentHost::RenderLayerBuffer(TiledLayerBufferComposite& aLayerBuffer,
|
|||||||
float resolution = aLayerBuffer.GetResolution();
|
float resolution = aLayerBuffer.GetResolution();
|
||||||
gfx::Size layerScale(1, 1);
|
gfx::Size layerScale(1, 1);
|
||||||
|
|
||||||
// Make sure we don't render at low resolution where we have valid high
|
// We assume that the current frame resolution is the one used in our high
|
||||||
// resolution content, to avoid overdraw and artifacts with semi-transparent
|
// precision layer buffer. Compensate for a changing frame resolution when
|
||||||
// layers.
|
// rendering the low precision buffer.
|
||||||
if (aLayerBuffer.GetFrameResolution() != mTiledBuffer.GetFrameResolution()) {
|
if (aLayerBuffer.GetFrameResolution() != mTiledBuffer.GetFrameResolution()) {
|
||||||
const CSSToParentLayerScale2D& layerResolution = aLayerBuffer.GetFrameResolution();
|
const CSSToParentLayerScale2D& layerResolution = aLayerBuffer.GetFrameResolution();
|
||||||
const CSSToParentLayerScale2D& localResolution = mTiledBuffer.GetFrameResolution();
|
const CSSToParentLayerScale2D& localResolution = mTiledBuffer.GetFrameResolution();
|
||||||
@ -509,9 +509,9 @@ TiledContentHost::RenderLayerBuffer(TiledLayerBufferComposite& aLayerBuffer,
|
|||||||
aVisibleRegion.ScaleRoundOut(layerScale.width, layerScale.height);
|
aVisibleRegion.ScaleRoundOut(layerScale.width, layerScale.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we're drawing the low precision buffer, make sure the high precision
|
// Make sure we don't render at low resolution where we have valid high
|
||||||
// buffer is masked out to avoid overdraw and rendering artifacts with
|
// resolution content, to avoid overdraw and artifacts with semi-transparent
|
||||||
// non-opaque layers.
|
// layers.
|
||||||
nsIntRegion maskRegion;
|
nsIntRegion maskRegion;
|
||||||
if (resolution != mTiledBuffer.GetResolution()) {
|
if (resolution != mTiledBuffer.GetResolution()) {
|
||||||
maskRegion = mTiledBuffer.GetValidRegion();
|
maskRegion = mTiledBuffer.GetValidRegion();
|
||||||
|
@ -167,8 +167,6 @@ public:
|
|||||||
static void RecycleCallback(TextureHost* textureHost, void* aClosure);
|
static void RecycleCallback(TextureHost* textureHost, void* aClosure);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void SwapTiles(TileHost& aTileA, TileHost& aTileB) { std::swap(aTileA, aTileB); }
|
|
||||||
|
|
||||||
CSSToParentLayerScale2D mFrameResolution;
|
CSSToParentLayerScale2D mFrameResolution;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -192,8 +190,7 @@ protected:
|
|||||||
* buffer after compositing a new one. Rendering takes us to RenderTile which
|
* buffer after compositing a new one. Rendering takes us to RenderTile which
|
||||||
* is similar to Composite for non-tiled ContentHosts.
|
* is similar to Composite for non-tiled ContentHosts.
|
||||||
*/
|
*/
|
||||||
class TiledContentHost : public ContentHost,
|
class TiledContentHost : public ContentHost
|
||||||
public TiledLayerComposer
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit TiledContentHost(const TextureInfo& aTextureInfo);
|
explicit TiledContentHost(const TextureInfo& aTextureInfo);
|
||||||
@ -217,12 +214,12 @@ public:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const nsIntRegion& GetValidLowPrecisionRegion() const override
|
const nsIntRegion& GetValidLowPrecisionRegion() const
|
||||||
{
|
{
|
||||||
return mLowPrecisionTiledBuffer.GetValidRegion();
|
return mLowPrecisionTiledBuffer.GetValidRegion();
|
||||||
}
|
}
|
||||||
|
|
||||||
const nsIntRegion& GetValidRegion() const override
|
const nsIntRegion& GetValidRegion() const
|
||||||
{
|
{
|
||||||
return mTiledBuffer.GetValidRegion();
|
return mTiledBuffer.GetValidRegion();
|
||||||
}
|
}
|
||||||
@ -235,8 +232,8 @@ public:
|
|||||||
mLowPrecisionTiledBuffer.SetCompositor(aCompositor);
|
mLowPrecisionTiledBuffer.SetCompositor(aCompositor);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool UseTiledLayerBuffer(ISurfaceAllocator* aAllocator,
|
bool UseTiledLayerBuffer(ISurfaceAllocator* aAllocator,
|
||||||
const SurfaceDescriptorTiles& aTiledDescriptor) override;
|
const SurfaceDescriptorTiles& aTiledDescriptor);
|
||||||
|
|
||||||
void Composite(EffectChain& aEffectChain,
|
void Composite(EffectChain& aEffectChain,
|
||||||
float aOpacity,
|
float aOpacity,
|
||||||
@ -247,7 +244,7 @@ public:
|
|||||||
|
|
||||||
virtual CompositableType GetType() override { return CompositableType::CONTENT_TILED; }
|
virtual CompositableType GetType() override { return CompositableType::CONTENT_TILED; }
|
||||||
|
|
||||||
virtual TiledLayerComposer* AsTiledLayerComposer() override { return this; }
|
virtual TiledContentHost* AsTiledContentHost() override { return this; }
|
||||||
|
|
||||||
virtual void Attach(Layer* aLayer,
|
virtual void Attach(Layer* aLayer,
|
||||||
Compositor* aCompositor,
|
Compositor* aCompositor,
|
||||||
|
@ -11,7 +11,6 @@
|
|||||||
#include "GLContext.h" // for GLContext
|
#include "GLContext.h" // for GLContext
|
||||||
#include "Layers.h" // for Layer
|
#include "Layers.h" // for Layer
|
||||||
#include "RenderTrace.h" // for RenderTraceInvalidateEnd, etc
|
#include "RenderTrace.h" // for RenderTraceInvalidateEnd, etc
|
||||||
#include "TiledLayerBuffer.h" // for TiledLayerComposer
|
|
||||||
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
|
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
|
||||||
#include "mozilla/RefPtr.h" // for RefPtr
|
#include "mozilla/RefPtr.h" // for RefPtr
|
||||||
#include "mozilla/layers/CompositorTypes.h"
|
#include "mozilla/layers/CompositorTypes.h"
|
||||||
@ -23,6 +22,7 @@
|
|||||||
#include "mozilla/layers/LayersTypes.h" // for MOZ_LAYERS_LOG
|
#include "mozilla/layers/LayersTypes.h" // for MOZ_LAYERS_LOG
|
||||||
#include "mozilla/layers/TextureHost.h" // for TextureHost
|
#include "mozilla/layers/TextureHost.h" // for TextureHost
|
||||||
#include "mozilla/layers/TextureHostOGL.h" // for TextureHostOGL
|
#include "mozilla/layers/TextureHostOGL.h" // for TextureHostOGL
|
||||||
|
#include "mozilla/layers/TiledContentHost.h"
|
||||||
#include "mozilla/layers/PaintedLayerComposite.h"
|
#include "mozilla/layers/PaintedLayerComposite.h"
|
||||||
#include "mozilla/mozalloc.h" // for operator delete
|
#include "mozilla/mozalloc.h" // for operator delete
|
||||||
#include "mozilla/unused.h"
|
#include "mozilla/unused.h"
|
||||||
@ -112,13 +112,12 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation
|
|||||||
case CompositableOperation::TOpUseTiledLayerBuffer: {
|
case CompositableOperation::TOpUseTiledLayerBuffer: {
|
||||||
MOZ_LAYERS_LOG(("[ParentSide] Paint TiledLayerBuffer"));
|
MOZ_LAYERS_LOG(("[ParentSide] Paint TiledLayerBuffer"));
|
||||||
const OpUseTiledLayerBuffer& op = aEdit.get_OpUseTiledLayerBuffer();
|
const OpUseTiledLayerBuffer& op = aEdit.get_OpUseTiledLayerBuffer();
|
||||||
CompositableHost* compositable = AsCompositable(op);
|
TiledContentHost* compositable = AsCompositable(op)->AsTiledContentHost();
|
||||||
|
|
||||||
TiledLayerComposer* tileComposer = compositable->AsTiledLayerComposer();
|
NS_ASSERTION(compositable, "The compositable is not tiled");
|
||||||
NS_ASSERTION(tileComposer, "compositable is not a tile composer");
|
|
||||||
|
|
||||||
const SurfaceDescriptorTiles& tileDesc = op.tileLayerDescriptor();
|
const SurfaceDescriptorTiles& tileDesc = op.tileLayerDescriptor();
|
||||||
bool success = tileComposer->UseTiledLayerBuffer(this, tileDesc);
|
bool success = compositable->UseTiledLayerBuffer(this, tileDesc);
|
||||||
if (!success) {
|
if (!success) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -131,6 +131,7 @@ EXPORTS.mozilla.layers += [
|
|||||||
'composite/LayerManagerComposite.h',
|
'composite/LayerManagerComposite.h',
|
||||||
'composite/PaintedLayerComposite.h',
|
'composite/PaintedLayerComposite.h',
|
||||||
'composite/TextureHost.h',
|
'composite/TextureHost.h',
|
||||||
|
'composite/TiledContentHost.h',
|
||||||
'Compositor.h',
|
'Compositor.h',
|
||||||
'CompositorTypes.h',
|
'CompositorTypes.h',
|
||||||
'D3D11ShareHandleImage.h',
|
'D3D11ShareHandleImage.h',
|
||||||
|
@ -41,7 +41,6 @@
|
|||||||
#include "ScopedGLHelpers.h"
|
#include "ScopedGLHelpers.h"
|
||||||
#include "GLReadTexImageHelper.h"
|
#include "GLReadTexImageHelper.h"
|
||||||
#include "GLBlitTextureImageHelper.h"
|
#include "GLBlitTextureImageHelper.h"
|
||||||
#include "TiledLayerBuffer.h" // for TiledLayerComposer
|
|
||||||
#include "HeapCopyOfStackArray.h"
|
#include "HeapCopyOfStackArray.h"
|
||||||
|
|
||||||
#if MOZ_WIDGET_ANDROID
|
#if MOZ_WIDGET_ANDROID
|
||||||
|
@ -10,81 +10,56 @@
|
|||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace layers {
|
namespace layers {
|
||||||
|
|
||||||
struct TestTiledLayerTile {
|
|
||||||
int value;
|
|
||||||
explicit TestTiledLayerTile(int v = 0) {
|
|
||||||
value = v;
|
|
||||||
}
|
|
||||||
bool operator== (const TestTiledLayerTile& o) const {
|
|
||||||
return value == o.value;
|
|
||||||
}
|
|
||||||
bool operator!= (const TestTiledLayerTile& o) const {
|
|
||||||
return value != o.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsPlaceholderTile() const {
|
|
||||||
return value == -1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class TestTiledLayerBuffer : public TiledLayerBuffer<TestTiledLayerBuffer, TestTiledLayerTile>
|
|
||||||
{
|
|
||||||
friend class TiledLayerBuffer<TestTiledLayerBuffer, TestTiledLayerTile>;
|
|
||||||
|
|
||||||
public:
|
|
||||||
TestTiledLayerTile GetPlaceholderTile() const {
|
|
||||||
return TestTiledLayerTile(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
TestTiledLayerTile ValidateTile(TestTiledLayerTile aTile, const nsIntPoint& aTileOrigin, const nsIntRegion& aDirtyRect) {
|
|
||||||
return TestTiledLayerTile();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ReleaseTile(TestTiledLayerTile aTile)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void SwapTiles(TestTiledLayerTile& aTileA, TestTiledLayerTile& aTileB)
|
|
||||||
{
|
|
||||||
TestTiledLayerTile oldTileA = aTileA;
|
|
||||||
aTileA = aTileB;
|
|
||||||
aTileB = oldTileA;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TestUpdate(const nsIntRegion& aNewValidRegion, const nsIntRegion& aPaintRegion)
|
|
||||||
{
|
|
||||||
Update(aNewValidRegion, aPaintRegion);
|
|
||||||
}
|
|
||||||
|
|
||||||
void UnlockTile(TestTiledLayerTile aTile) {}
|
|
||||||
void PostValidate(const nsIntRegion& aPaintRegion) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST(TiledLayerBuffer, TileConstructor) {
|
|
||||||
gfxPlatform::GetPlatform()->ComputeTileSize();
|
|
||||||
|
|
||||||
TestTiledLayerBuffer buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(TiledLayerBuffer, TileStart) {
|
TEST(TiledLayerBuffer, TileStart) {
|
||||||
gfxPlatform::GetPlatform()->ComputeTileSize();
|
gfxPlatform::GetPlatform()->ComputeTileSize();
|
||||||
|
|
||||||
TestTiledLayerBuffer buffer;
|
ASSERT_EQ(RoundDownToTileEdge(10, 256), 0);
|
||||||
|
ASSERT_EQ(RoundDownToTileEdge(-10, 256), -256);
|
||||||
ASSERT_EQ(buffer.RoundDownToTileEdge(10, 256), 0);
|
|
||||||
ASSERT_EQ(buffer.RoundDownToTileEdge(-10, 256), -256);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(TiledLayerBuffer, EmptyUpdate) {
|
TEST(TiledLayerBuffer, TilesPlacement) {
|
||||||
gfxPlatform::GetPlatform()->ComputeTileSize();
|
for (int firstY = -10; firstY < 10; ++firstY) {
|
||||||
|
for (int firstX = -10; firstX < 10; ++firstX) {
|
||||||
|
for (int height = 1; height < 10; ++height) {
|
||||||
|
for (int width = 1; width < 10; ++width) {
|
||||||
|
|
||||||
TestTiledLayerBuffer buffer;
|
const TilesPlacement p1 = TilesPlacement(firstX, firstY, width, height);
|
||||||
|
// Check that HasTile returns false with some positions that we know
|
||||||
|
// not to be in the rectangle of the TilesPlacement.
|
||||||
|
ASSERT_FALSE(p1.HasTile(TileIntPoint(firstX - 1, 0)));
|
||||||
|
ASSERT_FALSE(p1.HasTile(TileIntPoint(0, firstY - 1)));
|
||||||
|
ASSERT_FALSE(p1.HasTile(TileIntPoint(firstX + width + 1, 0)));
|
||||||
|
ASSERT_FALSE(p1.HasTile(TileIntPoint(0, firstY + height + 1)));
|
||||||
|
|
||||||
nsIntRegion validRegion(gfx::IntRect(0, 0, 10, 10));
|
// Verify that all positions within the rect that defines the
|
||||||
buffer.TestUpdate(validRegion, validRegion);
|
// TilesPlacement map to indices between 0 and width*height.
|
||||||
|
for (int y = firstY; y < (firstY+height); ++y) {
|
||||||
|
for (int x = firstX; x < (firstX+width); ++x) {
|
||||||
|
ASSERT_TRUE(p1.HasTile(TileIntPoint(x,y)));
|
||||||
|
ASSERT_TRUE(p1.TileIndex(TileIntPoint(x, y)) >= 0);
|
||||||
|
ASSERT_TRUE(p1.TileIndex(TileIntPoint(x, y)) < width * height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ASSERT_EQ(buffer.GetValidRegion(), validRegion);
|
// XXX - This causes some versions of gcc to warn that it optimizes
|
||||||
|
// away the test, which gets caught in -WError in PGO builds.
|
||||||
|
// The lazy thing to do is to just comment this out since this specific
|
||||||
|
// test isn't critically important, but we should remove the warning instead.
|
||||||
|
// cf. bug 1179287
|
||||||
|
//
|
||||||
|
// Verify that indices map to positions that are within the rect that
|
||||||
|
// defines the TilesPlacement.
|
||||||
|
// for (int i = 0; i < width * height; ++i) {
|
||||||
|
// ASSERT_TRUE(p1.TilePosition(i).x >= firstX);
|
||||||
|
// ASSERT_TRUE(p1.TilePosition(i).x < firstX + width);
|
||||||
|
// ASSERT_TRUE(p1.TilePosition(i).y >= firstY);
|
||||||
|
// ASSERT_TRUE(p1.TilePosition(i).y < firstY + height);
|
||||||
|
// }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,8 @@ UNIFIED_SOURCES += [
|
|||||||
'TestTextures.cpp',
|
'TestTextures.cpp',
|
||||||
# Test works but it doesn't assert anything
|
# Test works but it doesn't assert anything
|
||||||
#'gfxTextRunPerfTest.cpp',
|
#'gfxTextRunPerfTest.cpp',
|
||||||
'TestTiledLayerBuffer.cpp',
|
# Bug 1179287 - PGO bustage on Linux
|
||||||
|
#'TestTiledLayerBuffer.cpp',
|
||||||
'TestVsync.cpp',
|
'TestVsync.cpp',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
8
layout/reftests/bugs/1179078-1-ref.html
Normal file
8
layout/reftests/bugs/1179078-1-ref.html
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<style>
|
||||||
|
p {
|
||||||
|
border: 2px solid transparent;
|
||||||
|
border-image: linear-gradient(to right, orange, blue) 1 1;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<p>This paragraph must have an orange/blue gradient border.</p>
|
9
layout/reftests/bugs/1179078-1.html
Normal file
9
layout/reftests/bugs/1179078-1.html
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<style>
|
||||||
|
p {
|
||||||
|
border: 2px solid transparent;
|
||||||
|
border-image: linear-gradient(to right, orange, blue) 1 1;
|
||||||
|
border-image: linear-gradient(to right, garbage) 1 1;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<p>This paragraph must have an orange/blue gradient border.</p>
|
@ -1927,4 +1927,5 @@ skip-if(B2G||Mulet) == 1150021-1.xul 1150021-1-ref.xul
|
|||||||
== 1155828-1.html 1155828-1-ref.html
|
== 1155828-1.html 1155828-1-ref.html
|
||||||
== 1156129-1.html 1156129-1-ref.html
|
== 1156129-1.html 1156129-1-ref.html
|
||||||
== 1169331-1.html 1169331-1-ref.html
|
== 1169331-1.html 1169331-1-ref.html
|
||||||
|
== 1179078-1.html 1179078-1-ref.html
|
||||||
fuzzy(1,74) == 1174332-1.html 1174332-1-ref.html
|
fuzzy(1,74) == 1174332-1.html 1174332-1-ref.html
|
||||||
|
@ -104,6 +104,7 @@ default-preferences pref(layout.css.variables.enabled,true)
|
|||||||
== variable-reference-37.html variable-reference-37-ref.html
|
== variable-reference-37.html variable-reference-37-ref.html
|
||||||
== variable-reference-38.html variable-reference-38-ref.html
|
== variable-reference-38.html variable-reference-38-ref.html
|
||||||
== variable-reference-39.html support/color-green-ref.html
|
== variable-reference-39.html support/color-green-ref.html
|
||||||
|
== variable-reference-40.html variable-reference-40-ref.html
|
||||||
== variable-supports-01.html support/color-green-ref.html
|
== variable-supports-01.html support/color-green-ref.html
|
||||||
== variable-supports-02.html support/color-green-ref.html
|
== variable-supports-02.html support/color-green-ref.html
|
||||||
== variable-supports-03.html support/color-green-ref.html
|
== variable-supports-03.html support/color-green-ref.html
|
||||||
|
@ -0,0 +1,14 @@
|
|||||||
|
<!--
|
||||||
|
Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/
|
||||||
|
-->
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<title>CSS Reftest Reference</title>
|
||||||
|
<link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au">
|
||||||
|
<style>
|
||||||
|
p {
|
||||||
|
border: 2px solid transparent;
|
||||||
|
border-image: linear-gradient(to right, orange, blue) 1 1;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<p>This paragraph must have an orange/blue gradient border.</p>
|
@ -0,0 +1,17 @@
|
|||||||
|
<!--
|
||||||
|
Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/
|
||||||
|
-->
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<title>CSS Test: Test that a variable reference within a gradient value in a border-image shorthand parses correctly.</title>
|
||||||
|
<link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au">
|
||||||
|
<link rel="help" href="http://www.w3.org/TR/css-variables-1/#using-variables">
|
||||||
|
<link rel="match" href="variable-reference-40-ref.html">
|
||||||
|
<style>
|
||||||
|
p {
|
||||||
|
--orange: orange;
|
||||||
|
border: 2px solid transparent;
|
||||||
|
border-image: linear-gradient(to right, var(--orange), blue) 1 1;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<p>This paragraph must have an orange/blue gradient border.</p>
|
@ -11347,10 +11347,14 @@ CSSParserImpl::ParseBorderImage()
|
|||||||
nsCSSValue imageSourceValue;
|
nsCSSValue imageSourceValue;
|
||||||
while (!CheckEndProperty()) {
|
while (!CheckEndProperty()) {
|
||||||
// <border-image-source>
|
// <border-image-source>
|
||||||
if (!foundSource && ParseVariant(imageSourceValue, VARIANT_IMAGE, nullptr)) {
|
if (!foundSource) {
|
||||||
AppendValue(eCSSProperty_border_image_source, imageSourceValue);
|
nsAutoCSSParserInputStateRestorer stateRestorer(this);
|
||||||
foundSource = true;
|
if (ParseVariant(imageSourceValue, VARIANT_IMAGE, nullptr)) {
|
||||||
continue;
|
AppendValue(eCSSProperty_border_image_source, imageSourceValue);
|
||||||
|
foundSource = true;
|
||||||
|
stateRestorer.DoNotRestore();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// <border-image-slice>
|
// <border-image-slice>
|
||||||
|
@ -286,7 +286,7 @@ nsBaseChannel::ClassifyURI()
|
|||||||
if (mLoadFlags & LOAD_CLASSIFY_URI) {
|
if (mLoadFlags & LOAD_CLASSIFY_URI) {
|
||||||
nsRefPtr<nsChannelClassifier> classifier = new nsChannelClassifier();
|
nsRefPtr<nsChannelClassifier> classifier = new nsChannelClassifier();
|
||||||
if (classifier) {
|
if (classifier) {
|
||||||
classifier->Start(this, false);
|
classifier->Start(this);
|
||||||
} else {
|
} else {
|
||||||
Cancel(NS_ERROR_OUT_OF_MEMORY);
|
Cancel(NS_ERROR_OUT_OF_MEMORY);
|
||||||
}
|
}
|
||||||
|
@ -237,12 +237,9 @@ nsChannelClassifier::NotifyTrackingProtectionDisabled(nsIChannel *aChannel)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
nsChannelClassifier::Start(nsIChannel *aChannel, bool aContinueBeginConnect)
|
nsChannelClassifier::Start(nsIChannel *aChannel)
|
||||||
{
|
{
|
||||||
mChannel = aChannel;
|
mChannel = aChannel;
|
||||||
if (aContinueBeginConnect) {
|
|
||||||
mChannelInternal = do_QueryInterface(aChannel);
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult rv = StartInternal();
|
nsresult rv = StartInternal();
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
@ -530,13 +527,7 @@ nsChannelClassifier::OnClassifyComplete(nsresult aErrorCode)
|
|||||||
mChannel->Resume();
|
mChannel->Resume();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Even if we have cancelled the channel, we may need to call
|
|
||||||
// ContinueBeginConnect so that we abort appropriately.
|
|
||||||
if (mChannelInternal) {
|
|
||||||
mChannelInternal->ContinueBeginConnect();
|
|
||||||
}
|
|
||||||
mChannel = nullptr;
|
mChannel = nullptr;
|
||||||
mChannelInternal = nullptr;
|
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
@ -21,10 +21,8 @@ public:
|
|||||||
NS_DECL_NSIURICLASSIFIERCALLBACK
|
NS_DECL_NSIURICLASSIFIERCALLBACK
|
||||||
|
|
||||||
// Calls nsIURIClassifier.Classify with the principal of the given channel,
|
// Calls nsIURIClassifier.Classify with the principal of the given channel,
|
||||||
// and cancels the channel on a bad verdict. If callContinueBeginConnect is true,
|
// and cancels the channel on a bad verdict.
|
||||||
// and aChannel is an nsIHttpChannelInternal, nsChannelClassifier must call
|
void Start(nsIChannel *aChannel);
|
||||||
// nsIHttpChannelInternal.ContinueBeginConnect once Start has returned.
|
|
||||||
void Start(nsIChannel *aChannel, bool aContinueBeginConnect);
|
|
||||||
// Whether or not tracking protection should be enabled on this channel.
|
// Whether or not tracking protection should be enabled on this channel.
|
||||||
nsresult ShouldEnableTrackingProtection(nsIChannel *aChannel, bool *result);
|
nsresult ShouldEnableTrackingProtection(nsIChannel *aChannel, bool *result);
|
||||||
|
|
||||||
@ -34,7 +32,6 @@ private:
|
|||||||
// True if the channel has been suspended.
|
// True if the channel has been suspended.
|
||||||
bool mSuspendedChannel;
|
bool mSuspendedChannel;
|
||||||
nsCOMPtr<nsIChannel> mChannel;
|
nsCOMPtr<nsIChannel> mChannel;
|
||||||
nsCOMPtr<nsIHttpChannelInternal> mChannelInternal;
|
|
||||||
|
|
||||||
~nsChannelClassifier() {}
|
~nsChannelClassifier() {}
|
||||||
// Caches good classifications for the channel principal.
|
// Caches good classifications for the channel principal.
|
||||||
|
@ -1535,15 +1535,6 @@ HttpBaseChannel::RedirectTo(nsIURI *newURI)
|
|||||||
// HttpBaseChannel::nsIHttpChannelInternal
|
// HttpBaseChannel::nsIHttpChannelInternal
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
HttpBaseChannel::ContinueBeginConnect()
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(XRE_GetProcessType() != GeckoProcessType_Default,
|
|
||||||
"The parent overrides this");
|
|
||||||
MOZ_ASSERT(false, "This method must be overridden");
|
|
||||||
return NS_ERROR_NOT_IMPLEMENTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
HttpBaseChannel::GetTopWindowURI(nsIURI **aTopWindowURI)
|
HttpBaseChannel::GetTopWindowURI(nsIURI **aTopWindowURI)
|
||||||
{
|
{
|
||||||
|
@ -197,7 +197,6 @@ public:
|
|||||||
NS_IMETHOD GetCorsMode(uint32_t* aCorsMode) override;
|
NS_IMETHOD GetCorsMode(uint32_t* aCorsMode) override;
|
||||||
NS_IMETHOD SetCorsMode(uint32_t aCorsMode) override;
|
NS_IMETHOD SetCorsMode(uint32_t aCorsMode) override;
|
||||||
NS_IMETHOD GetTopWindowURI(nsIURI **aTopWindowURI) override;
|
NS_IMETHOD GetTopWindowURI(nsIURI **aTopWindowURI) override;
|
||||||
NS_IMETHOD ContinueBeginConnect() override;
|
|
||||||
NS_IMETHOD GetProxyURI(nsIURI **proxyURI) override;
|
NS_IMETHOD GetProxyURI(nsIURI **proxyURI) override;
|
||||||
|
|
||||||
inline void CleanRedirectCacheChainIfNecessary()
|
inline void CleanRedirectCacheChainIfNecessary()
|
||||||
|
@ -4782,6 +4782,11 @@ nsHttpChannel::GetSecurityInfo(nsISupports **securityInfo)
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If any of the functions that AsyncOpen calls returns immediately an error
|
||||||
|
// AsyncAbort(which calls onStart/onStopRequest) does not need to be call.
|
||||||
|
// To be sure that they are not call ReleaseListeners() is called.
|
||||||
|
// If AsyncOpen returns NS_OK, after that point AsyncAbort must be called on
|
||||||
|
// any error.
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsHttpChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *context)
|
nsHttpChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *context)
|
||||||
{
|
{
|
||||||
@ -4855,8 +4860,11 @@ nsHttpChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *context)
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
// On error BeginConnect() should call AsyncAbort() before exiting until
|
// BeginConnect() will not call AsyncAbort() on an error and if AsyncAbort needs
|
||||||
// ContineBeginConnect after that it should not call it.
|
// to be called the function calling BeginConnect will need to call AsyncAbort.
|
||||||
|
// If BeginConnect is called from AsyncOpen, AsyncnAbort doesn't need to be
|
||||||
|
// called. If it is called form another function (e.g. the function is called
|
||||||
|
// from OnProxyAvailable) that function should call AsyncOpen.
|
||||||
nsresult
|
nsresult
|
||||||
nsHttpChannel::BeginConnect()
|
nsHttpChannel::BeginConnect()
|
||||||
{
|
{
|
||||||
@ -4881,14 +4889,12 @@ nsHttpChannel::BeginConnect()
|
|||||||
if (NS_SUCCEEDED(rv))
|
if (NS_SUCCEEDED(rv))
|
||||||
rv = mURI->GetAsciiSpec(mSpec);
|
rv = mURI->GetAsciiSpec(mSpec);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
AsyncAbort(rv);
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reject the URL if it doesn't specify a host
|
// Reject the URL if it doesn't specify a host
|
||||||
if (host.IsEmpty()) {
|
if (host.IsEmpty()) {
|
||||||
rv = NS_ERROR_MALFORMED_URI;
|
rv = NS_ERROR_MALFORMED_URI;
|
||||||
AsyncAbort(rv);
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
LOG(("host=%s port=%d\n", host.get(), port));
|
LOG(("host=%s port=%d\n", host.get(), port));
|
||||||
@ -4964,7 +4970,6 @@ nsHttpChannel::BeginConnect()
|
|||||||
if (NS_SUCCEEDED(rv))
|
if (NS_SUCCEEDED(rv))
|
||||||
rv = mAuthProvider->Init(this);
|
rv = mAuthProvider->Init(this);
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
AsyncAbort(rv);
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4977,11 +4982,7 @@ nsHttpChannel::BeginConnect()
|
|||||||
// Check to see if we should redirect this channel elsewhere by
|
// Check to see if we should redirect this channel elsewhere by
|
||||||
// nsIHttpChannel.redirectTo API request
|
// nsIHttpChannel.redirectTo API request
|
||||||
if (mAPIRedirectToURI) {
|
if (mAPIRedirectToURI) {
|
||||||
rv = AsyncCall(&nsHttpChannel::HandleAsyncAPIRedirect);
|
return AsyncCall(&nsHttpChannel::HandleAsyncAPIRedirect);
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
AsyncAbort(rv);
|
|
||||||
}
|
|
||||||
return rv;
|
|
||||||
}
|
}
|
||||||
// Check to see if this principal exists on local blocklists.
|
// Check to see if this principal exists on local blocklists.
|
||||||
nsRefPtr<nsChannelClassifier> channelClassifier = new nsChannelClassifier();
|
nsRefPtr<nsChannelClassifier> channelClassifier = new nsChannelClassifier();
|
||||||
@ -5094,33 +5095,43 @@ nsHttpChannel::BeginConnect()
|
|||||||
}
|
}
|
||||||
mCaps &= ~NS_HTTP_ALLOW_PIPELINING;
|
mCaps &= ~NS_HTTP_ALLOW_PIPELINING;
|
||||||
}
|
}
|
||||||
if (!(mLoadFlags & LOAD_CLASSIFY_URI)) {
|
|
||||||
// On error ContinueBeginConnect() will call AsyncAbort so do not do it
|
// We may have been cancelled already, either by on-modify-request
|
||||||
// here
|
// listeners or load group observers; in that case, we should not send the
|
||||||
return ContinueBeginConnect();
|
// request to the server
|
||||||
|
if (mCanceled) {
|
||||||
|
return mStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!(mLoadFlags & LOAD_CLASSIFY_URI)) {
|
||||||
|
ContinueBeginConnect();
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
// mLocalBlocklist is true only if tracking protection is enabled and the
|
// mLocalBlocklist is true only if tracking protection is enabled and the
|
||||||
// URI is a tracking domain, it makes no guarantees about phishing or
|
// URI is a tracking domain, it makes no guarantees about phishing or
|
||||||
// malware, so if LOAD_CLASSIFY_URI is true we must call
|
// malware, so if LOAD_CLASSIFY_URI is true we must call
|
||||||
// nsChannelClassifier to catch phishing and malware URIs.
|
// nsChannelClassifier to catch phishing and malware URIs.
|
||||||
bool callContinueBeginConnect = true;
|
bool callContinueBeginConnect = true;
|
||||||
if (mCanceled || !mLocalBlocklist) {
|
if (!mLocalBlocklist) {
|
||||||
rv = ContinueBeginConnect();
|
// Here we call ContinueBeginConnectWithResult and not
|
||||||
if (NS_FAILED(rv)) {
|
// ContinueBeginConnect so that in the case of an error we do not start
|
||||||
// On error ContinueBeginConnect() will call AsyncAbort so do not do
|
// channelClassifier.
|
||||||
// it here
|
rv = ContinueBeginConnectWithResult();
|
||||||
return rv;
|
if (NS_FAILED(rv)) {
|
||||||
}
|
return rv;
|
||||||
callContinueBeginConnect = false;
|
}
|
||||||
|
callContinueBeginConnect = false;
|
||||||
}
|
}
|
||||||
// nsChannelClassifier calls ContinueBeginConnect if it has not already
|
// nsChannelClassifier calls ContinueBeginConnect if it has not already
|
||||||
// been called, after optionally cancelling the channel once we have a
|
// been called, after optionally cancelling the channel once we have a
|
||||||
// remote verdict. We call a concrete class instead of an nsI* that might
|
// remote verdict. We call a concrete class instead of an nsI* that might
|
||||||
// be overridden.
|
// be overridden.
|
||||||
if (!mCanceled) {
|
LOG(("nsHttpChannel::Starting nsChannelClassifier %p [this=%p]",
|
||||||
LOG(("nsHttpChannel::Starting nsChannelClassifier %p [this=%p]",
|
channelClassifier.get(), this));
|
||||||
channelClassifier.get(), this));
|
channelClassifier->Start(this);
|
||||||
channelClassifier->Start(this, callContinueBeginConnect);
|
if (callContinueBeginConnect) {
|
||||||
|
ContinueBeginConnect();
|
||||||
}
|
}
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
@ -5158,28 +5169,39 @@ nsHttpChannel::SetPriority(int32_t value)
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
nsresult
|
||||||
// nsHttpChannel::nsIHttpChannelInternal
|
nsHttpChannel::ContinueBeginConnectWithResult()
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
NS_IMETHODIMP
|
|
||||||
nsHttpChannel::ContinueBeginConnect()
|
|
||||||
{
|
{
|
||||||
LOG(("nsHttpChannel::ContinueBeginConnect [this=%p]", this));
|
LOG(("nsHttpChannel::ContinueBeginConnectWithResult [this=%p]", this));
|
||||||
|
NS_PRECONDITION(!mCallOnResume, "How did that happen?");
|
||||||
|
|
||||||
nsresult rv;
|
nsresult rv;
|
||||||
// We may have been cancelled already, either by on-modify-request
|
|
||||||
// listeners or load group observers or nsChannelClassifier; in that case,
|
if (mSuspendCount) {
|
||||||
// we should not send the request to the server
|
LOG(("Waiting until resume to do async connect [this=%p]\n", this));
|
||||||
if (mCanceled) {
|
mCallOnResume = &nsHttpChannel::ContinueBeginConnect;
|
||||||
|
rv = NS_OK;
|
||||||
|
} else if (mCanceled) {
|
||||||
|
// We may have been cancelled already, by nsChannelClassifier in that
|
||||||
|
// case, we should not send the request to the server
|
||||||
rv = mStatus;
|
rv = mStatus;
|
||||||
} else {
|
} else {
|
||||||
rv = Connect();
|
rv = Connect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LOG(("nsHttpChannel::ContinueBeginConnectWithResult result [this=%p rv=%x "
|
||||||
|
"mCanceled=%i]\n", this, rv, mCanceled));
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nsHttpChannel::ContinueBeginConnect()
|
||||||
|
{
|
||||||
|
nsresult rv = ContinueBeginConnectWithResult();
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
LOG(("Calling AsyncAbort [rv=%x mCanceled=%i]\n", rv, mCanceled));
|
|
||||||
CloseCacheEntry(true);
|
CloseCacheEntry(true);
|
||||||
AsyncAbort(rv);
|
AsyncAbort(rv);
|
||||||
}
|
}
|
||||||
return rv;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@ -5232,14 +5254,13 @@ nsHttpChannel::OnProxyAvailable(nsICancelable *request, nsIChannel *channel,
|
|||||||
LOG(("nsHttpChannel::OnProxyAvailable [this=%p] "
|
LOG(("nsHttpChannel::OnProxyAvailable [this=%p] "
|
||||||
"Handler no longer active.\n", this));
|
"Handler no longer active.\n", this));
|
||||||
rv = NS_ERROR_NOT_AVAILABLE;
|
rv = NS_ERROR_NOT_AVAILABLE;
|
||||||
AsyncAbort(rv);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// On error BeginConnect() will call AsyncAbort.
|
|
||||||
rv = BeginConnect();
|
rv = BeginConnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
|
AsyncAbort(rv);
|
||||||
Cancel(rv);
|
Cancel(rv);
|
||||||
}
|
}
|
||||||
return rv;
|
return rv;
|
||||||
|
@ -126,7 +126,6 @@ public:
|
|||||||
NS_IMETHOD AsyncOpen(nsIStreamListener *listener, nsISupports *aContext) override;
|
NS_IMETHOD AsyncOpen(nsIStreamListener *listener, nsISupports *aContext) override;
|
||||||
// nsIHttpChannelInternal
|
// nsIHttpChannelInternal
|
||||||
NS_IMETHOD SetupFallbackChannel(const char *aFallbackKey) override;
|
NS_IMETHOD SetupFallbackChannel(const char *aFallbackKey) override;
|
||||||
NS_IMETHOD ContinueBeginConnect() override;
|
|
||||||
// nsISupportsPriority
|
// nsISupportsPriority
|
||||||
NS_IMETHOD SetPriority(int32_t value) override;
|
NS_IMETHOD SetPriority(int32_t value) override;
|
||||||
// nsIClassOfService
|
// nsIClassOfService
|
||||||
@ -241,6 +240,8 @@ private:
|
|||||||
|
|
||||||
bool RequestIsConditional();
|
bool RequestIsConditional();
|
||||||
nsresult BeginConnect();
|
nsresult BeginConnect();
|
||||||
|
nsresult ContinueBeginConnectWithResult();
|
||||||
|
void ContinueBeginConnect();
|
||||||
nsresult Connect();
|
nsresult Connect();
|
||||||
void SpeculativeConnect();
|
void SpeculativeConnect();
|
||||||
nsresult SetupTransaction();
|
nsresult SetupTransaction();
|
||||||
|
@ -38,7 +38,7 @@ interface nsIHttpUpgradeListener : nsISupports
|
|||||||
* using any feature exposed by this interface, be aware that this interface
|
* using any feature exposed by this interface, be aware that this interface
|
||||||
* will change and you will be broken. You have been warned.
|
* will change and you will be broken. You have been warned.
|
||||||
*/
|
*/
|
||||||
[scriptable, uuid(26833ec7-4555-4f23-9281-3a12d4b76db1)]
|
[scriptable, uuid(c025c35a-dda3-4a1d-9e6c-e02d7149ac79)]
|
||||||
|
|
||||||
interface nsIHttpChannelInternal : nsISupports
|
interface nsIHttpChannelInternal : nsISupports
|
||||||
{
|
{
|
||||||
@ -253,12 +253,6 @@ interface nsIHttpChannelInternal : nsISupports
|
|||||||
*/
|
*/
|
||||||
attribute ACString networkInterfaceId;
|
attribute ACString networkInterfaceId;
|
||||||
|
|
||||||
/**
|
|
||||||
* Used only by nsChannelClassifier to resume connecting or abort the
|
|
||||||
* channel after a remote classification verdict.
|
|
||||||
*/
|
|
||||||
void continueBeginConnect();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read the proxy URI, which, if non-null, will be used to resolve
|
* Read the proxy URI, which, if non-null, will be used to resolve
|
||||||
* proxies for this channel.
|
* proxies for this channel.
|
||||||
|
108
netwerk/test/unit/test_suspend_channel_before_connect.js
Normal file
108
netwerk/test/unit/test_suspend_channel_before_connect.js
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
|
||||||
|
const CC = Components.Constructor;
|
||||||
|
|
||||||
|
Cu.import("resource://gre/modules/Services.jsm");
|
||||||
|
|
||||||
|
const ServerSocket = CC("@mozilla.org/network/server-socket;1",
|
||||||
|
"nsIServerSocket",
|
||||||
|
"init");
|
||||||
|
|
||||||
|
var obs = Cc["@mozilla.org/observer-service;1"]
|
||||||
|
.getService(Ci.nsIObserverService);
|
||||||
|
|
||||||
|
var ios = Cc["@mozilla.org/network/io-service;1"]
|
||||||
|
.getService(Components.interfaces.nsIIOService);
|
||||||
|
|
||||||
|
// A server that waits for a connect. If a channel is suspended it should not
|
||||||
|
// try to connect to the server until it is is resumed or not try at all if it
|
||||||
|
// is cancelled as in this test.
|
||||||
|
function TestServer() {
|
||||||
|
this.listener = ServerSocket(-1, true, -1);
|
||||||
|
this.port = this.listener.port;
|
||||||
|
this.listener.asyncListen(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
TestServer.prototype = {
|
||||||
|
onSocketAccepted: function(socket, trans) {
|
||||||
|
do_check_true(false, "Socket should not have tried to connect!");
|
||||||
|
},
|
||||||
|
|
||||||
|
onStopListening: function(socket) {
|
||||||
|
},
|
||||||
|
|
||||||
|
stop: function() {
|
||||||
|
try { this.listener.close(); } catch(ignore) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var requestListenerObserver = {
|
||||||
|
|
||||||
|
QueryInterface: function queryinterface(iid) {
|
||||||
|
if (iid.equals(Ci.nsISupports) ||
|
||||||
|
iid.equals(Ci.nsIObserver))
|
||||||
|
return this;
|
||||||
|
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||||
|
},
|
||||||
|
|
||||||
|
observe: function(subject, topic, data) {
|
||||||
|
if (topic === "http-on-modify-request" &&
|
||||||
|
subject instanceof Ci.nsIHttpChannel) {
|
||||||
|
|
||||||
|
var chan = subject.QueryInterface(Ci.nsIHttpChannel);
|
||||||
|
chan.suspend();
|
||||||
|
var obs = Cc["@mozilla.org/observer-service;1"].getService();
|
||||||
|
obs = obs.QueryInterface(Ci.nsIObserverService);
|
||||||
|
obs.removeObserver(this, "http-on-modify-request");
|
||||||
|
|
||||||
|
// Timers are bad, but we need to wait to see that we are not trying to
|
||||||
|
// connect to the server. There are no other event since nothing should
|
||||||
|
// happen until we resume the channel.
|
||||||
|
let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||||
|
timer.initWithCallback(() => {
|
||||||
|
chan.cancel(Cr.NS_BINDING_ABORTED);
|
||||||
|
chan.resume();
|
||||||
|
}, 1000, Ci.nsITimer.TYPE_ONE_SHOT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var listener = {
|
||||||
|
onStartRequest: function test_onStartR(request, ctx) {
|
||||||
|
},
|
||||||
|
|
||||||
|
onDataAvailable: function test_ODA() {
|
||||||
|
do_throw("Should not get any data!");
|
||||||
|
},
|
||||||
|
|
||||||
|
onStopRequest: function test_onStopR(request, ctx, status) {
|
||||||
|
do_execute_soon(run_next_test);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add observer and start a channel. Observer is going to suspend the channel on
|
||||||
|
// "http-on-modify-request" even. If a channel is suspended so early it should
|
||||||
|
// not try to connect at all until it is resumed. In this case we are going to
|
||||||
|
// wait for some time and cancel the channel before resuming it.
|
||||||
|
add_test(function testNoConnectChannelCanceledEarly() {
|
||||||
|
|
||||||
|
serv = new TestServer();
|
||||||
|
|
||||||
|
obs.addObserver(requestListenerObserver, "http-on-modify-request", false);
|
||||||
|
|
||||||
|
var chan = ios.newChannel2("http://localhost:" + serv.port,
|
||||||
|
"",
|
||||||
|
null,
|
||||||
|
null, // aLoadingNode
|
||||||
|
Services.scriptSecurityManager.getSystemPrincipal(),
|
||||||
|
null, // aTriggeringPrincipal
|
||||||
|
Ci.nsILoadInfo.SEC_NORMAL,
|
||||||
|
Ci.nsIContentPolicy.TYPE_OTHER);
|
||||||
|
|
||||||
|
chan.asyncOpen(listener, chan);
|
||||||
|
|
||||||
|
do_register_cleanup(function(){ serv.stop(); });
|
||||||
|
});
|
||||||
|
|
||||||
|
function run_test() {
|
||||||
|
run_next_test();
|
||||||
|
}
|
@ -319,3 +319,4 @@ skip-if = os == "android"
|
|||||||
[test_multipart_streamconv_application_package.js]
|
[test_multipart_streamconv_application_package.js]
|
||||||
[test_safeoutputstream_append.js]
|
[test_safeoutputstream_append.js]
|
||||||
[test_packaged_app_service.js]
|
[test_packaged_app_service.js]
|
||||||
|
[test_suspend_channel_before_connect.js]
|
||||||
|
@ -1078,7 +1078,7 @@
|
|||||||
if (cell.childElt == "twisty")
|
if (cell.childElt == "twisty")
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (cell.col) {
|
if (cell.col && event.button == 0) {
|
||||||
if (cell.col.cycler) {
|
if (cell.col.cycler) {
|
||||||
view.cycleCell(cell.row, cell.col);
|
view.cycleCell(cell.row, cell.col);
|
||||||
return;
|
return;
|
||||||
|
@ -365,8 +365,12 @@ uint32_t UniqueStacks::Stack::GetOrAddIndex() const
|
|||||||
uint32_t UniqueStacks::FrameKey::Hash() const
|
uint32_t UniqueStacks::FrameKey::Hash() const
|
||||||
{
|
{
|
||||||
uint32_t hash = 0;
|
uint32_t hash = 0;
|
||||||
if (!mLocation.empty()) {
|
if (!mLocation.IsEmpty()) {
|
||||||
|
#ifdef SPS_STANDALONE
|
||||||
hash = mozilla::HashString(mLocation.c_str());
|
hash = mozilla::HashString(mLocation.c_str());
|
||||||
|
#else
|
||||||
|
hash = mozilla::HashString(mLocation.get());
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
if (mLine.isSome()) {
|
if (mLine.isSome()) {
|
||||||
hash = mozilla::AddToHash(hash, *mLine);
|
hash = mozilla::AddToHash(hash, *mLine);
|
||||||
@ -539,7 +543,11 @@ void UniqueStacks::StreamFrame(const OnStackFrameKey& aFrame)
|
|||||||
#else
|
#else
|
||||||
{
|
{
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef SPS_STANDALONE
|
||||||
mUniqueStrings.WriteElement(mFrameTableWriter, aFrame.mLocation.c_str());
|
mUniqueStrings.WriteElement(mFrameTableWriter, aFrame.mLocation.c_str());
|
||||||
|
#else
|
||||||
|
mUniqueStrings.WriteElement(mFrameTableWriter, aFrame.mLocation.get());
|
||||||
|
#endif
|
||||||
if (aFrame.mLine.isSome()) {
|
if (aFrame.mLine.isSome()) {
|
||||||
mFrameTableWriter.NullElement(); // implementation
|
mFrameTableWriter.NullElement(); // implementation
|
||||||
mFrameTableWriter.NullElement(); // optimizations
|
mFrameTableWriter.NullElement(); // optimizations
|
||||||
|
@ -148,7 +148,13 @@ class UniqueStacks
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
struct FrameKey {
|
struct FrameKey {
|
||||||
|
#ifdef SPS_STANDALONE
|
||||||
std::string mLocation;
|
std::string mLocation;
|
||||||
|
#else
|
||||||
|
// This cannot be a std::string, as it is not memmove compatible, which
|
||||||
|
// is used by nsHashTable
|
||||||
|
nsCString mLocation;
|
||||||
|
#endif
|
||||||
mozilla::Maybe<unsigned> mLine;
|
mozilla::Maybe<unsigned> mLine;
|
||||||
mozilla::Maybe<unsigned> mCategory;
|
mozilla::Maybe<unsigned> mCategory;
|
||||||
mozilla::Maybe<void*> mJITAddress;
|
mozilla::Maybe<void*> mJITAddress;
|
||||||
|
@ -49,7 +49,7 @@ pref("dom.mozTCPSocket.enabled", true);
|
|||||||
pref("general.smoothScroll", true);
|
pref("general.smoothScroll", true);
|
||||||
|
|
||||||
// WebPayment
|
// WebPayment
|
||||||
pref("dom.mozPay.enabled", true);
|
pref("dom.mozPay.enabled", false);
|
||||||
|
|
||||||
// System messages
|
// System messages
|
||||||
pref("dom.sysmsg.enabled", true);
|
pref("dom.sysmsg.enabled", true);
|
||||||
|
@ -19,9 +19,6 @@ function test() {
|
|||||||
ok(aResponse.tabs[0].styleEditorActor, "styleEditorActor set");
|
ok(aResponse.tabs[0].styleEditorActor, "styleEditorActor set");
|
||||||
ok(aResponse.tabs[0].inspectorActor, "inspectorActor set");
|
ok(aResponse.tabs[0].inspectorActor, "inspectorActor set");
|
||||||
ok(aResponse.tabs[0].traceActor, "traceActor set");
|
ok(aResponse.tabs[0].traceActor, "traceActor set");
|
||||||
ok(aResponse.chromeDebugger, "chromeDebugger set");
|
|
||||||
ok(aResponse.consoleActor, "consoleActor set");
|
|
||||||
ok(aResponse.profilerActor, "profilerActor set");
|
|
||||||
ok(aResponse.deviceActor, "deviceActor set");
|
ok(aResponse.deviceActor, "deviceActor set");
|
||||||
|
|
||||||
client.close(() => {
|
client.close(() => {
|
||||||
|
@ -12,10 +12,10 @@ function test() {
|
|||||||
providerUri: "https://example.com:443/webapprtChrome/webapprt/test/chrome/mozpay-success.html?req=",
|
providerUri: "https://example.com:443/webapprtChrome/webapprt/test/chrome/mozpay-success.html?req=",
|
||||||
message: "Success."
|
message: "Success."
|
||||||
});
|
});
|
||||||
tests.push({
|
// tests.push({
|
||||||
providerUri: "https://example.com:443/webapprtChrome/webapprt/test/chrome/mozpay-failure.html?req=",
|
// providerUri: "https://example.com:443/webapprtChrome/webapprt/test/chrome/mozpay-failure.html?req=",
|
||||||
message: "Chocolate rejected."
|
// message: "Chocolate rejected."
|
||||||
});
|
// });
|
||||||
|
|
||||||
let jwt = "eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJhdWQiOiAibW9j" +
|
let jwt = "eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJhdWQiOiAibW9j" +
|
||||||
"a3BheXByb3ZpZGVyLnBocGZvZ2FwcC5jb20iLCAiaXNzIjogIkVudGVyI" +
|
"a3BheXByb3ZpZGVyLnBocGZvZ2FwcC5jb20iLCAiaXNzIjogIkVudGVyI" +
|
||||||
@ -36,23 +36,25 @@ function test() {
|
|||||||
requestMethod: "GET"
|
requestMethod: "GET"
|
||||||
};
|
};
|
||||||
|
|
||||||
let providerWindow;
|
// Disabled because the mozPay API is disabled, so the provider window
|
||||||
|
// won't be shown.
|
||||||
let winObserver = function(win, topic) {
|
//
|
||||||
if (topic == "domwindowopened") {
|
// let providerWindow;
|
||||||
win.addEventListener("load", function onLoadWindow() {
|
// let winObserver = function(win, topic) {
|
||||||
win.removeEventListener("load", onLoadWindow, false);
|
// if (topic == "domwindowopened") {
|
||||||
|
// win.addEventListener("load", function onLoadWindow() {
|
||||||
if (win.document.getElementById("content").getAttribute("src") ==
|
// win.removeEventListener("load", onLoadWindow, false);
|
||||||
(tests[curTest].providerUri + jwt)) {
|
//
|
||||||
ok(true, "Payment provider window shown.");
|
// if (win.document.getElementById("content") &&
|
||||||
providerWindow = win;
|
// win.document.getElementById("content").getAttribute("src") ==
|
||||||
}
|
// (tests[curTest].providerUri + jwt)) {
|
||||||
}, false);
|
// ok(true, "Payment provider window shown.");
|
||||||
}
|
// providerWindow = win;
|
||||||
}
|
// }
|
||||||
|
// }, false);
|
||||||
Services.ww.registerNotification(winObserver);
|
// }
|
||||||
|
// }
|
||||||
|
// Services.ww.registerNotification(winObserver);
|
||||||
|
|
||||||
let mutObserver = null;
|
let mutObserver = null;
|
||||||
|
|
||||||
@ -61,12 +63,12 @@ function test() {
|
|||||||
mutObserver = new MutationObserver(function(mutations) {
|
mutObserver = new MutationObserver(function(mutations) {
|
||||||
is(msg.textContent, tests[curTest].message, "Got: " + tests[curTest].message);
|
is(msg.textContent, tests[curTest].message, "Got: " + tests[curTest].message);
|
||||||
|
|
||||||
if (!providerWindow) {
|
// if (!providerWindow) {
|
||||||
ok(false, "Payment provider window shown.");
|
// ok(false, "Payment provider window shown.");
|
||||||
} else {
|
// } else {
|
||||||
providerWindow.close();
|
// providerWindow.close();
|
||||||
providerWindow = null;
|
// providerWindow = null;
|
||||||
}
|
// }
|
||||||
|
|
||||||
runNextTest();
|
runNextTest();
|
||||||
});
|
});
|
||||||
@ -76,7 +78,7 @@ function test() {
|
|||||||
loadWebapp("mozpay.webapp", undefined, onLoad);
|
loadWebapp("mozpay.webapp", undefined, onLoad);
|
||||||
|
|
||||||
function runNextTest() {
|
function runNextTest() {
|
||||||
providerWindow = null;
|
// providerWindow = null;
|
||||||
if (mutObserver) {
|
if (mutObserver) {
|
||||||
mutObserver.disconnect();
|
mutObserver.disconnect();
|
||||||
}
|
}
|
||||||
@ -97,7 +99,7 @@ function test() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
registerCleanupFunction(function() {
|
registerCleanupFunction(function() {
|
||||||
Services.ww.unregisterNotification(winObserver);
|
// Services.ww.unregisterNotification(winObserver);
|
||||||
mutObserver.disconnect();
|
mutObserver.disconnect();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -32,13 +32,21 @@
|
|||||||
"gInR5cCI6ICJtb2NrL3BheW1lbnRzL2luYXBwL3YxIn0.QZxc62USCy4U" +
|
"gInR5cCI6ICJtb2NrL3BheW1lbnRzL2luYXBwL3YxIn0.QZxc62USCy4U" +
|
||||||
"IyKIC1TKelVhNklvk-Ou1l_daKntaFI";
|
"IyKIC1TKelVhNklvk-Ou1l_daKntaFI";
|
||||||
|
|
||||||
var request = navigator.mozPay(jwt);
|
// mozPay is currently disabled in the desktop runtime, so we check
|
||||||
request.onsuccess = function onsuccess() {
|
// that the property is set to null on the navigator object.
|
||||||
document.getElementById("msg").textContent = "Success.";
|
window.addEventListener("load", function() {
|
||||||
};
|
document.getElementById("msg").textContent =
|
||||||
request.onerror = function onerror() {
|
(navigator.mozPay === null) ? "Success." : "navigator.mozPay defined";
|
||||||
document.getElementById("msg").textContent = request.error.name;
|
}, false);
|
||||||
};
|
|
||||||
|
// This is the old code for checking the behavior of the API when enabled:
|
||||||
|
// var request = navigator.mozPay(jwt);
|
||||||
|
// request.onsuccess = function onsuccess() {
|
||||||
|
// document.getElementById("msg").textContent = "Success.";
|
||||||
|
// };
|
||||||
|
// request.onerror = function onerror() {
|
||||||
|
// document.getElementById("msg").textContent = request.error.name;
|
||||||
|
// };
|
||||||
</script>
|
</script>
|
||||||
<p id="msg">Webapp waiting to be paid...</p>
|
<p id="msg">Webapp waiting to be paid...</p>
|
||||||
</body>
|
</body>
|
||||||
|
Loading…
Reference in New Issue
Block a user