From 7df631d1f7e6865b443e015dba30ce484a15c4fe Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Mon, 31 Dec 2012 11:45:51 +1300 Subject: [PATCH 001/469] Bug 816359. Part 1: When constructing inline frames, we should never treat transforms as making the inline an abs-pos containing block, since transforms don't apply to inlines. r=bz --- layout/base/nsCSSFrameConstructor.cpp | 6 ++---- layout/reftests/bugs/816359-1-ref.html | 2 ++ layout/reftests/bugs/816359-1.html | 5 +++++ layout/reftests/bugs/reftest.list | 1 + 4 files changed, 10 insertions(+), 4 deletions(-) create mode 100644 layout/reftests/bugs/816359-1-ref.html create mode 100644 layout/reftests/bugs/816359-1.html diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp index ddf4c964b99f..9295b2c083d2 100644 --- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -5796,8 +5796,7 @@ nsCSSFrameConstructor::AppendFramesToParent(nsFrameConstructorState& aStat if (!aFrameList.IsEmpty()) { const nsStyleDisplay* parentDisplay = aParentFrame->GetStyleDisplay(); bool positioned = - (parentDisplay->mPosition == NS_STYLE_POSITION_RELATIVE || - parentDisplay->HasTransform()) && + parentDisplay->mPosition == NS_STYLE_POSITION_RELATIVE && !aParentFrame->IsSVGText(); nsFrameItems ibSiblings; CreateIBSiblings(aState, aParentFrame, positioned, aFrameList, @@ -11108,8 +11107,7 @@ nsCSSFrameConstructor::ConstructInline(nsFrameConstructorState& aState, bool positioned = NS_STYLE_DISPLAY_INLINE == aDisplay->mDisplay && - (NS_STYLE_POSITION_RELATIVE == aDisplay->mPosition || - aDisplay->HasTransform()) && + NS_STYLE_POSITION_RELATIVE == aDisplay->mPosition && !aParentFrame->IsSVGText(); nsIFrame* newFrame = NS_NewInlineFrame(mPresShell, styleContext); diff --git a/layout/reftests/bugs/816359-1-ref.html b/layout/reftests/bugs/816359-1-ref.html new file mode 100644 index 000000000000..c042d9c9b364 --- /dev/null +++ b/layout/reftests/bugs/816359-1-ref.html @@ -0,0 +1,2 @@ + +
diff --git a/layout/reftests/bugs/816359-1.html b/layout/reftests/bugs/816359-1.html new file mode 100644 index 000000000000..91909e1a3490 --- /dev/null +++ b/layout/reftests/bugs/816359-1.html @@ -0,0 +1,5 @@ + + + +
+ diff --git a/layout/reftests/bugs/reftest.list b/layout/reftests/bugs/reftest.list index 6b23d05c2873..65ca0ed5c4e5 100644 --- a/layout/reftests/bugs/reftest.list +++ b/layout/reftests/bugs/reftest.list @@ -1736,4 +1736,5 @@ fuzzy(40,800) == 797797-2.html 797797-2-ref.html # 'opacity:N' and rgba(,,,N) te == 815593-1.html 815593-1-ref.html == 814952-1.html 814952-1-ref.html == 816458-1.html 816458-1-ref.html +== 816359-1.html 816359-1-ref.html == 818276-1.html 818276-1-ref.html From 90b99242bee9a859da80d8cdda31e935577ba58e Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Mon, 31 Dec 2012 11:45:57 +1300 Subject: [PATCH 002/469] Bug 816359. Part 2: Make nsStyleDisplay::HasTransform take a frame parameter and check that the frame supports transforms. r=mats" --- layout/base/nsCSSFrameConstructor.cpp | 13 +++++++------ layout/generic/nsFrame.cpp | 8 ++++---- layout/style/nsStyleStruct.cpp | 4 ++-- layout/style/nsStyleStruct.h | 8 ++++++-- layout/style/nsStyleStructInlines.h | 8 +++++++- 5 files changed, 26 insertions(+), 15 deletions(-) diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp index 9295b2c083d2..17e41f4ce911 100644 --- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -925,7 +925,7 @@ nsFrameConstructorState::nsFrameConstructorState(nsIPresShell* aPresShe mAdditionalStateBits(0), mFixedPosIsAbsPos(aAbsoluteContainingBlock && aAbsoluteContainingBlock->GetStyleDisplay()-> - HasTransform()), + HasTransform(aAbsoluteContainingBlock)), mHavePendingPopupgroup(false), mCreatingExtraFrames(false), mTreeMatchContext(true, nsRuleWalker::eRelevantLinkUnvisited, @@ -958,7 +958,7 @@ nsFrameConstructorState::nsFrameConstructorState(nsIPresShell* aPresShell, mAdditionalStateBits(0), mFixedPosIsAbsPos(aAbsoluteContainingBlock && aAbsoluteContainingBlock->GetStyleDisplay()-> - HasTransform()), + HasTransform(aAbsoluteContainingBlock)), mHavePendingPopupgroup(false), mCreatingExtraFrames(false), mTreeMatchContext(true, nsRuleWalker::eRelevantLinkUnvisited, @@ -1038,8 +1038,8 @@ nsFrameConstructorState::PushAbsoluteContainingBlock(nsIFrame* aNewAbsoluteConta /* See if we're wiring the fixed-pos and abs-pos lists together. This happens iff * we're a transformed element. */ - mFixedPosIsAbsPos = (aNewAbsoluteContainingBlock && - aNewAbsoluteContainingBlock->GetStyleDisplay()->HasTransform()); + mFixedPosIsAbsPos = aNewAbsoluteContainingBlock && + aNewAbsoluteContainingBlock->GetStyleDisplay()->HasTransform(aNewAbsoluteContainingBlock); if (aNewAbsoluteContainingBlock) { aNewAbsoluteContainingBlock->MarkAsAbsoluteContainingBlock(); @@ -7774,7 +7774,8 @@ DoApplyRenderingChangeToTree(nsIFrame* aFrame, needInvalidatingPaint = true; aFrame->MarkLayersActive(nsChangeHint_UpdateOpacityLayer); } - if (aChange & nsChangeHint_UpdateTransformLayer) { + if ((aChange & nsChangeHint_UpdateTransformLayer) && + aFrame->IsTransformed()) { aFrame->MarkLayersActive(nsChangeHint_UpdateTransformLayer); // If we're not already going to do an invalidating paint, see // if we can get away with only updating the transform on a @@ -7808,7 +7809,7 @@ ApplyRenderingChangeToTree(nsPresContext* aPresContext, // CSS transforms. NS_ASSERTION(!(aChange & nsChangeHint_UpdateTransformLayer) || aFrame->IsTransformed() || - aFrame->GetStyleDisplay()->HasTransform(), + aFrame->GetStyleDisplay()->HasTransformStyle(), "Unexpected UpdateTransformLayer hint"); nsIPresShell *shell = aPresContext->PresShell(); diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index 566162732032..8802714c3247 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -518,7 +518,7 @@ nsFrame::Init(nsIContent* aContent, NS_FRAME_IN_POPUP); } const nsStyleDisplay *disp = GetStyleDisplay(); - if (disp->HasTransform()) { + if (disp->HasTransform(this)) { // The frame gets reconstructed if we toggle the -moz-transform // property, so we can set this bit here and then ignore it. mState |= NS_FRAME_MAY_BE_TRANSFORMED; @@ -985,7 +985,7 @@ bool nsIFrame::IsTransformed() const { return ((mState & NS_FRAME_MAY_BE_TRANSFORMED) && - ((GetStyleDisplay()->HasTransform() && IsFrameOfType(eSupportsCSSTransforms)) || + (GetStyleDisplay()->HasTransform(this) || IsSVGTransformed() || (mContent && nsLayoutUtils::HasAnimationsForCompositor(mContent, @@ -1014,7 +1014,7 @@ bool nsIFrame::Preserves3DChildren() const { if (GetStyleDisplay()->mTransformStyle != NS_STYLE_TRANSFORM_STYLE_PRESERVE_3D || - !GetStyleDisplay()->HasTransform()) + !GetStyleDisplay()->HasTransform(this)) return false; // If we're all scroll frame, then all descendants will be clipped, so we can't preserve 3d. @@ -1031,7 +1031,7 @@ bool nsIFrame::Preserves3D() const { if (!GetParent() || !GetParent()->Preserves3DChildren() || - !GetStyleDisplay()->HasTransform()) { + !GetStyleDisplay()->HasTransform(this)) { return false; } return true; diff --git a/layout/style/nsStyleStruct.cpp b/layout/style/nsStyleStruct.cpp index ce1cfe45c0cc..804eced2bc62 100644 --- a/layout/style/nsStyleStruct.cpp +++ b/layout/style/nsStyleStruct.cpp @@ -2224,7 +2224,7 @@ nsChangeHint nsStyleDisplay::CalcDifference(const nsStyleDisplay& aOther) const /* If we've added or removed the transform property, we need to reconstruct the frame to add * or remove the view object, and also to handle abs-pos and fixed-pos containers. */ - if (HasTransform() != aOther.HasTransform()) { + if (HasTransformStyle() != aOther.HasTransformStyle()) { // We do not need to apply nsChangeHint_UpdateTransformLayer since // nsChangeHint_RepaintFrame will forcibly invalidate the frame area and // ensure layers are rebuilt (or removed). @@ -2232,7 +2232,7 @@ nsChangeHint nsStyleDisplay::CalcDifference(const nsStyleDisplay& aOther) const NS_CombineHint(nsChangeHint_UpdateOverflow, nsChangeHint_RepaintFrame))); } - else if (HasTransform()) { + else if (HasTransformStyle()) { /* Otherwise, if we've kept the property lying around and we already had a * transform, we need to see whether or not we've changed the transform. * If so, we need to recompute its overflow rect (which probably changed diff --git a/layout/style/nsStyleStruct.h b/layout/style/nsStyleStruct.h index 9ee33a2ebf07..626df7593faa 100644 --- a/layout/style/nsStyleStruct.h +++ b/layout/style/nsStyleStruct.h @@ -1692,8 +1692,9 @@ struct nsStyleDisplay { mOverflowX != NS_STYLE_OVERFLOW_CLIP; } - /* Returns whether the element has the -moz-transform property. */ - bool HasTransform() const { + /* Returns whether the element has the -moz-transform property + * or a related property. */ + bool HasTransformStyle() const { return mSpecifiedTransform != nullptr || mTransformStyle == NS_STYLE_TRANSFORM_STYLE_PRESERVE_3D || mBackfaceVisibility == NS_STYLE_BACKFACE_VISIBILITY_HIDDEN; @@ -1709,6 +1710,9 @@ struct nsStyleDisplay { inline bool IsPositioned(const nsIFrame* aFrame) const; inline bool IsRelativelyPositioned(const nsIFrame* aFrame) const; inline bool IsAbsolutelyPositioned(const nsIFrame* aFrame) const; + /* Returns whether the element has the -moz-transform property + * or a related property, and supports CSS transforms. */ + inline bool HasTransform(const nsIFrame* aFrame) const; }; struct nsStyleTable { diff --git a/layout/style/nsStyleStructInlines.h b/layout/style/nsStyleStructInlines.h index 0a245ecaa426..2fad54cace4b 100644 --- a/layout/style/nsStyleStructInlines.h +++ b/layout/style/nsStyleStructInlines.h @@ -124,12 +124,18 @@ nsStyleDisplay::IsFloating(const nsIFrame* aFrame) const return IsFloatingStyle() && !aFrame->IsSVGText(); } +bool +nsStyleDisplay::HasTransform(const nsIFrame* aFrame) const +{ + return HasTransformStyle() && aFrame->IsFrameOfType(nsIFrame::eSupportsCSSTransforms); +} + bool nsStyleDisplay::IsPositioned(const nsIFrame* aFrame) const { return (IsAbsolutelyPositionedStyle() || IsRelativelyPositionedStyle() || - (HasTransform() && aFrame->IsFrameOfType(nsIFrame::eSupportsCSSTransforms))) && + HasTransform(aFrame)) && !aFrame->IsSVGText(); } From 228b5e9fb422db63a8bb764921b9d7e08246be9b Mon Sep 17 00:00:00 2001 From: Cameron McCormack Date: Mon, 31 Dec 2012 10:17:40 +1100 Subject: [PATCH 003/469] Bug 818626 - Record in crash reports whether nsPrintObject trees are sane. r=roc --- layout/printing/nsPrintData.cpp | 61 +++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/layout/printing/nsPrintData.cpp b/layout/printing/nsPrintData.cpp index 8f046c889b0a..c4c97f927ef2 100644 --- a/layout/printing/nsPrintData.cpp +++ b/layout/printing/nsPrintData.cpp @@ -12,6 +12,10 @@ #include "nsIWebProgressListener.h" #include "mozilla/Services.h" +#ifdef MOZ_CRASHREPORTER +#include "nsExceptionHandler.h" +#endif + //----------------------------------------------------- // PR LOGGING #ifdef MOZ_LOGGING @@ -66,6 +70,62 @@ nsPrintData::nsPrintData(ePrintDataType aType) : } +#ifdef MOZ_CRASHREPORTER +#define ASSERT_AND_NOTE(message) \ + { NS_ASSERTION(false, message); \ + CrashReporter::AppendAppNotesToCrashReport(NS_LITERAL_CSTRING(message "\n")); } +#else +#define ASSERT_AND_NOTE(message) \ + NS_ASSERTION(false, message); +#endif + +static void +AssertPresShellsAndContextsSane(nsPrintObject* aPO, + nsTArray& aPresShells, + nsTArray& aPresContexts) +{ + if (aPO->mPresShell) { + if (aPresShells.Contains(aPO->mPresShell)) { + ASSERT_AND_NOTE("duplicate pres shells in print object tree"); + } else { + aPresShells.AppendElement(aPO->mPresShell); + } + } + if (aPO->mPresContext) { + if (aPresContexts.Contains(aPO->mPresContext)) { + ASSERT_AND_NOTE("duplicate pres contexts in print object tree"); + } else { + aPresContexts.AppendElement(aPO->mPresContext); + } + } + if (aPO->mPresShell && !aPO->mPresContext) { + ASSERT_AND_NOTE("print object has pres shell but no pres context"); + } + if (!aPO->mPresShell && aPO->mPresContext) { + ASSERT_AND_NOTE("print object has pres context but no pres shell"); + } + if (aPO->mPresContext && aPO->mPresContext->GetPresShell() != aPO->mPresShell) { + ASSERT_AND_NOTE("print object has mismatching pres shell and pres context"); + } + if (aPO->mPresContext && !aPO->mPresContext->GetPresShell()) { + ASSERT_AND_NOTE("mPresShell->GetPresShell() is null"); + } + + for (uint32_t i = 0; i < aPO->mKids.Length(); i++) { + AssertPresShellsAndContextsSane(aPO->mKids[i], aPresShells, aPresContexts); + } +} + +#undef ASSERT_AND_NOTE + +static void +AssertPresShellsAndContextsSane(nsPrintObject* aPO) +{ + nsTArray presShells; + nsTArray presContexts; + AssertPresShellsAndContextsSane(aPO, presShells, presContexts); +} + nsPrintData::~nsPrintData() { MOZ_COUNT_DTOR(nsPrintData); @@ -99,6 +159,7 @@ nsPrintData::~nsPrintData() } } + AssertPresShellsAndContextsSane(mPrintObject); delete mPrintObject; if (mBrandName) { From a04fe04baf546e585401f501348fc97bdaadad83 Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Mon, 31 Dec 2012 09:33:49 +0900 Subject: [PATCH 004/469] Bug 672193 Support some actions of WM_APPCOMMAND such as New, Open, Close, Save, Find, Help, SendMail, ReplyToMail and ForwardMail r=gavin+jimm --- browser/base/content/browser.js | 29 +++++++++++++++-- content/base/src/nsGkAtomList.h | 10 ++++++ widget/windows/nsWindow.cpp | 56 ++++++++++++++++++++++++++++----- 3 files changed, 86 insertions(+), 9 deletions(-) diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index 403eeefd233c..381fb8e1ffad 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -1750,7 +1750,6 @@ var nonBrowserWindowShutdown = gBrowserInit.nonBrowserWindowShutdown.bind( function HandleAppCommandEvent(evt) { - evt.stopPropagation(); switch (evt.command) { case "Back": BrowserBack(); @@ -1774,9 +1773,35 @@ function HandleAppCommandEvent(evt) { case "Home": BrowserHome(); break; - default: + case "New": + BrowserOpenTab(); break; + case "Close": + BrowserCloseTabOrWindow(); + break; + case "Find": + gFindBar.onFindCommand(); + break; + case "Help": + openHelpLink('firefox-help'); + break; + case "Open": + BrowserOpenFileWindow(); + break; + case "Print": + PrintUtils.print(); + break; + case "Save": + saveDocument(window.content.document); + break; + case "SendMail": + MailIntegration.sendLinkForWindow(window.content); + break; + default: + return; } + evt.stopPropagation(); + evt.preventDefault(); } function gotoHistoryIndex(aEvent) { diff --git a/content/base/src/nsGkAtomList.h b/content/base/src/nsGkAtomList.h index 64389731a8a4..331db5274a7b 100644 --- a/content/base/src/nsGkAtomList.h +++ b/content/base/src/nsGkAtomList.h @@ -2014,6 +2014,16 @@ GK_ATOM(Clear, "Clear") GK_ATOM(VolumeUp, "VolumeUp") GK_ATOM(VolumeDown, "VolumeDown") GK_ATOM(Menu, "Menu") +GK_ATOM(New, "New") +GK_ATOM(Open, "Open") +GK_ATOM(Close, "Close") +GK_ATOM(Save, "Save") +GK_ATOM(Find, "Find") +GK_ATOM(Help, "Help") +GK_ATOM(Print, "Print") +GK_ATOM(SendMail, "SendMail") +GK_ATOM(ForwardMail, "ForwardMail") +GK_ATOM(ReplyToMail, "ReplyToMail") // Smooth scroll events origins GK_ATOM(mouseWheel, "mouseWheel") // For discrete wheel events (e.g. not OSX magic mouse) diff --git a/widget/windows/nsWindow.cpp b/widget/windows/nsWindow.cpp index 916a046a2fc8..d7d3b44ef066 100644 --- a/widget/windows/nsWindow.cpp +++ b/widget/windows/nsWindow.cpp @@ -3687,15 +3687,43 @@ bool nsWindow::DispatchCommandEvent(uint32_t aEventCommand) case APPCOMMAND_BROWSER_HOME: command = nsGkAtoms::Home; break; + case APPCOMMAND_CLOSE: + command = nsGkAtoms::Close; + break; + case APPCOMMAND_FIND: + command = nsGkAtoms::Find; + break; + case APPCOMMAND_HELP: + command = nsGkAtoms::Help; + break; + case APPCOMMAND_NEW: + command = nsGkAtoms::New; + break; + case APPCOMMAND_OPEN: + command = nsGkAtoms::Open; + break; + case APPCOMMAND_PRINT: + command = nsGkAtoms::Print; + break; + case APPCOMMAND_SAVE: + command = nsGkAtoms::Save; + break; + case APPCOMMAND_FORWARD_MAIL: + command = nsGkAtoms::ForwardMail; + break; + case APPCOMMAND_REPLY_TO_MAIL: + command = nsGkAtoms::ReplyToMail; + break; + case APPCOMMAND_SEND_MAIL: + command = nsGkAtoms::SendMail; + break; default: return false; } nsCommandEvent event(true, nsGkAtoms::onAppCommand, command, this); InitEvent(event); - DispatchWindowEvent(&event); - - return true; + return DispatchWindowEvent(&event); } // Recursively dispatch synchronous paints for nsIWidget @@ -5028,10 +5056,24 @@ bool nsWindow::ProcessMessage(UINT msg, WPARAM &wParam, LPARAM &lParam, case APPCOMMAND_BROWSER_SEARCH: case APPCOMMAND_BROWSER_FAVORITES: case APPCOMMAND_BROWSER_HOME: - DispatchCommandEvent(appCommand); - // tell the driver that we handled the event - *aRetValue = 1; - result = true; + case APPCOMMAND_CLOSE: + case APPCOMMAND_FIND: + case APPCOMMAND_HELP: + case APPCOMMAND_NEW: + case APPCOMMAND_OPEN: + case APPCOMMAND_PRINT: + case APPCOMMAND_SAVE: + case APPCOMMAND_FORWARD_MAIL: + case APPCOMMAND_REPLY_TO_MAIL: + case APPCOMMAND_SEND_MAIL: + // We shouldn't consume the message always because if we don't handle + // the message, the sender (typically, utility of keyboard or mouse) + // may send other key messages which indicate well known shortcut key. + if (DispatchCommandEvent(appCommand)) { + // tell the driver that we handled the event + *aRetValue = 1; + result = true; + } break; } // default = false - tell the driver that the event was not handled From 30ab0f19610e7e7f6f2f5adecc7c50a1c05b78d5 Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Mon, 31 Dec 2012 09:33:49 +0900 Subject: [PATCH 005/469] Bug 825167 Use nsDependentSubstring instead of nsDependentString for nsTextStore::InsertTextAtSelection() since the string can be empty r=jimm --- widget/windows/nsTextStore.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/widget/windows/nsTextStore.cpp b/widget/windows/nsTextStore.cpp index 53ae078fdd9a..f529600132f7 100644 --- a/widget/windows/nsTextStore.cpp +++ b/widget/windows/nsTextStore.cpp @@ -1511,7 +1511,7 @@ nsTextStore::SetText(DWORD dwFlags, return hr; } // Replace just selected text - if (!InsertTextAtSelectionInternal(nsDependentString(pchText, cch), + if (!InsertTextAtSelectionInternal(nsDependentSubstring(pchText, cch), pChange)) { PR_LOG(sTextStoreLog, PR_LOG_ERROR, ("TSF: 0x%p nsTextStore::SetText() FAILED due to " @@ -2063,7 +2063,7 @@ nsTextStore::InsertTextAtSelection(DWORD dwFlags, return E_INVALIDARG; } - if (!InsertTextAtSelectionInternal(nsDependentString(pchText, cch), + if (!InsertTextAtSelectionInternal(nsDependentSubstring(pchText, cch), pChange)) { PR_LOG(sTextStoreLog, PR_LOG_ERROR, ("TSF: 0x%p nsTextStore::InsertTextAtSelection() FAILED due to " From e1a410c7ea36eae56343d9fd21f4a1c4bfa4ef94 Mon Sep 17 00:00:00 2001 From: Oleg Romashin Date: Sun, 30 Dec 2012 18:07:11 -0800 Subject: [PATCH 006/469] Bug 825002 - We should not start compositor thread if it is already started. r=nsilva --- gfx/layers/ipc/CompositorParent.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gfx/layers/ipc/CompositorParent.cpp b/gfx/layers/ipc/CompositorParent.cpp index 40a008042e60..f24c9d0e5d5b 100644 --- a/gfx/layers/ipc/CompositorParent.cpp +++ b/gfx/layers/ipc/CompositorParent.cpp @@ -125,6 +125,10 @@ CompositorParent::StartUpWithExistingThread(MessageLoop* aMsgLoop, void CompositorParent::StartUp() { + // Check if compositor started already with StartUpWithExistingThread + if (sCompositorThreadID) { + return; + } MOZ_ASSERT(!sCompositorLoop); CreateCompositorMap(); CreateThread(); From 2571318e8378ba4ce4c3989cca475aba2d880b1d Mon Sep 17 00:00:00 2001 From: Alexander Surkov Date: Mon, 31 Dec 2012 17:04:08 +0900 Subject: [PATCH 007/469] Bug 459357 - Support accessible name computation for SVG, r=tbsaunde --- accessible/src/generic/Accessible.cpp | 61 +++++++++++++++---- accessible/tests/mochitest/name.js | 13 ++++ accessible/tests/mochitest/name/Makefile.in | 1 + accessible/tests/mochitest/name/test_svg.html | 56 +++++++++++++++++ accessible/tests/mochitest/test_descr.html | 12 +--- 5 files changed, 121 insertions(+), 22 deletions(-) create mode 100644 accessible/tests/mochitest/name/test_svg.html diff --git a/accessible/src/generic/Accessible.cpp b/accessible/src/generic/Accessible.cpp index f0090458bca5..1e2ccb86222c 100644 --- a/accessible/src/generic/Accessible.cpp +++ b/accessible/src/generic/Accessible.cpp @@ -264,6 +264,16 @@ Accessible::Name(nsString& aName) aName.CompressWhitespace(); return eNameFromTooltip; } + } else if (mContent->IsSVG()) { + // If user agents need to choose among multiple ‘desc’ or ‘title’ elements + // for processing, the user agent shall choose the first one. + for (nsIContent* childElm = mContent->GetFirstChild(); childElm; + childElm = childElm->GetNextSibling()) { + if (childElm->IsSVG(nsGkAtoms::title)) { + nsTextEquivUtils::AppendTextEquivFromContent(this, childElm, &aName); + return eNameFromTooltip; + } + } } if (nameFlag != eNoNameOnPurpose) @@ -307,25 +317,40 @@ Accessible::Description(nsString& aDescription) // Try XUL description text XULDescriptionIterator iter(Document(), mContent); Accessible* descr = nullptr; - while ((descr = iter.Next())) + while ((descr = iter.Next())) { nsTextEquivUtils::AppendTextEquivFromContent(this, descr->GetContent(), &aDescription); } + } - if (aDescription.IsEmpty()) { - nsIAtom *descAtom = isXUL ? nsGkAtoms::tooltiptext : - nsGkAtoms::title; - if (mContent->GetAttr(kNameSpaceID_None, descAtom, aDescription)) { - nsAutoString name; - Name(name); - if (name.IsEmpty() || aDescription == name) - // Don't use tooltip for a description if this object - // has no name or the tooltip is the same as the name - aDescription.Truncate(); + if (aDescription.IsEmpty()) { + // Keep the Name() method logic. + if (mContent->IsHTML()) { + mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::title, aDescription); + } else if (mContent->IsXUL()) { + mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::tooltiptext, aDescription); + } else if (mContent->IsSVG()) { + for (nsIContent* childElm = mContent->GetFirstChild(); childElm; + childElm = childElm->GetNextSibling()) { + if (childElm->IsSVG(nsGkAtoms::title)) { + nsTextEquivUtils::AppendTextEquivFromContent(this, childElm, + &aDescription); + break; + } } } + + if (!aDescription.IsEmpty()) { + nsAutoString name; + ENameValueFlag nameFlag = Name(name); + + // Don't use tooltip for a description if it was used for a name. + if (nameFlag == eNameFromTooltip) + aDescription.Truncate(); + } } - aDescription.CompressWhitespace(); + } + aDescription.CompressWhitespace(); } NS_IMETHODIMP @@ -2494,6 +2519,18 @@ Accessible::NativeName(nsString& aName) if (mContent->IsXUL()) return GetXULName(aName); + if (mContent->IsSVG()) { + // If user agents need to choose among multiple ‘desc’ or ‘title’ elements + // for processing, the user agent shall choose the first one. + for (nsIContent* childElm = mContent->GetFirstChild(); childElm; + childElm = childElm->GetNextSibling()) { + if (childElm->IsSVG(nsGkAtoms::desc)) { + nsTextEquivUtils::AppendTextEquivFromContent(this, childElm, &aName); + return eNameOK; + } + } + } + return eNameOK; } diff --git a/accessible/tests/mochitest/name.js b/accessible/tests/mochitest/name.js index 8bd0f4aa1dd2..c8a940c3bb33 100644 --- a/accessible/tests/mochitest/name.js +++ b/accessible/tests/mochitest/name.js @@ -17,3 +17,16 @@ function testName(aAccOrElmOrID, aName, aMsg) } return acc; } + +/** + * Test accessible description for the given accessible. + */ +function testDescr(aAccOrElmOrID, aDescr) +{ + var acc = getAccessible(aAccOrElmOrID); + if (!acc) + return; + + is(acc.description, aDescr, + "Wrong description for " + prettyName(aAccOrElmOrID)); +} diff --git a/accessible/tests/mochitest/name/Makefile.in b/accessible/tests/mochitest/name/Makefile.in index 79d4e869b0ee..4739731aaf5e 100644 --- a/accessible/tests/mochitest/name/Makefile.in +++ b/accessible/tests/mochitest/name/Makefile.in @@ -21,6 +21,7 @@ MOCHITEST_A11Y_FILES =\ test_link.html \ test_list.html \ test_markup.html \ + test_svg.html \ test_browserui.xul \ test_tree.xul \ markuprules.xml \ diff --git a/accessible/tests/mochitest/name/test_svg.html b/accessible/tests/mochitest/name/test_svg.html new file mode 100644 index 000000000000..2a8e7b7505c4 --- /dev/null +++ b/accessible/tests/mochitest/name/test_svg.html @@ -0,0 +1,56 @@ + + + + Accessible name and description for SVG elements + + + + + + + + + + + + + + + Mozilla Bug 459357 + +

+ +
+  
+ + + A description + A name + + + + A tooltip + + + + diff --git a/accessible/tests/mochitest/test_descr.html b/accessible/tests/mochitest/test_descr.html index 10ce77fc9fcb..ef9313b9cd2f 100644 --- a/accessible/tests/mochitest/test_descr.html +++ b/accessible/tests/mochitest/test_descr.html @@ -8,18 +8,10 @@ src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"> + + diff --git a/dom/tests/mochitest/chrome/test_DOM_element_instanceof.xul b/dom/tests/mochitest/chrome/test_DOM_element_instanceof.xul new file mode 100644 index 000000000000..220220420e9a --- /dev/null +++ b/dom/tests/mochitest/chrome/test_DOM_element_instanceof.xul @@ -0,0 +1,34 @@ + + + + + + + From 4bebfa7b67c94e59f3bf9ab13b5384b615c32c9b Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Mon, 31 Dec 2012 10:37:22 -0800 Subject: [PATCH 028/469] Bug 824824. Add support for passing multiple touches as arguments to createTouchList. r=mbrubeck,peterv --- content/base/public/nsIDocument.h | 4 +++- content/base/src/nsDocument.cpp | 13 ++++++++++++- dom/bindings/Codegen.py | 4 ++-- dom/webidl/Document.webidl | 11 ++++++++++- 4 files changed, 27 insertions(+), 5 deletions(-) diff --git a/content/base/public/nsIDocument.h b/content/base/public/nsIDocument.h index 969b64699dda..153ed3a873dc 100644 --- a/content/base/public/nsIDocument.h +++ b/content/base/public/nsIDocument.h @@ -1941,8 +1941,10 @@ public: int32_t aScreenX, int32_t aScreenY, int32_t aClientX, int32_t aClientY, int32_t aRadiusX, int32_t aRadiusY, float aRotationAngle, float aForce); + already_AddRefed CreateTouchList(); already_AddRefed - CreateTouchList(nsIDOMTouch* aTouch); + CreateTouchList(nsIDOMTouch* aTouch, + const mozilla::dom::Sequence >& aTouches); already_AddRefed CreateTouchList(const mozilla::dom::Sequence >& aTouches); diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp index b73942094e98..2fa181aac709 100644 --- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -8676,10 +8676,21 @@ nsDocument::CreateTouchList(nsIVariant* aPoints, } already_AddRefed -nsIDocument::CreateTouchList(nsIDOMTouch* aTouch) +nsIDocument::CreateTouchList() +{ + nsRefPtr retval = new nsDOMTouchList(); + return retval.forget(); +} + +already_AddRefed +nsIDocument::CreateTouchList(nsIDOMTouch* aTouch, + const Sequence >& aTouches) { nsRefPtr retval = new nsDOMTouchList(); retval->Append(aTouch); + for (uint32_t i = 0; i < aTouches.Length(); ++i) { + retval->Append(aTouches[i]); + } return retval.forget(); } diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index a78468bc194f..29393257dc15 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -3899,7 +3899,7 @@ class CGMethodCall(CGThing): # We can't handle unions at the distinguishing index. if distinguishingType(sig).isUnion(): raise TypeError("No support for unions as distinguishing " - "arguments yet: %s", + "arguments yet: %s" % distinguishingArgument(sig).location) # We don't support variadics as the distinguishingArgument yet. # If you want to add support, consider this case: @@ -3917,7 +3917,7 @@ class CGMethodCall(CGThing): # double-check. if distinguishingArgument(sig).variadic: raise TypeError("No support for variadics as distinguishing " - "arguments yet: %s", + "arguments yet: %s" % distinguishingArgument(sig).location) # Convert all our arguments up to the distinguishing index. diff --git a/dom/webidl/Document.webidl b/dom/webidl/Document.webidl index cf22970c9f04..d6ade7298eb3 100644 --- a/dom/webidl/Document.webidl +++ b/dom/webidl/Document.webidl @@ -443,8 +443,17 @@ partial interface Document { optional long radiusY = 0, optional float rotationAngle = 0, optional float force = 0); + // XXXbz a hack to get around the fact that we don't support variadics as + // distinguishing arguments yet. Once this hack is removed. we can also + // remove the corresponding overload on nsIDocument, since Touch... and + // sequence look the same in the C++. [Creator, Pref="dom.w3c_touch_events.expose"] - TouchList createTouchList(Touch touch); + TouchList createTouchList(Touch touch, Touch... touches); + // XXXbz and another hack for the fact that we can't usefully have optional + // distinguishing arguments but need a working zero-arg form of + // createTouchList(). + [Creator, Pref="dom.w3c_touch_events.expose"] + TouchList createTouchList(); [Creator, Pref="dom.w3c_touch_events.expose"] TouchList createTouchList(sequence touches); */ From 8afc4b19415710e378779c1e0d28dd99bd57014d Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Fri, 7 Dec 2012 14:02:39 -0500 Subject: [PATCH 029/469] Bug 819418 - part 1 - be more selective in exporting aggregate statistics; r=vdjeric --- ipc/chromium/src/base/histogram.cc | 19 ++++++---- ipc/chromium/src/base/histogram.h | 2 + toolkit/components/telemetry/Telemetry.cpp | 28 ++++++++------ toolkit/components/telemetry/TelemetryPing.js | 15 +++++--- .../tests/unit/test_TelemetryPing.js | 8 +--- .../telemetry/tests/unit/test_nsITelemetry.js | 37 ++++++++++++++----- 6 files changed, 69 insertions(+), 40 deletions(-) diff --git a/ipc/chromium/src/base/histogram.cc b/ipc/chromium/src/base/histogram.cc index 3c76eb444993..90da947926fd 100644 --- a/ipc/chromium/src/base/histogram.cc +++ b/ipc/chromium/src/base/histogram.cc @@ -723,25 +723,28 @@ void Histogram::SampleSet::CheckSize(const Histogram& histogram) const { DCHECK_EQ(histogram.bucket_count(), counts_.size()); } - -void Histogram::SampleSet::AccumulateWithLinearStats(Sample value, - Count count, - size_t index) { +void Histogram::SampleSet::Accumulate(Sample value, Count count, + size_t index) { DCHECK(count == 1 || count == -1); counts_[index] += count; - int64_t amount = static_cast(count) * value; - sum_ += amount; - sum_squares_ += amount * value; redundant_count_ += count; + sum_ += static_cast(count) * value; DCHECK_GE(counts_[index], 0); DCHECK_GE(sum_, 0); DCHECK_GE(redundant_count_, 0); } +void Histogram::SampleSet::AccumulateWithLinearStats(Sample value, + Count count, + size_t index) { + Accumulate(value, count, index); + sum_squares_ += static_cast(count) * value * value; +} + void Histogram::SampleSet::AccumulateWithExponentialStats(Sample value, Count count, size_t index) { - AccumulateWithLinearStats(value, count, index); + Accumulate(value, count, index); DCHECK_GE(value, 0); double value_log = log(static_cast(value) + 1); log_sum_ += count * value_log; diff --git a/ipc/chromium/src/base/histogram.h b/ipc/chromium/src/base/histogram.h index 0d7a7d959f50..5e0e9f83d665 100644 --- a/ipc/chromium/src/base/histogram.h +++ b/ipc/chromium/src/base/histogram.h @@ -374,6 +374,8 @@ class Histogram { double log_sum_squares_; // sum of squares of logs of samples private: + void Accumulate(Sample value, Count count, size_t index); + // Allow tests to corrupt our innards for testing purposes. FRIEND_TEST(HistogramTest, CorruptSampleCounts); diff --git a/toolkit/components/telemetry/Telemetry.cpp b/toolkit/components/telemetry/Telemetry.cpp index 30984afe5b7c..b19327be5c50 100644 --- a/toolkit/components/telemetry/Telemetry.cpp +++ b/toolkit/components/telemetry/Telemetry.cpp @@ -527,20 +527,26 @@ ReflectHistogramAndSamples(JSContext *cx, JSObject *obj, Histogram *h, if (!(JS_DefineProperty(cx, obj, "min", INT_TO_JSVAL(h->declared_min()), NULL, NULL, JSPROP_ENUMERATE) && JS_DefineProperty(cx, obj, "max", INT_TO_JSVAL(h->declared_max()), NULL, NULL, JSPROP_ENUMERATE) && JS_DefineProperty(cx, obj, "histogram_type", INT_TO_JSVAL(h->histogram_type()), NULL, NULL, JSPROP_ENUMERATE) - && JS_DefineProperty(cx, obj, "sum", DOUBLE_TO_JSVAL(ss.sum()), NULL, NULL, JSPROP_ENUMERATE) - && JS_DefineProperty(cx, obj, "log_sum", DOUBLE_TO_JSVAL(ss.log_sum()), NULL, NULL, JSPROP_ENUMERATE) - && JS_DefineProperty(cx, obj, "log_sum_squares", DOUBLE_TO_JSVAL(ss.log_sum_squares()), NULL, NULL, JSPROP_ENUMERATE))) { + && JS_DefineProperty(cx, obj, "sum", DOUBLE_TO_JSVAL(ss.sum()), NULL, NULL, JSPROP_ENUMERATE))) { return REFLECT_FAILURE; } - // Export |sum_squares| as two separate 32-bit properties so that we - // can accurately reconstruct it on the analysis side. - uint64_t sum_squares = ss.sum_squares(); - uint32_t lo = sum_squares; - uint32_t hi = sum_squares >> 32; - if (!(JS_DefineProperty(cx, obj, "sum_squares_lo", INT_TO_JSVAL(lo), NULL, NULL, JSPROP_ENUMERATE) - && JS_DefineProperty(cx, obj, "sum_squares_hi", INT_TO_JSVAL(hi), NULL, NULL, JSPROP_ENUMERATE))) { - return REFLECT_FAILURE; + if (h->histogram_type() == Histogram::HISTOGRAM) { + if (!(JS_DefineProperty(cx, obj, "log_sum", DOUBLE_TO_JSVAL(ss.log_sum()), NULL, NULL, JSPROP_ENUMERATE) + && JS_DefineProperty(cx, obj, "log_sum_squares", DOUBLE_TO_JSVAL(ss.log_sum_squares()), NULL, NULL, JSPROP_ENUMERATE))) { + return REFLECT_FAILURE; + } + } else { + // Export |sum_squares| as two separate 32-bit properties so that we + // can accurately reconstruct it on the analysis side. + uint64_t sum_squares = ss.sum_squares(); + // Cast to avoid implicit truncation warnings. + uint32_t lo = static_cast(sum_squares); + uint32_t hi = static_cast(sum_squares >> 32); + if (!(JS_DefineProperty(cx, obj, "sum_squares_lo", INT_TO_JSVAL(lo), NULL, NULL, JSPROP_ENUMERATE) + && JS_DefineProperty(cx, obj, "sum_squares_hi", INT_TO_JSVAL(hi), NULL, NULL, JSPROP_ENUMERATE))) { + return REFLECT_FAILURE; + } } const size_t count = h->bucket_count(); diff --git a/toolkit/components/telemetry/TelemetryPing.js b/toolkit/components/telemetry/TelemetryPing.js index 6b056cd176ca..4cdbe668aea3 100644 --- a/toolkit/components/telemetry/TelemetryPing.js +++ b/toolkit/components/telemetry/TelemetryPing.js @@ -255,12 +255,17 @@ TelemetryPing.prototype = { bucket_count: r.length, histogram_type: hgram.histogram_type, values: {}, - sum: hgram.sum, - sum_squares_lo: hgram.sum_squares_lo, - sum_squares_hi: hgram.sum_squares_hi, - log_sum: hgram.log_sum, - log_sum_squares: hgram.log_sum_squares + sum: hgram.sum }; + + if (hgram.histogram_type == Telemetry.HISTOGRAM_EXPONENTIAL) { + retgram.log_sum = hgram.log_sum; + retgram.log_sum_squares = hgram.log_sum_squares; + } else { + retgram.sum_squares_lo = hgram.sum_squares_lo; + retgram.sum_squares_hi = hgram.sum_squares_hi; + } + let first = true; let last = 0; diff --git a/toolkit/components/telemetry/tests/unit/test_TelemetryPing.js b/toolkit/components/telemetry/tests/unit/test_TelemetryPing.js index aa26d7629ba5..e50e3b2629e3 100644 --- a/toolkit/components/telemetry/tests/unit/test_TelemetryPing.js +++ b/toolkit/components/telemetry/tests/unit/test_TelemetryPing.js @@ -211,9 +211,7 @@ function checkPayload(request, reason, successfulPings) { values: {0:1, 1:0}, sum: 0, sum_squares_lo: 0, - sum_squares_hi: 0, - log_sum: 0, - log_sum_squares: 0 + sum_squares_hi: 0 }; let flag = payload.histograms[TELEMETRY_TEST_FLAG]; do_check_eq(uneval(flag), uneval(expected_flag)); @@ -226,9 +224,7 @@ function checkPayload(request, reason, successfulPings) { values: {0:1, 1:successfulPings, 2:0}, sum: successfulPings, sum_squares_lo: successfulPings, - sum_squares_hi: 0, - log_sum: 0, - log_sum_squares: 0 + sum_squares_hi: 0 }; let tc = payload.histograms[TELEMETRY_SUCCESS]; do_check_eq(uneval(tc), uneval(expected_tc)); diff --git a/toolkit/components/telemetry/tests/unit/test_nsITelemetry.js b/toolkit/components/telemetry/tests/unit/test_nsITelemetry.js index 86ab0319cf1f..6a66fe39753f 100644 --- a/toolkit/components/telemetry/tests/unit/test_nsITelemetry.js +++ b/toolkit/components/telemetry/tests/unit/test_nsITelemetry.js @@ -27,13 +27,20 @@ function test_histogram(histogram_type, name, min, max, bucket_count) { h.add(v); } var s = h.snapshot(); - // verify sum + // verify properties do_check_eq(sum, s.sum); - // Doing the math to verify sum_squares was reflected correctly is - // tedious in JavaScript. Just make sure we have something. - do_check_neq(s.sum_squares_lo + s.sum_squares_hi, 0); - do_check_eq(log_sum, s.log_sum); - do_check_eq(log_sum_squares, s.log_sum_squares); + if (histogram_type == Telemetry.HISTOGRAM_EXPONENTIAL) { + do_check_eq(log_sum, s.log_sum); + do_check_eq(log_sum_squares, s.log_sum_squares); + do_check_false("sum_squares_lo" in s); + do_check_false("sum_squares_hi" in s); + } else { + // Doing the math to verify sum_squares was reflected correctly is + // tedious in JavaScript. Just make sure we have something. + do_check_neq(s.sum_squares_lo + s.sum_squares_hi, 0); + do_check_false("log_sum" in s); + do_check_false("log_sum_squares" in s); + } // there should be exactly one element per bucket for each(var i in s.counts) { @@ -60,6 +67,13 @@ function test_histogram(histogram_type, name, min, max, bucket_count) { do_check_eq(i, 0); } do_check_eq(s.sum, 0); + if (histogram_type == Telemetry.HISTOGRAM_EXPONENTIAL) { + do_check_eq(s.log_sum, 0); + do_check_eq(s.log_sum_squares, 0); + } else { + do_check_eq(s.sum_squares_lo, 0); + do_check_eq(s.sum_squares_hi, 0); + } h.add(0); h.add(1); @@ -160,10 +174,13 @@ function compareHistograms(h1, h2) { do_check_eq(s1.min, s2.min); do_check_eq(s1.max, s2.max); do_check_eq(s1.sum, s2.sum); - do_check_eq(s1.sum_squares_lo, s2.sum_squares_lo); - do_check_eq(s1.sum_squares_hi, s2.sum_squares_hi); - do_check_eq(s1.log_sum, s2.log_sum); - do_check_eq(s1.log_sum_squares, s2.log_sum_squares); + if (s1.histogram_type == Telemetry.HISTOGRAM_EXPONENTIAL) { + do_check_eq(s1.log_sum, s2.log_sum); + do_check_eq(s1.log_sum_squares, s2.log_sum_squares); + } else { + do_check_eq(s1.sum_squares_lo, s2.sum_squares_lo); + do_check_eq(s1.sum_squares_hi, s2.sum_squares_hi); + } do_check_eq(s1.counts.length, s2.counts.length); for (let i = 0; i < s1.counts.length; i++) From 1760dbd495924cdb78fdc2f4f9d48e5f9787bb8a Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Mon, 31 Dec 2012 14:12:21 -0500 Subject: [PATCH 030/469] Bug 824349 - Make TelemetryPing correctly implement nsIObserver; r=froydnj --- toolkit/components/telemetry/TelemetryPing.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolkit/components/telemetry/TelemetryPing.js b/toolkit/components/telemetry/TelemetryPing.js index 4cdbe668aea3..56a4e265efad 100644 --- a/toolkit/components/telemetry/TelemetryPing.js +++ b/toolkit/components/telemetry/TelemetryPing.js @@ -1077,7 +1077,7 @@ TelemetryPing.prototype = { }, classID: Components.ID("{55d6a5fa-130e-4ee6-a158-0133af3b86ba}"), - QueryInterface: XPCOMUtils.generateQI([Ci.nsITelemetryPing]), + QueryInterface: XPCOMUtils.generateQI([Ci.nsITelemetryPing, Ci.nsIObserver]), }; this.NSGetFactory = XPCOMUtils.generateNSGetFactory([TelemetryPing]); From f4b7abb12c72b611b7c73aff2d5fccc9b82a44ce Mon Sep 17 00:00:00 2001 From: Josh Aas Date: Mon, 31 Dec 2012 14:16:57 -0500 Subject: [PATCH 031/469] Bug 822620: Disable Notification Center support for Firefox 19 and 20, it isn't ready. r=dougt --- toolkit/components/alerts/mac/nsMacAlertsService.mm | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/toolkit/components/alerts/mac/nsMacAlertsService.mm b/toolkit/components/alerts/mac/nsMacAlertsService.mm index 5c55cfcfb629..d4e61426444e 100644 --- a/toolkit/components/alerts/mac/nsMacAlertsService.mm +++ b/toolkit/components/alerts/mac/nsMacAlertsService.mm @@ -100,6 +100,9 @@ NS_INTERFACE_MAP_END_THREADSAFE nsresult nsMacAlertsService::Init() { + // Notification Center support isn't ready, don't use it. + return NS_ERROR_NOT_AVAILABLE; +/* NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; nsresult rv; @@ -126,6 +129,7 @@ nsMacAlertsService::Init() return rv; NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; +*/ } nsresult From f908ab3aa216fac29f90bace77a9f9f8b2736004 Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Wed, 26 Dec 2012 11:01:00 -0800 Subject: [PATCH 032/469] Bug 824581 - RemoteOpenFileChild::AsyncRemoteFileOpen crashes on Windows/Mac r=jduell --- modules/libjar/test/unit/xpcshell.ini | 2 +- netwerk/ipc/RemoteOpenFileChild.cpp | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/modules/libjar/test/unit/xpcshell.ini b/modules/libjar/test/unit/xpcshell.ini index 1dc4446df439..fe8a33c0cb7e 100644 --- a/modules/libjar/test/unit/xpcshell.ini +++ b/modules/libjar/test/unit/xpcshell.ini @@ -4,7 +4,7 @@ tail = [test_jarchannel.js] [test_jarchannel_e10s.js] -skip-if = os == "mac" || os == "win" +skip-if = os == "mac" [test_bug278262.js] [test_bug333423.js] [test_bug336691.js] diff --git a/netwerk/ipc/RemoteOpenFileChild.cpp b/netwerk/ipc/RemoteOpenFileChild.cpp index 9cddaf82ab4e..ecd9afc3a647 100644 --- a/netwerk/ipc/RemoteOpenFileChild.cpp +++ b/netwerk/ipc/RemoteOpenFileChild.cpp @@ -108,13 +108,11 @@ RemoteOpenFileChild::AsyncRemoteFileOpen(int32_t aFlags, } #if defined(XP_WIN) || defined(MOZ_WIDGET_COCOA) - // we do nothing on these platforms: we'll just open file locally when asked - // for NSPR handle - mListener->OnRemoteFileOpenComplete(NS_OK); - mListener = nullptr; + // Windows/OSX desktop builds skip remoting, and just open file in child + // process when asked for NSPR handle + aListener->OnRemoteFileOpenComplete(NS_OK); mAsyncOpenCalled = true; return NS_OK; - #else URIParams uri; SerializeURI(mURI, uri); From df09d6193c1f536102ba4dd6aa8a4e5d9e23ed28 Mon Sep 17 00:00:00 2001 From: Sriram Ramasubramanian Date: Fri, 28 Dec 2012 14:55:56 -0800 Subject: [PATCH 033/469] Bug 825088: Compound Drawable for addon-row in about:home. [r=mfinkle] --HG-- extra : rebase_source : 12a6f764e08608ceb2bcbe64733fc61750e5fc34 --- mobile/android/base/AboutHomeContent.java | 35 ++++++++++--- mobile/android/base/AboutHomeSection.java | 11 ++++ mobile/android/base/Makefile.in | 1 - .../resources/drawable/abouthome_divider.xml | 12 ----- .../resources/layout/abouthome_addon_row.xml | 52 ++++--------------- .../layout/abouthome_last_tabs_row.xml | 6 --- .../layout/abouthome_remote_tab_row.xml | 36 ++++--------- .../android/base/resources/values/dimens.xml | 1 + .../android/base/resources/values/styles.xml | 12 +++++ 9 files changed, 74 insertions(+), 92 deletions(-) delete mode 100644 mobile/android/base/resources/drawable/abouthome_divider.xml diff --git a/mobile/android/base/AboutHomeContent.java b/mobile/android/base/AboutHomeContent.java index 6fe664b99036..881556aedfbc 100644 --- a/mobile/android/base/AboutHomeContent.java +++ b/mobile/android/base/AboutHomeContent.java @@ -38,11 +38,15 @@ import android.graphics.Path; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; +import android.graphics.Rect; import android.graphics.RectF; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; import android.os.SystemClock; import android.text.SpannableString; import android.text.TextUtils; import android.text.style.StyleSpan; +import android.text.style.TextAppearanceSpan; import android.util.AttributeSet; import android.util.Log; import android.util.SparseArray; @@ -116,6 +120,9 @@ public class AboutHomeContent extends ScrollView private View.OnClickListener mRemoteTabClickListener; + private static Rect sIconBounds; + private static TextAppearanceSpan sSubTitleSpan; + public interface UriLoadCallback { public void callback(String uriSpec); } @@ -137,6 +144,10 @@ public class AboutHomeContent extends ScrollView } public void init() { + int iconSize = mContext.getResources().getDimensionPixelSize(R.dimen.abouthome_addon_icon_size); + sIconBounds = new Rect(0, 0, iconSize, iconSize); + sSubTitleSpan = new TextAppearanceSpan(mContext, R.style.AboutHome_TextAppearance_SubTitle); + inflate(); mAccountManager = AccountManager.get(mContext); @@ -583,10 +594,19 @@ public class AboutHomeContent extends ScrollView for (int i = 0; i < array.length(); i++) { JSONObject jsonobj = array.getJSONObject(i); + String name = jsonobj.getString("name"); + String version = jsonobj.getString("version"); + String text = name + " " + version; - final View row = mInflater.inflate(R.layout.abouthome_addon_row, mAddons.getItemsContainer(), false); - ((TextView) row.findViewById(R.id.addon_title)).setText(jsonobj.getString("name")); - ((TextView) row.findViewById(R.id.addon_version)).setText(jsonobj.getString("version")); + SpannableString spannable = new SpannableString(text); + spannable.setSpan(sSubTitleSpan, name.length() + 1, text.length(), 0); + + final TextView row = (TextView) mInflater.inflate(R.layout.abouthome_addon_row, mAddons.getItemsContainer(), false); + row.setText(spannable, TextView.BufferType.SPANNABLE); + + Drawable drawable = mContext.getResources().getDrawable(R.drawable.ic_addons_empty); + drawable.setBounds(sIconBounds); + row.setCompoundDrawables(drawable, null, null, null); String iconUrl = jsonobj.getString("iconURL"); String pageUrl = getPageUrlFromIconUrl(iconUrl); @@ -604,8 +624,9 @@ public class AboutHomeContent extends ScrollView new Favicons.OnFaviconLoadedListener() { public void onFaviconLoaded(String url, Bitmap favicon) { if (favicon != null) { - ImageView icon = (ImageView) row.findViewById(R.id.addon_icon); - icon.setImageBitmap(favicon); + Drawable drawable = new BitmapDrawable(favicon); + drawable.setBounds(sIconBounds); + row.setCompoundDrawables(drawable, null, null, null); } } }); @@ -716,8 +737,8 @@ public class AboutHomeContent extends ScrollView else if (!TextUtils.equals(client, tab.name)) break; - final RelativeLayout row = (RelativeLayout) mInflater.inflate(R.layout.abouthome_remote_tab_row, mRemoteTabs.getItemsContainer(), false); - ((TextView) row.findViewById(R.id.remote_tab_title)).setText(TextUtils.isEmpty(tab.title) ? tab.url : tab.title); + final TextView row = (TextView) mInflater.inflate(R.layout.abouthome_remote_tab_row, mRemoteTabs.getItemsContainer(), false); + row.setText(TextUtils.isEmpty(tab.title) ? tab.url : tab.title); row.setTag(tab.url); mRemoteTabs.addItem(row); row.setOnClickListener(mRemoteTabClickListener); diff --git a/mobile/android/base/AboutHomeSection.java b/mobile/android/base/AboutHomeSection.java index dcbbb674289c..9094ea517f13 100644 --- a/mobile/android/base/AboutHomeSection.java +++ b/mobile/android/base/AboutHomeSection.java @@ -77,6 +77,7 @@ public class AboutHomeSection extends GeckoLinearLayout { public void addItem(View item) { mItemsContainer.addView(item); + mItemsContainer.addView(new Divider(getContext(), null)); } public void clear() { @@ -98,4 +99,14 @@ public class AboutHomeSection extends GeckoLinearLayout { public void hideMoreText() { mMoreText.setVisibility(View.GONE); } + + private class Divider extends View { + public Divider(Context context, AttributeSet attrs) { + super(context, attrs); + + setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, + (int) context.getResources().getDisplayMetrics().density)); + setBackgroundColor(0x3460666E); + } + } } diff --git a/mobile/android/base/Makefile.in b/mobile/android/base/Makefile.in index 7471d538fd23..20773ee862b9 100644 --- a/mobile/android/base/Makefile.in +++ b/mobile/android/base/Makefile.in @@ -1031,7 +1031,6 @@ MOZ_ANDROID_DRAWABLES += \ $(SYNC_RES_DRAWABLE) \ mobile/android/base/resources/drawable/abouthome_bg_repeat.xml \ mobile/android/base/resources/drawable/abouthome_bg_pb_repeat.xml \ - mobile/android/base/resources/drawable/abouthome_divider.xml \ mobile/android/base/resources/drawable/abouthome_promo_box.xml \ mobile/android/base/resources/drawable/action_bar_button.xml \ mobile/android/base/resources/drawable/address_bar_bg_normal.xml \ diff --git a/mobile/android/base/resources/drawable/abouthome_divider.xml b/mobile/android/base/resources/drawable/abouthome_divider.xml deleted file mode 100644 index 59a18b496278..000000000000 --- a/mobile/android/base/resources/drawable/abouthome_divider.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - android:shape="rectangle"> - - - - - diff --git a/mobile/android/base/resources/layout/abouthome_addon_row.xml b/mobile/android/base/resources/layout/abouthome_addon_row.xml index 58ea54cdad59..3cb5b88563cc 100644 --- a/mobile/android/base/resources/layout/abouthome_addon_row.xml +++ b/mobile/android/base/resources/layout/abouthome_addon_row.xml @@ -3,44 +3,14 @@ - 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/. --> - - - - - - - - - - - + diff --git a/mobile/android/base/resources/layout/abouthome_last_tabs_row.xml b/mobile/android/base/resources/layout/abouthome_last_tabs_row.xml index 77edfd01e697..599466297023 100644 --- a/mobile/android/base/resources/layout/abouthome_last_tabs_row.xml +++ b/mobile/android/base/resources/layout/abouthome_last_tabs_row.xml @@ -3,7 +3,6 @@ - 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/. --> - - - diff --git a/mobile/android/base/resources/layout/abouthome_remote_tab_row.xml b/mobile/android/base/resources/layout/abouthome_remote_tab_row.xml index 1e243a308389..4dcf194e434c 100644 --- a/mobile/android/base/resources/layout/abouthome_remote_tab_row.xml +++ b/mobile/android/base/resources/layout/abouthome_remote_tab_row.xml @@ -3,28 +3,14 @@ - 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/. --> - - - - - - - + diff --git a/mobile/android/base/resources/values/dimens.xml b/mobile/android/base/resources/values/dimens.xml index a824e34b146c..3923cadde8d5 100644 --- a/mobile/android/base/resources/values/dimens.xml +++ b/mobile/android/base/resources/values/dimens.xml @@ -5,6 +5,7 @@ + 32dp 110dp 0dp 0dp diff --git a/mobile/android/base/resources/values/styles.xml b/mobile/android/base/resources/values/styles.xml index c45188cf3121..170970712f04 100644 --- a/mobile/android/base/resources/values/styles.xml +++ b/mobile/android/base/resources/values/styles.xml @@ -256,4 +256,16 @@ center|left + + + + From 6798b3d00b93e4b395cc882a787133acd27202a1 Mon Sep 17 00:00:00 2001 From: Steve Fink Date: Tue, 18 Dec 2012 17:33:25 -0800 Subject: [PATCH 034/469] Bug 822831 - Do not use Unrooted in a signal handler. r=billm Landing attempt #2. Some excessively picky people seem to insist that it should successfully compile. --HG-- extra : rebase_source : 4669fa2322638b06a1c75bee0bbdc2f4479c1cff --- js/src/jsdbgapi.cpp | 2 +- js/src/jsdbgapi.h | 3 ++- js/src/jsfriendapi.h | 4 +++- js/src/vm/SPSProfiler.cpp | 4 +++- js/src/vm/SPSProfiler.h | 4 ++-- 5 files changed, 11 insertions(+), 6 deletions(-) diff --git a/js/src/jsdbgapi.cpp b/js/src/jsdbgapi.cpp index 2ed549c18869..c2efc7735a37 100644 --- a/js/src/jsdbgapi.cpp +++ b/js/src/jsdbgapi.cpp @@ -326,7 +326,7 @@ JS_ClearAllWatchPoints(JSContext *cx) /************************************************************************/ JS_PUBLIC_API(unsigned) -JS_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc) +JS_PCToLineNumber(JSContext *cx, RawScript script, jsbytecode *pc) { return js::PCToLineNumber(script, pc); } diff --git a/js/src/jsdbgapi.h b/js/src/jsdbgapi.h index 5f4d68dd4673..dab791593853 100644 --- a/js/src/jsdbgapi.h +++ b/js/src/jsdbgapi.h @@ -141,8 +141,9 @@ JS_ClearAllWatchPoints(JSContext *cx); /************************************************************************/ +// RawScript because this needs to be callable from a signal handler extern JS_PUBLIC_API(unsigned) -JS_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc); +JS_PCToLineNumber(JSContext *cx, js::RawScript script, jsbytecode *pc); extern JS_PUBLIC_API(jsbytecode *) JS_LineNumberToPC(JSContext *cx, JSScript *script, unsigned lineno); diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h index 4d66c77cecf1..37cff1e06508 100644 --- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -684,8 +684,10 @@ SetRuntimeProfilingStack(JSRuntime *rt, ProfileEntry *stack, uint32_t *size, JS_FRIEND_API(void) EnableRuntimeProfilingStack(JSRuntime *rt, bool enabled); +// Use RawScript rather than UnrootedScript because it may be called from a +// signal handler JS_FRIEND_API(jsbytecode*) -ProfilingGetPC(JSRuntime *rt, JSScript *script, void *ip); +ProfilingGetPC(JSRuntime *rt, RawScript script, void *ip); #ifdef JS_THREADSAFE JS_FRIEND_API(void *) diff --git a/js/src/vm/SPSProfiler.cpp b/js/src/vm/SPSProfiler.cpp index 259d29acbc9a..600761d17791 100644 --- a/js/src/vm/SPSProfiler.cpp +++ b/js/src/vm/SPSProfiler.cpp @@ -223,8 +223,10 @@ JMChunkInfo::JMChunkInfo(mjit::JSActiveFrame *frame, chunk(chunk) {} +// Use RawScript instead of UnrootedScript because this may be called from a +// signal handler jsbytecode* -SPSProfiler::ipToPC(UnrootedScript script, size_t ip) +SPSProfiler::ipToPC(RawScript script, size_t ip) { if (!jminfo.initialized()) return NULL; diff --git a/js/src/vm/SPSProfiler.h b/js/src/vm/SPSProfiler.h index 91d1a9adc232..5362d0738462 100644 --- a/js/src/vm/SPSProfiler.h +++ b/js/src/vm/SPSProfiler.h @@ -234,7 +234,7 @@ class SPSProfiler mjit::JITChunk *chunk, void* address); bool registerICCode(mjit::JITChunk *chunk, UnrootedScript script, jsbytecode* pc, void *start, size_t size); - jsbytecode *ipToPC(UnrootedScript script, size_t ip); + jsbytecode *ipToPC(RawScript script, size_t ip); private: JMChunkInfo *registerScript(mjit::JSActiveFrame *frame, @@ -243,7 +243,7 @@ class SPSProfiler void unregisterScript(UnrootedScript script, mjit::JITChunk *chunk); public: #else - jsbytecode *ipToPC(UnrootedScript script, size_t ip) { return NULL; } + jsbytecode *ipToPC(RawScript script, size_t ip) { return NULL; } #endif void setProfilingStack(ProfileEntry *stack, uint32_t *size, uint32_t max); From 76707515b7564ac35c5b31734a14e44c52437bae Mon Sep 17 00:00:00 2001 From: Andrew McCreight Date: Mon, 31 Dec 2012 15:54:37 -0500 Subject: [PATCH 035/469] Bug 821371, part 1 - Don't finish GC when CCTimerFired calls CycleCollectNow. r=smaug --- dom/base/nsJSEnvironment.cpp | 33 +++++++++++++++++++----------- js/xpconnect/src/XPCComponents.cpp | 2 +- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/dom/base/nsJSEnvironment.cpp b/dom/base/nsJSEnvironment.cpp index 0d2cddc78cb4..a10ca6903083 100644 --- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -3064,10 +3064,21 @@ DoMergingCC(bool aForced) } +static void +FinishAnyIncrementalGC() +{ + if (sCCLockedOut) { + // We're in the middle of an incremental GC, so finish it. + js::PrepareForIncrementalGC(nsJSRuntime::sRuntime); + js::FinishIncrementalGC(nsJSRuntime::sRuntime, js::gcreason::CC_FORCED); + } +} + static void FireForgetSkippable(uint32_t aSuspected, bool aRemoveChildless) { PRTime startTime = PR_Now(); + FinishAnyIncrementalGC(); nsCycleCollector_forgetSkippable(aRemoveChildless); sPreviousSuspectedCount = nsCycleCollector_suspectedCount(); ++sCleanupsSinceLastGC; @@ -3093,11 +3104,7 @@ nsJSContext::CycleCollectNow(nsICycleCollectorListener *aListener, return; } - if (sCCLockedOut) { - // We're in the middle of an incremental GC; finish it first - js::PrepareForIncrementalGC(nsJSRuntime::sRuntime); - js::FinishIncrementalGC(nsJSRuntime::sRuntime, js::gcreason::CC_FORCED); - } + FinishAnyIncrementalGC(); SAMPLE_LABEL("GC", "CycleCollectNow"); @@ -3289,10 +3296,6 @@ CCTimerFired(nsITimer *aTimer, void *aClosure) if (now - sCCLockedOutTime < NS_MAX_CC_LOCKEDOUT_TIME) { return; } - - // Finish the current incremental GC - js::PrepareForIncrementalGC(nsJSRuntime::sRuntime); - js::FinishIncrementalGC(nsJSRuntime::sRuntime, js::gcreason::CC_FORCED); } ++sCCTimerFireCount; @@ -3309,18 +3312,24 @@ CCTimerFired(nsITimer *aTimer, void *aClosure) if (ShouldTriggerCC(nsCycleCollector_suspectedCount())) { // Our efforts to avoid a CC have failed, so we return to let the // timer fire once more to trigger a CC. + MOZ_ASSERT(!sCCLockedOut); return; } } else { // We are in the final timer fire and still meet the conditions for - // triggering a CC. + // triggering a CC. Let CycleCollectNow finish the current IGC, if any, + // because that will allow us to include the GC time in the CC pause. nsJSContext::CycleCollectNow(nullptr, 0, false); } } else if ((sPreviousSuspectedCount + 100) <= suspected) { - // Only do a forget skippable if there are more than a few new objects. - FireForgetSkippable(suspected, false); + // Only do a forget skippable if there are more than a few new objects. + FireForgetSkippable(suspected, false); } + // If we were in the middle of an incremental GC, we should have finished + // it by now. + MOZ_ASSERT(!sCCLockedOut); + if (isLateTimerFire) { ccDelay = NS_CC_DELAY; diff --git a/js/xpconnect/src/XPCComponents.cpp b/js/xpconnect/src/XPCComponents.cpp index bdf10bccc744..20b226713c6c 100644 --- a/js/xpconnect/src/XPCComponents.cpp +++ b/js/xpconnect/src/XPCComponents.cpp @@ -4046,7 +4046,7 @@ nsXPCComponents_Utils::ForceGC() NS_IMETHODIMP nsXPCComponents_Utils::ForceCC() { - nsJSContext::CycleCollectNow(nullptr, 0); + nsJSContext::CycleCollectNow(); return NS_OK; } From da9e73dec3699ce5cbc36d650ddbad3b546ad40a Mon Sep 17 00:00:00 2001 From: Andrew McCreight Date: Mon, 31 Dec 2012 15:55:07 -0500 Subject: [PATCH 036/469] Bug 821371, part 2 - Log time taken for cycle collector prep. r=smaug --- dom/base/nsJSEnvironment.cpp | 60 +++++++++++++++----- toolkit/components/telemetry/Histograms.json | 14 +++++ 2 files changed, 59 insertions(+), 15 deletions(-) diff --git a/dom/base/nsJSEnvironment.cpp b/dom/base/nsJSEnvironment.cpp index a10ca6903083..2d5bafb4b3a1 100644 --- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -3094,6 +3094,14 @@ FireForgetSkippable(uint32_t aSuspected, bool aRemoveChildless) ++sForgetSkippableBeforeCC; } +MOZ_ALWAYS_INLINE +static uint32_t +TimeBetween(PRTime start, PRTime end) +{ + MOZ_ASSERT(end >= start); + return (uint32_t)(end - start) / PR_USEC_PER_MSEC; +} + //static void nsJSContext::CycleCollectNow(nsICycleCollectorListener *aListener, @@ -3104,29 +3112,40 @@ nsJSContext::CycleCollectNow(nsICycleCollectorListener *aListener, return; } - FinishAnyIncrementalGC(); - - SAMPLE_LABEL("GC", "CycleCollectNow"); - - KillCCTimer(); + SAMPLE_LABEL("CC", "CycleCollectNow"); PRTime start = PR_Now(); - uint32_t suspected = nsCycleCollector_suspectedCount(); + // Before we begin the cycle collection, make sure there is no active GC. + bool finishedIGC = sCCLockedOut; + FinishAnyIncrementalGC(); + PRTime endGCTime = PR_Now(); + uint32_t gcDuration = TimeBetween(start, endGCTime); - // nsCycleCollector_forgetSkippable may mark some gray js to black. + KillCCTimer(); + + uint32_t suspected = nsCycleCollector_suspectedCount(); + bool ranSyncForgetSkippable = false; + + // Run forgetSkippable synchronously to reduce the size of the CC graph. This + // is particularly useful if we recently finished a GC. if (sCleanupsSinceLastGC < 2 && aExtraForgetSkippableCalls >= 0) { while (sCleanupsSinceLastGC < 2) { FireForgetSkippable(nsCycleCollector_suspectedCount(), false); + ranSyncForgetSkippable = true; } } for (int32_t i = 0; i < aExtraForgetSkippableCalls; ++i) { FireForgetSkippable(nsCycleCollector_suspectedCount(), false); + ranSyncForgetSkippable = true; } - bool mergingCC = DoMergingCC(aForced); + PRTime endSkippableTime = PR_Now(); + uint32_t skippableDuration = TimeBetween(endGCTime, endSkippableTime); + // Prepare to actually run the CC. + bool mergingCC = DoMergingCC(aForced); nsCycleCollectorResults ccResults; nsCycleCollector_collect(mergingCC, &ccResults, aListener); sCCollectedWaitingForGC += ccResults.mFreedRefCounted + ccResults.mFreedGCed; @@ -3137,13 +3156,19 @@ nsJSContext::CycleCollectNow(nsICycleCollectorListener *aListener, PokeGC(js::gcreason::CC_WAITING); } - PRTime now = PR_Now(); + PRTime endCCTime = PR_Now(); + + // Log information about the CC via telemetry, JSON and the console. + uint32_t ccNowDuration = TimeBetween(start, endCCTime); + Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_FINISH_IGC, finishedIGC); + Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_SYNC_SKIPPABLE, ranSyncForgetSkippable); + Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_FULL, ccNowDuration); if (sLastCCEndTime) { uint32_t timeBetween = (uint32_t)(start - sLastCCEndTime) / PR_USEC_PER_SEC; Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_TIME_BETWEEN, timeBetween); } - sLastCCEndTime = now; + sLastCCEndTime = endCCTime; Telemetry::Accumulate(Telemetry::FORGET_SKIPPABLE_MAX, sMaxForgetSkippableTime / PR_USEC_PER_MSEC); @@ -3167,10 +3192,10 @@ nsJSContext::CycleCollectNow(nsICycleCollectorListener *aListener, NS_NAMED_MULTILINE_LITERAL_STRING(kFmt, NS_LL("CC(T+%.1f) duration: %llums, suspected: %lu, visited: %lu RCed and %lu%s GCed, collected: %lu RCed and %lu GCed (%lu waiting for GC)%s\n") - NS_LL("ForgetSkippable %lu times before CC, min: %lu ms, max: %lu ms, avg: %lu ms, total: %lu ms, removed: %lu")); + NS_LL("ForgetSkippable %lu times before CC, min: %lu ms, max: %lu ms, avg: %lu ms, total: %lu ms, sync: %lu ms, removed: %lu")); nsString msg; msg.Adopt(nsTextFormatter::smprintf(kFmt.get(), double(delta) / PR_USEC_PER_SEC, - (now - start) / PR_USEC_PER_MSEC, suspected, + ccNowDuration, suspected, ccResults.mVisitedRefCounted, ccResults.mVisitedGCed, mergeMsg.get(), ccResults.mFreedRefCounted, ccResults.mFreedGCed, sCCollectedWaitingForGC, gcMsg.get(), @@ -3180,7 +3205,7 @@ nsJSContext::CycleCollectNow(nsICycleCollectorListener *aListener, (sTotalForgetSkippableTime / cleanups) / PR_USEC_PER_MSEC, sTotalForgetSkippableTime / PR_USEC_PER_MSEC, - sRemovedPurples)); + skippableDuration, sRemovedPurples)); nsCOMPtr cs = do_GetService(NS_CONSOLESERVICE_CONTRACTID); if (cs) { @@ -3192,6 +3217,8 @@ nsJSContext::CycleCollectNow(nsICycleCollectorListener *aListener, NS_NAMED_MULTILINE_LITERAL_STRING(kJSONFmt, NS_LL("{ \"timestamp\": %llu, ") NS_LL("\"duration\": %llu, ") + NS_LL("\"finish_gc_duration\": %llu, ") + NS_LL("\"sync_skippable_duration\": %llu, ") NS_LL("\"suspected\": %lu, ") NS_LL("\"visited\": { ") NS_LL("\"RCed\": %lu, ") @@ -3210,8 +3237,9 @@ nsJSContext::CycleCollectNow(nsICycleCollectorListener *aListener, NS_LL("\"removed\": %lu } ") NS_LL("}")); nsString json; - json.Adopt(nsTextFormatter::smprintf(kJSONFmt.get(), - now, (now - start) / PR_USEC_PER_MSEC, suspected, + json.Adopt(nsTextFormatter::smprintf(kJSONFmt.get(), endCCTime, + ccNowDuration, gcDuration, skippableDuration, + suspected, ccResults.mVisitedRefCounted, ccResults.mVisitedGCed, ccResults.mFreedRefCounted, ccResults.mFreedGCed, sCCollectedWaitingForGC, @@ -3228,6 +3256,8 @@ nsJSContext::CycleCollectNow(nsICycleCollectorListener *aListener, observerService->NotifyObservers(nullptr, "cycle-collection-statistics", json.get()); } } + + // Update global state to indicate we have just run a cycle collection. sMinForgetSkippableTime = UINT32_MAX; sMaxForgetSkippableTime = 0; sTotalForgetSkippableTime = 0; diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index d8915ce4c817..3b91d2e6096b 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -28,6 +28,20 @@ "n_buckets": 50, "description": "Time spent on one cycle collection (ms)" }, + "CYCLE_COLLECTOR_FULL": { + "kind": "exponential", + "high": "10000", + "n_buckets": 50, + "description": "Full pause time for one cycle collection, including preparation (ms)" + }, + "CYCLE_COLLECTOR_FINISH_IGC": { + "kind": "boolean", + "description": "Cycle collection finished an incremental GC" + }, + "CYCLE_COLLECTOR_SYNC_SKIPPABLE": { + "kind": "boolean", + "description": "Cycle collection synchronously ran forget skippable" + }, "CYCLE_COLLECTOR_VISITED_REF_COUNTED": { "kind": "exponential", "high": "300000", From fac46bef15d10f270fcc0bca7f186da031044b06 Mon Sep 17 00:00:00 2001 From: Andrew McCreight Date: Mon, 31 Dec 2012 17:03:54 -0500 Subject: [PATCH 037/469] Bug 821371, part 3: Remove bogus asserts. r=bustage --- dom/base/nsJSEnvironment.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/dom/base/nsJSEnvironment.cpp b/dom/base/nsJSEnvironment.cpp index 2d5bafb4b3a1..60f46d4c360b 100644 --- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -3342,7 +3342,6 @@ CCTimerFired(nsITimer *aTimer, void *aClosure) if (ShouldTriggerCC(nsCycleCollector_suspectedCount())) { // Our efforts to avoid a CC have failed, so we return to let the // timer fire once more to trigger a CC. - MOZ_ASSERT(!sCCLockedOut); return; } } else { @@ -3356,10 +3355,6 @@ CCTimerFired(nsITimer *aTimer, void *aClosure) FireForgetSkippable(suspected, false); } - // If we were in the middle of an incremental GC, we should have finished - // it by now. - MOZ_ASSERT(!sCCLockedOut); - if (isLateTimerFire) { ccDelay = NS_CC_DELAY; From 5cd17e7cdaa52e2f1a6d8d8e4ff2345eae908cba Mon Sep 17 00:00:00 2001 From: Randell Jesup Date: Mon, 31 Dec 2012 18:12:12 -0500 Subject: [PATCH 038/469] Bug 811757: Allow the user to explicitly share devices between tabs r=anant --- content/media/webrtc/MediaEngine.h | 14 ++- content/media/webrtc/MediaEngineDefault.cpp | 12 +- content/media/webrtc/MediaEngineDefault.h | 14 ++- content/media/webrtc/MediaEngineWebRTC.h | 20 ++- .../media/webrtc/MediaEngineWebRTCAudio.cpp | 119 +++++++++++------- .../media/webrtc/MediaEngineWebRTCVideo.cpp | 88 +++++++------ dom/media/MediaManager.cpp | 16 +-- dom/media/MediaManager.h | 25 ++-- 8 files changed, 182 insertions(+), 126 deletions(-) diff --git a/content/media/webrtc/MediaEngine.h b/content/media/webrtc/MediaEngine.h index 391f17a9dbd5..ce66ba11aa04 100644 --- a/content/media/webrtc/MediaEngine.h +++ b/content/media/webrtc/MediaEngine.h @@ -28,6 +28,12 @@ enum MediaEngineState { kReleased }; +// We only support 1 audio and 1 video track for now. +enum { + kVideoTrack = 1, + kAudioTrack = 2 +}; + class MediaEngine { public: @@ -74,10 +80,14 @@ public: virtual nsresult Snapshot(uint32_t aDuration, nsIDOMFile** aFile) = 0; /* Called when the stream wants more data */ - virtual void NotifyPull(MediaStreamGraph* aGraph, StreamTime aDesiredTime) = 0; + virtual void NotifyPull(MediaStreamGraph* aGraph, + SourceMediaStream *aSource, + TrackID aId, + StreamTime aDesiredTime, + TrackTicks &aLastEndTime) = 0; /* Stop the device and release the corresponding MediaStream */ - virtual nsresult Stop() = 0; + virtual nsresult Stop(SourceMediaStream *aSource, TrackID aID) = 0; /* Return false if device is currently allocated or started */ bool IsAvailable() { diff --git a/content/media/webrtc/MediaEngineDefault.cpp b/content/media/webrtc/MediaEngineDefault.cpp index 2daf48f5f0f8..be9a3c6050e0 100644 --- a/content/media/webrtc/MediaEngineDefault.cpp +++ b/content/media/webrtc/MediaEngineDefault.cpp @@ -168,7 +168,7 @@ MediaEngineDefaultVideoSource::Start(SourceMediaStream* aStream, TrackID aID) } nsresult -MediaEngineDefaultVideoSource::Stop() +MediaEngineDefaultVideoSource::Stop(SourceMediaStream *aSource, TrackID aID) { if (mState != kStarted) { return NS_ERROR_FAILURE; @@ -180,8 +180,8 @@ MediaEngineDefaultVideoSource::Stop() mTimer->Cancel(); mTimer = NULL; - mSource->EndTrack(mTrackID); - mSource->Finish(); + aSource->EndTrack(aID); + aSource->Finish(); mState = kStopped; return NS_OK; @@ -353,7 +353,7 @@ MediaEngineDefaultAudioSource::Start(SourceMediaStream* aStream, TrackID aID) } nsresult -MediaEngineDefaultAudioSource::Stop() +MediaEngineDefaultAudioSource::Stop(SourceMediaStream *aSource, TrackID aID) { if (mState != kStarted) { return NS_ERROR_FAILURE; @@ -365,8 +365,8 @@ MediaEngineDefaultAudioSource::Stop() mTimer->Cancel(); mTimer = NULL; - mSource->EndTrack(mTrackID); - mSource->Finish(); + aSource->EndTrack(aID); + aSource->Finish(); mState = kStopped; return NS_OK; diff --git a/content/media/webrtc/MediaEngineDefault.h b/content/media/webrtc/MediaEngineDefault.h index 4b0b9bd77e03..e34b7b1b95d1 100644 --- a/content/media/webrtc/MediaEngineDefault.h +++ b/content/media/webrtc/MediaEngineDefault.h @@ -42,9 +42,14 @@ public: virtual nsresult Allocate(); virtual nsresult Deallocate(); virtual nsresult Start(SourceMediaStream*, TrackID); - virtual nsresult Stop(); + virtual nsresult Stop(SourceMediaStream*, TrackID); virtual nsresult Snapshot(uint32_t aDuration, nsIDOMFile** aFile); virtual void NotifyPull(MediaStreamGraph* aGraph, StreamTime aDesiredTime); + virtual void NotifyPull(MediaStreamGraph* aGraph, + SourceMediaStream *aSource, + TrackID aId, + StreamTime aDesiredTime, + TrackTicks &aLastEndTime) {} NS_DECL_ISUPPORTS NS_DECL_NSITIMERCALLBACK @@ -79,9 +84,14 @@ public: virtual nsresult Allocate(); virtual nsresult Deallocate(); virtual nsresult Start(SourceMediaStream*, TrackID); - virtual nsresult Stop(); + virtual nsresult Stop(SourceMediaStream*, TrackID); virtual nsresult Snapshot(uint32_t aDuration, nsIDOMFile** aFile); virtual void NotifyPull(MediaStreamGraph* aGraph, StreamTime aDesiredTime); + virtual void NotifyPull(MediaStreamGraph* aGraph, + SourceMediaStream *aSource, + TrackID aId, + StreamTime aDesiredTime, + TrackTicks &aLastEndTime) {} NS_DECL_ISUPPORTS NS_DECL_NSITIMERCALLBACK diff --git a/content/media/webrtc/MediaEngineWebRTC.h b/content/media/webrtc/MediaEngineWebRTC.h index 627cdbd6cb65..67f662ae68f7 100644 --- a/content/media/webrtc/MediaEngineWebRTC.h +++ b/content/media/webrtc/MediaEngineWebRTC.h @@ -88,9 +88,13 @@ public: virtual nsresult Allocate(); virtual nsresult Deallocate(); virtual nsresult Start(SourceMediaStream*, TrackID); - virtual nsresult Stop(); + virtual nsresult Stop(SourceMediaStream*, TrackID); virtual nsresult Snapshot(uint32_t aDuration, nsIDOMFile** aFile); - virtual void NotifyPull(MediaStreamGraph* aGraph, StreamTime aDesiredTime); + virtual void NotifyPull(MediaStreamGraph* aGraph, + SourceMediaStream *aSource, + TrackID aId, + StreamTime aDesiredTime, + TrackTicks &aLastEndTime); NS_DECL_ISUPPORTS @@ -136,7 +140,7 @@ private: TrackTicks mLastEndTime; mozilla::ReentrantMonitor mMonitor; // Monitor for processing WebRTC frames. - SourceMediaStream* mSource; + nsTArray mSources; // When this goes empty, we shut down HW int mFps; // Track rate (30 fps by default) int mMinFps; // Min rate we want to accept @@ -184,9 +188,13 @@ public: virtual nsresult Allocate(); virtual nsresult Deallocate(); virtual nsresult Start(SourceMediaStream*, TrackID); - virtual nsresult Stop(); + virtual nsresult Stop(SourceMediaStream*, TrackID); virtual nsresult Snapshot(uint32_t aDuration, nsIDOMFile** aFile); - virtual void NotifyPull(MediaStreamGraph* aGraph, StreamTime aDesiredTime); + virtual void NotifyPull(MediaStreamGraph* aGraph, + SourceMediaStream *aSource, + TrackID aId, + StreamTime aDesiredTime, + TrackTicks &aLastEndTime); // VoEMediaProcess. void Process(const int channel, const webrtc::ProcessingTypes type, @@ -208,6 +216,7 @@ private: webrtc::VoENetwork* mVoENetwork; mozilla::ReentrantMonitor mMonitor; + nsTArray mSources; // When this goes empty, we shut down HW int mCapIndex; int mChannel; @@ -217,7 +226,6 @@ private: nsString mDeviceName; nsString mDeviceUUID; - SourceMediaStream* mSource; NullTransport *mNullTransport; }; diff --git a/content/media/webrtc/MediaEngineWebRTCAudio.cpp b/content/media/webrtc/MediaEngineWebRTCAudio.cpp index 06fe47edb4ff..09c2a9798ced 100644 --- a/content/media/webrtc/MediaEngineWebRTCAudio.cpp +++ b/content/media/webrtc/MediaEngineWebRTCAudio.cpp @@ -49,52 +49,60 @@ MediaEngineWebRTCAudioSource::GetUUID(nsAString& aUUID) nsresult MediaEngineWebRTCAudioSource::Allocate() { - if (mState != kReleased) { - return NS_ERROR_FAILURE; + if (mState == kReleased && mInitDone) { + webrtc::VoEHardware* ptrVoEHw = webrtc::VoEHardware::GetInterface(mVoiceEngine); + int res = ptrVoEHw->SetRecordingDevice(mCapIndex); + ptrVoEHw->Release(); + if (res) { + return NS_ERROR_FAILURE; + } + mState = kAllocated; + LOG(("Audio device %d allocated", mCapIndex)); + } else if (mSources.IsEmpty()) { + LOG(("Audio device %d reallocated", mCapIndex)); + } else { + LOG(("Audio device %d allocated shared", mCapIndex)); } - - webrtc::VoEHardware* ptrVoEHw = webrtc::VoEHardware::GetInterface(mVoiceEngine); - int res = ptrVoEHw->SetRecordingDevice(mCapIndex); - ptrVoEHw->Release(); - if (res) { - return NS_ERROR_FAILURE; - } - - LOG(("Audio device %d allocated", mCapIndex)); - mState = kAllocated; return NS_OK; } nsresult MediaEngineWebRTCAudioSource::Deallocate() { - if (mState != kStopped && mState != kAllocated) { - return NS_ERROR_FAILURE; - } + if (mSources.IsEmpty()) { + if (mState != kStopped && mState != kAllocated) { + return NS_ERROR_FAILURE; + } - mState = kReleased; + mState = kReleased; + LOG(("Audio device %d deallocated", mCapIndex)); + } else { + LOG(("Audio device %d deallocated but still in use", mCapIndex)); + } return NS_OK; } nsresult MediaEngineWebRTCAudioSource::Start(SourceMediaStream* aStream, TrackID aID) { - if (!mInitDone || mState != kAllocated) { - return NS_ERROR_FAILURE; - } - if (!aStream) { + if (!mInitDone || !aStream) { return NS_ERROR_FAILURE; } - mSource = aStream; + mSources.AppendElement(aStream); AudioSegment* segment = new AudioSegment(); segment->Init(CHANNELS); - mSource->AddTrack(aID, SAMPLE_FREQUENCY, 0, segment); - mSource->AdvanceKnownTracksTime(STREAM_TIME_MAX); + aStream->AddTrack(aID, SAMPLE_FREQUENCY, 0, segment); + aStream->AdvanceKnownTracksTime(STREAM_TIME_MAX); LOG(("Initial audio")); mTrackID = aID; + if (mState == kStarted) { + return NS_OK; + } + mState = kStarted; + if (mVoEBase->StartReceive(mChannel)) { return NS_ERROR_FAILURE; } @@ -105,13 +113,19 @@ MediaEngineWebRTCAudioSource::Start(SourceMediaStream* aStream, TrackID aID) // Attach external media processor, so this::Process will be called. mVoERender->RegisterExternalMediaProcessing(mChannel, webrtc::kRecordingPerChannel, *this); - mState = kStarted; return NS_OK; } nsresult -MediaEngineWebRTCAudioSource::Stop() +MediaEngineWebRTCAudioSource::Stop(SourceMediaStream *aSource, TrackID aID) { + if (!mSources.RemoveElement(aSource)) { + // Already stopped - this is allowed + return NS_OK; + } + if (!mSources.IsEmpty()) { + return NS_OK; + } if (mState != kStarted) { return NS_ERROR_FAILURE; } @@ -119,6 +133,12 @@ MediaEngineWebRTCAudioSource::Stop() return NS_ERROR_FAILURE; } + { + ReentrantMonitorAutoEnter enter(mMonitor); + mState = kStopped; + aSource->EndTrack(aID); + } + mVoERender->DeRegisterExternalMediaProcessing(mChannel, webrtc::kRecordingPerChannel); if (mVoEBase->StopSend(mChannel)) { @@ -127,27 +147,22 @@ MediaEngineWebRTCAudioSource::Stop() if (mVoEBase->StopReceive(mChannel)) { return NS_ERROR_FAILURE; } - - { - ReentrantMonitorAutoEnter enter(mMonitor); - mState = kStopped; - mSource->EndTrack(mTrackID); - } - return NS_OK; } void MediaEngineWebRTCAudioSource::NotifyPull(MediaStreamGraph* aGraph, - StreamTime aDesiredTime) + SourceMediaStream *aSource, + TrackID aID, + StreamTime aDesiredTime, + TrackTicks &aLastEndTime) { // Ignore - we push audio data #ifdef DEBUG - static TrackTicks mLastEndTime = 0; TrackTicks target = TimeToTicksRoundUp(SAMPLE_FREQUENCY, aDesiredTime); - TrackTicks delta = target - mLastEndTime; - LOG(("Audio:NotifyPull: target %lu, delta %lu",(uint32_t) target, (uint32_t) delta)); - mLastEndTime = target; + TrackTicks delta = target - aLastEndTime; + LOG(("Audio:NotifyPull: target %lu, delta %lu",(uint64_t) target, (uint64_t) delta)); + aLastEndTime = target; #endif } @@ -235,10 +250,13 @@ MediaEngineWebRTCAudioSource::Shutdown() } if (mState == kStarted) { - Stop(); + while (!mSources.IsEmpty()) { + Stop(mSources[0], kAudioTrack); // XXX change to support multiple tracks + } + MOZ_ASSERT(mState == kStopped); } - if (mState == kAllocated) { + if (mState == kAllocated || mState == kStopped) { Deallocate(); } @@ -269,17 +287,22 @@ MediaEngineWebRTCAudioSource::Process(const int channel, if (mState != kStarted) return; - nsRefPtr buffer = SharedBuffer::Create(length * sizeof(sample)); + uint32_t len = mSources.Length(); + for (uint32_t i = 0; i < len; i++) { + nsRefPtr buffer = SharedBuffer::Create(length * sizeof(sample)); - sample* dest = static_cast(buffer->Data()); - memcpy(dest, audio10ms, length * sizeof(sample)); + sample* dest = static_cast(buffer->Data()); + memcpy(dest, audio10ms, length * sizeof(sample)); - AudioSegment segment; - segment.Init(CHANNELS); - segment.AppendFrames( - buffer.forget(), length, 0, length, AUDIO_FORMAT_S16 - ); - mSource->AppendToTrack(mTrackID, &segment); + AudioSegment segment; + segment.Init(CHANNELS); + segment.AppendFrames(buffer.forget(), length, 0, length, AUDIO_FORMAT_S16); + + SourceMediaStream *source = mSources[i]; + if (source) { + source->AppendToTrack(mTrackID, &segment); + } + } return; } diff --git a/content/media/webrtc/MediaEngineWebRTCVideo.cpp b/content/media/webrtc/MediaEngineWebRTCVideo.cpp index 1788a3840aaa..f3c672944f4b 100644 --- a/content/media/webrtc/MediaEngineWebRTCVideo.cpp +++ b/content/media/webrtc/MediaEngineWebRTCVideo.cpp @@ -97,7 +97,10 @@ MediaEngineWebRTCVideoSource::DeliverFrame( // this means that no *real* frame can be inserted during this period. void MediaEngineWebRTCVideoSource::NotifyPull(MediaStreamGraph* aGraph, - StreamTime aDesiredTime) + SourceMediaStream *aSource, + TrackID aID, + StreamTime aDesiredTime, + TrackTicks &aLastEndTime) { VideoSegment segment; @@ -108,14 +111,14 @@ MediaEngineWebRTCVideoSource::NotifyPull(MediaStreamGraph* aGraph, // Note: we're not giving up mImage here nsRefPtr image = mImage; TrackTicks target = TimeToTicksRoundUp(USECS_PER_S, aDesiredTime); - TrackTicks delta = target - mLastEndTime; + TrackTicks delta = target - aLastEndTime; #ifdef LOG_ALL_FRAMES LOG(("NotifyPull, target = %lu, delta = %lu", (uint64_t) target, (uint64_t) delta)); #endif // NULL images are allowed segment.AppendFrame(image ? image.forget() : nullptr, delta, gfxIntSize(mWidth, mHeight)); - mSource->AppendToTrack(mTrackID, &(segment)); - mLastEndTime = target; + aSource->AppendToTrack(aID, &(segment)); + aLastEndTime = target; } void @@ -189,32 +192,40 @@ MediaEngineWebRTCVideoSource::GetUUID(nsAString& aUUID) nsresult MediaEngineWebRTCVideoSource::Allocate() { - if (mState != kReleased) { - return NS_ERROR_FAILURE; - } - if (!mCapabilityChosen) { // XXX these should come from constraints ChooseCapability(mWidth, mHeight, mMinFps); } - if (mViECapture->AllocateCaptureDevice(mUniqueId, KMaxUniqueIdLength, mCaptureIndex)) { - return NS_ERROR_FAILURE; + if (mState == kReleased && mInitDone) { + if (mViECapture->AllocateCaptureDevice(mUniqueId, KMaxUniqueIdLength, mCaptureIndex)) { + return NS_ERROR_FAILURE; + } + mState = kAllocated; + LOG(("Video device %d allocated", mCaptureIndex)); + } else if (mSources.IsEmpty()) { + LOG(("Video device %d reallocated", mCaptureIndex)); + } else { + LOG(("Video device %d allocated shared", mCaptureIndex)); } - mState = kAllocated; return NS_OK; } nsresult MediaEngineWebRTCVideoSource::Deallocate() { - if (mState != kStopped && mState != kAllocated) { - return NS_ERROR_FAILURE; - } + if (mSources.IsEmpty()) { + if (mState != kStopped && mState != kAllocated) { + return NS_ERROR_FAILURE; + } - mViECapture->ReleaseCaptureDevice(mCaptureIndex); - mState = kReleased; + mViECapture->ReleaseCaptureDevice(mCaptureIndex); + mState = kReleased; + LOG(("Video device %d deallocated", mCaptureIndex)); + } else { + LOG(("Video device %d deallocated but still in use", mCaptureIndex)); + } return NS_OK; } @@ -231,28 +242,22 @@ nsresult MediaEngineWebRTCVideoSource::Start(SourceMediaStream* aStream, TrackID aID) { int error = 0; - if (!mInitDone || mState != kAllocated) { + if (!mInitDone || !aStream) { return NS_ERROR_FAILURE; } - if (!aStream) { - return NS_ERROR_FAILURE; - } + mSources.AppendElement(aStream); + + aStream->AddTrack(aID, USECS_PER_S, 0, new VideoSegment()); + aStream->AdvanceKnownTracksTime(STREAM_TIME_MAX); if (mState == kStarted) { return NS_OK; } - - mSource = aStream; - mTrackID = aID; + mState = kStarted; mImageContainer = layers::LayerManager::CreateImageContainer(); - mSource->AddTrack(aID, USECS_PER_S, 0, new VideoSegment()); - mSource->AdvanceKnownTracksTime(STREAM_TIME_MAX); - mLastEndTime = 0; - mState = kStarted; - error = mViERender->AddRenderer(mCaptureIndex, webrtc::kVideoI420, (webrtc::ExternalRenderer*)this); if (error == -1) { return NS_ERROR_FAILURE; @@ -271,8 +276,16 @@ MediaEngineWebRTCVideoSource::Start(SourceMediaStream* aStream, TrackID aID) } nsresult -MediaEngineWebRTCVideoSource::Stop() +MediaEngineWebRTCVideoSource::Stop(SourceMediaStream *aSource, TrackID aID) { + if (!mSources.RemoveElement(aSource)) { + // Already stopped - this is allowed + return NS_OK; + } + if (!mSources.IsEmpty()) { + return NS_OK; + } + if (mState != kStarted) { return NS_ERROR_FAILURE; } @@ -280,7 +293,7 @@ MediaEngineWebRTCVideoSource::Stop() { ReentrantMonitorAutoEnter enter(mMonitor); mState = kStopped; - mSource->EndTrack(mTrackID); + aSource->EndTrack(aID); } mViERender->StopRender(mCaptureIndex); @@ -423,22 +436,19 @@ MediaEngineWebRTCVideoSource::Init() void MediaEngineWebRTCVideoSource::Shutdown() { - bool continueShutdown = false; - if (!mInitDone) { return; } if (mState == kStarted) { - mViERender->StopRender(mCaptureIndex); - mViERender->RemoveRenderer(mCaptureIndex); - continueShutdown = true; + while (!mSources.IsEmpty()) { + Stop(mSources[0], kVideoTrack); // XXX change to support multiple tracks + } + MOZ_ASSERT(mState == kStopped); } - if (mState == kAllocated || continueShutdown) { - mViECapture->StopCapture(mCaptureIndex); - mViECapture->ReleaseCaptureDevice(mCaptureIndex); - continueShutdown = false; + if (mState == kAllocated || mState == kStopped) { + Deallocate(); } mViECapture->Release(); diff --git a/dom/media/MediaManager.cpp b/dom/media/MediaManager.cpp index 51b3ce95b19f..ce974fed76dc 100644 --- a/dom/media/MediaManager.cpp +++ b/dom/media/MediaManager.cpp @@ -670,22 +670,18 @@ public: new nsTArray >; /** - * We only display available devices in the UI for now. We can easily - * change this later, when we implement a more sophisticated UI that - * lets the user revoke a device currently held by another tab (or - * we decide to provide a stream from a device already allocated). + * We're allowing multiple tabs to access the same camera for parity + * with Chrome. See bug 811757 for some of the issues surrounding + * this decision. To disallow, we'd filter by IsAvailable() as we used + * to. */ for (i = 0; i < videoCount; i++) { MediaEngineVideoSource *vSource = videoSources[i]; - if (vSource->IsAvailable()) { - devices->AppendElement(new MediaDevice(vSource)); - } + devices->AppendElement(new MediaDevice(vSource)); } for (i = 0; i < audioCount; i++) { MediaEngineAudioSource *aSource = audioSources[i]; - if (aSource->IsAvailable()) { - devices->AppendElement(new MediaDevice(aSource)); - } + devices->AppendElement(new MediaDevice(aSource)); } NS_DispatchToMainThread(new DeviceSuccessCallbackRunnable( diff --git a/dom/media/MediaManager.h b/dom/media/MediaManager.h index 930c1c10328e..33895828826f 100644 --- a/dom/media/MediaManager.h +++ b/dom/media/MediaManager.h @@ -27,12 +27,6 @@ extern PRLogModuleInfo* GetMediaManagerLog(); #define MM_LOG(msg) #endif -// We only support 1 audio and 1 video track for now. -enum { - kVideoTrack = 1, - kAudioTrack = 2 -}; - class GetUserMediaNotificationEvent: public nsRunnable { public: @@ -155,11 +149,11 @@ public: { NS_ASSERTION(!NS_IsMainThread(), "Never call on main thread"); if (mAudioSource) { - mAudioSource->Stop(); + mAudioSource->Stop(mSourceStream, kAudioTrack); mAudioSource->Deallocate(); } if (mVideoSource) { - mVideoSource->Stop(); + mVideoSource->Stop(mSourceStream, kVideoTrack); mVideoSource->Deallocate(); } // Do this after stopping all tracks with EndTrack() @@ -202,7 +196,10 @@ public: : mMediaThread(aThread) , mAudioSource(aAudioSource) , mVideoSource(aVideoSource) - , mStream(aStream) {} + , mStream(aStream) + , mSourceStream(aStream->GetStream()->AsSourceStream()) + , mLastEndTimeAudio(0) + , mLastEndTimeVideo(0) {} ~GetUserMediaCallbackMediaStreamListener() { @@ -231,8 +228,7 @@ public: // b) if on MediaStreamGraph thread, dispatch a runnable to MainThread // to call Invalidate() (with a strong ref to this listener) runnable = new MediaOperationRunnable(MEDIA_STOP, - mStream->GetStream()->AsSourceStream(), - mAudioSource, mVideoSource); + mSourceStream, mAudioSource, mVideoSource); mMediaThread->Dispatch(runnable, NS_DISPATCH_NORMAL); return; @@ -253,10 +249,10 @@ public: // Currently audio sources ignore NotifyPull, but they could // watch it especially for fake audio. if (mAudioSource) { - mAudioSource->NotifyPull(aGraph, aDesiredTime); + mAudioSource->NotifyPull(aGraph, mSourceStream, kAudioTrack, aDesiredTime, mLastEndTimeAudio); } if (mVideoSource) { - mVideoSource->NotifyPull(aGraph, aDesiredTime); + mVideoSource->NotifyPull(aGraph, mSourceStream, kVideoTrack, aDesiredTime, mLastEndTimeVideo); } } @@ -272,6 +268,9 @@ private: nsRefPtr mAudioSource; nsRefPtr mVideoSource; nsRefPtr mStream; + SourceMediaStream *mSourceStream; // mStream controls ownership + TrackTicks mLastEndTimeAudio; + TrackTicks mLastEndTimeVideo; }; typedef nsTArray > StreamListeners; From 8d4b69e76bf5a3a2a477a0df6a65eb9d4f5c8ec3 Mon Sep 17 00:00:00 2001 From: Randell Jesup Date: Mon, 31 Dec 2012 18:12:15 -0500 Subject: [PATCH 039/469] Bug 825526: Improve lifetime control of SourceMediaStream in gUM r=anant --- dom/media/MediaManager.cpp | 13 + dom/media/MediaManager.h | 270 +++++++++--------- .../src/mediapipeline/MediaPipeline.cpp | 5 +- 3 files changed, 146 insertions(+), 142 deletions(-) diff --git a/dom/media/MediaManager.cpp b/dom/media/MediaManager.cpp index ce974fed76dc..f841243fd2e3 100644 --- a/dom/media/MediaManager.cpp +++ b/dom/media/MediaManager.cpp @@ -1099,4 +1099,17 @@ MediaManager::GetActiveMediaCaptureWindows(nsISupportsArray **aArray) return NS_OK; } +void +GetUserMediaCallbackMediaStreamListener::Invalidate() +{ + nsRefPtr runnable; + // We can't take a chance on blocking here, so proxy this to another + // thread. + // Pass a ref to us (which is threadsafe) so it can query us for the + // source stream info. + runnable = new MediaOperationRunnable(MEDIA_STOP, + this, mAudioSource, mVideoSource); + mMediaThread->Dispatch(runnable, NS_DISPATCH_NORMAL); +} + } // namespace mozilla diff --git a/dom/media/MediaManager.h b/dom/media/MediaManager.h index 33895828826f..836ce718b8e1 100644 --- a/dom/media/MediaManager.h +++ b/dom/media/MediaManager.h @@ -61,126 +61,6 @@ class GetUserMediaNotificationEvent: public nsRunnable GetUserMediaStatus mStatus; }; -typedef enum { - MEDIA_START, - MEDIA_STOP -} MediaOperation; - -class GetUserMediaCallbackMediaStreamListener; - -// Generic class for running long media operations like Start off the main -// thread, and then (because nsDOMMediaStreams aren't threadsafe), -// ProxyReleases mStream since it's cycle collected. -class MediaOperationRunnable : public nsRunnable -{ -public: - MediaOperationRunnable(MediaOperation aType, - nsDOMMediaStream* aStream, - MediaEngineSource* aAudioSource, - MediaEngineSource* aVideoSource) - : mType(aType) - , mAudioSource(aAudioSource) - , mVideoSource(aVideoSource) - , mStream(aStream) - {} - - MediaOperationRunnable(MediaOperation aType, - SourceMediaStream* aStream, - MediaEngineSource* aAudioSource, - MediaEngineSource* aVideoSource) - : mType(aType) - , mAudioSource(aAudioSource) - , mVideoSource(aVideoSource) - , mStream(nullptr) - , mSourceStream(aStream) - {} - - ~MediaOperationRunnable() - { - // nsDOMMediaStreams are cycle-collected and thus main-thread-only for - // refcounting and releasing - if (mStream) { - nsCOMPtr mainThread = do_GetMainThread(); - nsDOMMediaStream *stream; - mStream.forget(&stream); - NS_ProxyRelease(mainThread, stream, true); - } - } - - NS_IMETHOD - Run() - { - // No locking between these is required as all the callbacks for the - // same MediaStream will occur on the same thread. - if (mStream) { - mSourceStream = mStream->GetStream()->AsSourceStream(); - } - switch (mType) { - case MEDIA_START: - { - NS_ASSERTION(!NS_IsMainThread(), "Never call on main thread"); - nsresult rv; - - mSourceStream->SetPullEnabled(true); - - if (mAudioSource) { - rv = mAudioSource->Start(mSourceStream, kAudioTrack); - if (NS_FAILED(rv)) { - MM_LOG(("Starting audio failed, rv=%d",rv)); - } - } - if (mVideoSource) { - rv = mVideoSource->Start(mSourceStream, kVideoTrack); - if (NS_FAILED(rv)) { - MM_LOG(("Starting video failed, rv=%d",rv)); - } - } - - MM_LOG(("started all sources")); - nsRefPtr event = - new GetUserMediaNotificationEvent(GetUserMediaNotificationEvent::STARTING); - - - NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL); - } - break; - - case MEDIA_STOP: - { - NS_ASSERTION(!NS_IsMainThread(), "Never call on main thread"); - if (mAudioSource) { - mAudioSource->Stop(mSourceStream, kAudioTrack); - mAudioSource->Deallocate(); - } - if (mVideoSource) { - mVideoSource->Stop(mSourceStream, kVideoTrack); - mVideoSource->Deallocate(); - } - // Do this after stopping all tracks with EndTrack() - mSourceStream->Finish(); - - nsRefPtr event = - new GetUserMediaNotificationEvent(GetUserMediaNotificationEvent::STOPPING); - - NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL); - } - break; - - default: - MOZ_ASSERT(false,"invalid MediaManager operation"); - break; - } - return NS_OK; - } - -private: - MediaOperation mType; - nsRefPtr mAudioSource; // threadsafe - nsRefPtr mVideoSource; // threadsafe - nsRefPtr mStream; // not threadsafe - SourceMediaStream *mSourceStream; -}; - /** * This class is an implementation of MediaStreamListener. This is used * to Start() and Stop() the underlying MediaEngineSource when MediaStreams @@ -199,7 +79,7 @@ public: , mStream(aStream) , mSourceStream(aStream->GetStream()->AsSourceStream()) , mLastEndTimeAudio(0) - , mLastEndTimeVideo(0) {} + , mLastEndTimeVideo(0) { MOZ_ASSERT(mSourceStream); } ~GetUserMediaCallbackMediaStreamListener() { @@ -213,27 +93,14 @@ public: } } - void - Invalidate() + SourceMediaStream *GetSourceStream() { - nsRefPtr runnable; - - // We can't take a chance on blocking here, so proxy this to another - // thread. - // XXX FIX! I'm cheating and passing a raw pointer to the sourcestream - // which is valid as long as the mStream pointer here is. - // Solutions (see bug 825235): - // a) if on MainThread, pass mStream and let it addref - // (MediaOperation will need to ProxyRelease however) - // b) if on MediaStreamGraph thread, dispatch a runnable to MainThread - // to call Invalidate() (with a strong ref to this listener) - runnable = new MediaOperationRunnable(MEDIA_STOP, - mSourceStream, mAudioSource, mVideoSource); - mMediaThread->Dispatch(runnable, NS_DISPATCH_NORMAL); - - return; + return mStream->GetStream()->AsSourceStream(); } + void + Invalidate(); // implement in .cpp to avoid circular dependency with MediaOperationRunnable + void Remove() { @@ -273,6 +140,131 @@ private: TrackTicks mLastEndTimeVideo; }; +typedef enum { + MEDIA_START, + MEDIA_STOP +} MediaOperation; + +// Generic class for running long media operations like Start off the main +// thread, and then (because nsDOMMediaStreams aren't threadsafe), +// ProxyReleases mStream since it's cycle collected. +class MediaOperationRunnable : public nsRunnable +{ +public: + MediaOperationRunnable(MediaOperation aType, + nsDOMMediaStream* aStream, + MediaEngineSource* aAudioSource, + MediaEngineSource* aVideoSource) + : mType(aType) + , mAudioSource(aAudioSource) + , mVideoSource(aVideoSource) + , mStream(aStream) + {} + + MediaOperationRunnable(MediaOperation aType, + GetUserMediaCallbackMediaStreamListener* aListener, + MediaEngineSource* aAudioSource, + MediaEngineSource* aVideoSource) + : mType(aType) + , mAudioSource(aAudioSource) + , mVideoSource(aVideoSource) + , mStream(nullptr) + , mListener(aListener) + {} + + ~MediaOperationRunnable() + { + // nsDOMMediaStreams are cycle-collected and thus main-thread-only for + // refcounting and releasing + if (mStream) { + nsCOMPtr mainThread = do_GetMainThread(); + nsDOMMediaStream *stream; + mStream.forget(&stream); + NS_ProxyRelease(mainThread, stream, true); + } + } + + NS_IMETHOD + Run() + { + SourceMediaStream *source; + // No locking between these is required as all the callbacks for the + // same MediaStream will occur on the same thread. + if (mStream) { + source = mStream->GetStream()->AsSourceStream(); + } else { + source = mListener->GetSourceStream(); + } + MOZ_ASSERT(source); + if (!source) // paranoia + return NS_ERROR_FAILURE; + + switch (mType) { + case MEDIA_START: + { + NS_ASSERTION(!NS_IsMainThread(), "Never call on main thread"); + nsresult rv; + + source->SetPullEnabled(true); + + if (mAudioSource) { + rv = mAudioSource->Start(source, kAudioTrack); + if (NS_FAILED(rv)) { + MM_LOG(("Starting audio failed, rv=%d",rv)); + } + } + if (mVideoSource) { + rv = mVideoSource->Start(source, kVideoTrack); + if (NS_FAILED(rv)) { + MM_LOG(("Starting video failed, rv=%d",rv)); + } + } + + MM_LOG(("started all sources")); + nsRefPtr event = + new GetUserMediaNotificationEvent(GetUserMediaNotificationEvent::STARTING); + + + NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL); + } + break; + + case MEDIA_STOP: + { + NS_ASSERTION(!NS_IsMainThread(), "Never call on main thread"); + if (mAudioSource) { + mAudioSource->Stop(source, kAudioTrack); + mAudioSource->Deallocate(); + } + if (mVideoSource) { + mVideoSource->Stop(source, kVideoTrack); + mVideoSource->Deallocate(); + } + // Do this after stopping all tracks with EndTrack() + source->Finish(); + + nsRefPtr event = + new GetUserMediaNotificationEvent(GetUserMediaNotificationEvent::STOPPING); + + NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL); + } + break; + + default: + MOZ_ASSERT(false,"invalid MediaManager operation"); + break; + } + return NS_OK; + } + +private: + MediaOperation mType; + nsRefPtr mAudioSource; // threadsafe + nsRefPtr mVideoSource; // threadsafe + nsRefPtr mStream; // not threadsafe + nsRefPtr mListener; // threadsafe +}; + typedef nsTArray > StreamListeners; typedef nsClassHashtable WindowTable; diff --git a/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp b/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp index 189f5827d9a6..5ef9a3b4eae3 100644 --- a/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp +++ b/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp @@ -485,7 +485,7 @@ nsresult MediaPipelineTransmit::Init() { nsresult MediaPipelineTransmit::TransportReady(TransportFlow *flow) { // Call base ready function. MediaPipeline::TransportReady(flow); - + if (flow == rtp_transport_) { // TODO(ekr@rtfm.com): Move onto MSG thread. listener_->SetActive(true); @@ -605,7 +605,7 @@ NotifyQueuedTrackChanges(MediaStreamGraph* graph, TrackID tid, MOZ_MTLOG(PR_LOG_DEBUG, "MediaPipeline::NotifyQueuedTrackChanges()"); if (!active_) { - MOZ_MTLOG(PR_LOG_DEBUG, "Discarding packets because transport not ready"); + MOZ_MTLOG(PR_LOG_DEBUG, "Discarding packets because transport not ready"); return; } @@ -872,4 +872,3 @@ void MediaPipelineReceiveVideo::PipelineRenderer::RenderVideoFrame( } // end namespace - From 29153d6bc13ffcfba514a1c57a3ff0e27686a177 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 1 Jan 2013 16:45:43 +1300 Subject: [PATCH 040/469] Bug 814718. Explicitly store the blocking state that we last delivered to MediaStreamListeners. r=jesup --- content/media/MediaStreamGraph.cpp | 8 +++----- content/media/MediaStreamGraph.h | 6 ++++++ 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/content/media/MediaStreamGraph.cpp b/content/media/MediaStreamGraph.cpp index ccd67b598310..e1b543f9400a 100644 --- a/content/media/MediaStreamGraph.cpp +++ b/content/media/MediaStreamGraph.cpp @@ -802,21 +802,19 @@ MediaStreamGraphImpl::UpdateCurrentTime() // Calculate blocked time and fire Blocked/Unblocked events GraphTime blockedTime = 0; GraphTime t = prevCurrentTime; - // Save current blocked status - bool wasBlocked = stream->mBlocked.GetAt(prevCurrentTime); while (t < nextCurrentTime) { GraphTime end; bool blocked = stream->mBlocked.GetAt(t, &end); if (blocked) { blockedTime += NS_MIN(end, nextCurrentTime) - t; } - if (blocked != wasBlocked) { + if (blocked != stream->mNotifiedBlocked) { for (uint32_t j = 0; j < stream->mListeners.Length(); ++j) { MediaStreamListener* l = stream->mListeners[j]; l->NotifyBlockingChanged(this, blocked ? MediaStreamListener::BLOCKED : MediaStreamListener::UNBLOCKED); } - wasBlocked = blocked; + stream->mNotifiedBlocked = blocked; } t = end; } @@ -1941,7 +1939,7 @@ MediaStream::AddListenerImpl(already_AddRefed aListener) { MediaStreamListener* listener = *mListeners.AppendElement() = aListener; listener->NotifyBlockingChanged(GraphImpl(), - mBlocked.GetAt(GraphImpl()->mCurrentTime) ? MediaStreamListener::BLOCKED : MediaStreamListener::UNBLOCKED); + mNotifiedBlocked ? MediaStreamListener::BLOCKED : MediaStreamListener::UNBLOCKED); if (mNotifiedFinished) { listener->NotifyFinished(GraphImpl()); } diff --git a/content/media/MediaStreamGraph.h b/content/media/MediaStreamGraph.h index 25aa01ee10f4..7093a7239d12 100644 --- a/content/media/MediaStreamGraph.h +++ b/content/media/MediaStreamGraph.h @@ -261,6 +261,7 @@ public: , mGraphUpdateIndices(0) , mFinished(false) , mNotifiedFinished(false) + , mNotifiedBlocked(false) , mWrapper(aWrapper) , mMainThreadCurrentTime(0) , mMainThreadFinished(false) @@ -457,6 +458,11 @@ protected: * and fired NotifyFinished notifications. */ bool mNotifiedFinished; + /** + * When true, the last NotifyBlockingChanged delivered to the listeners + * indicated that the stream is blocked. + */ + bool mNotifiedBlocked; // Temporary data for ordering streams by dependency graph bool mHasBeenOrdered; From f29ed4b405ff5b6cf91e4fbb6ea03ce55d9482b3 Mon Sep 17 00:00:00 2001 From: Andrea Canciani Date: Wed, 15 Jun 2011 09:37:36 +0000 Subject: [PATCH 041/469] win32-font: Improve static data reset function Bug 717178. Part 2: Import changesets eb29a25d, 6e3e3291 and 101fab7c from upstream. ====== From 101fab7cd8a90f7cf3d8113c792b3f8c2a9afb7d Mon Sep 17 00:00:00 2001 The hashtable is guaranteed to only contain font faces which are currently referenced, hence there is no need to remove any font face when it is reset (just like for toy-font). This makes the function simpler and fixes the assertion Assertion failed: predicate != NULL, file cairo-hash.c, line 373 hit by multiple tests (the first one being "clear"). See https://bugs.freedesktop.org/show_bug.cgi?id=38049 ====== From eb29a25dd6dddc511388bf883c9b95843ecdb823 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Tue, 16 Nov 2010 13:18:39 +0000 Subject: win32: Use a font_face hash table to provide unique font faces Similar to the freetype and toy font backends, use a hash table to map logfont,hfont to font faces. This fixes the multiple embedding of the same font in PDF. https://bugs.freedesktop.org/show_bug.cgi?id=24849 ====== From 6e3e329170ab4b96bc0d587c8071e869e228e758 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Thu, 18 Nov 2010 12:37:45 +0000 Subject: win32: fix font_face hashing some bugs were discovered while testing with firefox ====== --- gfx/cairo/README | 2 + gfx/cairo/cairo/src/cairo-debug.c | 4 + .../cairo/src/cairo-mutex-list-private.h | 4 + gfx/cairo/cairo/src/cairo-win32-font.c | 165 +++++++- gfx/cairo/cairo/src/cairoint.h | 3 + gfx/cairo/win32-gdi-font-cache.patch | 375 ++++++++++++++++++ 6 files changed, 545 insertions(+), 8 deletions(-) create mode 100644 gfx/cairo/win32-gdi-font-cache.patch diff --git a/gfx/cairo/README b/gfx/cairo/README index 2ac84fdbaad5..ae6116241dd9 100644 --- a/gfx/cairo/README +++ b/gfx/cairo/README @@ -198,6 +198,8 @@ dwrite-font-match-robustness.patch: bug 717178, don't crash when _name_tables_ma handle-multi-path-clip.patch: bug 813124, handle multiple clip paths correctly +win32-gdi-font-cache.patch: Bug 717178, cache GDI font faces to reduce usage of GDI resources + ==== pixman patches ==== pixman-android-cpu-detect.patch: Add CPU detection support for Android, where we can't reliably access /proc/self/auxv. diff --git a/gfx/cairo/cairo/src/cairo-debug.c b/gfx/cairo/cairo/src/cairo-debug.c index c95675318397..e9e72b6aa93b 100644 --- a/gfx/cairo/cairo/src/cairo-debug.c +++ b/gfx/cairo/cairo/src/cairo-debug.c @@ -69,6 +69,10 @@ cairo_debug_reset_static_data (void) _cairo_ft_font_reset_static_data (); #endif +#if CAIRO_HAS_WIN32_FONT + _cairo_win32_font_reset_static_data (); +#endif + _cairo_intern_string_reset_static_data (); _cairo_scaled_font_reset_static_data (); diff --git a/gfx/cairo/cairo/src/cairo-mutex-list-private.h b/gfx/cairo/cairo/src/cairo-mutex-list-private.h index 5827667f4ad0..7d5ba0299756 100644 --- a/gfx/cairo/cairo/src/cairo-mutex-list-private.h +++ b/gfx/cairo/cairo/src/cairo-mutex-list-private.h @@ -51,6 +51,10 @@ CAIRO_MUTEX_DECLARE (_cairo_scaled_font_error_mutex) CAIRO_MUTEX_DECLARE (_cairo_ft_unscaled_font_map_mutex) #endif +#if CAIRO_HAS_WIN32_FONT +CAIRO_MUTEX_DECLARE (_cairo_win32_font_face_mutex) +#endif + #if CAIRO_HAS_XLIB_SURFACE CAIRO_MUTEX_DECLARE (_cairo_xlib_display_mutex) #endif diff --git a/gfx/cairo/cairo/src/cairo-win32-font.c b/gfx/cairo/cairo/src/cairo-win32-font.c index 6ba20d53d0cf..7d61ece6a23a 100644 --- a/gfx/cairo/cairo/src/cairo-win32-font.c +++ b/gfx/cairo/cairo/src/cairo-win32-font.c @@ -47,6 +47,8 @@ #include "cairo-win32-private.h" #include "cairo-error-private.h" +#include + #ifndef SPI_GETFONTSMOOTHINGTYPE #define SPI_GETFONTSMOOTHINGTYPE 0x200a #endif @@ -1892,9 +1894,7 @@ struct _cairo_win32_font_face { /* implement the platform-specific interface */ static void -_cairo_win32_font_face_destroy (void *abstract_face) -{ -} +_cairo_win32_font_face_destroy (void *abstract_face); static cairo_bool_t _is_scale (const cairo_matrix_t *matrix, double scale) @@ -1937,6 +1937,118 @@ const cairo_font_face_backend_t _cairo_win32_font_face_backend = { _cairo_win32_font_face_scaled_font_create }; +/* We maintain a hash table from LOGFONT,HFONT => #cairo_font_face_t. + * The primary purpose of this mapping is to provide unique + * #cairo_font_face_t values so that our cache and mapping from + * #cairo_font_face_t => #cairo_scaled_font_t works. Once the + * corresponding #cairo_font_face_t objects fall out of downstream + * caches, we don't need them in this hash table anymore. + * + * Modifications to this hash table are protected by + * _cairo_win32_font_face_mutex. + */ + +static cairo_hash_table_t *cairo_win32_font_face_hash_table = NULL; + +static int +_cairo_win32_font_face_keys_equal (const void *key_a, + const void *key_b); + +static void +_cairo_win32_font_face_hash_table_destroy (void) +{ + cairo_hash_table_t *hash_table; + + /* We manually acquire the lock rather than calling + * _cairo_win32_font_face_hash_table_lock simply to avoid creating + * the table only to destroy it again. */ + CAIRO_MUTEX_LOCK (_cairo_win32_font_face_mutex); + hash_table = cairo_win32_font_face_hash_table; + cairo_win32_font_face_hash_table = NULL; + CAIRO_MUTEX_UNLOCK (_cairo_win32_font_face_mutex); + + if (hash_table != NULL) + _cairo_hash_table_destroy (hash_table); +} + +static cairo_hash_table_t * +_cairo_win32_font_face_hash_table_lock (void) +{ + CAIRO_MUTEX_LOCK (_cairo_win32_font_face_mutex); + + if (unlikely (cairo_win32_font_face_hash_table == NULL)) + { + cairo_win32_font_face_hash_table = + _cairo_hash_table_create (_cairo_win32_font_face_keys_equal); + + if (unlikely (cairo_win32_font_face_hash_table == NULL)) { + CAIRO_MUTEX_UNLOCK (_cairo_win32_font_face_mutex); + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return NULL; + } + } + + return cairo_win32_font_face_hash_table; +} + +static void +_cairo_win32_font_face_hash_table_unlock (void) +{ + CAIRO_MUTEX_UNLOCK (_cairo_win32_font_face_mutex); +} + +static void +_cairo_win32_font_face_init_key (cairo_win32_font_face_t *key, + LOGFONTW *logfont, + HFONT font) +{ + unsigned long hash = _CAIRO_HASH_INIT_VALUE; + + key->logfont = *logfont; + key->hfont = font; + + hash = _cairo_hash_bytes (0, logfont->lfFaceName, 2*wcslen(logfont->lfFaceName)); + hash = _cairo_hash_bytes (hash, &logfont->lfWeight, sizeof(logfont->lfWeight)); + hash = _cairo_hash_bytes (hash, &logfont->lfItalic, sizeof(logfont->lfItalic)); + + key->base.hash_entry.hash = hash; +} + +static int +_cairo_win32_font_face_keys_equal (const void *key_a, + const void *key_b) +{ + const cairo_win32_font_face_t *face_a = key_a; + const cairo_win32_font_face_t *face_b = key_b; + + if (face_a->logfont.lfWeight == face_b->logfont.lfWeight && + face_a->logfont.lfItalic == face_b->logfont.lfItalic && + face_a->logfont.lfUnderline == face_b->logfont.lfUnderline && + face_a->logfont.lfStrikeOut == face_b->logfont.lfStrikeOut && + face_a->logfont.lfCharSet == face_b->logfont.lfCharSet && + face_a->logfont.lfOutPrecision == face_b->logfont.lfOutPrecision && + face_a->logfont.lfClipPrecision == face_b->logfont.lfClipPrecision && + face_a->logfont.lfPitchAndFamily == face_b->logfont.lfPitchAndFamily && + (wcscmp (face_a->logfont.lfFaceName, face_b->logfont.lfFaceName) == 0)) + return TRUE; + else + return FALSE; +} + +static void +_cairo_win32_font_face_destroy (void *abstract_face) +{ + cairo_hash_table_t *hash_table; + cairo_win32_font_face_t *font_face = abstract_face; + + hash_table = _cairo_win32_font_face_hash_table_lock (); + if (unlikely (hash_table == NULL)) { + return; + } + _cairo_hash_table_remove (hash_table, &font_face->base.hash_entry); + _cairo_win32_font_face_hash_table_unlock (); +} + /** * cairo_win32_font_face_create_for_logfontw_hfont: * @logfont: A #LOGFONTW structure specifying the font to use. @@ -1959,20 +2071,51 @@ const cairo_font_face_backend_t _cairo_win32_font_face_backend = { cairo_font_face_t * cairo_win32_font_face_create_for_logfontw_hfont (LOGFONTW *logfont, HFONT font) { - cairo_win32_font_face_t *font_face; + cairo_win32_font_face_t *font_face, key; + cairo_hash_table_t *hash_table; + cairo_status_t status; + hash_table = _cairo_win32_font_face_hash_table_lock (); + if (unlikely (hash_table == NULL)) { + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return (cairo_font_face_t *)&_cairo_font_face_nil; + } + + _cairo_win32_font_face_init_key (&key, logfont, font); + + /* Return existing unscaled font if it exists in the hash table. */ + font_face = _cairo_hash_table_lookup (hash_table, + &key.base.hash_entry); + if (font_face != NULL) { + cairo_font_face_reference (&font_face->base); + goto DONE; + } + + /* Otherwise create it and insert into hash table. */ font_face = malloc (sizeof (cairo_win32_font_face_t)); if (!font_face) { _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); - return (cairo_font_face_t *)&_cairo_font_face_nil; + goto FAIL; } - font_face->logfont = *logfont; - font_face->hfont = font; - + _cairo_win32_font_face_init_key (font_face, logfont, font); _cairo_font_face_init (&font_face->base, &_cairo_win32_font_face_backend); + assert (font_face->base.hash_entry.hash == key.base.hash_entry.hash); + status = _cairo_hash_table_insert (hash_table, + &font_face->base.hash_entry); + if (unlikely (status)) + goto FAIL; + +DONE: + _cairo_win32_font_face_hash_table_unlock (); + return &font_face->base; + +FAIL: + _cairo_win32_font_face_hash_table_unlock (); + + return (cairo_font_face_t *)&_cairo_font_face_nil; } /** @@ -2181,3 +2324,9 @@ cairo_win32_scaled_font_get_device_to_logical (cairo_scaled_font_t *scaled_font, } *device_to_logical = win_font->device_to_logical; } + +void +_cairo_win32_font_reset_static_data (void) +{ + _cairo_win32_font_face_hash_table_destroy (); +} diff --git a/gfx/cairo/cairo/src/cairoint.h b/gfx/cairo/cairo/src/cairoint.h index 45567d3dd0b8..aeccd70d6fcd 100644 --- a/gfx/cairo/cairo/src/cairoint.h +++ b/gfx/cairo/cairo/src/cairoint.h @@ -408,6 +408,9 @@ _cairo_toy_font_face_reset_static_data (void); cairo_private void _cairo_ft_font_reset_static_data (void); +cairo_private void +_cairo_win32_font_reset_static_data (void); + /* the font backend interface */ struct _cairo_unscaled_font_backend { diff --git a/gfx/cairo/win32-gdi-font-cache.patch b/gfx/cairo/win32-gdi-font-cache.patch new file mode 100644 index 000000000000..e082a2e4dcae --- /dev/null +++ b/gfx/cairo/win32-gdi-font-cache.patch @@ -0,0 +1,375 @@ +# HG changeset patch +# User Andrea Canciani , Adrian Johnson +# Date 1354838294 -46800 +# Node ID 390df735b9d5c5ba07a4d3fe9ca2ebc9e7626a78 +# Parent e30a5b6a5a003b85fc1ca8b76719a56ef59d976e +Bug 717178. Part 2: Import changesets eb29a25d, 6e3e3291 and 101fab7c from upstream. +====== + +From 101fab7cd8a90f7cf3d8113c792b3f8c2a9afb7d Mon Sep 17 00:00:00 2001 +From: Andrea Canciani +Date: Wed, 15 Jun 2011 09:37:36 +0000 +Subject: win32-font: Improve static data reset function + +The hashtable is guaranteed to only contain font faces which are +currently referenced, hence there is no need to remove any font face +when it is reset (just like for toy-font). + +This makes the function simpler and fixes the assertion + +Assertion failed: predicate != NULL, file cairo-hash.c, line 373 + +hit by multiple tests (the first one being "clear"). + +See https://bugs.freedesktop.org/show_bug.cgi?id=38049 + +====== + +From eb29a25dd6dddc511388bf883c9b95843ecdb823 Mon Sep 17 00:00:00 2001 +From: Adrian Johnson +Date: Tue, 16 Nov 2010 13:18:39 +0000 +Subject: win32: Use a font_face hash table to provide unique font faces + +Similar to the freetype and toy font backends, use a hash table +to map logfont,hfont to font faces. + +This fixes the multiple embedding of the same font in PDF. + +https://bugs.freedesktop.org/show_bug.cgi?id=24849 + +====== + +From 6e3e329170ab4b96bc0d587c8071e869e228e758 Mon Sep 17 00:00:00 2001 +From: Adrian Johnson +Date: Thu, 18 Nov 2010 12:37:45 +0000 +Subject: win32: fix font_face hashing + +some bugs were discovered while testing with firefox + +====== + +diff --git a/gfx/cairo/cairo/src/cairo-debug.c b/gfx/cairo/cairo/src/cairo-debug.c +--- a/gfx/cairo/cairo/src/cairo-debug.c ++++ b/gfx/cairo/cairo/src/cairo-debug.c +@@ -64,16 +64,20 @@ cairo_debug_reset_static_data (void) + _cairo_scaled_font_map_destroy (); + + _cairo_toy_font_face_reset_static_data (); + + #if CAIRO_HAS_FT_FONT + _cairo_ft_font_reset_static_data (); + #endif + ++#if CAIRO_HAS_WIN32_FONT ++ _cairo_win32_font_reset_static_data (); ++#endif ++ + _cairo_intern_string_reset_static_data (); + + _cairo_scaled_font_reset_static_data (); + + _cairo_pattern_reset_static_data (); + + _cairo_clip_reset_static_data (); + +diff --git a/gfx/cairo/cairo/src/cairo-mutex-list-private.h b/gfx/cairo/cairo/src/cairo-mutex-list-private.h +--- a/gfx/cairo/cairo/src/cairo-mutex-list-private.h ++++ b/gfx/cairo/cairo/src/cairo-mutex-list-private.h +@@ -46,16 +46,20 @@ CAIRO_MUTEX_DECLARE (_cairo_intern_strin + CAIRO_MUTEX_DECLARE (_cairo_scaled_font_map_mutex) + CAIRO_MUTEX_DECLARE (_cairo_scaled_glyph_page_cache_mutex) + CAIRO_MUTEX_DECLARE (_cairo_scaled_font_error_mutex) + + #if CAIRO_HAS_FT_FONT + CAIRO_MUTEX_DECLARE (_cairo_ft_unscaled_font_map_mutex) + #endif + ++#if CAIRO_HAS_WIN32_FONT ++CAIRO_MUTEX_DECLARE (_cairo_win32_font_face_mutex) ++#endif ++ + #if CAIRO_HAS_XLIB_SURFACE + CAIRO_MUTEX_DECLARE (_cairo_xlib_display_mutex) + #endif + + #if CAIRO_HAS_XCB_SURFACE + CAIRO_MUTEX_DECLARE (_cairo_xcb_connections_mutex) + #endif + +diff --git a/gfx/cairo/cairo/src/cairo-win32-font.c b/gfx/cairo/cairo/src/cairo-win32-font.c +--- a/gfx/cairo/cairo/src/cairo-win32-font.c ++++ b/gfx/cairo/cairo/src/cairo-win32-font.c +@@ -42,16 +42,18 @@ + # define _WIN32_WINNT 0x0500 + #endif + + #include "cairoint.h" + + #include "cairo-win32-private.h" + #include "cairo-error-private.h" + ++#include ++ + #ifndef SPI_GETFONTSMOOTHINGTYPE + #define SPI_GETFONTSMOOTHINGTYPE 0x200a + #endif + #ifndef FE_FONTSMOOTHINGCLEARTYPE + #define FE_FONTSMOOTHINGCLEARTYPE 2 + #endif + #ifndef CLEARTYPE_QUALITY + #define CLEARTYPE_QUALITY 5 +@@ -1887,19 +1889,17 @@ struct _cairo_win32_font_face { + cairo_font_face_t base; + LOGFONTW logfont; + HFONT hfont; + }; + + /* implement the platform-specific interface */ + + static void +-_cairo_win32_font_face_destroy (void *abstract_face) +-{ +-} ++_cairo_win32_font_face_destroy (void *abstract_face); + + static cairo_bool_t + _is_scale (const cairo_matrix_t *matrix, double scale) + { + return matrix->xx == scale && matrix->yy == scale && + matrix->xy == 0. && matrix->yx == 0. && + matrix->x0 == 0. && matrix->y0 == 0.; + } +@@ -1932,16 +1932,128 @@ static cairo_status_t + + const cairo_font_face_backend_t _cairo_win32_font_face_backend = { + CAIRO_FONT_TYPE_WIN32, + _cairo_win32_font_face_create_for_toy, + _cairo_win32_font_face_destroy, + _cairo_win32_font_face_scaled_font_create + }; + ++/* We maintain a hash table from LOGFONT,HFONT => #cairo_font_face_t. ++ * The primary purpose of this mapping is to provide unique ++ * #cairo_font_face_t values so that our cache and mapping from ++ * #cairo_font_face_t => #cairo_scaled_font_t works. Once the ++ * corresponding #cairo_font_face_t objects fall out of downstream ++ * caches, we don't need them in this hash table anymore. ++ * ++ * Modifications to this hash table are protected by ++ * _cairo_win32_font_face_mutex. ++ */ ++ ++static cairo_hash_table_t *cairo_win32_font_face_hash_table = NULL; ++ ++static int ++_cairo_win32_font_face_keys_equal (const void *key_a, ++ const void *key_b); ++ ++static void ++_cairo_win32_font_face_hash_table_destroy (void) ++{ ++ cairo_hash_table_t *hash_table; ++ ++ /* We manually acquire the lock rather than calling ++ * _cairo_win32_font_face_hash_table_lock simply to avoid creating ++ * the table only to destroy it again. */ ++ CAIRO_MUTEX_LOCK (_cairo_win32_font_face_mutex); ++ hash_table = cairo_win32_font_face_hash_table; ++ cairo_win32_font_face_hash_table = NULL; ++ CAIRO_MUTEX_UNLOCK (_cairo_win32_font_face_mutex); ++ ++ if (hash_table != NULL) ++ _cairo_hash_table_destroy (hash_table); ++} ++ ++static cairo_hash_table_t * ++_cairo_win32_font_face_hash_table_lock (void) ++{ ++ CAIRO_MUTEX_LOCK (_cairo_win32_font_face_mutex); ++ ++ if (unlikely (cairo_win32_font_face_hash_table == NULL)) ++ { ++ cairo_win32_font_face_hash_table = ++ _cairo_hash_table_create (_cairo_win32_font_face_keys_equal); ++ ++ if (unlikely (cairo_win32_font_face_hash_table == NULL)) { ++ CAIRO_MUTEX_UNLOCK (_cairo_win32_font_face_mutex); ++ _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); ++ return NULL; ++ } ++ } ++ ++ return cairo_win32_font_face_hash_table; ++} ++ ++static void ++_cairo_win32_font_face_hash_table_unlock (void) ++{ ++ CAIRO_MUTEX_UNLOCK (_cairo_win32_font_face_mutex); ++} ++ ++static void ++_cairo_win32_font_face_init_key (cairo_win32_font_face_t *key, ++ LOGFONTW *logfont, ++ HFONT font) ++{ ++ unsigned long hash = _CAIRO_HASH_INIT_VALUE; ++ ++ key->logfont = *logfont; ++ key->hfont = font; ++ ++ hash = _cairo_hash_bytes (0, logfont->lfFaceName, 2*wcslen(logfont->lfFaceName)); ++ hash = _cairo_hash_bytes (hash, &logfont->lfWeight, sizeof(logfont->lfWeight)); ++ hash = _cairo_hash_bytes (hash, &logfont->lfItalic, sizeof(logfont->lfItalic)); ++ ++ key->base.hash_entry.hash = hash; ++} ++ ++static int ++_cairo_win32_font_face_keys_equal (const void *key_a, ++ const void *key_b) ++{ ++ const cairo_win32_font_face_t *face_a = key_a; ++ const cairo_win32_font_face_t *face_b = key_b; ++ ++ if (face_a->logfont.lfWeight == face_b->logfont.lfWeight && ++ face_a->logfont.lfItalic == face_b->logfont.lfItalic && ++ face_a->logfont.lfUnderline == face_b->logfont.lfUnderline && ++ face_a->logfont.lfStrikeOut == face_b->logfont.lfStrikeOut && ++ face_a->logfont.lfCharSet == face_b->logfont.lfCharSet && ++ face_a->logfont.lfOutPrecision == face_b->logfont.lfOutPrecision && ++ face_a->logfont.lfClipPrecision == face_b->logfont.lfClipPrecision && ++ face_a->logfont.lfPitchAndFamily == face_b->logfont.lfPitchAndFamily && ++ (wcscmp (face_a->logfont.lfFaceName, face_b->logfont.lfFaceName) == 0)) ++ return TRUE; ++ else ++ return FALSE; ++} ++ ++static void ++_cairo_win32_font_face_destroy (void *abstract_face) ++{ ++ cairo_hash_table_t *hash_table; ++ cairo_win32_font_face_t *font_face = abstract_face; ++ ++ hash_table = _cairo_win32_font_face_hash_table_lock (); ++ if (unlikely (hash_table == NULL)) { ++ return; ++ } ++ _cairo_hash_table_remove (hash_table, &font_face->base.hash_entry); ++ _cairo_win32_font_face_hash_table_unlock (); ++} ++ + /** + * cairo_win32_font_face_create_for_logfontw_hfont: + * @logfont: A #LOGFONTW structure specifying the font to use. + * If @font is %NULL then the lfHeight, lfWidth, lfOrientation and lfEscapement + * fields of this structure are ignored. Otherwise lfWidth, lfOrientation and + * lfEscapement must be zero. + * @font: An #HFONT that can be used when the font matrix is a scale by + * -lfHeight and the CTM is identity. +@@ -1954,30 +2066,61 @@ const cairo_font_face_backend_t _cairo_w + * and can be used with functions such as cairo_win32_scaled_font_select_font(). + * + * Return value: a newly created #cairo_font_face_t. Free with + * cairo_font_face_destroy() when you are done using it. + **/ + cairo_font_face_t * + cairo_win32_font_face_create_for_logfontw_hfont (LOGFONTW *logfont, HFONT font) + { +- cairo_win32_font_face_t *font_face; ++ cairo_win32_font_face_t *font_face, key; ++ cairo_hash_table_t *hash_table; ++ cairo_status_t status; + ++ hash_table = _cairo_win32_font_face_hash_table_lock (); ++ if (unlikely (hash_table == NULL)) { ++ _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); ++ return (cairo_font_face_t *)&_cairo_font_face_nil; ++ } ++ ++ _cairo_win32_font_face_init_key (&key, logfont, font); ++ ++ /* Return existing unscaled font if it exists in the hash table. */ ++ font_face = _cairo_hash_table_lookup (hash_table, ++ &key.base.hash_entry); ++ if (font_face != NULL) { ++ cairo_font_face_reference (&font_face->base); ++ goto DONE; ++ } ++ ++ /* Otherwise create it and insert into hash table. */ + font_face = malloc (sizeof (cairo_win32_font_face_t)); + if (!font_face) { + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); +- return (cairo_font_face_t *)&_cairo_font_face_nil; ++ goto FAIL; + } + +- font_face->logfont = *logfont; +- font_face->hfont = font; +- ++ _cairo_win32_font_face_init_key (font_face, logfont, font); + _cairo_font_face_init (&font_face->base, &_cairo_win32_font_face_backend); + ++ assert (font_face->base.hash_entry.hash == key.base.hash_entry.hash); ++ status = _cairo_hash_table_insert (hash_table, ++ &font_face->base.hash_entry); ++ if (unlikely (status)) ++ goto FAIL; ++ ++DONE: ++ _cairo_win32_font_face_hash_table_unlock (); ++ + return &font_face->base; ++ ++FAIL: ++ _cairo_win32_font_face_hash_table_unlock (); ++ ++ return (cairo_font_face_t *)&_cairo_font_face_nil; + } + + /** + * cairo_win32_font_face_create_for_logfontw: + * @logfont: A #LOGFONTW structure specifying the font to use. + * The lfHeight, lfWidth, lfOrientation and lfEscapement + * fields of this structure are ignored. + * +@@ -2176,8 +2319,14 @@ cairo_win32_scaled_font_get_device_to_lo + cairo_win32_scaled_font_t *win_font = (cairo_win32_scaled_font_t *)scaled_font; + if (! _cairo_scaled_font_is_win32 (scaled_font)) { + _cairo_error_throw (CAIRO_STATUS_FONT_TYPE_MISMATCH); + cairo_matrix_init_identity (device_to_logical); + return; + } + *device_to_logical = win_font->device_to_logical; + } ++ ++void ++_cairo_win32_font_reset_static_data (void) ++{ ++ _cairo_win32_font_face_hash_table_destroy (); ++} +diff --git a/gfx/cairo/cairo/src/cairoint.h b/gfx/cairo/cairo/src/cairoint.h +--- a/gfx/cairo/cairo/src/cairoint.h ++++ b/gfx/cairo/cairo/src/cairoint.h +@@ -403,16 +403,19 @@ cairo_private void + _cairo_reset_static_data (void); + + cairo_private void + _cairo_toy_font_face_reset_static_data (void); + + cairo_private void + _cairo_ft_font_reset_static_data (void); + ++cairo_private void ++_cairo_win32_font_reset_static_data (void); ++ + /* the font backend interface */ + + struct _cairo_unscaled_font_backend { + void (*destroy) (void *unscaled_font); + }; + + /* #cairo_toy_font_face_t - simple family/slant/weight font faces used for + * the built-in font API From f2ed12db1ea280c783806ad9fc0c00527177a042 Mon Sep 17 00:00:00 2001 From: Vladan Djeric Date: Thu, 27 Dec 2012 12:28:33 -0500 Subject: [PATCH 042/469] Bug 824577 - about:telemetry addon section was not getting displayed. r=mak --- toolkit/content/aboutTelemetry.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/toolkit/content/aboutTelemetry.js b/toolkit/content/aboutTelemetry.js index b911236811ca..b722835341dc 100644 --- a/toolkit/content/aboutTelemetry.js +++ b/toolkit/content/aboutTelemetry.js @@ -714,13 +714,17 @@ function onLoad() { } // Show addon histogram data - histograms = Telemetry.addonHistogramSnapshots; - if (Object.keys(histograms).length) { - let addonDiv = document.getElementById("addon-histograms"); + let addonDiv = document.getElementById("addon-histograms"); + let addonHistogramsRendered = false; + let addonData = Telemetry.addonHistogramSnapshots; + for (let [addon, histograms] of Iterator(addonData)) { for (let [name, hgram] of Iterator(histograms)) { - Histogram.render(addonDiv, "ADDON_" + name, hgram); + addonHistogramsRendered = true; + Histogram.render(addonDiv, addon + ": " + name, hgram); } - } else { + } + + if (!addonHistogramsRendered) { showEmptySectionMessage("addon-histograms-section"); } From 190a1a2986da0437bd5a97d4cf09169dca53ad7d Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Mon, 17 Dec 2012 15:40:50 -0500 Subject: [PATCH 043/469] Bug 756709 - Make ThreadLocal::set crash on failure (which really can only happen if per-thread memory for the TLS entry couldn't be allocated, which should be really rare). r=Ms2ger --HG-- extra : rebase_source : ecda463195c9b67ef6b7d02ef32ed0aa56bc11bc --- mfbt/ThreadLocal.h | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/mfbt/ThreadLocal.h b/mfbt/ThreadLocal.h index 712f1f12d404..2b4eb30207a3 100644 --- a/mfbt/ThreadLocal.h +++ b/mfbt/ThreadLocal.h @@ -5,8 +5,8 @@ /* Cross-platform lightweight thread local data wrappers. */ -#ifndef mozilla_TLS_h_ -#define mozilla_TLS_h_ +#ifndef mozilla_ThreadLocal_h_ +#define mozilla_ThreadLocal_h_ #if defined(XP_WIN) // This file will get included in any file that wants to add a profiler mark. @@ -17,8 +17,8 @@ // Unfortunately, even including these headers causes us to add a bunch of ugly // stuff to our namespace e.g #define CreateEvent CreateEventW extern "C" { -__declspec(dllimport) void * __stdcall TlsGetValue(unsigned long); -__declspec(dllimport) int __stdcall TlsSetValue(unsigned long, void *); +__declspec(dllimport) void* __stdcall TlsGetValue(unsigned long); +__declspec(dllimport) int __stdcall TlsSetValue(unsigned long, void*); __declspec(dllimport) unsigned long __stdcall TlsAlloc(); } #else @@ -83,7 +83,7 @@ class ThreadLocal inline T get() const; - inline bool set(const T value); + inline void set(const T value); bool initialized() const { return inited; @@ -98,7 +98,7 @@ template inline bool ThreadLocal::init() { - MOZ_STATIC_ASSERT(sizeof(T) <= sizeof(void *), + MOZ_STATIC_ASSERT(sizeof(T) <= sizeof(void*), "mozilla::ThreadLocal can't be used for types larger than " "a pointer"); MOZ_ASSERT(!initialized()); @@ -126,19 +126,22 @@ ThreadLocal::get() const } template -inline bool +inline void ThreadLocal::set(const T value) { MOZ_ASSERT(initialized()); Helper h; h.value = value; + bool succeeded; #ifdef XP_WIN - return TlsSetValue(key, h.ptr); + succeeded = TlsSetValue(key, h.ptr); #else - return !pthread_setspecific(key, h.ptr); + succeeded = !pthread_setspecific(key, h.ptr); #endif + if (!succeeded) + MOZ_CRASH(); } } // namespace mozilla -#endif // mozilla_TLS_h_ +#endif // mozilla_ThreadLocal_h_ From a8d117b970752884049530f60ba6c1fcd31c6652 Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Tue, 25 Dec 2012 14:16:24 -0500 Subject: [PATCH 044/469] Bug 823283 - Followup comment typo fix. r=lumpy --HG-- extra : rebase_source : 06d73c3465c2e0f0ef105b505c06ac34930c23ff --- js/src/frontend/BytecodeEmitter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 94c921ba2b2d..97a5c13317c9 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -1185,7 +1185,7 @@ TryConvertToGname(BytecodeEmitter *bce, ParseNode *pn, JSOp *op) !bce->sc->strict) { // If you change anything here, you might also need to change - // js::CheckUndeclaredVarAssignment. + // js::ReportIfUndeclaredVarAssignment. switch (*op) { case JSOP_NAME: *op = JSOP_GETGNAME; break; case JSOP_SETNAME: *op = JSOP_SETGNAME; break; From 856405164c5b612373f24f28648c0e0204778176 Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Wed, 19 Dec 2012 17:32:22 -0500 Subject: [PATCH 045/469] Bug 824163 - Properly specify the path to the user.js to be put into the jsreftest profile so that it's not affected by the test subset being run. r=ted --HG-- extra : rebase_source : 3df9aab1b17e1c10d54a10e519e20ef49410e3ca --- testing/testsuite-targets.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/testsuite-targets.mk b/testing/testsuite-targets.mk index 659b46d7d924..bb4ae79bb1ae 100644 --- a/testing/testsuite-targets.mk +++ b/testing/testsuite-targets.mk @@ -241,7 +241,7 @@ jstestbrowser: $(MAKE) -C $(DEPTH)/config $(MAKE) -C $(DEPTH)/js/src/config $(MAKE) stage-jstests - $(call RUN_REFTEST,$(DIST)/$(TESTS_PATH)/jstests.list --extra-profile-file=$(DIST)/$(TESTS_PATH)/user.js) + $(call RUN_REFTEST,$(DIST)/$(TESTS_PATH)/jstests.list --extra-profile-file=$(DIST)/test-package-stage/jsreftest/tests/user.js) $(CHECK_TEST_ERROR) GARBAGE += $(addsuffix .log,$(MOCHITESTS) reftest crashtest jstestbrowser) From c4fadd19811452f4d283f4201961e1a2a7de500c Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Sat, 15 Sep 2012 11:19:55 -0700 Subject: [PATCH 046/469] Bug 823283 - Remove all remaining uses of JSRESOLVE_QUALIFIED, and the few remaining tests (which were pretty much purely diagnostic). r=luke --HG-- extra : rebase_source : 51e2ac7ccc76be84d12600baeb6d458c2927bea7 --- dom/bindings/Codegen.py | 2 +- dom/bindings/DOMJSProxyHandler.cpp | 2 +- js/src/ion/IonBuilder.cpp | 2 +- js/src/jsapi.cpp | 32 +++++----- js/src/jsapi.h | 4 +- js/src/jsfun.cpp | 8 +-- js/src/jsobj.cpp | 13 ++-- js/src/jsproxy.cpp | 15 +++-- js/src/methodjit/FastOps.cpp | 2 +- js/src/shell/js.cpp | 89 +++++++++++++-------------- js/src/vm/ScopeObject.cpp | 2 +- js/xpconnect/src/XPCComponents.cpp | 5 +- js/xpconnect/src/XPCQuickStubs.cpp | 5 +- js/xpconnect/wrappers/AccessCheck.cpp | 2 +- js/xpconnect/wrappers/XrayWrapper.cpp | 19 +++--- 15 files changed, 93 insertions(+), 109 deletions(-) diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 14a9e91a83ce..c025cdd0ab1b 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -5836,7 +5836,7 @@ class CGDOMJSProxyHandler_getOwnPropertyDescriptor(ClassMethod): return setOrIndexedGet + """JSObject* expando; if (!xpc::WrapperFactory::IsXrayWrapper(proxy) && (expando = GetExpandoObject(proxy))) { - unsigned flags = (set ? JSRESOLVE_ASSIGNING : 0) | JSRESOLVE_QUALIFIED; + unsigned flags = (set ? JSRESOLVE_ASSIGNING : 0); if (!JS_GetPropertyDescriptorById(cx, expando, id, flags, desc)) { return false; } diff --git a/dom/bindings/DOMJSProxyHandler.cpp b/dom/bindings/DOMJSProxyHandler.cpp index 8b734924ef66..34de291441cb 100644 --- a/dom/bindings/DOMJSProxyHandler.cpp +++ b/dom/bindings/DOMJSProxyHandler.cpp @@ -95,7 +95,7 @@ DOMProxyHandler::getPropertyDescriptor(JSContext* cx, JSObject* proxy, jsid id, return true; } - return JS_GetPropertyDescriptorById(cx, proto, id, JSRESOLVE_QUALIFIED, desc); + return JS_GetPropertyDescriptorById(cx, proto, id, 0, desc); } bool diff --git a/js/src/ion/IonBuilder.cpp b/js/src/ion/IonBuilder.cpp index 68007eb928d4..68814c9f3589 100644 --- a/js/src/ion/IonBuilder.cpp +++ b/js/src/ion/IonBuilder.cpp @@ -4560,7 +4560,7 @@ IonBuilder::jsop_initprop(HandlePropertyName name) RootedShape shape(cx); RootedId id(cx, NameToId(name)); bool res = LookupPropertyWithFlags(cx, templateObject, id, - JSRESOLVE_QUALIFIED, &holder, &shape); + 0, &holder, &shape); if (!res) return false; diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 9d4aa5d5dfcb..c2e30da31006 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -3350,7 +3350,7 @@ JS_GetConstructor(JSContext *cx, JSObject *protoArg) CHECK_REQUEST(cx); assertSameCompartment(cx, proto); { - JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED); + JSAutoResolveFlags rf(cx, 0); if (!JSObject::getProperty(cx, proto, proto, cx->names().constructor, &cval)) return NULL; @@ -3597,7 +3597,7 @@ JS_LookupPropertyById(JSContext *cx, JSObject *objArg, jsid idArg, jsval *vp) RootedObject obj2(cx); RootedShape prop(cx); - return LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop) && + return LookupPropertyById(cx, obj, id, 0, &obj2, &prop) && LookupResult(cx, obj, obj2, id, prop, vp); } @@ -3668,7 +3668,7 @@ JS_HasPropertyById(JSContext *cx, JSObject *objArg, jsid idArg, JSBool *foundp) RootedId id(cx, idArg); RootedObject obj2(cx); RootedShape prop(cx); - JSBool ok = LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop); + JSBool ok = LookupPropertyById(cx, obj, id, 0, &obj2, &prop); *foundp = (prop != NULL); return ok; } @@ -3714,7 +3714,7 @@ JS_AlreadyHasOwnPropertyById(JSContext *cx, JSObject *objArg, jsid id_, JSBool * RootedObject obj2(cx); RootedShape prop(cx); - if (!LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop)) + if (!LookupPropertyById(cx, obj, id, 0, &obj2, &prop)) return JS_FALSE; *foundp = (obj == obj2); return JS_TRUE; @@ -3838,7 +3838,7 @@ DefinePropertyById(JSContext *cx, HandleObject obj, HandleId id, HandleValue val ? JS_FUNC_TO_DATA_PTR(JSObject *, setter) : NULL); - JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED); + JSAutoResolveFlags rf(cx, 0); if (flags != 0 && obj->isNative()) { return DefineNativeProperty(cx, obj, id, value, getter, setter, attrs, flags, tinyid); @@ -4092,7 +4092,7 @@ JS_GetPropertyAttrsGetterAndSetterById(JSContext *cx, JSObject *objArg, jsid idA RootedObject obj(cx, objArg); RootedId id(cx, idArg); AutoPropertyDescriptorRooter desc(cx); - if (!GetPropertyDescriptorById(cx, obj, id, JSRESOLVE_QUALIFIED, JS_FALSE, &desc)) + if (!GetPropertyDescriptorById(cx, obj, id, 0, JS_FALSE, &desc)) return false; *attrsp = desc.attrs; @@ -4164,7 +4164,7 @@ SetPropertyAttributesById(JSContext *cx, HandleObject obj, HandleId id, unsigned RootedObject obj2(cx); RootedShape shape(cx); - if (!LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &shape)) + if (!LookupPropertyById(cx, obj, id, 0, &obj2, &shape)) return false; if (!shape || obj != obj2) { *foundp = false; @@ -4215,7 +4215,7 @@ JS_ForwardGetPropertyTo(JSContext *cx, JSObject *objArg, jsid idArg, JSObject *o CHECK_REQUEST(cx); assertSameCompartment(cx, obj, id); assertSameCompartment(cx, onBehalfOf); - JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED); + JSAutoResolveFlags rf(cx, 0); RootedValue value(cx); if (!JSObject::getGeneric(cx, obj, onBehalfOf, id, &value)) @@ -4254,7 +4254,7 @@ JS_ForwardGetElementTo(JSContext *cx, JSObject *objArg, uint32_t index, JSObject AssertHeapIsIdle(cx); CHECK_REQUEST(cx); assertSameCompartment(cx, obj); - JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED); + JSAutoResolveFlags rf(cx, 0); RootedValue value(cx); if (!JSObject::getElement(cx, obj, onBehalfOf, index, &value)) @@ -4272,7 +4272,7 @@ JS_GetElementIfPresent(JSContext *cx, JSObject *objArg, uint32_t index, JSObject AssertHeapIsIdle(cx); CHECK_REQUEST(cx); assertSameCompartment(cx, obj); - JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED); + JSAutoResolveFlags rf(cx, 0); RootedValue value(cx); bool isPresent; @@ -4343,7 +4343,7 @@ JS_SetPropertyById(JSContext *cx, JSObject *objArg, jsid idArg, jsval *vp) AssertHeapIsIdle(cx); CHECK_REQUEST(cx); assertSameCompartment(cx, obj, id); - JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING); + JSAutoResolveFlags rf(cx, JSRESOLVE_ASSIGNING); RootedValue value(cx, *vp); if (!JSObject::setGeneric(cx, obj, obj, id, &value, false)) @@ -4360,7 +4360,7 @@ JS_SetElement(JSContext *cx, JSObject *objArg, uint32_t index, jsval *vp) AssertHeapIsIdle(cx); CHECK_REQUEST(cx); assertSameCompartment(cx, obj, *vp); - JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING); + JSAutoResolveFlags rf(cx, JSRESOLVE_ASSIGNING); RootedValue value(cx, *vp); if (!JSObject::setElement(cx, obj, obj, index, &value, false)) @@ -4393,7 +4393,7 @@ JS_DeletePropertyById2(JSContext *cx, JSObject *objArg, jsid id, jsval *rval) AssertHeapIsIdle(cx); CHECK_REQUEST(cx); assertSameCompartment(cx, obj, id); - JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED); + JSAutoResolveFlags rf(cx, 0); RootedValue value(cx); @@ -4417,7 +4417,7 @@ JS_DeleteElement2(JSContext *cx, JSObject *objArg, uint32_t index, jsval *rval) AssertHeapIsIdle(cx); CHECK_REQUEST(cx); assertSameCompartment(cx, obj); - JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED); + JSAutoResolveFlags rf(cx, 0); RootedValue value(cx); if (!JSObject::deleteElement(cx, obj, index, &value, false)) @@ -4433,7 +4433,7 @@ JS_DeleteProperty2(JSContext *cx, JSObject *objArg, const char *name, jsval *rva RootedObject obj(cx, objArg); CHECK_REQUEST(cx); assertSameCompartment(cx, obj); - JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED); + JSAutoResolveFlags rf(cx, 0); JSAtom *atom = Atomize(cx, name, strlen(name)); if (!atom) @@ -4453,7 +4453,7 @@ JS_DeleteUCProperty2(JSContext *cx, JSObject *objArg, const jschar *name, size_t RootedObject obj(cx, objArg); CHECK_REQUEST(cx); assertSameCompartment(cx, obj); - JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED); + JSAutoResolveFlags rf(cx, 0); JSAtom *atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen)); if (!atom) diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 7156e99b1b98..bf84ce4347f7 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -1836,7 +1836,6 @@ typedef JSBool /* * Like JSResolveOp, but flags provide contextual information as follows: * - * JSRESOLVE_QUALIFIED a qualified property id: obj.id or obj[id], not id * JSRESOLVE_ASSIGNING obj[id] is on the left-hand side of an assignment * * The *objp out parameter, on success, should be null to indicate that id @@ -4230,8 +4229,7 @@ JS_IdToValue(JSContext *cx, jsid id, jsval *vp); /* * JSNewResolveOp flag bits. */ -#define JSRESOLVE_QUALIFIED 0x01 /* resolve a qualified property id */ -#define JSRESOLVE_ASSIGNING 0x02 /* resolve on the left of assignment */ +#define JSRESOLVE_ASSIGNING 0x01 /* resolve on the left of assignment */ /* * Invoke the [[DefaultValue]] hook (see ES5 8.6.2) with the provided hint on diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 067a33b4266b..2b0b8978cca2 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -211,22 +211,22 @@ fun_enumerate(JSContext *cx, HandleObject obj) if (!obj->isBoundFunction()) { id = NameToId(cx->names().classPrototype); - if (!JSObject::hasProperty(cx, obj, id, &found, JSRESOLVE_QUALIFIED)) + if (!JSObject::hasProperty(cx, obj, id, &found, 0)) return false; } id = NameToId(cx->names().length); - if (!JSObject::hasProperty(cx, obj, id, &found, JSRESOLVE_QUALIFIED)) + if (!JSObject::hasProperty(cx, obj, id, &found, 0)) return false; id = NameToId(cx->names().name); - if (!JSObject::hasProperty(cx, obj, id, &found, JSRESOLVE_QUALIFIED)) + if (!JSObject::hasProperty(cx, obj, id, &found, 0)) return false; for (unsigned i = 0; i < ArrayLength(poisonPillProps); i++) { const uint16_t offset = poisonPillProps[i]; id = NameToId(OFFSET_TO_NAME(cx->runtime, offset)); - if (!JSObject::hasProperty(cx, obj, id, &found, JSRESOLVE_QUALIFIED)) + if (!JSObject::hasProperty(cx, obj, id, &found, 0)) return false; } diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 14f86ec766d1..53d1297ba402 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -140,7 +140,7 @@ JSBool js_HasOwnProperty(JSContext *cx, LookupGenericOp lookup, HandleObject obj, HandleId id, MutableHandleObject objp, MutableHandleShape propp) { - JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED); + JSAutoResolveFlags rf(cx, 0); if (lookup) { if (!lookup(cx, obj, id, objp, propp)) return false; @@ -328,7 +328,7 @@ js::GetFirstArgumentAsObject(JSContext *cx, unsigned argc, Value *vp, const char static bool HasProperty(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp, bool *foundp) { - if (!JSObject::hasProperty(cx, obj, id, foundp, JSRESOLVE_QUALIFIED)) + if (!JSObject::hasProperty(cx, obj, id, foundp, 0)) return false; if (!*foundp) { vp.setUndefined(); @@ -1520,11 +1520,8 @@ js_InferFlags(JSContext *cx, unsigned defaultFlags) if (!script) return defaultFlags; - const JSCodeSpec *cs = &js_CodeSpec[*pc]; - uint32_t format = cs->format; + uint32_t format = js_CodeSpec[*pc].format; unsigned flags = 0; - if (JOF_MODE(format) != JOF_NAME) - flags |= JSRESOLVE_QUALIFIED; if (format & JOF_SET) flags |= JSRESOLVE_ASSIGNING; return flags; @@ -3444,7 +3441,7 @@ baseops::GetPropertyDefault(JSContext *cx, HandleObject obj, HandleId id, Handle { RootedShape prop(cx); RootedObject obj2(cx); - if (!LookupPropertyWithFlags(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop)) + if (!LookupPropertyWithFlags(cx, obj, id, 0, &obj2, &prop)) return false; if (!prop) { @@ -3458,7 +3455,7 @@ baseops::GetPropertyDefault(JSContext *cx, HandleObject obj, HandleId id, Handle JSBool js::GetMethod(JSContext *cx, HandleObject obj, HandleId id, unsigned getHow, MutableHandleValue vp) { - JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED); + JSAutoResolveFlags rf(cx, 0); GenericIdOp op = obj->getOps()->getGeneric; if (!op) { diff --git a/js/src/jsproxy.cpp b/js/src/jsproxy.cpp index 7c2658345d26..c1780d853f67 100644 --- a/js/src/jsproxy.cpp +++ b/js/src/jsproxy.cpp @@ -379,7 +379,7 @@ DirectProxyHandler::getPropertyDescriptor(JSContext *cx, JSObject *proxy, PropertyDescriptor *desc) { RootedObject target(cx, GetProxyTargetObject(proxy)); - return JS_GetPropertyDescriptorById(cx, target, id, JSRESOLVE_QUALIFIED, desc); + return JS_GetPropertyDescriptorById(cx, target, id, 0, desc); } static bool @@ -406,7 +406,7 @@ DirectProxyHandler::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, PropertyDescriptor *desc) { RootedObject target(cx, GetProxyTargetObject(proxy)); - return GetOwnPropertyDescriptor(cx, target, id, JSRESOLVE_QUALIFIED, desc); + return GetOwnPropertyDescriptor(cx, target, id, 0, desc); } bool @@ -546,7 +546,7 @@ DirectProxyHandler::hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp) { RootedObject target(cx, GetProxyTargetObject(proxy)); AutoPropertyDescriptorRooter desc(cx); - if (!JS_GetPropertyDescriptorById(cx, target, id, JSRESOLVE_QUALIFIED, &desc)) + if (!JS_GetPropertyDescriptorById(cx, target, id, 0, &desc)) return false; *bp = (desc.obj == target); return true; @@ -1254,7 +1254,7 @@ static bool HasOwn(JSContext *cx, HandleObject obj, HandleId id, bool *bp) { AutoPropertyDescriptorRooter desc(cx); - if (!JS_GetPropertyDescriptorById(cx, obj, id, JSRESOLVE_QUALIFIED, &desc)) + if (!JS_GetPropertyDescriptorById(cx, obj, id, 0, &desc)) return false; *bp = (desc.obj == obj); return true; @@ -1587,7 +1587,7 @@ ScriptedDirectProxyHandler::getPropertyDescriptor(JSContext *cx, JSObject *proxy JS_ASSERT(!desc->obj); return true; } - return JS_GetPropertyDescriptorById(cx, proto, id, JSRESOLVE_QUALIFIED, desc); + return JS_GetPropertyDescriptorById(cx, proto, id, 0, desc); } bool @@ -2211,8 +2211,7 @@ Proxy::getPropertyDescriptor(JSContext *cx, JSObject *proxy_, jsid id_, bool set if (desc->obj) return true; INVOKE_ON_PROTOTYPE(cx, handler, proxy, - JS_GetPropertyDescriptorById(cx, proto, id, - JSRESOLVE_QUALIFIED, desc)); + JS_GetPropertyDescriptorById(cx, proto, id, 0, desc)); } bool @@ -2398,7 +2397,7 @@ Proxy::set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id AutoPropertyDescriptorRooter desc(cx); if (handler->hasOwn(cx, proxy, id, &hasOwn) && !hasOwn && handler->getPrototypeOf(cx, proxy, proto.address()) && proto && - JS_GetPropertyDescriptorById(cx, proto, id, JSRESOLVE_QUALIFIED, &desc) && + JS_GetPropertyDescriptorById(cx, proto, id, 0, &desc) && desc.obj && desc.setter) { return JSObject::setGeneric(cx, proto, receiver, id, vp, strict); diff --git a/js/src/methodjit/FastOps.cpp b/js/src/methodjit/FastOps.cpp index db7b9e171bd8..fbd57481b5f5 100644 --- a/js/src/methodjit/FastOps.cpp +++ b/js/src/methodjit/FastOps.cpp @@ -2492,7 +2492,7 @@ mjit::Compiler::jsop_initprop() #ifdef DEBUG bool res = #endif - LookupPropertyWithFlags(cx, baseobj, id, JSRESOLVE_QUALIFIED, &holder, &shape); + LookupPropertyWithFlags(cx, baseobj, id, 0, &holder, &shape); JS_ASSERT(res && shape && holder == baseobj); RegisterID objReg = frame.copyDataIntoReg(obj); diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index aea96fe32152..d015b4cf7ac6 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -2798,7 +2798,7 @@ resolver_enumerate(JSContext *cx, HandleObject obj) RootedObject ignore(cx); for (size_t i = 0; ok && i < ida.length(); i++) { Rooted id(cx, ida[i]); - ok = CopyProperty(cx, obj, referent, id, JSRESOLVE_QUALIFIED, &ignore); + ok = CopyProperty(cx, obj, referent, id, 0, &ignore); } return ok; } @@ -4195,9 +4195,8 @@ its_resolve(JSContext *cx, HandleObject obj, HandleId id, unsigned flags, { if (its_noisy) { IdStringifier idString(cx, id); - fprintf(gOutFile, "resolving its property %s, flags {%s,%s}\n", + fprintf(gOutFile, "resolving its property %s, flags {%s}\n", idString.getBytes(), - (flags & JSRESOLVE_QUALIFIED) ? "qualified" : "", (flags & JSRESOLVE_ASSIGNING) ? "assigning" : ""); } return true; @@ -4446,54 +4445,52 @@ global_resolve(JSContext *cx, HandleObject obj, HandleId id, unsigned flags, #endif #if defined(SHELL_HACK) && defined(DEBUG) && defined(XP_UNIX) - if (!(flags & JSRESOLVE_QUALIFIED)) { - /* - * Do this expensive hack only for unoptimized Unix builds, which are - * not used for benchmarking. - */ - char *path, *comp, *full; - const char *name; - bool ok, found; - JSFunction *fun; + /* + * Do this expensive hack only for unoptimized Unix builds, which are + * not used for benchmarking. + */ + char *path, *comp, *full; + const char *name; + bool ok, found; + JSFunction *fun; - if (!JSVAL_IS_STRING(id)) - return true; - path = getenv("PATH"); - if (!path) - return true; - path = JS_strdup(cx, path); - if (!path) - return false; - JSAutoByteString name(cx, JSVAL_TO_STRING(id)); - if (!name) - return false; - ok = true; - for (comp = strtok(path, ":"); comp; comp = strtok(NULL, ":")) { - if (*comp != '\0') { - full = JS_smprintf("%s/%s", comp, name.ptr()); - if (!full) { - JS_ReportOutOfMemory(cx); - ok = false; - break; - } - } else { - full = (char *)name; - } - found = (access(full, X_OK) == 0); - if (*comp != '\0') - free(full); - if (found) { - fun = JS_DefineFunction(cx, obj, name, Exec, 0, - JSPROP_ENUMERATE); - ok = (fun != NULL); - if (ok) - objp.set(obj); + if (!JSVAL_IS_STRING(id)) + return true; + path = getenv("PATH"); + if (!path) + return true; + path = JS_strdup(cx, path); + if (!path) + return false; + JSAutoByteString name(cx, JSVAL_TO_STRING(id)); + if (!name) + return false; + ok = true; + for (comp = strtok(path, ":"); comp; comp = strtok(NULL, ":")) { + if (*comp != '\0') { + full = JS_smprintf("%s/%s", comp, name.ptr()); + if (!full) { + JS_ReportOutOfMemory(cx); + ok = false; break; } + } else { + full = (char *)name; + } + found = (access(full, X_OK) == 0); + if (*comp != '\0') + free(full); + if (found) { + fun = JS_DefineFunction(cx, obj, name, Exec, 0, + JSPROP_ENUMERATE); + ok = (fun != NULL); + if (ok) + objp.set(obj); + break; } - JS_free(cx, path); - return ok; } + JS_free(cx, path); + return ok; #else return true; #endif diff --git a/js/src/vm/ScopeObject.cpp b/js/src/vm/ScopeObject.cpp index 4bf5be2ea58d..e49dbdf55441 100644 --- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -1350,7 +1350,7 @@ class DebugScopeProxy : public BaseProxyHandler return true; } - return JS_GetPropertyDescriptorById(cx, scope, id, JSRESOLVE_QUALIFIED, desc); + return JS_GetPropertyDescriptorById(cx, scope, id, 0, desc); } bool get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid idArg, Value *vp) MOZ_OVERRIDE diff --git a/js/xpconnect/src/XPCComponents.cpp b/js/xpconnect/src/XPCComponents.cpp index 04f00f939809..bdf10bccc744 100644 --- a/js/xpconnect/src/XPCComponents.cpp +++ b/js/xpconnect/src/XPCComponents.cpp @@ -3150,11 +3150,8 @@ xpc::SandboxProxyHandler::getPropertyDescriptor(JSContext *cx, JSObject *proxy, js::RootedId id(cx, id_); MOZ_ASSERT(js::GetObjectCompartment(obj) == js::GetObjectCompartment(proxy)); - // XXXbz Not sure about the JSRESOLVE_QUALIFIED here, but we have - // no way to tell for sure whether to use it. if (!JS_GetPropertyDescriptorById(cx, obj, id, - (set ? JSRESOLVE_ASSIGNING : 0) | JSRESOLVE_QUALIFIED, - desc)) + (set ? JSRESOLVE_ASSIGNING : 0), desc)) return false; if (!desc->obj) diff --git a/js/xpconnect/src/XPCQuickStubs.cpp b/js/xpconnect/src/XPCQuickStubs.cpp index 8965399102df..f0cbda4a3305 100644 --- a/js/xpconnect/src/XPCQuickStubs.cpp +++ b/js/xpconnect/src/XPCQuickStubs.cpp @@ -155,7 +155,7 @@ LookupGetterOrSetter(JSContext *cx, JSBool wantGetter, unsigned argc, jsval *vp) jsid id; JSPropertyDescriptor desc; if (!JS_ValueToId(cx, idval, &id) || - !JS_GetPropertyDescriptorById(cx, obj, id, JSRESOLVE_QUALIFIED, &desc)) + !JS_GetPropertyDescriptorById(cx, obj, id, 0, &desc)) return false; // No property at all means no getters or setters possible. @@ -238,8 +238,7 @@ DefineGetterOrSetter(JSContext *cx, unsigned argc, JSBool wantGetter, jsval *vp) return forward(cx, argc, vp); if (!JS_ValueToId(cx, idval, &id) || - !JS_LookupPropertyWithFlagsById(cx, obj, id, - JSRESOLVE_QUALIFIED, &obj2, &v) || + !JS_LookupPropertyWithFlagsById(cx, obj, id, 0, &obj2, &v) || (obj2 && !JS_GetPropertyAttrsGetterAndSetterById(cx, obj2, id, &attrs, &found, &getter, &setter))) diff --git a/js/xpconnect/wrappers/AccessCheck.cpp b/js/xpconnect/wrappers/AccessCheck.cpp index c7a968c088e3..3e1dcdba669f 100644 --- a/js/xpconnect/wrappers/AccessCheck.cpp +++ b/js/xpconnect/wrappers/AccessCheck.cpp @@ -392,7 +392,7 @@ ExposedPropertiesOnly::check(JSContext *cx, JSObject *wrapper, jsid id, Wrapper: Access access = NO_ACCESS; JSPropertyDescriptor desc; - if (!JS_GetPropertyDescriptorById(cx, hallpass, id, JSRESOLVE_QUALIFIED, &desc)) { + if (!JS_GetPropertyDescriptorById(cx, hallpass, id, 0, &desc)) { return false; // Error } if (!desc.obj || !(desc.attrs & JSPROP_ENUMERATE)) diff --git a/js/xpconnect/wrappers/XrayWrapper.cpp b/js/xpconnect/wrappers/XrayWrapper.cpp index 46fc7bb5e84a..c9b70afbbc82 100644 --- a/js/xpconnect/wrappers/XrayWrapper.cpp +++ b/js/xpconnect/wrappers/XrayWrapper.cpp @@ -638,7 +638,7 @@ XPCWrappedNativeXrayTraits::resolveDOMCollectionProperty(JSContext *cx, JSObject bool retval = true; JSObject *pobj = NULL; - unsigned flags = (set ? JSRESOLVE_ASSIGNING : 0) | JSRESOLVE_QUALIFIED; + unsigned flags = (set ? JSRESOLVE_ASSIGNING : 0); nsresult rv = wn->GetScriptableInfo()->GetCallback()->NewResolve(wn, cx, wrapper, id, flags, &pobj, &retval); if (NS_FAILED(rv)) { @@ -647,11 +647,8 @@ XPCWrappedNativeXrayTraits::resolveDOMCollectionProperty(JSContext *cx, JSObject return false; } - if (pobj && !JS_GetPropertyDescriptorById(cx, holder, id, - JSRESOLVE_QUALIFIED, desc)) - { + if (pobj && !JS_GetPropertyDescriptorById(cx, holder, id, 0, desc)) return false; - } return true; } @@ -979,7 +976,7 @@ XPCWrappedNativeXrayTraits::resolveOwnProperty(JSContext *cx, js::Wrapper &jsWra return true; } - unsigned flags = (set ? JSRESOLVE_ASSIGNING : 0) | JSRESOLVE_QUALIFIED; + unsigned flags = (set ? JSRESOLVE_ASSIGNING : 0); JSBool hasProp; if (!JS_HasPropertyById(cx, holder, id, &hasProp)) { return false; @@ -1327,7 +1324,7 @@ XrayWrapper::getPropertyDescriptor(JSContext *cx, JSObject *wrappe { JSAutoCompartment ac(cx, obj); if (!JS_GetPropertyDescriptorById(cx, obj, id, - (set ? JSRESOLVE_ASSIGNING : 0) | JSRESOLVE_QUALIFIED, + (set ? JSRESOLVE_ASSIGNING : 0), desc)) { return false; } @@ -1368,7 +1365,7 @@ XrayWrapper::getPropertyDescriptor(JSContext *cx, JSObject *wrappe if (desc->obj) return true; - if (!JS_GetPropertyDescriptorById(cx, holder, id, JSRESOLVE_QUALIFIED, desc)) + if (!JS_GetPropertyDescriptorById(cx, holder, id, 0, desc)) return false; if (desc->obj) { desc->obj = wrapper; @@ -1396,7 +1393,7 @@ XrayWrapper::getPropertyDescriptor(JSContext *cx, JSObject *wrappe desc->obj = wrapper; - unsigned flags = (set ? JSRESOLVE_ASSIGNING : 0) | JSRESOLVE_QUALIFIED; + unsigned flags = (set ? JSRESOLVE_ASSIGNING : 0); return JS_DefinePropertyById(cx, holder, id, desc->value, desc->getter, desc->setter, desc->attrs) && JS_GetPropertyDescriptorById(cx, holder, id, flags, desc); @@ -1429,7 +1426,7 @@ XrayWrapper::getOwnPropertyDescriptor(JSContext *cx, JSObject *wra { JSAutoCompartment ac(cx, obj); if (!JS_GetPropertyDescriptorById(cx, obj, id, - (set ? JSRESOLVE_ASSIGNING : 0) | JSRESOLVE_QUALIFIED, + (set ? JSRESOLVE_ASSIGNING : 0), desc)) { return false; } @@ -1445,7 +1442,7 @@ XrayWrapper::getOwnPropertyDescriptor(JSContext *cx, JSObject *wra if (desc->obj) return true; - unsigned flags = (set ? JSRESOLVE_ASSIGNING : 0) | JSRESOLVE_QUALIFIED; + unsigned flags = (set ? JSRESOLVE_ASSIGNING : 0); if (!JS_GetPropertyDescriptorById(cx, holder, id, flags, desc)) return false; From a3f38a3a84d29c0cdd5705358b31ca0410c821ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hubert=20Figui=C3=A8re?= Date: Tue, 25 Dec 2012 15:06:13 -0800 Subject: [PATCH 047/469] Bug 821498 - Make sure to always send the queued reports too. r=fabrice,margaret --HG-- extra : rebase_source : 59a5f2fe7e0086131538cb66cb0d04e50dc32f5e --- b2g/chrome/content/shell.js | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/b2g/chrome/content/shell.js b/b2g/chrome/content/shell.js index db959efe3968..9d08092db5fa 100644 --- a/b2g/chrome/content/shell.js +++ b/b2g/chrome/content/shell.js @@ -103,7 +103,7 @@ var shell = { } catch(e) { } // Bail if there isn't a valid crashID. - if (!crashID) { + if (!crashID && !this.CrashSubmit.pendingIDs().length) { return; } @@ -125,10 +125,20 @@ var shell = { }); }, + // this function submit the pending crashes. + // make sure you are online. + submitQueuedCrashes: function shell_submitQueuedCrashes() { + // submit the pending queue. + let pending = shell.CrashSubmit.pendingIDs(); + for (let crashid of pending) { + shell.CrashSubmit.submit(crashid); + } + }, + // This function submits a crash when we're online. submitCrash: function shell_submitCrash(aCrashID) { if (this.onlineForCrashReport()) { - this.CrashSubmit.submit(aCrashID); + this.submitQueuedCrashes(); return; } @@ -136,13 +146,7 @@ var shell = { let network = subject.QueryInterface(Ci.nsINetworkInterface); if (network.state == Ci.nsINetworkInterface.NETWORK_STATE_CONNECTED && network.type == Ci.nsINetworkInterface.NETWORK_TYPE_WIFI) { - shell.CrashSubmit.submit(aCrashID); - - // submit the pending queue. - let pending = shell.CrashSubmit.pendingIDs(); - for (let crashid of pending) { - shell.CrashSubmit.submit(crashid); - } + shell.submitQueuedCrashes(); Services.obs.removeObserver(observer, topic); } From 1301f9f2b658babf5adb341e2648440cc8e32297 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hubert=20Figui=C3=A8re?= Date: Thu, 27 Dec 2012 12:36:28 -0500 Subject: [PATCH 048/469] Bug 806515 - Part 2: use the URL field for content crash. r=kairo --HG-- extra : rebase_source : 1e2ccc8af82adeec4b3cddf8c40af4406b6b1b38 --- dom/ipc/ContentParent.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index 1c1c7f6b7b52..0f2651bfb1ec 100644 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -649,7 +649,7 @@ ContentParent::ActorDestroy(ActorDestroyReason why) CrashReporterParent* crashReporter = static_cast(ManagedPCrashReporterParent()[0]); - crashReporter->AnnotateCrashReport(NS_LITERAL_CSTRING("AppManifestURL"), + crashReporter->AnnotateCrashReport(NS_LITERAL_CSTRING("URL"), NS_ConvertUTF16toUTF8(mAppManifestURL)); crashReporter->GenerateCrashReport(this, NULL); From b4ffef6b041623aca520d2d196e8e2bd96344d4b Mon Sep 17 00:00:00 2001 From: Andrew McCreight Date: Fri, 24 Aug 2012 13:22:23 -0700 Subject: [PATCH 049/469] Bug 824958 - Eliminate nsXULPrototypeScript::ScriptObjectHolder and make field private. r=smaug --- content/xul/content/src/nsXULElement.cpp | 31 ++++++++++--------- content/xul/content/src/nsXULElement.h | 12 +++---- content/xul/document/src/nsXULContentSink.cpp | 2 +- content/xul/document/src/nsXULDocument.cpp | 14 ++++----- 4 files changed, 29 insertions(+), 30 deletions(-) diff --git a/content/xul/content/src/nsXULElement.cpp b/content/xul/content/src/nsXULElement.cpp index 2d0b34b44b47..58ccaecebf03 100644 --- a/content/xul/content/src/nsXULElement.cpp +++ b/content/xul/content/src/nsXULElement.cpp @@ -1858,8 +1858,9 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsXULPrototypeNode) if (tmp->mType == nsXULPrototypeNode::eType_Script) { nsXULPrototypeScript *script = static_cast(tmp); - NS_IMPL_CYCLE_COLLECTION_TRACE_JS_CALLBACK(script->mScriptObject.mObject, - "mScriptObject.mObject") + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_CALLBACK(script->GetScriptObject(), + "mScriptObject") + } NS_IMPL_CYCLE_COLLECTION_TRACE_END @@ -1975,7 +1976,7 @@ nsXULPrototypeElement::Serialize(nsIObjectOutputStream* aStream, rv = tmp; } - if (script->mScriptObject.mObject) { + if (script->GetScriptObject()) { // This may return NS_OK without muxing script->mSrcURI's // data into the cache file, in the case where that // muxed document is already there (written by a prior @@ -2236,7 +2237,7 @@ nsXULPrototypeScript::nsXULPrototypeScript(uint32_t aLineNo, uint32_t aVersion) mOutOfLine(true), mSrcLoadWaiters(nullptr), mLangVersion(aVersion), - mScriptObject() + mScriptObject(nullptr) { } @@ -2253,9 +2254,9 @@ nsXULPrototypeScript::Serialize(nsIObjectOutputStream* aStream, { nsIScriptContext *context = aGlobal->GetScriptContext(); NS_ASSERTION(!mSrcLoading || mSrcLoadWaiters != nullptr || - !mScriptObject.mObject, + !mScriptObject, "script source still loading when serializing?!"); - if (!mScriptObject.mObject) + if (!mScriptObject) return NS_ERROR_FAILURE; // Write basic prototype data @@ -2265,7 +2266,7 @@ nsXULPrototypeScript::Serialize(nsIObjectOutputStream* aStream, rv = aStream->Write32(mLangVersion); if (NS_FAILED(rv)) return rv; // And delegate the writing to the nsIScriptContext - rv = context->Serialize(aStream, mScriptObject.mObject); + rv = context->Serialize(aStream, mScriptObject); if (NS_FAILED(rv)) return rv; return NS_OK; @@ -2328,7 +2329,7 @@ nsXULPrototypeScript::Deserialize(nsIObjectInputStream* aStream, nsresult rv; NS_ASSERTION(!mSrcLoading || mSrcLoadWaiters != nullptr || - !mScriptObject.mObject, + !mScriptObject, "prototype script not well-initialized when deserializing?!"); // Read basic prototype data @@ -2381,7 +2382,7 @@ nsXULPrototypeScript::DeserializeOutOfLine(nsIObjectInputStream* aInput, } } - if (! mScriptObject.mObject) { + if (!mScriptObject) { if (mSrcURI) { rv = cache->GetInputStream(mSrcURI, getter_AddRefs(objectInput)); } @@ -2402,7 +2403,7 @@ nsXULPrototypeScript::DeserializeOutOfLine(nsIObjectInputStream* aInput, bool isChrome = false; mSrcURI->SchemeIs("chrome", &isChrome); if (isChrome) - cache->PutScript(mSrcURI, mScriptObject.mObject); + cache->PutScript(mSrcURI, mScriptObject); } cache->FinishInputStream(mSrcURI); } else { @@ -2489,8 +2490,8 @@ nsXULPrototypeScript::Compile(const PRUnichar* aText, void nsXULPrototypeScript::UnlinkJSObjects() { - if (mScriptObject.mObject) { - mScriptObject.mObject = nullptr; + if (mScriptObject) { + mScriptObject = nullptr; nsContentUtils::DropJSObjects(this); } } @@ -2498,15 +2499,15 @@ nsXULPrototypeScript::UnlinkJSObjects() void nsXULPrototypeScript::Set(JSScript* aObject) { - NS_ASSERTION(!mScriptObject.mObject, "Leaking script object."); + MOZ_ASSERT(!mScriptObject, "Leaking script object."); if (!aObject) { - mScriptObject.mObject = nullptr; + mScriptObject = nullptr; return; } nsContentUtils::HoldJSObjects( this, NS_CYCLE_COLLECTION_PARTICIPANT(nsXULPrototypeNode)); - mScriptObject.mObject = aObject; + mScriptObject = aObject; } //---------------------------------------------------------------------- diff --git a/content/xul/content/src/nsXULElement.h b/content/xul/content/src/nsXULElement.h index 9844f18c402f..f803a17cc323 100644 --- a/content/xul/content/src/nsXULElement.h +++ b/content/xul/content/src/nsXULElement.h @@ -235,13 +235,10 @@ public: } void Set(JSScript* aObject); - struct ScriptObjectHolder + JSScript *GetScriptObject() { - ScriptObjectHolder() : mObject(nullptr) - { - } - JSScript* mObject; - }; + return mScriptObject; + } nsCOMPtr mSrcURI; uint32_t mLineNo; @@ -249,7 +246,8 @@ public: bool mOutOfLine; nsXULDocument* mSrcLoadWaiters; // [OWNER] but not COMPtr uint32_t mLangVersion; - ScriptObjectHolder mScriptObject; +private: + JSScript* mScriptObject; }; class nsXULPrototypeText : public nsXULPrototypeNode diff --git a/content/xul/document/src/nsXULContentSink.cpp b/content/xul/document/src/nsXULContentSink.cpp index 7d70913f865a..3068587e3970 100644 --- a/content/xul/document/src/nsXULContentSink.cpp +++ b/content/xul/document/src/nsXULContentSink.cpp @@ -530,7 +530,7 @@ XULContentSinkImpl::HandleEndElement(const PRUnichar *aName) static_cast(node.get()); // If given a src= attribute, we must ignore script tag content. - if (! script->mSrcURI && ! script->mScriptObject.mObject) { + if (!script->mSrcURI && !script->GetScriptObject()) { nsCOMPtr doc = do_QueryReferent(mDocument); script->mOutOfLine = false; diff --git a/content/xul/document/src/nsXULDocument.cpp b/content/xul/document/src/nsXULDocument.cpp index 226e28f4d502..63343e198b96 100644 --- a/content/xul/document/src/nsXULDocument.cpp +++ b/content/xul/document/src/nsXULDocument.cpp @@ -2932,7 +2932,7 @@ nsXULDocument::ResumeWalk() if (NS_SUCCEEDED(rv) && blocked) return NS_OK; } - else if (scriptproto->mScriptObject.mObject) { + else if (scriptproto->GetScriptObject()) { // An inline script rv = ExecuteScript(scriptproto); if (NS_FAILED(rv)) return rv; @@ -3285,7 +3285,7 @@ nsXULDocument::LoadScript(nsXULPrototypeScript* aScriptProto, bool* aBlock) bool isChromeDoc = IsChromeURI(mDocumentURI); - if (isChromeDoc && aScriptProto->mScriptObject.mObject) { + if (isChromeDoc && aScriptProto->GetScriptObject()) { rv = ExecuteScript(aScriptProto); // Ignore return value from execution, and don't block @@ -3308,7 +3308,7 @@ nsXULDocument::LoadScript(nsXULPrototypeScript* aScriptProto, bool* aBlock) aScriptProto->Set(newScriptObject); } - if (aScriptProto->mScriptObject.mObject) { + if (aScriptProto->GetScriptObject()) { rv = ExecuteScript(aScriptProto); // Ignore return value from execution, and don't block @@ -3466,7 +3466,7 @@ nsXULDocument::OnStreamComplete(nsIStreamLoader* aLoader, if (useXULCache && IsChromeURI(mDocumentURI)) { nsXULPrototypeCache::GetInstance()->PutScript( scriptProto->mSrcURI, - scriptProto->mScriptObject.mObject); + scriptProto->GetScriptObject()); } if (mIsWritingFastLoad && mCurrentPrototype != mMasterPrototype) { @@ -3517,7 +3517,7 @@ nsXULDocument::OnStreamComplete(nsIStreamLoader* aLoader, doc->mNextSrcLoadWaiter = nullptr; // Execute only if we loaded and compiled successfully, then resume - if (NS_SUCCEEDED(aStatus) && scriptProto->mScriptObject.mObject) { + if (NS_SUCCEEDED(aStatus) && scriptProto->GetScriptObject()) { doc->ExecuteScript(scriptProto); } doc->ResumeWalk(); @@ -3558,8 +3558,8 @@ nsXULDocument::ExecuteScript(nsXULPrototypeScript *aScript) // failure getting a script context is fatal. NS_ENSURE_TRUE(context != nullptr, NS_ERROR_UNEXPECTED); - if (aScript->mScriptObject.mObject) - rv = ExecuteScript(context, aScript->mScriptObject.mObject); + if (aScript->GetScriptObject()) + rv = ExecuteScript(context, aScript->GetScriptObject()); else rv = NS_ERROR_UNEXPECTED; return rv; From f4cd4d86eed3a1903a66c555aa2d4980dc3bed88 Mon Sep 17 00:00:00 2001 From: Mark Finkle Date: Sat, 22 Dec 2012 00:27:41 -0500 Subject: [PATCH 050/469] Bug 823550 - Ensure saving favicons to DB happens on the GeckoBackgroundThread r=kats --- mobile/android/base/Favicons.java | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/mobile/android/base/Favicons.java b/mobile/android/base/Favicons.java index 44c236809684..f1347546dc2f 100644 --- a/mobile/android/base/Favicons.java +++ b/mobile/android/base/Favicons.java @@ -6,6 +6,7 @@ package org.mozilla.gecko; import org.mozilla.gecko.db.BrowserDB; +import org.mozilla.gecko.util.GeckoBackgroundThread; import org.mozilla.gecko.util.GeckoJarReader; import org.apache.http.HttpEntity; @@ -205,17 +206,20 @@ public class Favicons { } // Runs in background thread - private void saveFaviconToDb(Bitmap favicon) { + private void saveFaviconToDb(final Bitmap favicon) { if (!mPersist) { return; } - // since the Async task can run this on any number of threads in the - // pool, we need to protect against inserting the same url twice - synchronized(Favicons.this) { - ContentResolver resolver = mContext.getContentResolver(); - BrowserDB.updateFaviconForUrl(resolver, mPageUrl, favicon, mFaviconUrl); - } + // Even though this code is in a background thread, all DB writes + // should happen in GeckoBackgroundThread or we could get locked + // databases. + GeckoBackgroundThread.post(new Runnable() { + public void run() { + ContentResolver resolver = mContext.getContentResolver(); + BrowserDB.updateFaviconForUrl(resolver, mPageUrl, favicon, mFaviconUrl); + } + }); } // Runs in background thread From 186baf5f18d8bc065fd3c4da99381762d6b28c29 Mon Sep 17 00:00:00 2001 From: Cameron McCormack Date: Sat, 22 Dec 2012 16:35:51 +1100 Subject: [PATCH 051/469] Bug 820148 - Add RELEASE_BUILD macro available in pref js files. r=ted --- build/Makefile.in | 2 -- config/rules.mk | 6 ++++++ configure.in | 9 +++++++++ js/src/config/rules.mk | 6 ++++++ 4 files changed, 21 insertions(+), 2 deletions(-) diff --git a/build/Makefile.in b/build/Makefile.in index 62f6cb4cc606..061ef29516b6 100644 --- a/build/Makefile.in +++ b/build/Makefile.in @@ -45,10 +45,8 @@ endif endif ifdef LIBXUL_SDK -GRE_MILESTONE = $(shell $(PYTHON) $(topsrcdir)/config/printconfigsetting.py $(LIBXUL_DIST)/bin/platform.ini Build Milestone) APP_INI_DEPS = $(LIBXUL_DIST)/bin/platform.ini else -GRE_MILESTONE = $(shell tail -n 1 $(topsrcdir)/config/milestone.txt 2>/dev/null || tail -1 $(topsrcdir)/config/milestone.txt) APP_INI_DEPS = $(topsrcdir)/config/milestone.txt endif diff --git a/config/rules.mk b/config/rules.mk index 3c74398b0f9a..52cefa52593f 100644 --- a/config/rules.mk +++ b/config/rules.mk @@ -1203,6 +1203,12 @@ PP_TARGETS += PREF_JS_EXPORTS endif endif +# Set a flag that can be used in pref files to disable features if +# we are not building for Aurora or Nightly. +ifeq (,$(findstring a,$(GRE_MILESTONE))) +PREF_PPFLAGS += -DRELEASE_BUILD +endif + ################################################################################ # Copy each element of AUTOCFG_JS_EXPORTS to $(FINAL_TARGET)/defaults/autoconfig diff --git a/configure.in b/configure.in index 4eebea830d1d..3a328b5162a2 100644 --- a/configure.in +++ b/configure.in @@ -3946,6 +3946,15 @@ else fi fi +dnl set GRE_MILESTONE +dnl ======================================================== +if test -n "$LIBXUL_SDK"; then + GRE_MILESTONE=`$PYTHON "$_topsrcdir"/config/printconfigsetting.py "$LIBXUL_DIST"/bin/platform.ini Build Milestone` +else + GRE_MILESTONE=`tail -n 1 "$_topsrcdir"/config/milestone.txt 2>/dev/null || tail -1 "$_topsrcdir"/config/milestone.txt` +fi +AC_SUBST(GRE_MILESTONE) + dnl system libevent Support dnl ======================================================== MOZ_ARG_WITH_STRING(system-libevent, diff --git a/js/src/config/rules.mk b/js/src/config/rules.mk index 3c74398b0f9a..52cefa52593f 100644 --- a/js/src/config/rules.mk +++ b/js/src/config/rules.mk @@ -1203,6 +1203,12 @@ PP_TARGETS += PREF_JS_EXPORTS endif endif +# Set a flag that can be used in pref files to disable features if +# we are not building for Aurora or Nightly. +ifeq (,$(findstring a,$(GRE_MILESTONE))) +PREF_PPFLAGS += -DRELEASE_BUILD +endif + ################################################################################ # Copy each element of AUTOCFG_JS_EXPORTS to $(FINAL_TARGET)/defaults/autoconfig From fb807cea7c7c6263e1731e3d6124e3feb0d6694f Mon Sep 17 00:00:00 2001 From: Cameron McCormack Date: Tue, 6 Nov 2012 13:59:25 +1100 Subject: [PATCH 052/469] Bug 807336 - Suppress CSS property parse errors inside failing @supports rules. r=dbaron --- layout/style/nsCSSParser.cpp | 85 ++++++++++++++++++++++++++++++++++-- 1 file changed, 81 insertions(+), 4 deletions(-) diff --git a/layout/style/nsCSSParser.cpp b/layout/style/nsCSSParser.cpp index cc2793035a2c..18ffb5a7c3e7 100644 --- a/layout/style/nsCSSParser.cpp +++ b/layout/style/nsCSSParser.cpp @@ -233,6 +233,12 @@ protected: class nsAutoParseCompoundProperty; friend class nsAutoParseCompoundProperty; + class nsAutoParseCompoundProperty; + friend class nsAutoParseCompoundProperty; + + class nsAutoSuppressErrors; + friend class nsAutoSuppressErrors; + void AppendRule(css::Rule* aRule); friend void AppendRuleToSheet(css::Rule*, void*); // calls AppendRule @@ -258,6 +264,58 @@ protected: CSSParserImpl* mParser; }; + /** + * This helper class conditionally sets mInFailingSupportsRule to + * true if aCondition = false, and resets it to its original value in its + * destructor. If we are already somewhere within a failing @supports + * rule, passing in aCondition = true does not change mInFailingSupportsRule. + */ + class nsAutoFailingSupportsRule { + public: + nsAutoFailingSupportsRule(CSSParserImpl* aParser, + bool aCondition) + : mParser(aParser), + mOriginalValue(aParser->mInFailingSupportsRule) + { + if (!aCondition) { + mParser->mInFailingSupportsRule = true; + } + } + + ~nsAutoFailingSupportsRule() + { + mParser->mInFailingSupportsRule = mOriginalValue; + } + + private: + CSSParserImpl* mParser; + bool mOriginalValue; + }; + + /** + * Auto class to set aParser->mSuppressErrors to the specified value + * and restore it to its original value later. + */ + class nsAutoSuppressErrors { + public: + nsAutoSuppressErrors(CSSParserImpl* aParser, + bool aSuppressErrors) + : mParser(aParser), + mOriginalValue(aParser->mSuppressErrors) + { + mParser->mSuppressErrors = aSuppressErrors; + } + + ~nsAutoSuppressErrors() + { + mParser->mSuppressErrors = mOriginalValue; + } + + private: + CSSParserImpl* mParser; + bool mOriginalValue; + }; + // the caller must hold on to aString until parsing is done void InitScanner(nsCSSScanner& aScanner, css::ErrorReporter& aReporter, @@ -689,6 +747,15 @@ protected: // some quirks during shorthand parsing bool mParsingCompoundProperty : 1; + // True if we are somewhere within a @supports rule whose condition is + // false. + bool mInFailingSupportsRule : 1; + + // True if we will suppress all parse errors (except unexpected EOFs). + // This is used to prevent errors for declarations inside a failing + // @supports rule. + bool mSuppressErrors : 1; + // Stack of rule groups; used for @media and such. InfallibleTArray > mGroupStack; @@ -719,16 +786,16 @@ static void AppendRuleToSheet(css::Rule* aRule, void* aParser) } #define REPORT_UNEXPECTED(msg_) \ - mReporter->ReportUnexpected(#msg_) + { if (!mSuppressErrors) mReporter->ReportUnexpected(#msg_); } #define REPORT_UNEXPECTED_P(msg_, param_) \ - mReporter->ReportUnexpected(#msg_, param_) + { if (!mSuppressErrors) mReporter->ReportUnexpected(#msg_, param_); } #define REPORT_UNEXPECTED_TOKEN(msg_) \ - mReporter->ReportUnexpected(#msg_, mToken) + { if (!mSuppressErrors) mReporter->ReportUnexpected(#msg_, mToken); } #define REPORT_UNEXPECTED_TOKEN_CHAR(msg_, ch_) \ - mReporter->ReportUnexpected(#msg_, mToken, ch_) + { if (!mSuppressErrors) mReporter->ReportUnexpected(#msg_, mToken, ch_); } #define REPORT_UNEXPECTED_EOF(lf_) \ mReporter->ReportUnexpectedEOF(#lf_) @@ -756,6 +823,8 @@ CSSParserImpl::CSSParserImpl() mUnsafeRulesEnabled(false), mHTMLMediaMode(false), mParsingCompoundProperty(false), + mInFailingSupportsRule(false), + mSuppressErrors(false), mNextFree(nullptr) { } @@ -2375,6 +2444,10 @@ CSSParserImpl::ParseSupportsRule(RuleAppendFunc aAppendFunc, void* aProcessData) // Remove spaces from the start and end of the recorded supports condition. condition.Trim(" ", true, true, false); + // Record whether we are in a failing @supports, so that property parse + // errors don't get reported. + nsAutoFailingSupportsRule failing(this, conditionMet); + nsRefPtr rule = new CSSSupportsRule(conditionMet, condition); return ParseGroupRule(rule, aAppendFunc, aProcessData); } @@ -4309,6 +4382,10 @@ CSSParserImpl::ParseDeclaration(css::Declaration* aDeclaration, return false; } + // Don't report property parse errors if we're inside a failing @supports + // rule. + nsAutoSuppressErrors suppressErrors(this, mInFailingSupportsRule); + // Map property name to its ID and then parse the property nsCSSProperty propID = nsCSSProps::LookupProperty(propertyName, nsCSSProps::eEnabled); From fc51b305dabb8b238c9edfb59b2c1dea1d7c5072 Mon Sep 17 00:00:00 2001 From: Jan-Ivar Bruaroey Date: Fri, 21 Dec 2012 15:21:15 -0500 Subject: [PATCH 053/469] Bug 822158: Use async dispatch of Ice(Gathering)Completed to unwind stack r=jesup,ekr --- .../src/peerconnection/PeerConnectionImpl.cpp | 24 ++++++++++++------- .../src/peerconnection/PeerConnectionImpl.h | 4 ++-- .../peerconnection/PeerConnectionMedia.cpp | 2 ++ 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp index b9930600ff06..cdb25944e8a2 100644 --- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp +++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp @@ -896,6 +896,8 @@ PeerConnectionImpl::CheckApiState(bool assert_ice_ready) const if (mReadyState == kClosed) return NS_ERROR_FAILURE; + if (!mMedia) + return NS_ERROR_FAILURE; return NS_OK; } @@ -1045,17 +1047,19 @@ PeerConnectionImpl::GetHandle() void PeerConnectionImpl::IceGatheringCompleted(NrIceCtx *aCtx) { + // Do an async call here to unwind the stack. refptr keeps the PC alive. + nsRefPtr pc(this); RUN_ON_THREAD(mThread, - WrapRunnable(this, + WrapRunnable(pc, &PeerConnectionImpl::IceGatheringCompleted_m, aCtx), - NS_DISPATCH_SYNC); + NS_DISPATCH_NORMAL); } -void +nsresult PeerConnectionImpl::IceGatheringCompleted_m(NrIceCtx *aCtx) { - PC_AUTO_ENTER_API_CALL_NO_CHECK(); + PC_AUTO_ENTER_API_CALL(false); MOZ_ASSERT(aCtx); CSFLogDebugS(logTag, __FUNCTION__ << ": ctx: " << static_cast(aCtx)); @@ -1072,22 +1076,25 @@ PeerConnectionImpl::IceGatheringCompleted_m(NrIceCtx *aCtx) NS_DISPATCH_NORMAL); } #endif + return NS_OK; } void PeerConnectionImpl::IceCompleted(NrIceCtx *aCtx) { + // Do an async call here to unwind the stack. refptr keeps the PC alive. + nsRefPtr pc(this); RUN_ON_THREAD(mThread, - WrapRunnable(this, + WrapRunnable(pc, &PeerConnectionImpl::IceCompleted_m, aCtx), - NS_DISPATCH_SYNC); + NS_DISPATCH_NORMAL); } -void +nsresult PeerConnectionImpl::IceCompleted_m(NrIceCtx *aCtx) { - PC_AUTO_ENTER_API_CALL_NO_CHECK(); + PC_AUTO_ENTER_API_CALL(false); MOZ_ASSERT(aCtx); CSFLogDebugS(logTag, __FUNCTION__ << ": ctx: " << static_cast(aCtx)); @@ -1104,6 +1111,7 @@ PeerConnectionImpl::IceCompleted_m(NrIceCtx *aCtx) NS_DISPATCH_NORMAL); } #endif + return NS_OK; } void diff --git a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h index f393a2c16df6..617533ce930a 100644 --- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h +++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h @@ -217,8 +217,8 @@ private: void ShutdownMedia(bool isSynchronous); // ICE callbacks run on the right thread. - void IceGatheringCompleted_m(NrIceCtx *aCtx); - void IceCompleted_m(NrIceCtx *aCtx); + nsresult IceGatheringCompleted_m(NrIceCtx *aCtx); + nsresult IceCompleted_m(NrIceCtx *aCtx); // The role we are adopting Role mRole; diff --git a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp index 774e849858a6..0ac18d1cffad 100644 --- a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp +++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp @@ -245,6 +245,8 @@ PeerConnectionMedia::DisconnectMediaStreams() void PeerConnectionMedia::ShutdownMediaTransport() { + mIceCtx->SignalCompleted.disconnect(this); + mIceCtx->SignalGatheringCompleted.disconnect(this); mTransportFlows.clear(); mIceStreams.clear(); mIceCtx = NULL; From f194fd510a85a3d84a4549584ba4c36fb43aa6ae Mon Sep 17 00:00:00 2001 From: Gian-Carlo Pascutto Date: Fri, 21 Dec 2012 08:48:30 +0100 Subject: [PATCH 054/469] Bug 823665 - Rename urlclassifier.confirm-age to max-complete-age. r=gcp --- b2g/app/b2g.js | 2 +- browser/app/profile/firefox.js | 2 +- mobile/android/app/mobile.js | 2 +- mobile/xul/app/mobile.js | 2 +- .../url-classifier/nsUrlClassifierDBService.cpp | 2 +- .../components/url-classifier/tests/unit/test_partial.js | 8 ++++---- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/b2g/app/b2g.js b/b2g/app/b2g.js index 1e37734c7406..8a4d56785325 100644 --- a/b2g/app/b2g.js +++ b/b2g/app/b2g.js @@ -333,7 +333,7 @@ pref("urlclassifier.gethashtables", "goog-phish-shavar,goog-malware-shavar"); // If an urlclassifier table has not been updated in this number of seconds, // a gethash request will be forced to check that the result is still in // the database. -pref("urlclassifier.confirm-age", 2700); +pref("urlclassifier.max-complete-age", 2700); // URL for checking the reason for a malware warning. pref("browser.safebrowsing.malware.reportURL", "http://safebrowsing.clients.google.com/safebrowsing/diagnostic?client=%NAME%&hl=%LOCALE%&site="); diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index c878dd726658..57f2ab2a8d9f 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -741,7 +741,7 @@ pref("urlclassifier.gethashtables", "goog-phish-shavar,goog-malware-shavar"); // If an urlclassifier table has not been updated in this number of seconds, // a gethash request will be forced to check that the result is still in // the database. -pref("urlclassifier.confirm-age", 2700); +pref("urlclassifier.max-complete-age", 2700); #endif pref("browser.geolocation.warning.infoURL", "http://www.mozilla.com/%LOCALE%/firefox/geolocation/"); diff --git a/mobile/android/app/mobile.js b/mobile/android/app/mobile.js index 72c01d1f3644..65395735702b 100644 --- a/mobile/android/app/mobile.js +++ b/mobile/android/app/mobile.js @@ -584,7 +584,7 @@ pref("urlclassifier.gethashtables", "goog-phish-shavar,goog-malware-shavar"); // If an urlclassifier table has not been updated in this number of seconds, // a gethash request will be forced to check that the result is still in // the database. -pref("urlclassifier.confirm-age", 2700); +pref("urlclassifier.max-complete-age", 2700); #endif // True if this is the first time we are showing about:firstrun diff --git a/mobile/xul/app/mobile.js b/mobile/xul/app/mobile.js index 09471174419d..81e3639da099 100644 --- a/mobile/xul/app/mobile.js +++ b/mobile/xul/app/mobile.js @@ -625,7 +625,7 @@ pref("urlclassifier.gethashtables", "goog-phish-shavar,goog-malware-shavar"); // If an urlclassifier table has not been updated in this number of seconds, // a gethash request will be forced to check that the result is still in // the database. -pref("urlclassifier.confirm-age", 2700); +pref("urlclassifier.max-complete-age", 2700); // URL for checking the reason for a malware warning. pref("browser.safebrowsing.malware.reportURL", "http://safebrowsing.clients.google.com/safebrowsing/diagnostic?client=%NAME%&hl=%LOCALE%&site="); diff --git a/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp b/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp index 13c0df9963aa..78d1da38f65f 100644 --- a/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp +++ b/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp @@ -70,7 +70,7 @@ PRLogModuleInfo *gUrlClassifierDbServiceLog = nullptr; #define GETHASH_TABLES_PREF "urlclassifier.gethashtables" -#define CONFIRM_AGE_PREF "urlclassifier.confirm-age" +#define CONFIRM_AGE_PREF "urlclassifier.max-complete-age" #define CONFIRM_AGE_DEFAULT_SEC (45 * 60) class nsUrlClassifierDBServiceWorker; diff --git a/toolkit/components/url-classifier/tests/unit/test_partial.js b/toolkit/components/url-classifier/tests/unit/test_partial.js index 69ba49af2983..fc3600409c66 100644 --- a/toolkit/components/url-classifier/tests/unit/test_partial.js +++ b/toolkit/components/url-classifier/tests/unit/test_partial.js @@ -743,7 +743,7 @@ function testStaleList() }; // Consider a match stale after one second. - prefBranch.setIntPref("urlclassifier.confirm-age", 1); + prefBranch.setIntPref("urlclassifier.max-complete-age", 1); // Apply the update. doStreamUpdate(update, function() { @@ -752,7 +752,7 @@ function testStaleList() new Timer(3000, function() { // Now the lists should be marked stale. Check assertions. checkAssertions(assertions, function() { - prefBranch.setIntPref("urlclassifier.confirm-age", 2700); + prefBranch.setIntPref("urlclassifier.max-complete-age", 2700); runNextTest(); }); }, updateError); @@ -783,7 +783,7 @@ function testStaleListEmpty() }; // Consider a match stale after one second. - prefBranch.setIntPref("urlclassifier.confirm-age", 1); + prefBranch.setIntPref("urlclassifier.max-complete-age", 1); // Apply the update. doStreamUpdate(update, function() { @@ -792,7 +792,7 @@ function testStaleListEmpty() new Timer(3000, function() { // Now the lists should be marked stale. Check assertions. checkAssertions(assertions, function() { - prefBranch.setIntPref("urlclassifier.confirm-age", 2700); + prefBranch.setIntPref("urlclassifier.max-complete-age", 2700); runNextTest(); }); }, updateError); From e86ce735017bf9474eb1d6bd6698fc17a694602a Mon Sep 17 00:00:00 2001 From: "Adam Roach [:abr]" Date: Wed, 19 Dec 2012 09:25:51 -0600 Subject: [PATCH 055/469] Bug 797534: Update PeerConnectionImpl to use SDP from SIPCC, r=ehugg --- dom/media/PeerConnection.js | 6 + .../src/peerconnection/PeerConnectionImpl.cpp | 14 +- .../src/sipcc/core/ccapp/ccprovider.c | 68 ++++++-- .../signaling/src/sipcc/core/common/ui.c | 75 ++++++++- .../signaling/src/sipcc/core/gsm/fsmdef.c | 157 ++++++++++++++---- .../signaling/src/sipcc/core/gsm/gsm_sdp.c | 8 +- .../signaling/src/sipcc/core/gsm/h/gsm_sdp.h | 4 + .../sipcc/core/includes/sessionConstants.h | 2 + .../signaling/src/sipcc/core/includes/uiapi.h | 16 +- .../signaling/src/sipcc/core/sdp/sdp_attr.c | 4 +- .../src/sipcc/core/sipstack/ccsip_sdp.c | 6 +- .../src/sipcc/core/sipstack/h/ccsip_sdp.h | 2 +- .../src/sipcc/cpr/include/cpr_types.h | 10 ++ .../src/sipcc/include/cc_constants.h | 4 +- .../src/softphonewrapper/CC_SIPCCCallInfo.cpp | 8 +- .../signaling/test/signaling_unittests.cpp | 65 ++++++++ 16 files changed, 378 insertions(+), 71 deletions(-) diff --git a/dom/media/PeerConnection.js b/dom/media/PeerConnection.js index 62fe188a6178..c1b3b771b156 100644 --- a/dom/media/PeerConnection.js +++ b/dom/media/PeerConnection.js @@ -210,6 +210,7 @@ function PeerConnection() { this.onstatechange = null; this.ongatheringchange = null; this.onicechange = null; + this.localDescription = null; this.remoteDescription = null; // Data channel. @@ -441,6 +442,11 @@ PeerConnection.prototype = { break; } + this.localDescription = { + type: desc.type, sdp: desc.sdp, + __exposedProps__: { type: "rw", sdp: "rw"} + }; + this.remoteDescription = { type: desc.type, sdp: desc.sdp, __exposedProps__: { type: "rw", sdp: "rw" } diff --git a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp index cdb25944e8a2..75472238dd55 100644 --- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp +++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp @@ -186,6 +186,12 @@ public: } break; } + + case UPDATELOCALDESC: + case UPDATEREMOTEDESC: + /* No action necessary */ + break; + default: CSFLogDebugS(logTag, ": **** UNHANDLED CALL STATE : " << mStateStr); break; @@ -980,11 +986,15 @@ PeerConnectionImpl::onCallEvent(ccapi_call_event_e aCallEvent, switch (event) { case SETLOCALDESC: - mLocalSDP = mLocalRequestedSDP; + case UPDATELOCALDESC: + mLocalSDP = aInfo->getSDP(); break; + case SETREMOTEDESC: - mRemoteSDP = mRemoteRequestedSDP; + case UPDATEREMOTEDESC: + mRemoteSDP = aInfo->getSDP(); break; + case CONNECTED: CSFLogDebugS(logTag, "Setting PeerConnnection state to kActive"); ChangeReadyState(kActive); diff --git a/media/webrtc/signaling/src/sipcc/core/ccapp/ccprovider.c b/media/webrtc/signaling/src/sipcc/core/ccapp/ccprovider.c index f6c2d944effe..881fe99c301d 100755 --- a/media/webrtc/signaling/src/sipcc/core/ccapp/ccprovider.c +++ b/media/webrtc/signaling/src/sipcc/core/ccapp/ccprovider.c @@ -983,6 +983,7 @@ session_data_t * getDeepCopyOfSessionData(session_data_t *data) newData->plcd_name = strlib_copy(data->plcd_name); newData->plcd_number = strlib_copy(data->plcd_number); newData->status = strlib_copy(data->status); + newData->sdp = strlib_copy(data->sdp); calllogger_copy_call_log(&newData->call_log, &data->call_log); } else { newData->ref_count = 1; @@ -1001,6 +1002,7 @@ session_data_t * getDeepCopyOfSessionData(session_data_t *data) newData->plcd_name = strlib_empty(); newData->plcd_number = strlib_empty(); newData->status = strlib_empty(); + newData->sdp = strlib_empty(); calllogger_init_call_log(&newData->call_log); } @@ -1045,6 +1047,8 @@ void cleanSessionData(session_data_t *data) data->plcd_number = strlib_empty(); strlib_free(data->status); data->status = strlib_empty(); + strlib_free(data->sdp); + data->sdp = strlib_empty(); calllogger_free_call_log(&data->call_log); } } @@ -1296,7 +1300,11 @@ cc_call_handle_t ccappGetConnectedCall(){ static void ccappUpdateSessionData (session_update_t *sessUpd) { static const char fname[] = "ccappUpdateSessionData"; - session_data_t * data = (session_data_t *)findhash(sessUpd->sessionID), *sess_data_p; + /* TODO -- I don't think the hash handling is synchronized; we could + end up with data integrity issues here if we end up in a race. + */ + session_data_t *data = (session_data_t *)findhash(sessUpd->sessionID); + session_data_t *sess_data_p; boolean createdSessionData = TRUE; cc_deviceinfo_ref_t handle = 0; boolean previouslyInConference = FALSE; @@ -1304,11 +1312,16 @@ static void ccappUpdateSessionData (session_update_t *sessUpd) if ( data == NULL ) { cc_call_state_t call_state = sessUpd->update.ccSessionUpd.data.state_data.state; - if ( ( sessUpd->eventID == CALL_INFORMATION ) || - ( sessUpd->eventID == CALL_STATE || sessUpd->eventID == CALL_NEWCALL - || sessUpd->eventID == CREATE_OFFER || sessUpd->eventID == CREATE_ANSWER - || sessUpd->eventID == SET_LOCAL_DESC || sessUpd->eventID == SET_REMOTE_DESC - || sessUpd->eventID == REMOTE_STREAM_ADD)) { + if ( sessUpd->eventID == CALL_INFORMATION || + sessUpd->eventID == CALL_STATE || + sessUpd->eventID == CALL_NEWCALL || + sessUpd->eventID == CREATE_OFFER || + sessUpd->eventID == CREATE_ANSWER || + sessUpd->eventID == SET_LOCAL_DESC || + sessUpd->eventID == SET_REMOTE_DESC || + sessUpd->eventID == UPDATE_LOCAL_DESC || + sessUpd->eventID == UPDATE_REMOTE_DESC || + sessUpd->eventID == REMOTE_STREAM_ADD ) { CCAPP_DEBUG(DEB_F_PREFIX"CALL_SESSION_CREATED for session id 0x%x event is 0x%x \n", DEB_F_PREFIX_ARGS(SIP_CC_PROV, fname), sessUpd->sessionID, @@ -1343,9 +1356,14 @@ static void ccappUpdateSessionData (session_update_t *sessUpd) data->sess_id = sessUpd->sessionID; data->state = call_state; data->line = sessUpd->update.ccSessionUpd.data.state_data.line_id; - if (sessUpd->eventID == CALL_NEWCALL || sessUpd->eventID == CREATE_OFFER || - sessUpd->eventID == CREATE_ANSWER || sessUpd->eventID == SET_LOCAL_DESC || - sessUpd->eventID == SET_REMOTE_DESC || sessUpd->eventID == REMOTE_STREAM_ADD ) { + if (sessUpd->eventID == CALL_NEWCALL || + sessUpd->eventID == CREATE_OFFER || + sessUpd->eventID == CREATE_ANSWER || + sessUpd->eventID == SET_LOCAL_DESC || + sessUpd->eventID == SET_REMOTE_DESC || + sessUpd->eventID == UPDATE_LOCAL_DESC || + sessUpd->eventID == UPDATE_REMOTE_DESC || + sessUpd->eventID == REMOTE_STREAM_ADD ) { data->attr = sessUpd->update.ccSessionUpd.data.state_data.attr; data->inst = sessUpd->update.ccSessionUpd.data.state_data.inst; } @@ -1365,15 +1383,28 @@ static void ccappUpdateSessionData (session_update_t *sessUpd) data->gci[0] = 0; data->vid_dir = SDP_DIRECTION_INACTIVE; data->callref = 0; + data->sdp = strlib_empty(); calllogger_init_call_log(&data->call_log); - if ( sessUpd->eventID == CREATE_OFFER || sessUpd->eventID == CREATE_ANSWER - || sessUpd->eventID == SET_LOCAL_DESC || sessUpd->eventID == SET_REMOTE_DESC - || sessUpd->eventID == REMOTE_STREAM_ADD) { - data->sdp = sessUpd->update.ccSessionUpd.data.state_data.sdp; - data->cause = sessUpd->update.ccSessionUpd.data.state_data.cause; - data->media_stream_track_id = sessUpd->update.ccSessionUpd.data.state_data.media_stream_track_id; - data->media_stream_id = sessUpd->update.ccSessionUpd.data.state_data.media_stream_id; + switch (sessUpd->eventID) { + case CREATE_OFFER: + case CREATE_ANSWER: + case SET_LOCAL_DESC: + case SET_REMOTE_DESC: + case UPDATE_LOCAL_DESC: + case UPDATE_REMOTE_DESC: + data->sdp = sessUpd->update.ccSessionUpd.data.state_data.sdp; + /* Fall through to the next case... */ + case REMOTE_STREAM_ADD: + data->cause = + sessUpd->update.ccSessionUpd.data.state_data.cause; + data->media_stream_track_id = sessUpd->update.ccSessionUpd.data. + state_data.media_stream_track_id; + data->media_stream_id = sessUpd->update.ccSessionUpd.data. + state_data.media_stream_id; + break; + default: + break; } /* @@ -1697,8 +1728,11 @@ static void ccappUpdateSessionData (session_update_t *sessUpd) case CREATE_ANSWER: case SET_LOCAL_DESC: case SET_REMOTE_DESC: - case REMOTE_STREAM_ADD: + case UPDATE_LOCAL_DESC: + case UPDATE_REMOTE_DESC: data->sdp = sessUpd->update.ccSessionUpd.data.state_data.sdp; + /* Fall through to the next case... */ + case REMOTE_STREAM_ADD: data->cause = sessUpd->update.ccSessionUpd.data.state_data.cause; data->state = sessUpd->update.ccSessionUpd.data.state_data.state; data->media_stream_track_id = sessUpd->update.ccSessionUpd.data.state_data.media_stream_track_id; diff --git a/media/webrtc/signaling/src/sipcc/core/common/ui.c b/media/webrtc/signaling/src/sipcc/core/common/ui.c index 750a43539d6b..1970c5aafd72 100755 --- a/media/webrtc/signaling/src/sipcc/core/common/ui.c +++ b/media/webrtc/signaling/src/sipcc/core/common/ui.c @@ -25,6 +25,7 @@ #include "platform_api.h" #include "vcm.h" #include "ccapp_task.h" +#include "peer_connection_types.h" /* * Note: Do not include "msprovider.h" here unless the dependencies on @@ -95,6 +96,7 @@ void ui_call_state (call_events event, line_t nLine, callid_t nCallID, cc_causes_t cause) { session_update_t msg; + memset( &msg, 0, sizeof(session_update_t)); TNP_DEBUG(DEB_L_C_F_PREFIX"event=%d \n", DEB_L_C_F_PREFIX_ARGS(UI_API, nLine, nCallID, __FUNCTION__), event); @@ -131,6 +133,7 @@ ui_new_call (call_events event, line_t nLine, callid_t nCallID, int call_attr, uint16_t call_instance_id, boolean dialed_digits) { session_update_t msg; + memset( &msg, 0, sizeof(session_update_t)); TNP_DEBUG(DEB_L_C_F_PREFIX"state=%d attr=%d call_instance=%d, dialed_digits=%s\n", DEB_L_C_F_PREFIX_ARGS(UI_API, nLine, nCallID, __FUNCTION__), event, call_attr, call_instance_id, (dialed_digits)? "true" : "false"); @@ -172,6 +175,7 @@ void ui_set_call_attr (line_t line_id, callid_t call_id, call_attr_t attr) { session_update_t msg; + memset( &msg, 0, sizeof(session_update_t)); TNP_DEBUG(DEB_L_C_F_PREFIX"attr=%d\n", DEB_L_C_F_PREFIX_ARGS(UI_API, line_id, call_id, __FUNCTION__), attr); @@ -202,6 +206,7 @@ void ui_update_callref (line_t line, callid_t call_id, unsigned int callref) { session_update_t msg; + memset( &msg, 0, sizeof(session_update_t)); TNP_DEBUG(DEB_L_C_F_PREFIX"callref = %d\n", DEB_L_C_F_PREFIX_ARGS(UI_API, line, call_id, __FUNCTION__), callref); @@ -237,6 +242,7 @@ void ui_update_gcid (line_t line, callid_t call_id, char *gcid) { session_update_t msg; + memset( &msg, 0, sizeof(session_update_t)); TNP_DEBUG(DEB_L_C_F_PREFIX"gcid = %s\n", DEB_L_C_F_PREFIX_ARGS(UI_API, line, call_id, __FUNCTION__), gcid); @@ -270,6 +276,7 @@ void ui_update_video_avail (line_t line, callid_t call_id, int avail) { session_update_t msg; + memset( &msg, 0, sizeof(session_update_t)); TNP_DEBUG(DEB_L_C_F_PREFIX, DEB_L_C_F_PREFIX_ARGS(UI_API, line, call_id, __FUNCTION__)); @@ -291,6 +298,7 @@ ui_update_video_avail (line_t line, callid_t call_id, int avail) void ui_update_media_interface_change(line_t line, callid_t call_id, group_call_event_t event) { session_update_t msg; + memset( &msg, 0, sizeof(session_update_t)); if (event != MEDIA_INTERFACE_UPDATE_BEGIN && event != MEDIA_INTERFACE_UPDATE_SUCCESSFUL && @@ -324,6 +332,7 @@ void ui_call_stop_ringer (line_t line, callid_t call_id) { session_update_t msg; + memset( &msg, 0, sizeof(session_update_t)); TNP_DEBUG(DEB_L_C_F_PREFIX, DEB_L_C_F_PREFIX_ARGS(UI_API, line, call_id, __FUNCTION__)); @@ -348,6 +357,7 @@ void ui_call_start_ringer (vcm_ring_mode_t ringMode, short once, line_t line, callid_t call_id) { session_update_t msg; + memset( &msg, 0, sizeof(session_update_t)); TNP_DEBUG(DEB_L_C_F_PREFIX, DEB_L_C_F_PREFIX_ARGS(UI_API, line, call_id, __FUNCTION__)); @@ -381,6 +391,7 @@ void ui_update_video_offered (line_t line, callid_t call_id, int avail) { session_update_t msg; + memset( &msg, 0, sizeof(session_update_t)); TNP_DEBUG(DEB_L_C_F_PREFIX, DEB_L_C_F_PREFIX_ARGS(UI_API, line, call_id, __FUNCTION__)); @@ -447,6 +458,8 @@ ui_call_info (string_t pCallingPartyNameStr, char lineName[MAX_LINE_NAME_SIZE]; char lineNumber[MAX_LINE_NAME_SIZE]; + memset( &msg, 0, sizeof(session_update_t)); + TNP_DEBUG(DEB_L_C_F_PREFIX"call instance=%d callednum=%s calledname=%s clngnum=%s clngname = %s\n", DEB_L_C_F_PREFIX_ARGS(UI_API, line, call_id, __FUNCTION__), call_instance_id, pCalledPartyNumberStr, @@ -531,6 +544,7 @@ void ui_cc_capability (line_t line, callid_t call_id, string_t recv_info_list) { session_update_t msg; + memset( &msg, 0, sizeof(session_update_t)); TNP_DEBUG(DEB_L_C_F_PREFIX"recv_info_list:%s\n", DEB_L_C_F_PREFIX_ARGS(UI_API, line, call_id, __FUNCTION__), @@ -592,6 +606,7 @@ static void ui_set_call_status_display (string_t status, line_t line, callid_t callID, int timeout, char priority) { session_update_t msg; + memset( &msg, 0, sizeof(session_update_t)); TNP_DEBUG(DEB_L_C_F_PREFIX"the stat string =%s, timeout= %d, priority=%d\n", DEB_L_C_F_PREFIX_ARGS(UI_API, line, callID, __FUNCTION__), status, @@ -1036,6 +1051,7 @@ ui_update_placed_call_info (line_t line, callid_t call_id, string_t cldName, string_t cldNumber) { session_update_t msg; + memset( &msg, 0, sizeof(session_update_t)); TNP_DEBUG(DEB_L_C_F_PREFIX"calledName:calledNumber %s:%s\n", DEB_L_C_F_PREFIX_ARGS(UI_API, line, call_id, __FUNCTION__), cldName, cldNumber); @@ -1077,6 +1093,7 @@ void ui_delete_last_digit (line_t line_id, callid_t call_id) { session_update_t msg; + memset( &msg, 0, sizeof(session_update_t)); TNP_DEBUG(DEB_L_C_F_PREFIX"called\n", DEB_L_C_F_PREFIX_ARGS(UI_API, line_id, call_id, __FUNCTION__)); @@ -1106,6 +1123,7 @@ void ui_control_featurekey_bksp (line_t line_id, callid_t call_id, boolean enable) { session_update_t msg; + memset( &msg, 0, sizeof(session_update_t)); TNP_DEBUG(DEB_L_C_F_PREFIX"enable=%d\n", DEB_L_C_F_PREFIX_ARGS(UI_API, line_id, call_id, __FUNCTION__), enable); @@ -1134,6 +1152,7 @@ void ui_call_selected (line_t line_id, callid_t call_id, int selected) { session_update_t msg; + memset( &msg, 0, sizeof(session_update_t)); TNP_DEBUG(DEB_L_C_F_PREFIX"selected=%d\n", DEB_L_C_F_PREFIX_ARGS(UI_API, line_id, call_id, __FUNCTION__), selected); @@ -1221,6 +1240,7 @@ ui_select_feature_key_set (line_t line_id, callid_t call_id, char *set_name, { int i; session_update_t msg; + memset( &msg, 0, sizeof(session_update_t)); TNP_DEBUG(DEB_L_C_F_PREFIX"called\n", DEB_L_C_F_PREFIX_ARGS(UI_API, line_id, call_id, __FUNCTION__)); @@ -1234,8 +1254,6 @@ ui_select_feature_key_set (line_t line_id, callid_t call_id, char *set_name, return; } - memset( &msg, 0, sizeof(session_update_t)); - msg.sessionID = createSessionId(line_id, call_id); msg.eventID = CALL_SELECT_FEATURE_SET; @@ -1299,6 +1317,7 @@ ui_update_call_security (line_t line, callid_t call_id, cc_security_e call_security) { session_update_t msg; + memset( &msg, 0, sizeof(session_update_t)); TNP_DEBUG(DEB_L_C_F_PREFIX"security=%d\n", DEB_L_C_F_PREFIX_ARGS(UI_API, line, call_id, __FUNCTION__), call_security); @@ -1338,6 +1357,7 @@ ui_terminate_feature (line_t line, callid_t call_id, callid_t target_call_id) { session_update_t msg; + memset( &msg, 0, sizeof(session_update_t)); TNP_DEBUG(DEB_L_C_F_PREFIX"target_call_id=%d\n", DEB_L_C_F_PREFIX_ARGS(UI_API, line, call_id, __FUNCTION__), target_call_id); @@ -1486,6 +1506,7 @@ void ui_log_disposition (callid_t call_id, int logdisp) { session_update_t msg; fsmdef_dcb_t *dcb = fsmdef_get_dcb_by_call_id(call_id); + memset( &msg, 0, sizeof(session_update_t)); if (call_id == CC_NO_CALL_ID || dcb == NULL) { @@ -1532,10 +1553,11 @@ static void post_message_helper( line_t nLine, callid_t nCallId, uint16_t call_instance_id, - char *sdp, + string_t sdp, cc_int32_t status) { session_update_t msg; + memset( &msg, 0, sizeof(session_update_t)); if (nCallId == CC_NO_CALL_ID) { /* no operation when no call ID */ @@ -1567,7 +1589,7 @@ static void post_message_helper( * @return none */ void ui_create_offer(call_events event, line_t nLine, callid_t nCallID, - uint16_t call_instance_id, char* sdp) + uint16_t call_instance_id, string_t sdp) { TNP_DEBUG(DEB_L_C_F_PREFIX"state=%d attr=%d call_instance=%d\n", DEB_L_C_F_PREFIX_ARGS(UI_API, nLine, nCallID, __FUNCTION__), event, call_instance_id); @@ -1584,7 +1606,7 @@ void ui_create_offer(call_events event, line_t nLine, callid_t nCallID, * @return none */ void ui_create_answer(call_events event, line_t nLine, callid_t nCallID, - uint16_t call_instance_id, char* sdp) + uint16_t call_instance_id, string_t sdp) { TNP_DEBUG(DEB_L_C_F_PREFIX"state=%d call_instance=%d\n", DEB_L_C_F_PREFIX_ARGS(UI_API, nLine, nCallID, __FUNCTION__), event, call_instance_id); @@ -1601,7 +1623,7 @@ void ui_create_answer(call_events event, line_t nLine, callid_t nCallID, */ void ui_set_local_description(call_events event, line_t nLine, callid_t nCallID, - uint16_t call_instance_id, char* sdp, cc_int32_t status) + uint16_t call_instance_id, string_t sdp, cc_int32_t status) { TNP_DEBUG(DEB_L_C_F_PREFIX"state=%d call_instance=%d\n", DEB_L_C_F_PREFIX_ARGS(UI_API, nLine, nCallID, __FUNCTION__), event, call_instance_id); @@ -1618,7 +1640,7 @@ void ui_set_local_description(call_events event, line_t nLine, callid_t nCallID, */ void ui_set_remote_description(call_events event, line_t nLine, callid_t nCallID, - uint16_t call_instance_id, char* sdp, cc_int32_t status) + uint16_t call_instance_id, string_t sdp, cc_int32_t status) { TNP_DEBUG(DEB_L_C_F_PREFIX"state=%d call_instance=%d\n", DEB_L_C_F_PREFIX_ARGS(UI_API, nLine, nCallID, __FUNCTION__), event, call_instance_id); @@ -1628,6 +1650,44 @@ void ui_set_remote_description(call_events event, line_t nLine, callid_t nCallID return; } +/** + * Let PeerConnection know about an updated local session description + * + * @return none + */ + +void ui_update_local_description(call_events event, line_t nLine, callid_t nCallID, + uint16_t call_instance_id, string_t sdp) +{ + TNP_DEBUG(DEB_L_C_F_PREFIX"state=%d call_instance=%d\n", + DEB_L_C_F_PREFIX_ARGS(UI_API, nLine, nCallID, __FUNCTION__), + event, call_instance_id); + + post_message_helper(UPDATE_LOCAL_DESC, event, nLine, nCallID, call_instance_id, + sdp, PC_OK); + + return; +} + +/** + * Let PeerConnection know about an updated remote session description + * + * @return none + */ + +void ui_update_remote_description(call_events event, line_t nLine, callid_t nCallID, + uint16_t call_instance_id, string_t sdp) +{ + TNP_DEBUG(DEB_L_C_F_PREFIX"state=%d call_instance=%d\n", + DEB_L_C_F_PREFIX_ARGS(UI_API, nLine, nCallID, __FUNCTION__), + event, call_instance_id); + + post_message_helper(UPDATE_REMOTE_DESC, event, nLine, nCallID, + call_instance_id, sdp, PC_OK); + + return; +} + /** * Send Remote Stream data to the UI @@ -1639,6 +1699,7 @@ void ui_on_remote_stream_added(call_events event, line_t nLine, callid_t nCallID { session_update_t msg; fsmdef_dcb_t *dcb = fsmdef_get_dcb_by_call_id(nCallID); + memset( &msg, 0, sizeof(session_update_t)); if (nCallID == CC_NO_CALL_ID || dcb == NULL) { /* no operation when no call ID */ diff --git a/media/webrtc/signaling/src/sipcc/core/gsm/fsmdef.c b/media/webrtc/signaling/src/sipcc/core/gsm/fsmdef.c index 33a31ffc86dc..6d9d1b335dad 100755 --- a/media/webrtc/signaling/src/sipcc/core/gsm/fsmdef.c +++ b/media/webrtc/signaling/src/sipcc/core/gsm/fsmdef.c @@ -2905,7 +2905,8 @@ fsmdef_ev_createoffer (sm_event_t *event) { vcmGetIceParams(dcb->peerconnection, &ufrag, &ice_pwd); if (!ufrag || !ice_pwd) { - ui_create_offer(evCreateOfferError, line, call_id, dcb->caller_id.call_instance_id, NULL); + ui_create_offer(evCreateOfferError, line, call_id, + dcb->caller_id.call_instance_id, strlib_empty()); return (fsmdef_release(fcb, cause, FALSE)); } @@ -2935,20 +2936,26 @@ fsmdef_ev_createoffer (sm_event_t *event) { cause = gsmsdp_create_local_sdp(dcb, FALSE, TRUE, TRUE, TRUE, TRUE); if (cause != CC_CAUSE_OK) { - ui_create_offer(evCreateOfferError, line, call_id, dcb->caller_id.call_instance_id, NULL); + ui_create_offer(evCreateOfferError, line, call_id, + dcb->caller_id.call_instance_id, strlib_empty()); FSM_DEBUG_SM(get_debug_string(FSM_DBG_SDP_BUILD_ERR)); return (fsmdef_release(fcb, cause, FALSE)); } cause = gsmsdp_encode_sdp_and_update_version(dcb, &msg_body); if (cause != CC_CAUSE_OK) { - ui_create_offer(evCreateOfferError, line, call_id, dcb->caller_id.call_instance_id, NULL); + cc_free_msg_body_parts(&msg_body); + ui_create_offer(evCreateOfferError, line, call_id, + dcb->caller_id.call_instance_id, strlib_empty()); FSM_DEBUG_SM(get_debug_string(FSM_DBG_SDP_BUILD_ERR)); return (fsmdef_release(fcb, cause, FALSE)); } /* Pass offer SDP back to UI */ - ui_create_offer(evCreateOffer, line, call_id, dcb->caller_id.call_instance_id, msg_body.parts[0].body); + ui_create_offer(evCreateOffer, line, call_id, + dcb->caller_id.call_instance_id, + strlib_malloc(msg_body.parts[0].body, -1)); + cc_free_msg_body_parts(&msg_body); return (SM_RC_END); } @@ -3012,7 +3019,8 @@ fsmdef_ev_createanswer (sm_event_t *event) { vcmGetIceParams(dcb->peerconnection, &ufrag, &ice_pwd); if (!ufrag || !ice_pwd) { - ui_create_offer(evCreateAnswerError, line, call_id, dcb->caller_id.call_instance_id, NULL); + ui_create_offer(evCreateAnswerError, line, call_id, + dcb->caller_id.call_instance_id, strlib_empty()); return (fsmdef_release(fcb, cause, FALSE)); } @@ -3052,7 +3060,8 @@ fsmdef_ev_createanswer (sm_event_t *event) { */ cause = gsmsdp_create_local_sdp(dcb, FALSE, has_audio, has_video, has_data, FALSE); if (cause != CC_CAUSE_OK) { - ui_create_answer(evCreateAnswerError, line, call_id, dcb->caller_id.call_instance_id, NULL); + ui_create_answer(evCreateAnswerError, line, call_id, + dcb->caller_id.call_instance_id, strlib_empty()); FSM_DEBUG_SM(get_debug_string(FSM_DBG_SDP_BUILD_ERR)); // Force clean up call without sending release return (fsmdef_release(fcb, cause, FALSE)); @@ -3064,19 +3073,25 @@ fsmdef_ev_createanswer (sm_event_t *event) { cause = gsmsdp_negotiate_media_lines(fcb, dcb->sdp, TRUE, TRUE, FALSE, TRUE); if (cause != CC_CAUSE_OK) { - ui_create_answer(evCreateAnswerError, line, call_id, dcb->caller_id.call_instance_id, NULL); + ui_create_answer(evCreateAnswerError, line, call_id, + dcb->caller_id.call_instance_id, strlib_empty()); return (fsmdef_release(fcb, cause, FALSE)); } cause = gsmsdp_encode_sdp_and_update_version(dcb, &msg_body); if (cause != CC_CAUSE_OK) { - ui_create_answer(evCreateAnswerError, line, call_id, dcb->caller_id.call_instance_id, NULL); + cc_free_msg_body_parts(&msg_body); + ui_create_answer(evCreateAnswerError, line, call_id, + dcb->caller_id.call_instance_id, strlib_empty()); FSM_DEBUG_SM(get_debug_string(FSM_DBG_SDP_BUILD_ERR)); return (fsmdef_release(fcb, cause, FALSE)); } /* Pass SDP back to UI */ - ui_create_answer(evCreateAnswer, line, call_id, dcb->caller_id.call_instance_id, msg_body.parts[0].body); + ui_create_answer(evCreateAnswer, line, call_id, + dcb->caller_id.call_instance_id, + strlib_malloc(msg_body.parts[0].body, -1)); + cc_free_msg_body_parts(&msg_body); return (SM_RC_END); } @@ -3099,12 +3114,16 @@ fsmdef_ev_setlocaldesc(sm_event_t *event) { callid_t call_id = msg->call_id; line_t line = msg->line; cc_causes_t lsm_rc; + char *local_sdp = 0; + uint32_t local_sdp_len = 0; FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__)); config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode)); if (!sdpmode) { - ui_set_local_description(evSetLocalDescError, line, call_id, dcb->caller_id.call_instance_id, NULL, PC_SETLOCALDESCERROR); + ui_set_local_description(evSetLocalDescError, line, call_id, + dcb->caller_id.call_instance_id, strlib_empty(), + PC_SETLOCALDESCERROR); return (SM_RC_END); } @@ -3116,15 +3135,20 @@ fsmdef_ev_setlocaldesc(sm_event_t *event) { if (JSEP_OFFER == action) { cause = gsmsdp_encode_sdp(dcb->sdp, &msg_body); if (cause != CC_CAUSE_OK) { + cc_free_msg_body_parts(&msg_body); FSM_DEBUG_SM(get_debug_string(FSM_DBG_SDP_BUILD_ERR)); - ui_set_local_description(evSetLocalDescError, line, call_id, dcb->caller_id.call_instance_id, NULL, PC_SETLOCALDESCERROR); + ui_set_local_description(evSetLocalDescError, line, call_id, + dcb->caller_id.call_instance_id, strlib_empty(), + PC_SETLOCALDESCERROR); return (SM_RC_END); } /* compare and fail if different: * anant: Why? The JS should be able to modify the SDP. Commenting out for now (same for answer) if (strcmp(msg_body.parts[0].body, sdp) != 0) { - ui_set_local_description(evSetLocalDescError, line, call_id, dcb->caller_id.call_instance_id, NULL, PC_SDPCHANGED); + ui_set_local_description(evSetLocalDescError, line, call_id, + dcb->caller_id.call_instance_id, strlib_empty(), PC_SDPCHANGED); + cc_free_msg_body_parts(&msg_body); return (SM_RC_END); } */ @@ -3136,14 +3160,19 @@ fsmdef_ev_setlocaldesc(sm_event_t *event) { /* compare SDP generated from CreateAnswer */ cause = gsmsdp_encode_sdp(dcb->sdp, &msg_body); if (cause != CC_CAUSE_OK) { + cc_free_msg_body_parts(&msg_body); FSM_DEBUG_SM(get_debug_string(FSM_DBG_SDP_BUILD_ERR)); - ui_set_local_description(evSetLocalDescError, line, call_id, dcb->caller_id.call_instance_id, NULL, PC_SETLOCALDESCERROR); + ui_set_local_description(evSetLocalDescError, line, call_id, + dcb->caller_id.call_instance_id, strlib_empty(), + PC_SETLOCALDESCERROR); return (SM_RC_END); } /* compare and fail if different if (strcmp(msg_body.parts[0].body, sdp) != 0) { - ui_set_local_description(evSetLocalDescError, line, call_id, dcb->caller_id.call_instance_id, NULL, PC_SDPCHANGED); + cc_free_msg_body_parts(&msg_body); + ui_set_local_description(evSetLocalDescError, line, call_id, + dcb->caller_id.call_instance_id, strlib_empty(), PC_SDPCHANGED); return (SM_RC_END); }*/ @@ -3161,7 +3190,8 @@ fsmdef_ev_setlocaldesc(sm_event_t *event) { */ cause = gsmsdp_install_peer_ice_attributes(fcb); if (cause != CC_CAUSE_OK) { - ui_set_local_description(evSetLocalDescError, line, call_id, dcb->caller_id.call_instance_id, NULL, PC_SDPCHANGED); + ui_set_local_description(evSetLocalDescError, line, call_id, + dcb->caller_id.call_instance_id, strlib_empty(), PC_SDPCHANGED); return (SM_RC_END); } @@ -3183,8 +3213,20 @@ fsmdef_ev_setlocaldesc(sm_event_t *event) { fsm_change_state(fcb, __LINE__, FSMDEF_S_CONNECTED); } + /* We're done with the msg_body contents -- free them.*/ + cc_free_msg_body_parts(&msg_body); - ui_set_local_description(evSetLocalDesc, line, call_id, dcb->caller_id.call_instance_id, NULL, PC_OK); + /* Encode the current local SDP structure into a char buffer */ + local_sdp = sipsdp_write_to_buf(dcb->sdp->src_sdp, &local_sdp_len); + if (!local_sdp) { + ui_set_local_description(evSetLocalDescError, line, call_id, + dcb->caller_id.call_instance_id, strlib_empty(), + PC_SETLOCALDESCERROR); + return (SM_RC_END); + } + ui_set_local_description(evSetLocalDesc, line, call_id, + dcb->caller_id.call_instance_id, strlib_malloc(local_sdp,-1), PC_OK); + free(local_sdp); return (SM_RC_END); } @@ -3211,13 +3253,16 @@ fsmdef_ev_setremotedesc(sm_event_t *event) { boolean has_audio; boolean has_video; boolean has_data; + char *remote_sdp = 0; + uint32_t remote_sdp_len = 0; FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__)); config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode)); if (!sdpmode) { ui_set_remote_description(evSetRemoteDescError, line, call_id, - dcb->caller_id.call_instance_id, NULL, PC_SETREMOTEDESCERROR); + dcb->caller_id.call_instance_id, strlib_empty(), + PC_SETREMOTEDESCERROR); return (SM_RC_END); } @@ -3228,6 +3273,13 @@ fsmdef_ev_setremotedesc(sm_event_t *event) { cc_initialize_msg_body_parts_info(&msg_body); + /* !!! NOTE !!! The following code sets up the pointers inside + msg_body.parts[0] to point directly to the buffers from the + event->msg structure. While this is more efficient than + copying them, we must take exceptional care not to call + cc_free_msg_body_parts() on this particular msg_body, since + doing so would result in the buffers being freed twice. */ + msg_body.num_parts = 1; msg_body.content_type = cc_content_type_SDP; part = &msg_body.parts[0]; @@ -3244,7 +3296,8 @@ fsmdef_ev_setremotedesc(sm_event_t *event) { cause = gsmsdp_process_offer_sdp(fcb, &msg_body, TRUE); if (cause != CC_CAUSE_OK) { ui_set_remote_description(evSetRemoteDescError, line, call_id, - dcb->caller_id.call_instance_id, NULL, PC_SETREMOTEDESCERROR); + dcb->caller_id.call_instance_id, strlib_empty(), + PC_SETREMOTEDESCERROR); return (SM_RC_END); } @@ -3260,8 +3313,9 @@ fsmdef_ev_setremotedesc(sm_event_t *event) { */ cause = gsmsdp_create_local_sdp(dcb, TRUE, has_audio, has_video, has_data, FALSE); if (cause != CC_CAUSE_OK) { - ui_set_remote_description(evSetRemoteDescError, line, call_id, dcb->caller_id.call_instance_id, - NULL, PC_SETREMOTEDESCERROR); + ui_set_remote_description(evSetRemoteDescError, line, call_id, + dcb->caller_id.call_instance_id, strlib_empty(), + PC_SETREMOTEDESCERROR); FSM_DEBUG_SM(get_debug_string(FSM_DBG_SDP_BUILD_ERR)); // Force clean up call without sending release return (fsmdef_release(fcb, cause, FALSE)); @@ -3269,8 +3323,9 @@ fsmdef_ev_setremotedesc(sm_event_t *event) { cause = gsmsdp_negotiate_media_lines(fcb, dcb->sdp, TRUE, TRUE, TRUE, FALSE); if (cause != CC_CAUSE_OK) { - ui_set_remote_description(evSetRemoteDescError, line, call_id, dcb->caller_id.call_instance_id, - NULL, PC_SETREMOTEDESCERROR); + ui_set_remote_description(evSetRemoteDescError, line, call_id, + dcb->caller_id.call_instance_id, strlib_empty(), + PC_SETREMOTEDESCERROR); return (fsmdef_release(fcb, cause, FALSE)); } @@ -3282,8 +3337,9 @@ fsmdef_ev_setremotedesc(sm_event_t *event) { cause = gsmsdp_negotiate_answer_sdp(fcb, &msg_body); if (cause != CC_CAUSE_OK) { - ui_set_remote_description(evSetRemoteDescError, line, call_id, dcb->caller_id.call_instance_id, - NULL, PC_SETREMOTEDESCERROR); + ui_set_remote_description(evSetRemoteDescError, line, call_id, + dcb->caller_id.call_instance_id, strlib_empty(), + PC_SETREMOTEDESCERROR); return (SM_RC_END); } @@ -3293,8 +3349,9 @@ fsmdef_ev_setremotedesc(sm_event_t *event) { */ cause = gsmsdp_install_peer_ice_attributes(fcb); if (cause != CC_CAUSE_OK) { - ui_set_remote_description(evSetRemoteDescError, line, call_id, dcb->caller_id.call_instance_id, - NULL, PC_SETREMOTEDESCERROR); + ui_set_remote_description(evSetRemoteDescError, line, call_id, + dcb->caller_id.call_instance_id, strlib_empty(), + PC_SETREMOTEDESCERROR); return (SM_RC_END); } @@ -3309,12 +3366,31 @@ fsmdef_ev_setremotedesc(sm_event_t *event) { fsm_change_state(fcb, __LINE__, FSMDEF_S_CONNECTED); } - ui_set_remote_description(evSetRemoteDesc, line, call_id, dcb->caller_id.call_instance_id, NULL, PC_OK); + /* For the sake of accuracy, we regenerate the SDP text from our parsed + version: if we have any local variation in how we've interpreted the + received SDP, then localDescription will reflect that variation. In + practice, this shouldn't happen; but, if it does, at least this will + allow the WebRTC application to figure out what's going on. */ + + remote_sdp = sipsdp_write_to_buf(dcb->sdp->dest_sdp, &remote_sdp_len); + + if (!remote_sdp) { + ui_set_remote_description(evSetRemoteDescError, line, call_id, + dcb->caller_id.call_instance_id, strlib_empty(), + PC_SETREMOTEDESCERROR); + return (SM_RC_END); + } + + ui_set_remote_description(evSetRemoteDesc, line, call_id, + dcb->caller_id.call_instance_id, strlib_malloc(remote_sdp,-1), + PC_OK); + + free(remote_sdp); return (SM_RC_END); } - +/* TODO -- remove me. See bug 821066. */ static sm_rcs_t fsmdef_ev_localdesc(sm_event_t *event) { fsm_fcb_t *fcb = (fsm_fcb_t *) event->data; @@ -3342,6 +3418,7 @@ fsmdef_ev_localdesc(sm_event_t *event) { return (SM_RC_END); } +/* TODO -- remove me. See bug 821066. */ static sm_rcs_t fsmdef_ev_remotedesc(sm_event_t *event) { fsm_fcb_t *fcb = (fsm_fcb_t *) event->data; @@ -3517,6 +3594,10 @@ fsmdef_ev_addcandidate(sm_event_t *event) { int sdpmode = 0; short vcm_res; uint16_t level; + line_t line = msg->line; + callid_t call_id = msg->call_id; + char *remote_sdp = 0; + uint32_t remote_sdp_len = 0; FSM_DEBUG_SM(DEB_F_PREFIX"Entered.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__)); @@ -3532,19 +3613,35 @@ fsmdef_ev_addcandidate(sm_event_t *event) { return SM_RC_CLEANUP; } - /* Perform level lookup based on mid value */ /* comment until mid is properly updated cause = gsmsdp_find_level_from_mid(dcb, (const char *)msg->data.candidate.mid, &level); */ + /* Update remote SDP with new candidate information */ + level = msg->data.candidate.level; + gsmsdp_set_ice_attribute (SDP_ATTR_ICE_CANDIDATE, level, + dcb->sdp->dest_sdp, (char *)msg->data.candidate.candidate); + vcm_res = vcmSetIceCandidate(dcb->peerconnection, (char *)msg->data.candidate.candidate, msg->data.candidate.level); if(vcm_res) { FSM_DEBUG_SM(DEB_F_PREFIX"failure setting ice candidate.\n", DEB_F_PREFIX_ARGS(FSM, __FUNCTION__)); } + /* Serialize the updated SDP and inform the PeerConnection of the + new SDP contents. */ - return (SM_RC_END); + remote_sdp = sipsdp_write_to_buf(dcb->sdp->dest_sdp, &remote_sdp_len); + + if (!remote_sdp) { + return (SM_RC_END); + } + + ui_update_remote_description(evUpdateRemoteDesc, line, call_id, + dcb->caller_id.call_instance_id, strlib_malloc(remote_sdp,-1)); + + free(remote_sdp); + return (SM_RC_END); } static void diff --git a/media/webrtc/signaling/src/sipcc/core/gsm/gsm_sdp.c b/media/webrtc/signaling/src/sipcc/core/gsm/gsm_sdp.c index 53d442c89de7..71fa8ccb1203 100644 --- a/media/webrtc/signaling/src/sipcc/core/gsm/gsm_sdp.c +++ b/media/webrtc/signaling/src/sipcc/core/gsm/gsm_sdp.c @@ -1562,7 +1562,7 @@ gsmsdp_get_ice_attributes (sdp_attr_e sdp_attr, uint16_t level, void *sdp_p, cha } /* - * gsmsdp_set_attributes + * gsmsdp_set_ice_attribute * * Description: * @@ -1575,7 +1575,7 @@ gsmsdp_get_ice_attributes (sdp_attr_e sdp_attr, uint16_t level, void *sdp_p, cha * sdp_p - Pointer to the SDP to set the ice candidate attribute against. * ice_attrib - ice attribute to set */ -static void +void gsmsdp_set_ice_attribute (sdp_attr_e sdp_attr, uint16_t level, void *sdp_p, char *ice_attrib) { uint16_t a_instance = 0; @@ -5882,12 +5882,12 @@ gsmsdp_encode_sdp (cc_sdp_t *sdp_p, cc_msgbody_info_t *msg_body) cc_msgbody_t *part; uint32_t body_length; - if (msg_body == NULL) { + if (!msg_body || !sdp_p) { return CC_CAUSE_ERROR; } /* Support single SDP encoding for now */ - sdp_body = sipsdp_write_to_buf(sdp_p, &body_length); + sdp_body = sipsdp_write_to_buf(sdp_p->src_sdp, &body_length); if (sdp_body == NULL) { return CC_CAUSE_ERROR; diff --git a/media/webrtc/signaling/src/sipcc/core/gsm/h/gsm_sdp.h b/media/webrtc/signaling/src/sipcc/core/gsm/h/gsm_sdp.h index 25ae4cfdb92b..1121699ca42b 100644 --- a/media/webrtc/signaling/src/sipcc/core/gsm/h/gsm_sdp.h +++ b/media/webrtc/signaling/src/sipcc/core/gsm/h/gsm_sdp.h @@ -135,5 +135,9 @@ void gsmsdp_process_cap_constraints(fsmdef_dcb_t *dcb, const cc_media_constraint cc_causes_t gsmsdp_get_offered_media_types (fsm_fcb_t *fcb_p, cc_sdp_t *sdp_p, boolean *has_audio, boolean *has_video, boolean *has_data); fsmdef_media_t* gsmsdp_find_media_by_media_type(fsmdef_dcb_t *dcb, sdp_media_e media_type); + +extern void gsmsdp_set_ice_attribute (sdp_attr_e sdp_attr, uint16_t level, + void *sdp_p, char *ice_attrib); + #endif diff --git a/media/webrtc/signaling/src/sipcc/core/includes/sessionConstants.h b/media/webrtc/signaling/src/sipcc/core/includes/sessionConstants.h index a094c3d8672a..20fbc1735a05 100755 --- a/media/webrtc/signaling/src/sipcc/core/includes/sessionConstants.h +++ b/media/webrtc/signaling/src/sipcc/core/includes/sessionConstants.h @@ -220,6 +220,8 @@ typedef enum { CREATE_ANSWER, SET_LOCAL_DESC, SET_REMOTE_DESC, + UPDATE_LOCAL_DESC, + UPDATE_REMOTE_DESC, REMOTE_STREAM_ADD } group_call_event_t; diff --git a/media/webrtc/signaling/src/sipcc/core/includes/uiapi.h b/media/webrtc/signaling/src/sipcc/core/includes/uiapi.h index 6604264eb15f..238f01627e97 100644 --- a/media/webrtc/signaling/src/sipcc/core/includes/uiapi.h +++ b/media/webrtc/signaling/src/sipcc/core/includes/uiapi.h @@ -37,6 +37,8 @@ typedef enum { evCreateAnswerError = CREATEANSWERERROR, evSetLocalDesc = SETLOCALDESC, evSetRemoteDesc = SETREMOTEDESC, + evUpdateLocalDesc = UPDATELOCALDESC, + evUpdateRemoteDesc = UPDATEREMOTEDESC, evSetLocalDescError = SETLOCALDESCERROR, evSetRemoteDescError = SETREMOTEDESCERROR, evOnRemoteStreamAdd = REMOTESTREAMADD, @@ -150,13 +152,19 @@ void ui_call_start_ringer(vcm_ring_mode_t ringMode, short once, line_t line, cal void ui_BLF_notification (int request_id, cc_blf_state_t blf_state, int app_id); void ui_update_media_interface_change(line_t line, callid_t call_id, group_call_event_t event); void ui_create_offer(call_events event, line_t nLine, callid_t nCallID, - uint16_t call_instance_id, char* sdp); + uint16_t call_instance_id, string_t sdp); void ui_create_answer(call_events event, line_t nLine, callid_t nCallID, - uint16_t call_instance_id, char* sdp); + uint16_t call_instance_id, string_t sdp); void ui_set_local_description(call_events event, line_t nLine, callid_t nCallID, - uint16_t call_instance_id, char* sdp, cc_int32_t status); + uint16_t call_instance_id, string_t sdp, cc_int32_t status); void ui_set_remote_description(call_events event, line_t nLine, callid_t nCallID, - uint16_t call_instance_id, char* sdp, cc_int32_t status); + uint16_t call_instance_id, string_t sdp, cc_int32_t status); + +void ui_update_local_description(call_events event, line_t nLine, callid_t nCallID, + uint16_t call_instance_id, string_t sdp); +void ui_update_remote_description(call_events event, line_t nLine, callid_t nCallID, + uint16_t call_instance_id, string_t sdp); + void ui_on_remote_stream_added(call_events event, line_t nLine, callid_t nCallID, uint16_t call_instance_id, cc_media_remote_track_table_t media_tracks); diff --git a/media/webrtc/signaling/src/sipcc/core/sdp/sdp_attr.c b/media/webrtc/signaling/src/sipcc/core/sdp/sdp_attr.c index 177628ff3d3f..b9be686af4de 100644 --- a/media/webrtc/signaling/src/sipcc/core/sdp/sdp_attr.c +++ b/media/webrtc/signaling/src/sipcc/core/sdp/sdp_attr.c @@ -517,6 +517,8 @@ sdp_result_e sdp_parse_attr_fmtp (sdp_t *sdp_p, sdp_attr_t *attr_p, /* END */ /* Once we move to RFC compliant video codec implementations, the above * patch should be removed */ + + src_ptr = temp_ptr; while (!done) { fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "= \t", &result1); if (result1 == SDP_SUCCESS) { @@ -1026,7 +1028,7 @@ sdp_result_e sdp_parse_attr_fmtp (sdp_t *sdp_p, sdp_attr_t *attr_p, fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; fmtp_p->level = (short) strtoul_result; codec_info_found = TRUE; - } if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[16].name, + } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[16].name, sdp_fmtp_codec_param[16].strlen) == 0) { fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; fmtp_p->is_interlace = TRUE; diff --git a/media/webrtc/signaling/src/sipcc/core/sipstack/ccsip_sdp.c b/media/webrtc/signaling/src/sipcc/core/sipstack/ccsip_sdp.c index b0c951499f29..4bc58049df93 100644 --- a/media/webrtc/signaling/src/sipcc/core/sipstack/ccsip_sdp.c +++ b/media/webrtc/signaling/src/sipcc/core/sipstack/ccsip_sdp.c @@ -322,7 +322,7 @@ sipsdp_src_dest_create (const char *peerconnection, * and by examining SDP library error counters. */ char * -sipsdp_write_to_buf (cc_sdp_t *sdp_info, uint32_t *retbytes) +sipsdp_write_to_buf (sdp_t *sdp_info, uint32_t *retbytes) { flex_string fs; uint32_t sdp_len; @@ -330,12 +330,12 @@ sipsdp_write_to_buf (cc_sdp_t *sdp_info, uint32_t *retbytes) flex_string_init(&fs); - if (!sdp_info || !sdp_info->src_sdp) { + if (!sdp_info) { CCSIP_DEBUG_ERROR(SIP_F_PREFIX"NULL sdp_info or src_sdp\n", __FUNCTION__); return (NULL); } - if ((rc = sdp_build(sdp_info->src_sdp, &fs)) + if ((rc = sdp_build(sdp_info, &fs)) != SDP_SUCCESS) { CCSIP_DEBUG_TASK(DEB_F_PREFIX"sdp_build rc=%s\n", DEB_F_PREFIX_ARGS(SIP_SDP, __FUNCTION__), sdp_get_result_name(rc)); diff --git a/media/webrtc/signaling/src/sipcc/core/sipstack/h/ccsip_sdp.h b/media/webrtc/signaling/src/sipcc/core/sipstack/h/ccsip_sdp.h index b927a834601f..beeac0dc2b51 100644 --- a/media/webrtc/signaling/src/sipcc/core/sipstack/h/ccsip_sdp.h +++ b/media/webrtc/signaling/src/sipcc/core/sipstack/h/ccsip_sdp.h @@ -142,7 +142,7 @@ PMH_EXTERN void sipsdp_free(cc_sdp_t **sip_sdp); * Memory is allocated and should be freed by the user when done * Returns NULL on failure. */ -PMH_EXTERN char *sipsdp_write_to_buf(cc_sdp_t *, uint32_t *); +PMH_EXTERN char *sipsdp_write_to_buf(sdp_t *, uint32_t *); #define SIPSDP_FREE(x) \ if (x) \ diff --git a/media/webrtc/signaling/src/sipcc/cpr/include/cpr_types.h b/media/webrtc/signaling/src/sipcc/cpr/include/cpr_types.h index 33f1707e32a2..87a7b238a82b 100644 --- a/media/webrtc/signaling/src/sipcc/cpr/include/cpr_types.h +++ b/media/webrtc/signaling/src/sipcc/cpr/include/cpr_types.h @@ -102,6 +102,16 @@ extern const cpr_ip_addr_t ip_addr_invalid; #define CPR_IP_ADDR_INIT(a) a.type = CPR_IP_ADDR_INVALID; +/* + * !!! NOTE !!! + * + * The strings of type string_t are actually very special blocks + * of memory that have a "hidden" header block immediately preceding + * the pointer. You MUST use the functions in string_lib.c to + * create, manipulate, destroy, copy, or otherwise work with these + * strings. + */ + typedef const char *string_t; __END_DECLS diff --git a/media/webrtc/signaling/src/sipcc/include/cc_constants.h b/media/webrtc/signaling/src/sipcc/include/cc_constants.h index 8c96cd281e65..cc623d20155f 100644 --- a/media/webrtc/signaling/src/sipcc/include/cc_constants.h +++ b/media/webrtc/signaling/src/sipcc/include/cc_constants.h @@ -274,7 +274,7 @@ typedef enum { REMINUSE, HOLDREVERT, WHISPER, - PRESERVATION, + PRESERVATION, WAITINGFORDIGITS = 21, CREATEOFFER, CREATEANSWER, @@ -282,6 +282,8 @@ typedef enum { CREATEANSWERERROR, SETLOCALDESC, SETREMOTEDESC, + UPDATELOCALDESC, + UPDATEREMOTEDESC, SETLOCALDESCERROR, SETREMOTEDESCERROR, REMOTESTREAMADD, diff --git a/media/webrtc/signaling/src/softphonewrapper/CC_SIPCCCallInfo.cpp b/media/webrtc/signaling/src/softphonewrapper/CC_SIPCCCallInfo.cpp index fb6c90abad47..23ba7a08f3ab 100644 --- a/media/webrtc/signaling/src/softphonewrapper/CC_SIPCCCallInfo.cpp +++ b/media/webrtc/signaling/src/softphonewrapper/CC_SIPCCCallInfo.cpp @@ -135,6 +135,12 @@ std::string CC_SIPCCCallInfo::callStateToString (cc_call_state_t state) case SETREMOTEDESC: statestr = "SETREMOTEDESC"; break; + case UPDATELOCALDESC: + statestr = "UPDATELOCALDESC"; + break; + case UPDATEREMOTEDESC: + statestr = "UPDATEREMOTEDESC"; + break; case SETLOCALDESCERROR: statestr = "SETLOCALDESCERROR"; break; @@ -418,7 +424,7 @@ bool CC_SIPCCCallInfo::isVideoMuted() string CC_SIPCCCallInfo::getSDP() { - return CCAPI_CallInfo_getSDP(callinfo_ref); + return CCAPI_CallInfo_getSDP(callinfo_ref); } cc_int32_t CC_SIPCCCallInfo::getStatusCode() diff --git a/media/webrtc/signaling/test/signaling_unittests.cpp b/media/webrtc/signaling/test/signaling_unittests.cpp index 30eb3d814a83..fb8a526d19b8 100644 --- a/media/webrtc/signaling/test/signaling_unittests.cpp +++ b/media/webrtc/signaling/test/signaling_unittests.cpp @@ -533,6 +533,24 @@ class SignalingAgent { char* offer() const { return offer_; } char* answer() const { return answer_; } + std::string getLocalDescription() const { + char *sdp = nullptr; + pc->GetLocalDescription(&sdp); + if (!sdp) { + return ""; + } + return sdp; + } + + std::string getRemoteDescription() const { + char *sdp = 0; + pc->GetRemoteDescription(&sdp); + if (!sdp) { + return ""; + } + return sdp; + } + void CreateOffer(sipcc::MediaConstraints& constraints, uint32_t offerFlags, uint32_t sdpCheck) { @@ -1432,6 +1450,53 @@ TEST_F(SignalingTest, OfferAllDynamicTypes) } +TEST_F(SignalingTest, OfferAnswerCheckDescriptions) +{ + sipcc::MediaConstraints constraints; + OfferAnswer(constraints, constraints, OFFER_AV | ANSWER_AV, true, + SHOULD_SENDRECV_AV, SHOULD_SENDRECV_AV); + + std::cout << "Caller's LocalDescription: " << std::endl << + a1_.getLocalDescription() << std::endl << std::endl; + std::cout << "Caller's Remote Description: " << std::endl << + a1_.getRemoteDescription() << std::endl << std::endl; + std::cout << "Callee's LocalDescription: " << std::endl << + a2_.getLocalDescription() << std::endl << std::endl; + std::cout << "Callee's Remote Description: " << std::endl << + a2_.getRemoteDescription() << std::endl << std::endl; + + ASSERT_EQ(a1_.getLocalDescription(),a2_.getRemoteDescription()); + ASSERT_EQ(a2_.getLocalDescription(),a1_.getRemoteDescription()); +} + +TEST_F(SignalingTest, CheckTrickleSdpChange) +{ + sipcc::MediaConstraints constraints; + OfferAnswerTrickle(constraints, constraints, + SHOULD_SENDRECV_AV, SHOULD_SENDRECV_AV); + std::cerr << "ICE handshake completed" << std::endl; + + PR_Sleep(kDefaultTimeout * 2); // Wait for some data to get written + a1_.CloseSendStreams(); + a2_.CloseReceiveStreams(); + + std::cout << "Caller's LocalDescription: " << std::endl << + a1_.getLocalDescription() << std::endl << std::endl; + std::cout << "Caller's Remote Description: " << std::endl << + a1_.getRemoteDescription() << std::endl << std::endl; + std::cout << "Callee's LocalDescription: " << std::endl << + a2_.getLocalDescription() << std::endl << std::endl; + std::cout << "Callee's Remote Description: " << std::endl << + a2_.getRemoteDescription() << std::endl << std::endl; + + ASSERT_NE(a1_.getLocalDescription().find("\r\na=candidate"), string::npos); + ASSERT_NE(a1_.getRemoteDescription().find("\r\na=candidate"), string::npos); + ASSERT_NE(a2_.getLocalDescription().find("\r\na=candidate"), string::npos); + ASSERT_NE(a2_.getRemoteDescription().find("\r\na=candidate"), string::npos); + ASSERT_EQ(a1_.getLocalDescription(),a2_.getRemoteDescription()); + ASSERT_EQ(a2_.getLocalDescription(),a1_.getRemoteDescription()); +} + } // End namespace test. int main(int argc, char **argv) { From ff272006a83eb17e1fa0acc41a126b10771b98e7 Mon Sep 17 00:00:00 2001 From: "Adam Roach [:abr]" Date: Thu, 20 Dec 2012 16:05:28 -0600 Subject: [PATCH 056/469] Bug 818714: Set media enabled to FALSE unless added using addStream, r=ehugg --- .../src/peerconnection/PeerConnectionImpl.cpp | 3 + .../signaling/src/sipcc/core/gsm/fsmdef.c | 8 +- .../signaling/src/sipcc/core/gsm/gsm_sdp.c | 34 +++-- .../webrtc/signaling/src/sipcc/core/gsm/lsm.c | 13 +- .../signaling/test/signaling_unittests.cpp | 123 +++++++++++++----- 5 files changed, 138 insertions(+), 43 deletions(-) diff --git a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp index 75472238dd55..6c6b194b5147 100644 --- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp +++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp @@ -508,6 +508,9 @@ PeerConnectionImpl::CreateDataChannel(const nsACString& aLabel, CSFLogDebugS(logTag, __FUNCTION__ << ": making DOMDataChannel"); + // TODO -- need something like "mCall->addStream(stream_id, 0, DATA);" so + // the SDP can be generated correctly + return NS_NewDOMDataChannel(dataChannel.forget(), mWindow, aRetval); #else return NS_OK; diff --git a/media/webrtc/signaling/src/sipcc/core/gsm/fsmdef.c b/media/webrtc/signaling/src/sipcc/core/gsm/fsmdef.c index 6d9d1b335dad..ca5c4d9cfcf9 100755 --- a/media/webrtc/signaling/src/sipcc/core/gsm/fsmdef.c +++ b/media/webrtc/signaling/src/sipcc/core/gsm/fsmdef.c @@ -3058,7 +3058,7 @@ fsmdef_ev_createanswer (sm_event_t *event) { * The sdp member of the dcb has local and remote sdp * this next function fills in the local part */ - cause = gsmsdp_create_local_sdp(dcb, FALSE, has_audio, has_video, has_data, FALSE); + cause = gsmsdp_create_local_sdp(dcb, TRUE, has_audio, has_video, has_data, FALSE); if (cause != CC_CAUSE_OK) { ui_create_answer(evCreateAnswerError, line, call_id, dcb->caller_id.call_instance_id, strlib_empty()); @@ -3070,7 +3070,11 @@ fsmdef_ev_createanswer (sm_event_t *event) { /* TODO(ekr@rtfm.com): The second true is because we are acting as if we are processing an offer. The first, however, is for an initial offer and we may want to set that conditionally. */ - cause = gsmsdp_negotiate_media_lines(fcb, dcb->sdp, TRUE, TRUE, FALSE, TRUE); + cause = gsmsdp_negotiate_media_lines(fcb, dcb->sdp, + /* initial_offer */ TRUE, + /* offer */ TRUE, + /* notify_stream_added */ FALSE, + /* create_answer */ TRUE); if (cause != CC_CAUSE_OK) { ui_create_answer(evCreateAnswerError, line, call_id, diff --git a/media/webrtc/signaling/src/sipcc/core/gsm/gsm_sdp.c b/media/webrtc/signaling/src/sipcc/core/gsm/gsm_sdp.c index 71fa8ccb1203..2718ccdba54f 100644 --- a/media/webrtc/signaling/src/sipcc/core/gsm/gsm_sdp.c +++ b/media/webrtc/signaling/src/sipcc/core/gsm/gsm_sdp.c @@ -122,15 +122,33 @@ static const cc_media_cap_table_t *gsmsdp_get_media_capability (fsmdef_dcb_t *dc *(dcb_p->media_cap_tbl) = g_media_table; - /* - * Turn off two default streams, this is temporary - * until we can handle multiple streams properly - */ if (sdpmode) { - dcb_p->media_cap_tbl->cap[CC_AUDIO_1].enabled = TRUE; - dcb_p->media_cap_tbl->cap[CC_VIDEO_1].enabled = TRUE; - dcb_p->media_cap_tbl->cap[CC_AUDIO_1].support_direction = SDP_DIRECTION_RECVONLY; - dcb_p->media_cap_tbl->cap[CC_VIDEO_1].support_direction = SDP_DIRECTION_RECVONLY; + /* This needs to change when we handle more than one stream + of each media type at a time. */ + + dcb_p->media_cap_tbl->cap[CC_AUDIO_1].enabled = FALSE; + dcb_p->media_cap_tbl->cap[CC_VIDEO_1].enabled = FALSE; + + /* We initialize as RECVONLY to allow the application to + display incoming media streams, even if it doesn't + plan to send media for those streams. This will be + upgraded to SENDRECV when and if a stream is added. */ + + dcb_p->media_cap_tbl->cap[CC_AUDIO_1].support_direction = + SDP_DIRECTION_RECVONLY; + + dcb_p->media_cap_tbl->cap[CC_VIDEO_1].support_direction = + SDP_DIRECTION_RECVONLY; + + /* + * This really should be set to FALSE unless we have added + * a data channel using createDataChannel(). Right now, + * though, those operations are not queued (and, in fact, + * the W3C hasn't specified the proper behavior here anyway, so + * we would only be implementing speculatively) -- so we'll + * always offer data channels until the standard is + * a bit more set. + */ dcb_p->media_cap_tbl->cap[CC_DATACHANNEL_1].enabled = TRUE; } else { dcb_p->media_cap_tbl->cap[CC_DATACHANNEL_1].enabled = FALSE; diff --git a/media/webrtc/signaling/src/sipcc/core/gsm/lsm.c b/media/webrtc/signaling/src/sipcc/core/gsm/lsm.c index 4440b29578f2..6f79878d8068 100755 --- a/media/webrtc/signaling/src/sipcc/core/gsm/lsm.c +++ b/media/webrtc/signaling/src/sipcc/core/gsm/lsm.c @@ -975,17 +975,24 @@ lsm_rx_start (lsm_lcb_t *lcb, const char *fname, fsmdef_media_t *media) media->src_port = open_rcv.port; } - /* TODO(ekr@rtfm.com): Needs changing for when we have > 2 streams */ + /* TODO(ekr@rtfm.com): Needs changing for when we + have > 2 streams. (adam@nostrum.com): For now, + we know that the stream IDs are assigned in the + same order as things appear in the media objects. + The "level" in the media objects are indexed + starting from one, while pc_stream_id is + zero-indexed. This means that the stream ID + will (for now) be equal to media->level-1. */ if ( media->cap_index == CC_VIDEO_1 ) { attrs.video.opaque = media->video; - pc_stream_id = 1; + pc_stream_id = media->level - 1; } else { attrs.audio.packetization_period = media->packetization_period; attrs.audio.max_packetization_period = media->max_packetization_period; attrs.audio.avt_payload_type = media->avt_payload_type; attrs.audio.mixing_mode = mix_mode; attrs.audio.mixing_party = mix_party; - pc_stream_id = 0; + pc_stream_id = media->level - 1; } pc_track_id = 0; dcb->cur_video_avail &= ~CC_ATTRIB_CAST; diff --git a/media/webrtc/signaling/test/signaling_unittests.cpp b/media/webrtc/signaling/test/signaling_unittests.cpp index fb8a526d19b8..d8ffa630a081 100644 --- a/media/webrtc/signaling/test/signaling_unittests.cpp +++ b/media/webrtc/signaling/test/signaling_unittests.cpp @@ -77,12 +77,15 @@ enum sdpTestFlags SHOULD_RECV_AUDIO = (1<<1), SHOULD_INACTIVE_AUDIO = (1<<2), SHOULD_REJECT_AUDIO = (1<<3), - SHOULD_SEND_VIDEO = (1<<4), - SHOULD_RECV_VIDEO = (1<<5), - SHOULD_INACTIVE_VIDEO = (1<<6), - SHOULD_REJECT_VIDEO = (1<<7), - DONT_CHECK_AUDIO = (1<<8), - DONT_CHECK_VIDEO = (1<<9), + SHOULD_OMIT_AUDIO = (1<<4), + DONT_CHECK_AUDIO = (1<<5), + + SHOULD_SEND_VIDEO = (1<<8), + SHOULD_RECV_VIDEO = (1<<9), + SHOULD_INACTIVE_VIDEO = (1<<10), + SHOULD_REJECT_VIDEO = (1<<11), + SHOULD_OMIT_VIDEO = (1<<12), + DONT_CHECK_VIDEO = (1<<13), SHOULD_SENDRECV_AUDIO = SHOULD_SEND_AUDIO | SHOULD_RECV_AUDIO, SHOULD_SENDRECV_VIDEO = SHOULD_SEND_VIDEO | SHOULD_RECV_VIDEO, @@ -90,11 +93,11 @@ enum sdpTestFlags AUDIO_FLAGS = SHOULD_SEND_AUDIO | SHOULD_RECV_AUDIO | SHOULD_INACTIVE_AUDIO | SHOULD_REJECT_AUDIO - | DONT_CHECK_AUDIO, + | DONT_CHECK_AUDIO | SHOULD_OMIT_AUDIO, VIDEO_FLAGS = SHOULD_SEND_VIDEO | SHOULD_RECV_VIDEO | SHOULD_INACTIVE_VIDEO | SHOULD_REJECT_VIDEO - | DONT_CHECK_VIDEO + | DONT_CHECK_VIDEO | SHOULD_OMIT_VIDEO }; enum offerAnswerFlags @@ -730,21 +733,26 @@ private: ASSERT_NE(sdp.find("c=IN IP4"), std::string::npos); ASSERT_NE(sdp.find("a=fingerprint:sha-256"), std::string::npos); - cout << "SDPSanityCheck flags = " << std::hex << std::showbase + cout << "SDPSanityCheck flags for " + << (offer ? "offer" : "answer") + << " = " << std::hex << std::showbase << flags << std::dec + << ((flags & SHOULD_SEND_AUDIO)?" SHOULD_SEND_AUDIO":"") << ((flags & SHOULD_RECV_AUDIO)?" SHOULD_RECV_AUDIO":"") << ((flags & SHOULD_INACTIVE_AUDIO)?" SHOULD_INACTIVE_AUDIO":"") << ((flags & SHOULD_REJECT_AUDIO)?" SHOULD_REJECT_AUDIO":"") + << ((flags & SHOULD_OMIT_AUDIO)?" SHOULD_OMIT_AUDIO":"") + << ((flags & DONT_CHECK_AUDIO)?" DONT_CHECK_AUDIO":"") + << ((flags & SHOULD_SEND_VIDEO)?" SHOULD_SEND_VIDEO":"") << ((flags & SHOULD_RECV_VIDEO)?" SHOULD_RECV_VIDEO":"") << ((flags & SHOULD_INACTIVE_VIDEO)?" SHOULD_INACTIVE_VIDEO":"") << ((flags & SHOULD_REJECT_VIDEO)?" SHOULD_REJECT_VIDEO":"") - << endl; + << ((flags & SHOULD_OMIT_VIDEO)?" SHOULD_OMIT_VIDEO":"") + << ((flags & DONT_CHECK_VIDEO)?" DONT_CHECK_VIDEO":"") - if ((flags & AUDIO_FLAGS) && offer) { - ASSERT_NE(sdp.find("a=rtpmap:0 PCMU/8000"), std::string::npos); - } + << endl; switch(flags & AUDIO_FLAGS) { case 0: @@ -753,14 +761,23 @@ private: case SHOULD_SEND_AUDIO: ASSERT_NE(sdp.find("a=rtpmap:109 opus/48000"), std::string::npos); ASSERT_NE(sdp.find(" 0-15\r\na=sendonly"), std::string::npos); + if (offer) { + ASSERT_NE(sdp.find("a=rtpmap:0 PCMU/8000"), std::string::npos); + } break; case SHOULD_RECV_AUDIO: ASSERT_NE(sdp.find("a=rtpmap:109 opus/48000"), std::string::npos); ASSERT_NE(sdp.find(" 0-15\r\na=recvonly"), std::string::npos); + if (offer) { + ASSERT_NE(sdp.find("a=rtpmap:0 PCMU/8000"), std::string::npos); + } break; case SHOULD_SENDRECV_AUDIO: ASSERT_NE(sdp.find("a=rtpmap:109 opus/48000"), std::string::npos); ASSERT_NE(sdp.find(" 0-15\r\na=sendrecv"), std::string::npos); + if (offer) { + ASSERT_NE(sdp.find("a=rtpmap:0 PCMU/8000"), std::string::npos); + } break; case SHOULD_INACTIVE_AUDIO: ASSERT_NE(sdp.find("a=rtpmap:109 opus/48000"), std::string::npos); @@ -770,6 +787,9 @@ private: ASSERT_EQ(sdp.find("a=rtpmap:109 opus/48000"), std::string::npos); ASSERT_NE(sdp.find("m=audio 0 "), std::string::npos); break; + case SHOULD_OMIT_AUDIO: + ASSERT_EQ(sdp.find("m=audio"), std::string::npos); + break; case DONT_CHECK_AUDIO: break; default: @@ -799,6 +819,9 @@ private: case SHOULD_REJECT_VIDEO: ASSERT_NE(sdp.find("m=video 0 "), std::string::npos); break; + case SHOULD_OMIT_VIDEO: + ASSERT_EQ(sdp.find("m=video"), std::string::npos); + break; case DONT_CHECK_VIDEO: break; default: @@ -952,7 +975,7 @@ TEST_F(SignalingTest, CreateOfferNoVideoStream) constraints.setBooleanConstraint("OfferToReceiveAudio", true, false); constraints.setBooleanConstraint("OfferToReceiveVideo", true, false); CreateOffer(constraints, OFFER_AUDIO, - SHOULD_SENDRECV_AUDIO | SHOULD_RECV_VIDEO); + SHOULD_SENDRECV_AUDIO | SHOULD_OMIT_VIDEO); } TEST_F(SignalingTest, CreateOfferNoAudioStream) @@ -961,7 +984,7 @@ TEST_F(SignalingTest, CreateOfferNoAudioStream) constraints.setBooleanConstraint("OfferToReceiveAudio", true, false); constraints.setBooleanConstraint("OfferToReceiveVideo", true, false); CreateOffer(constraints, OFFER_VIDEO, - SHOULD_RECV_AUDIO | SHOULD_SENDRECV_VIDEO); + SHOULD_OMIT_AUDIO | SHOULD_SENDRECV_VIDEO); } TEST_F(SignalingTest, CreateOfferDontReceiveAudio) @@ -1078,8 +1101,8 @@ TEST_F(SignalingTest, OfferAnswerDontAddAudioStreamOnOffer) answerconstraints.setBooleanConstraint("OfferToReceiveAudio", true, false); answerconstraints.setBooleanConstraint("OfferToReceiveVideo", true, false); OfferAnswer(offerconstraints, answerconstraints, OFFER_VIDEO | ANSWER_AV, - false, SHOULD_RECV_AUDIO | SHOULD_SENDRECV_VIDEO, - SHOULD_SEND_AUDIO | SHOULD_SENDRECV_VIDEO); + false, SHOULD_OMIT_AUDIO | SHOULD_SENDRECV_VIDEO, + SHOULD_OMIT_AUDIO | SHOULD_SENDRECV_VIDEO); } TEST_F(SignalingTest, OfferAnswerDontAddVideoStreamOnOffer) @@ -1091,8 +1114,8 @@ TEST_F(SignalingTest, OfferAnswerDontAddVideoStreamOnOffer) answerconstraints.setBooleanConstraint("OfferToReceiveAudio", true, false); answerconstraints.setBooleanConstraint("OfferToReceiveVideo", true, false); OfferAnswer(offerconstraints, answerconstraints, OFFER_AUDIO | ANSWER_AV, - false, SHOULD_SENDRECV_AUDIO | SHOULD_RECV_VIDEO, - SHOULD_SENDRECV_AUDIO | SHOULD_SEND_VIDEO); + false, SHOULD_SENDRECV_AUDIO | SHOULD_OMIT_VIDEO, + SHOULD_SENDRECV_AUDIO | SHOULD_OMIT_VIDEO); } TEST_F(SignalingTest, OfferAnswerDontAddAudioStreamOnAnswer) @@ -1167,7 +1190,8 @@ TEST_F(SignalingTest, OfferAnswerDontAddVideoStreamOnOfferDontReceiveVideoOnOffe answerconstraints.setBooleanConstraint("OfferToReceiveAudio", true, false); answerconstraints.setBooleanConstraint("OfferToReceiveVideo", true, false); OfferAnswer(offerconstraints, answerconstraints, OFFER_AUDIO | ANSWER_AV, - false, SHOULD_SENDRECV_AUDIO, SHOULD_SENDRECV_AUDIO); + false, SHOULD_SENDRECV_AUDIO | SHOULD_OMIT_VIDEO, + SHOULD_SENDRECV_AUDIO | SHOULD_OMIT_VIDEO); } TEST_F(SignalingTest, OfferAnswerDontReceiveAudioNoAudioStreamOnOfferDontReceiveVideoOnAnswer) @@ -1242,16 +1266,6 @@ TEST_F(SignalingTest, OfferAnswerDontAddAudioVideoStreamsOnAnswerNoConstraints) SHOULD_RECV_AUDIO | SHOULD_RECV_VIDEO); } -TEST_F(SignalingTest, OfferModifiedAnswer) -{ - sipcc::MediaConstraints constraints; - OfferModifiedAnswer(constraints, constraints, SHOULD_SENDRECV_AV, - SHOULD_SENDRECV_AV); - PR_Sleep(kDefaultTimeout * 2); // Wait for completion - a1_.CloseSendStreams(); - a2_.CloseReceiveStreams(); -} - TEST_F(SignalingTest, FullCall) { sipcc::MediaConstraints constraints; @@ -1269,6 +1283,55 @@ TEST_F(SignalingTest, FullCall) ASSERT_GE(a2_.GetPacketsReceived(0), 40); } +TEST_F(SignalingTest, FullCallAudioOnly) +{ + sipcc::MediaConstraints constraints; + OfferAnswer(constraints, constraints, OFFER_AUDIO | ANSWER_AUDIO, + true, SHOULD_SENDRECV_AUDIO, SHOULD_SENDRECV_AUDIO); + + PR_Sleep(kDefaultTimeout * 2); // Wait for some data to get written + + a1_.CloseSendStreams(); + a2_.CloseReceiveStreams(); + // Check that we wrote a bunch of data + ASSERT_GE(a1_.GetPacketsSent(0), 40); + //ASSERT_GE(a2_.GetPacketsSent(0), 40); + //ASSERT_GE(a1_.GetPacketsReceived(0), 40); + ASSERT_GE(a2_.GetPacketsReceived(0), 40); +} + +TEST_F(SignalingTest, FullCallVideoOnly) +{ + sipcc::MediaConstraints constraints; + OfferAnswer(constraints, constraints, OFFER_VIDEO | ANSWER_VIDEO, + true, SHOULD_SENDRECV_VIDEO, SHOULD_SENDRECV_VIDEO); + + PR_Sleep(kDefaultTimeout * 2); // Wait for some data to get written + + a1_.CloseSendStreams(); + a2_.CloseReceiveStreams(); + + // FIXME -- Ideally we would check that packets were sent + // and received; however, the test driver setup does not + // currently support sending/receiving with Fake_VideoStreamSource. + // + // Check that we wrote a bunch of data + // ASSERT_GE(a1_.GetPacketsSent(0), 40); + //ASSERT_GE(a2_.GetPacketsSent(0), 40); + //ASSERT_GE(a1_.GetPacketsReceived(0), 40); + // ASSERT_GE(a2_.GetPacketsReceived(0), 40); +} + +TEST_F(SignalingTest, OfferModifiedAnswer) +{ + sipcc::MediaConstraints constraints; + OfferModifiedAnswer(constraints, constraints, SHOULD_SENDRECV_AV, + SHOULD_SENDRECV_AV); + PR_Sleep(kDefaultTimeout * 2); // Wait for completion + a1_.CloseSendStreams(); + a2_.CloseReceiveStreams(); +} + TEST_F(SignalingTest, FullCallTrickle) { sipcc::MediaConstraints constraints; From e0f74b0102a9808d42b6a0d2d6f2d2e09055c64b Mon Sep 17 00:00:00 2001 From: "Adam Roach [:abr]" Date: Fri, 21 Dec 2012 14:55:41 -0600 Subject: [PATCH 057/469] Bug 821003: Replace snprintf macro with static function r=jesup --- .../signaling/src/sipcc/cpr/win32/cpr_win_stdio.c | 11 +++++++++++ .../signaling/src/sipcc/cpr/win32/cpr_win_stdio.h | 3 ++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/media/webrtc/signaling/src/sipcc/cpr/win32/cpr_win_stdio.c b/media/webrtc/signaling/src/sipcc/cpr/win32/cpr_win_stdio.c index 9419d1cdccfe..44f600509a93 100755 --- a/media/webrtc/signaling/src/sipcc/cpr/win32/cpr_win_stdio.c +++ b/media/webrtc/signaling/src/sipcc/cpr/win32/cpr_win_stdio.c @@ -67,3 +67,14 @@ buginf (const char *_format, ...) return (0); } +int +cpr_win_snprintf(char *buffer, size_t n, const char *format, ...) +{ + va_list argp; + int ret; + va_start(argp, format); + ret = _vscprintf(format, argp); + vsnprintf_s(buffer, n, _TRUNCATE, format, argp); + va_end(argp); + return ret; +} diff --git a/media/webrtc/signaling/src/sipcc/cpr/win32/cpr_win_stdio.h b/media/webrtc/signaling/src/sipcc/cpr/win32/cpr_win_stdio.h index 0feed4279d5e..8835188300cb 100755 --- a/media/webrtc/signaling/src/sipcc/cpr/win32/cpr_win_stdio.h +++ b/media/webrtc/signaling/src/sipcc/cpr/win32/cpr_win_stdio.h @@ -9,6 +9,7 @@ #include -#define snprintf _snprintf +#define snprintf cpr_win_snprintf +int cpr_win_snprintf(char *buffer, size_t n, const char *format, ...); #endif From 889ac174c8bbb099096bd12c044ecb05ca3794ff Mon Sep 17 00:00:00 2001 From: Randell Jesup Date: Sat, 22 Dec 2012 03:09:36 -0500 Subject: [PATCH 058/469] Bug 799417: Backend support for list of documents that have active gUM MediaStreams r=derf --- dom/media/Makefile.in | 1 + dom/media/MediaManager.cpp | 47 +++++++++++++++++++++++++++++++-- dom/media/MediaManager.h | 10 +++++-- dom/media/nsIMediaManager.idl | 18 +++++++++++++ layout/build/Makefile.in | 1 + layout/build/nsLayoutModule.cpp | 7 +++++ 6 files changed, 80 insertions(+), 4 deletions(-) create mode 100644 dom/media/nsIMediaManager.idl diff --git a/dom/media/Makefile.in b/dom/media/Makefile.in index 9accd09faf04..3f8f0a8d4093 100644 --- a/dom/media/Makefile.in +++ b/dom/media/Makefile.in @@ -28,6 +28,7 @@ XPIDLSRCS = \ nsIDOMMediaStream.idl \ nsIDOMRTCPeerConnection.idl \ nsIDOMNavigatorUserMedia.idl \ + nsIMediaManager.idl \ $(NULL) EXPORTS_NAMESPACE = mozilla diff --git a/dom/media/MediaManager.cpp b/dom/media/MediaManager.cpp index 79a2c3782079..6053b23a5897 100644 --- a/dom/media/MediaManager.cpp +++ b/dom/media/MediaManager.cpp @@ -10,6 +10,7 @@ #include "nsIUUIDGenerator.h" #include "nsIScriptGlobalObject.h" #include "nsIPopupWindowManager.h" +#include "nsISupportsArray.h" // For PR_snprintf #include "prprf.h" @@ -690,9 +691,17 @@ private: already_AddRefed mError; }; -nsRefPtr MediaManager::sSingleton; +NS_IMPL_THREADSAFE_ISUPPORTS2(MediaManager, nsIMediaManagerService, nsIObserver) -NS_IMPL_THREADSAFE_ISUPPORTS1(MediaManager, nsIObserver) +/* static */ StaticRefPtr MediaManager::sSingleton; + +/* static */ already_AddRefed +MediaManager::GetInstance() +{ + // so we can have non-refcounted getters + nsRefPtr service = MediaManager::Get(); + return service.forget(); +} /** * The entry point for this file. A call from Navigator::mozGetUserMedia @@ -1050,4 +1059,38 @@ MediaManager::Observe(nsISupports* aSubject, const char* aTopic, return NS_OK; } +static PLDHashOperator +WindowsHashToArrayFunc (const uint64_t& aId, + StreamListeners* aData, + void *userArg) +{ + nsISupportsArray *array = + static_cast(userArg); + nsPIDOMWindow *window = static_cast + (nsGlobalWindow::GetInnerWindowWithId(aId)); + (void) aData; + + MOZ_ASSERT(window); + if (window) { + array->AppendElement(window); + } + return PL_DHASH_NEXT; +} + + +nsresult +MediaManager::GetActiveMediaCaptureWindows(nsISupportsArray **aArray) +{ + MOZ_ASSERT(aArray); + nsISupportsArray *array; + nsresult rv = NS_NewISupportsArray(&array); // AddRefs + if (NS_FAILED(rv)) + return rv; + + mActiveWindows.EnumerateRead(WindowsHashToArrayFunc, array); + + *aArray = array; + return NS_OK; +} + } // namespace mozilla diff --git a/dom/media/MediaManager.h b/dom/media/MediaManager.h index 7e1a54a912e0..3139564e423a 100644 --- a/dom/media/MediaManager.h +++ b/dom/media/MediaManager.h @@ -4,6 +4,7 @@ #include "MediaEngine.h" #include "mozilla/Services.h" +#include "nsIMediaManager.h" #include "nsHashKeys.h" #include "nsGlobalWindow.h" @@ -14,6 +15,7 @@ #include "nsPIDOMWindow.h" #include "nsIDOMNavigatorUserMedia.h" #include "mozilla/Attributes.h" +#include "mozilla/StaticPtr.h" #include "prlog.h" namespace mozilla { @@ -272,9 +274,12 @@ private: nsRefPtr mSource; }; -class MediaManager MOZ_FINAL : public nsIObserver +class MediaManager MOZ_FINAL : public nsIMediaManagerService, + public nsIObserver { public: + static already_AddRefed GetInstance(); + static MediaManager* Get() { if (!sSingleton) { sSingleton = new MediaManager(); @@ -296,6 +301,7 @@ public: NS_DECL_ISUPPORTS NS_DECL_NSIOBSERVER + NS_DECL_NSIMEDIAMANAGERSERVICE MediaEngine* GetBackend(); StreamListeners *GetWindowListeners(uint64_t aWindowId) { @@ -345,7 +351,7 @@ private: // protected with mMutex: MediaEngine* mBackend; - static nsRefPtr sSingleton; + static StaticRefPtr sSingleton; }; } // namespace mozilla diff --git a/dom/media/nsIMediaManager.idl b/dom/media/nsIMediaManager.idl new file mode 100644 index 000000000000..75c4bb0b83ad --- /dev/null +++ b/dom/media/nsIMediaManager.idl @@ -0,0 +1,18 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsISupports.idl" + +interface nsISupportsArray; + +%{C++ +#define NS_MEDIAMANAGERSERVICE_CID {0xabc622ea, 0x9655, 0x4123, {0x80, 0xd9, 0x22, 0x62, 0x1b, 0xdd, 0x54, 0x65}} +#define MEDIAMANAGERSERVICE_CONTRACTID "@mozilla.org/mediaManagerService;1" +%} + +[scriptable, builtinclass, uuid(afe82ff1-2caa-4304-85da-0158a5dee56b)] +interface nsIMediaManagerService : nsISupports +{ + readonly attribute nsISupportsArray activeMediaCaptureWindows; +}; diff --git a/layout/build/Makefile.in b/layout/build/Makefile.in index 173bb128e8ec..6d9506d0b43c 100644 --- a/layout/build/Makefile.in +++ b/layout/build/Makefile.in @@ -302,6 +302,7 @@ LOCAL_INCLUDES += -I$(srcdir)/../base \ -I$(topsrcdir)/dom/settings \ -I$(topsrcdir)/dom/permission \ -I$(topsrcdir)/dom/telephony \ + -I$(topsrcdir)/dom/media \ -I. \ -I$(topsrcdir)/editor/libeditor/base \ -I$(topsrcdir)/editor/libeditor/text \ diff --git a/layout/build/nsLayoutModule.cpp b/layout/build/nsLayoutModule.cpp index 0f57fbda31ac..2159e9020816 100644 --- a/layout/build/nsLayoutModule.cpp +++ b/layout/build/nsLayoutModule.cpp @@ -233,6 +233,7 @@ static void Shutdown(); #include "mozilla/dom/sms/SmsServicesFactory.h" #include "nsIPowerManagerService.h" #include "nsIAlarmHalService.h" +#include "nsIMediaManager.h" #include "nsMixedContentBlocker.h" #include "AudioChannelService.h" @@ -244,6 +245,7 @@ static void Shutdown(); #ifdef MOZ_WIDGET_GONK #include "GonkGPSGeolocationProvider.h" #endif +#include "MediaManager.h" using namespace mozilla; using namespace mozilla::dom; @@ -326,6 +328,8 @@ NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsITimeService, NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsIGeolocationProvider, GonkGPSGeolocationProvider::GetSingleton) #endif +NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsIMediaManagerService, + MediaManager::GetInstance) //----------------------------------------------------------------------------- @@ -840,6 +844,7 @@ NS_DEFINE_NAMED_CID(NS_TIMESERVICE_CID); #ifdef MOZ_WIDGET_GONK NS_DEFINE_NAMED_CID(GONK_GPS_GEOLOCATION_PROVIDER_CID); #endif +NS_DEFINE_NAMED_CID(NS_MEDIAMANAGERSERVICE_CID); static nsresult CreateWindowCommandTableConstructor(nsISupports *aOuter, @@ -1119,6 +1124,7 @@ static const mozilla::Module::CIDEntry kLayoutCIDs[] = { #ifdef MOZ_WIDGET_GONK { &kGONK_GPS_GEOLOCATION_PROVIDER_CID, false, NULL, nsIGeolocationProviderConstructor }, #endif + { &kNS_MEDIAMANAGERSERVICE_CID, false, NULL, nsIMediaManagerServiceConstructor }, { NULL } }; @@ -1262,6 +1268,7 @@ static const mozilla::Module::ContractIDEntry kLayoutContracts[] = { #ifdef MOZ_WIDGET_GONK { GONK_GPS_GEOLOCATION_PROVIDER_CONTRACTID, &kGONK_GPS_GEOLOCATION_PROVIDER_CID }, #endif + { MEDIAMANAGERSERVICE_CONTRACTID, &kNS_MEDIAMANAGERSERVICE_CID }, { NULL } }; From 75d26f98a10db8507d91c4efb55cceddc4f8590a Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Sat, 22 Dec 2012 00:27:27 -0800 Subject: [PATCH 059/469] Bug 822766. Be a bit more careful with our level assert in ReplaceAnimationRule. r=dbaron --- layout/style/crashtests/822766-1.html | 31 +++++++++++++++++++++++++ layout/style/crashtests/crashtests.list | 1 + layout/style/nsStyleSet.cpp | 3 ++- 3 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 layout/style/crashtests/822766-1.html diff --git a/layout/style/crashtests/822766-1.html b/layout/style/crashtests/822766-1.html new file mode 100644 index 000000000000..77bb1e25a839 --- /dev/null +++ b/layout/style/crashtests/822766-1.html @@ -0,0 +1,31 @@ + + + + + + + + diff --git a/layout/style/crashtests/crashtests.list b/layout/style/crashtests/crashtests.list index 06284fee0b46..db6ba70f42ac 100644 --- a/layout/style/crashtests/crashtests.list +++ b/layout/style/crashtests/crashtests.list @@ -83,3 +83,4 @@ load 788836.html load 806310-1.html load 812824.html load 822842.html +load 822766-1.html diff --git a/layout/style/nsStyleSet.cpp b/layout/style/nsStyleSet.cpp index 6ab33e4f3552..020d8f4ba512 100644 --- a/layout/style/nsStyleSet.cpp +++ b/layout/style/nsStyleSet.cpp @@ -516,7 +516,8 @@ ReplaceAnimationRule(nsRuleNode *aOldRuleNode, } NS_ABORT_IF_FALSE(!IsMoreSpecificThanAnimation(n) && - n->GetLevel() != nsStyleSet::eAnimationSheet, + (n->IsRoot() || + n->GetLevel() != nsStyleSet::eAnimationSheet), "wrong level"); if (aNewAnimRule) { From 53a5112fb0cf31e30b1ba1f4186ee7e19ac86f57 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Sat, 22 Dec 2012 00:27:27 -0800 Subject: [PATCH 060/469] Bug 804631. Add the WebIDL API for Document. r=peterv I'm not entirely happy with the XPath bits. If we had an nsXPathEvaluator member, or if the WebIDL API were on nsIDOMXPathEvaluator or something, all that stuff would need a lot less code... --- content/base/public/nsContentUtils.h | 6 +- content/base/public/nsIDocument.h | 230 +++- content/base/src/Makefile.in | 1 + content/base/src/nsContentUtils.cpp | 6 +- content/base/src/nsDocument.cpp | 1263 +++++++++++++----- content/base/src/nsDocument.h | 73 +- content/base/src/nsINode.cpp | 5 +- content/base/src/nsRange.h | 12 + content/events/src/nsContentEventHandler.cpp | 9 +- content/html/document/src/nsHTMLDocument.cpp | 4 +- content/html/document/src/nsHTMLDocument.h | 10 +- content/svg/document/src/nsSVGDocument.h | 8 + content/xul/document/src/nsXULDocument.h | 7 + dom/base/nsDOMWindowUtils.cpp | 7 +- dom/bindings/Bindings.conf | 38 +- dom/bindings/Makefile.in | 1 + dom/interfaces/core/nsIDOMDocument.idl | 2 + dom/webidl/Document.webidl | 427 +++++- dom/webidl/Location.webidl | 28 + dom/webidl/WebIDL.mk | 1 + js/xpconnect/src/dom_quickstubs.qsconf | 18 +- 21 files changed, 1706 insertions(+), 450 deletions(-) create mode 100644 dom/webidl/Location.webidl diff --git a/content/base/public/nsContentUtils.h b/content/base/public/nsContentUtils.h index eed6698691a3..f684f360cd81 100644 --- a/content/base/public/nsContentUtils.h +++ b/content/base/public/nsContentUtils.h @@ -354,10 +354,10 @@ public: /** * Checks whether two nodes come from the same origin. */ - static nsresult CheckSameOrigin(nsINode* aTrustedNode, + static nsresult CheckSameOrigin(const nsINode* aTrustedNode, nsIDOMNode* aUnTrustedNode); - static nsresult CheckSameOrigin(nsINode* aTrustedNode, - nsINode* unTrustedNode); + static nsresult CheckSameOrigin(const nsINode* aTrustedNode, + const nsINode* unTrustedNode); // Check if the (JS) caller can access aNode. static bool CanCallerAccess(nsIDOMNode *aNode); diff --git a/content/base/public/nsIDocument.h b/content/base/public/nsIDocument.h index 84593d73a154..bd67f6503bf0 100644 --- a/content/base/public/nsIDocument.h +++ b/content/base/public/nsIDocument.h @@ -45,9 +45,15 @@ class nsIDocumentObserver; class nsIDOMDocument; class nsIDOMDocumentFragment; class nsIDOMDocumentType; +class nsDOMDocumentType; +class nsXMLProcessingInstruction; class nsIDOMElement; class nsIDOMEventTarget; class nsIDOMNodeList; +class nsIDOMTouch; +class nsIDOMTouchList; +class nsIDOMXPathExpression; +class nsIDOMXPathNSResolver; class nsILayoutHistoryState; class nsIObjectLoadingContent; class nsIObserver; @@ -61,27 +67,35 @@ class nsIURI; class nsIVariant; class nsIViewManager; class nsPresContext; +class nsRange; class nsScriptLoader; class nsSMILAnimationController; class nsStyleSet; +class nsTextNode; class nsWindowSizes; class nsSmallVoidArray; namespace mozilla { +class ErrorResult; + namespace css { class Loader; class ImageLoader; } // namespace css namespace dom { -class Link; +class Comment; +class DocumentFragment; +class DOMImplementation; class Element; +class Link; +template class Sequence; } // namespace dom } // namespace mozilla #define NS_IDOCUMENT_IID \ -{ 0x1517f31a, 0x0ef9, 0x4629, \ - { 0xb4, 0x7f, 0x56, 0x31, 0x0d, 0x80, 0x61, 0xaf } } +{ 0xff03d72f, 0x87cd, 0x4d11, \ + { 0x81, 0x8d, 0xa8, 0xb4, 0xf5, 0x98, 0x1a, 0x10 } } // Flag for AddStyleSheet(). #define NS_STYLESHEET_FROM_CATALOG (1 << 0) @@ -100,6 +114,13 @@ enum DocumentFlavor { // Window activation status #define NS_DOCUMENT_STATE_WINDOW_INACTIVE NS_DEFINE_EVENT_STATE_MACRO(1) +// Some function forward-declarations +class nsContentList; + +already_AddRefed +NS_GetContentList(nsINode* aRootNode, + int32_t aMatchNameSpaceId, + const nsAString& aTagname); //---------------------------------------------------------------------- // Document interface. This is implemented by all document objects in @@ -531,7 +552,7 @@ public: /** * Return the doctype for this document. */ - nsIContent* GetDocumentType() const; + nsDOMDocumentType* GetDoctype() const; /** * Return the root element for this document. @@ -714,7 +735,7 @@ public: * document is truly gone. Use this object when you're trying to find a * content wrapper in XPConnect. */ - virtual nsIScriptGlobalObject* GetScopeObject() = 0; + virtual nsIScriptGlobalObject* GetScopeObject() const = 0; /** * Return the window containing the document (the outer window). @@ -870,7 +891,10 @@ public: enum ReadyState { READYSTATE_UNINITIALIZED = 0, READYSTATE_LOADING = 1, READYSTATE_INTERACTIVE = 3, READYSTATE_COMPLETE = 4}; virtual void SetReadyStateInternal(ReadyState rs) = 0; - virtual ReadyState GetReadyStateEnum() = 0; + ReadyState GetReadyStateEnum() + { + return mReadyState; + } // notify that a content node changed state. This must happen under // a scriptblocker but NOT within a begin/end update. @@ -1204,7 +1228,7 @@ public: /** * See GetAnonymousElementByAttribute on nsIDOMDocumentXBL. */ - virtual nsIContent* + virtual Element* GetAnonymousElementByAttribute(nsIContent* aElement, nsIAtom* aAttrName, const nsAString& aAttrValue) const = 0; @@ -1215,10 +1239,9 @@ public: * * @see nsIDOMWindowUtils::elementFromPoint */ - virtual nsresult ElementFromPointHelper(float aX, float aY, + virtual Element* ElementFromPointHelper(float aX, float aY, bool aIgnoreRootScrollFrame, - bool aFlushLayout, - nsIDOMElement** aReturn) = 0; + bool aFlushLayout) = 0; virtual nsresult NodesFromRectHelper(float aX, float aY, float aTopSize, float aRightSize, @@ -1702,7 +1725,7 @@ public: virtual void PostVisibilityUpdateEvent() = 0; - bool IsSyntheticDocument() { return mIsSyntheticDocument; } + bool IsSyntheticDocument() const { return mIsSyntheticDocument; } void SetNeedLayoutFlush() { mNeedLayoutFlush = true; @@ -1757,6 +1780,164 @@ public: return mCreatingStaticClone; } + // WebIDL API + nsIScriptGlobalObject* GetParentObject() const + { + return GetScopeObject(); + } + static already_AddRefed Constructor(nsISupports* aGlobal, + mozilla::ErrorResult& rv); + virtual mozilla::dom::DOMImplementation* + GetImplementation(mozilla::ErrorResult& rv) = 0; + void GetURL(nsString& retval) const; + void GetDocumentURI(nsString& retval) const; + void GetCompatMode(nsString& retval) const; + void GetCharacterSet(nsAString& retval) const; + // Skip GetContentType, because our NS_IMETHOD version above works fine here. + // GetDoctype defined above + Element* GetDocumentElement() const + { + return GetRootElement(); + } + already_AddRefed + GetElementsByTagName(const nsAString& aTagName) + { + return NS_GetContentList(this, kNameSpaceID_Unknown, aTagName); + } + already_AddRefed + GetElementsByTagNameNS(const nsAString& aNamespaceURI, + const nsAString& aLocalName); + already_AddRefed + GetElementsByClassName(const nsAString& aClasses); + // GetElementById defined above + already_AddRefed CreateElement(const nsAString& aTagName, + mozilla::ErrorResult& rv); + already_AddRefed CreateElementNS(const nsAString& aNamespaceURI, + const nsAString& aQualifiedName, + mozilla::ErrorResult& rv); + already_AddRefed + CreateDocumentFragment(mozilla::ErrorResult& rv) const; + already_AddRefed CreateTextNode(const nsAString& aData, + mozilla::ErrorResult& rv) const; + already_AddRefed + CreateComment(const nsAString& aData, mozilla::ErrorResult& rv) const; + already_AddRefed + CreateProcessingInstruction(const nsAString& target, const nsAString& data, + mozilla::ErrorResult& rv) const; + already_AddRefed + ImportNode(nsINode& aNode, bool aDeep, mozilla::ErrorResult& rv) const; + nsINode* AdoptNode(nsINode& aNode, mozilla::ErrorResult& rv); + already_AddRefed CreateEvent(const nsAString& aEventType, + mozilla::ErrorResult& rv) const; + already_AddRefed CreateRange(mozilla::ErrorResult& rv); + already_AddRefed + CreateNodeIterator(nsINode& aRoot, uint32_t aWhatToShow, + nsIDOMNodeFilter* aFilter, mozilla::ErrorResult& rv) const; + already_AddRefed + CreateTreeWalker(nsINode& aRoot, uint32_t aWhatToShow, + nsIDOMNodeFilter* aFilter, mozilla::ErrorResult& rv) const; + + // Deprecated WebIDL bits + already_AddRefed + CreateCDATASection(const nsAString& aData, mozilla::ErrorResult& rv); + already_AddRefed + CreateAttribute(const nsAString& aName, mozilla::ErrorResult& rv); + already_AddRefed + CreateAttributeNS(const nsAString& aNamespaceURI, + const nsAString& aQualifiedName, + mozilla::ErrorResult& rv); + void GetInputEncoding(nsAString& aInputEncoding); + already_AddRefed GetLocation() const; + void GetReferrer(nsAString& aReferrer) const; + void GetLastModified(nsAString& aLastModified) const; + void GetReadyState(nsAString& aReadyState) const; + // Not const because otherwise the compiler can't figure out whether to call + // this GetTitle or the nsAString version from non-const methods, since + // neither is an exact match. + virtual void GetTitle(nsString& aTitle) = 0; + virtual void SetTitle(const nsAString& aTitle, mozilla::ErrorResult& rv) = 0; + void GetDir(nsAString& aDirection) const; + void SetDir(const nsAString& aDirection, mozilla::ErrorResult& rv); + nsIDOMWindow* GetDefaultView() const + { + return GetWindow(); + } + Element* GetActiveElement(); + bool HasFocus(mozilla::ErrorResult& rv) const; + // Event handlers are all on nsINode already + bool MozSyntheticDocument() const + { + return IsSyntheticDocument(); + } + Element* GetCurrentScript(); + void ReleaseCapture() const; + virtual void MozSetImageElement(const nsAString& aImageElementId, + Element* aElement) = 0; + // Not const because all the full-screen goop is not const + virtual bool MozFullScreenEnabled() = 0; + virtual Element* GetMozFullScreenElement(mozilla::ErrorResult& rv) = 0; + bool MozFullScreen() + { + return IsFullScreenDoc(); + } + void MozCancelFullScreen(); + Element* GetMozPointerLockElement(); + void MozExitPointerLock() + { + UnlockPointer(); + } + bool Hidden() const + { + return mVisibilityState != eVisible; + } + bool MozHidden() // Not const because of WarnOnceAbout + { + WarnOnceAbout(ePrefixedVisibilityAPI); + return Hidden(); + } + void GetVisibilityState(nsAString& aState); + void GetMozVisibilityState(nsAString& aState); + virtual nsIDOMStyleSheetList* StyleSheets() = 0; + void GetSelectedStyleSheetSet(nsAString& aSheetSet); + virtual void SetSelectedStyleSheetSet(const nsAString& aSheetSet) = 0; + virtual void GetLastStyleSheetSet(nsString& aSheetSet) = 0; + void GetPreferredStyleSheetSet(nsAString& aSheetSet); + virtual nsIDOMDOMStringList* StyleSheetSets() = 0; + virtual void EnableStyleSheetsForSet(const nsAString& aSheetSet) = 0; + Element* ElementFromPoint(float aX, float aY); + // QuerySelector and QuerySelectorAll already defined on nsINode + nsINodeList* GetAnonymousNodes(Element& aElement); + Element* GetAnonymousElementByAttribute(Element& aElement, + const nsAString& aAttrName, + const nsAString& aAttrValue); + void AddBinding(Element& aElement, const nsAString& aURI, + mozilla::ErrorResult& rv); + void RemoveBinding(Element& aElement, const nsAString& aURI, + mozilla::ErrorResult& rv); + Element* GetBindingParent(nsINode& aNode); + void LoadBindingDocument(const nsAString& aURI, mozilla::ErrorResult& rv); + already_AddRefed + CreateExpression(const nsAString& aExpression, + nsIDOMXPathNSResolver* aResolver, + mozilla::ErrorResult& rv); + already_AddRefed + CreateNSResolver(nsINode* aNodeResolver, mozilla::ErrorResult& rv); + already_AddRefed + Evaluate(const nsAString& aExpression, nsINode* aContextNode, + nsIDOMXPathNSResolver* aResolver, uint16_t aType, + nsISupports* aResult, mozilla::ErrorResult& rv); + // Touch event handlers already on nsINode + already_AddRefed + CreateTouch(nsIDOMWindow* aView, nsISupports* aTarget, + int32_t aIdentifier, int32_t aPageX, int32_t aPageY, + int32_t aScreenX, int32_t aScreenY, int32_t aClientX, + int32_t aClientY, int32_t aRadiusX, int32_t aRadiusY, + float aRotationAngle, float aForce); + already_AddRefed + CreateTouchList(nsIDOMTouch* aTouch); + already_AddRefed + CreateTouchList(const mozilla::dom::Sequence >& aTouches); + private: uint64_t mWarnedAbout; @@ -1801,6 +1982,23 @@ protected: return mContentType; } + inline void + SetDocumentDirectionality(mozilla::Directionality aDir) + { + mDirectionality = aDir; + } + + // This needs to stay in sync with the list in GetVisibilityState. + // XXXbz visibilityState needs to be an IDL enum. + enum VisibilityState { + eHidden = 0, + eVisible, + eVisibilityStateCount + }; + + nsCString mReferrer; + nsString mLastModified; + nsCOMPtr mDocumentURI; nsCOMPtr mOriginalURI; nsCOMPtr mDocumentBaseURI; @@ -1845,6 +2043,12 @@ protected: // Compatibility mode nsCompatibility mCompatMode; + // Our readyState + ReadyState mReadyState; + + // Our visibility state + VisibilityState mVisibilityState; + // True if BIDI is enabled. bool mBidiEnabled; // True if a MathML element has ever been owned by this document. @@ -1934,6 +2138,10 @@ protected: // True if DisallowBFCaching has been called on this document. bool mBFCacheDisallowed; + // If true, we have an input encoding. If this is false, then the + // document was created entirely in memory + bool mHaveInputEncoding; + // The document's script global object, the object from which the // document can get its script context and scope. This is the // *inner* window object. diff --git a/content/base/src/Makefile.in b/content/base/src/Makefile.in index c9684b58c9fb..20529b61e6a9 100644 --- a/content/base/src/Makefile.in +++ b/content/base/src/Makefile.in @@ -185,6 +185,7 @@ LOCAL_INCLUDES += \ -I$(topsrcdir)/caps/include \ -I$(topsrcdir)/content/events/src \ -I$(topsrcdir)/content/html/content/src \ + -I$(topsrcdir)/content/html/document/src \ -I$(topsrcdir)/content/xbl/src \ -I$(topsrcdir)/content/xml/content/src \ -I$(topsrcdir)/content/xml/document/src \ diff --git a/content/base/src/nsContentUtils.cpp b/content/base/src/nsContentUtils.cpp index 1c3e6e0cd8e0..d1294fb47855 100644 --- a/content/base/src/nsContentUtils.cpp +++ b/content/base/src/nsContentUtils.cpp @@ -1506,7 +1506,7 @@ nsContentUtils::Shutdown() */ // static nsresult -nsContentUtils::CheckSameOrigin(nsINode *aTrustedNode, +nsContentUtils::CheckSameOrigin(const nsINode *aTrustedNode, nsIDOMNode *aUnTrustedNode) { MOZ_ASSERT(aTrustedNode); @@ -1518,8 +1518,8 @@ nsContentUtils::CheckSameOrigin(nsINode *aTrustedNode, } nsresult -nsContentUtils::CheckSameOrigin(nsINode* aTrustedNode, - nsINode* unTrustedNode) +nsContentUtils::CheckSameOrigin(const nsINode* aTrustedNode, + const nsINode* unTrustedNode) { MOZ_ASSERT(aTrustedNode); MOZ_ASSERT(unTrustedNode); diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp index 23bd89c0e7ac..79eee58d9ef8 100644 --- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -96,6 +96,8 @@ #include "nsIDOMUserDataHandler.h" #include "nsIDOMXPathEvaluator.h" +#include "nsIDOMXPathExpression.h" +#include "nsIDOMXPathNSResolver.h" #include "nsIXPathEvaluatorInternal.h" #include "nsIParserService.h" #include "nsContentCreatorFunctions.h" @@ -103,6 +105,7 @@ #include "nsIScriptContext.h" #include "nsBindingManager.h" #include "nsIDOMHTMLDocument.h" +#include "nsHTMLDocument.h" #include "nsIDOMHTMLFormElement.h" #include "nsIRequest.h" #include "nsILink.h" @@ -165,6 +168,9 @@ #include "nsHTMLStyleSheet.h" #include "nsHTMLCSSStyleSheet.h" #include "mozilla/dom/DOMImplementation.h" +#include "mozilla/dom/Comment.h" +#include "nsTextNode.h" +#include "nsXMLProcessingInstruction.h" #include "mozilla/dom/Link.h" #include "nsXULAppAPI.h" #include "nsDOMTouchEvent.h" @@ -176,6 +182,8 @@ #include "nsWrapperCacheInlines.h" #include "nsSandboxFlags.h" #include "nsIAppsService.h" +#include "mozilla/dom/BindingUtils.h" +#include "mozilla/dom/DocumentFragment.h" using namespace mozilla; using namespace mozilla::dom; @@ -1290,6 +1298,7 @@ nsIDocument::nsIDocument() mCharacterSet(NS_LITERAL_CSTRING("ISO-8859-1")), mNodeInfoManager(nullptr), mCompatMode(eCompatibility_FullStandards), + mVisibilityState(eHidden), mIsInitialDocumentInWindow(false), mMayStartLayout(true), mVisible(true), @@ -1313,7 +1322,6 @@ nsIDocument::nsIDocument() nsDocument::nsDocument(const char* aContentType) : nsIDocument() , mAnimatingImages(true) - , mVisibilityState(eHidden) { SetContentTypeInternal(nsDependentCString(aContentType)); @@ -2478,6 +2486,13 @@ nsDocument::SetDocumentURI(nsIURI* aURI) NS_IMETHODIMP nsDocument::GetLastModified(nsAString& aLastModified) +{ + nsIDocument::GetLastModified(aLastModified); + return NS_OK; +} + +void +nsIDocument::GetLastModified(nsAString& aLastModified) const { if (!mLastModified.IsEmpty()) { aLastModified.Assign(mLastModified); @@ -2486,8 +2501,6 @@ nsDocument::GetLastModified(nsAString& aLastModified) // (or even the current time), fall back to what NS4.x returned. aLastModified.Assign(NS_LITERAL_STRING("01/01/1970 00:00:00")); } - - return NS_OK; } void @@ -2629,17 +2642,26 @@ nsDocument::GetAllowPlugins(bool * aAllowPlugins) NS_IMETHODIMP nsDocument::HasFocus(bool* aResult) { - *aResult = false; + ErrorResult rv; + *aResult = nsIDocument::HasFocus(rv); + return rv.ErrorCode(); +} +bool +nsIDocument::HasFocus(ErrorResult& rv) const +{ nsIFocusManager* fm = nsFocusManager::GetFocusManager(); - if (!fm) - return NS_ERROR_NOT_AVAILABLE; + if (!fm) { + rv.Throw(NS_ERROR_NOT_AVAILABLE); + return false; + } // Is there a focused DOMWindow? nsCOMPtr focusedWindow; fm->GetFocusedWindow(getter_AddRefs(focusedWindow)); - if (!focusedWindow) - return NS_OK; + if (!focusedWindow) { + return false; + } // Are we an ancestor of the focused DOMWindow? nsCOMPtr domDocument; @@ -2650,26 +2672,37 @@ nsDocument::HasFocus(bool* aResult) currentDoc = currentDoc->GetParentDocument()) { if (currentDoc == this) { // Yes, we are an ancestor - *aResult = true; - return NS_OK; + return true; } } - return NS_OK; + return false; } NS_IMETHODIMP nsDocument::GetReferrer(nsAString& aReferrer) { - CopyUTF8toUTF16(mReferrer, aReferrer); + nsIDocument::GetReferrer(aReferrer); return NS_OK; } +void +nsIDocument::GetReferrer(nsAString& aReferrer) const +{ + CopyUTF8toUTF16(mReferrer, aReferrer); +} + NS_IMETHODIMP nsDocument::GetActiveElement(nsIDOMElement **aElement) { - *aElement = nullptr; + nsCOMPtr el(do_QueryInterface(nsIDocument::GetActiveElement())); + el.forget(aElement); + return NS_OK; +} +Element* +nsIDocument::GetActiveElement() +{ // Get the focused element. nsCOMPtr window = GetWindow(); if (window) { @@ -2683,8 +2716,7 @@ nsDocument::GetActiveElement(nsIDOMElement **aElement) focusedContent = focusedContent->FindFirstNonChromeOnlyAccessContent(); } if (focusedContent) { - CallQueryInterface(focusedContent, aElement); - return NS_OK; + return focusedContent->AsElement(); } } } @@ -2692,51 +2724,54 @@ nsDocument::GetActiveElement(nsIDOMElement **aElement) // No focused element anywhere in this document. Try to get the BODY. nsCOMPtr htmlDoc = do_QueryObject(this); if (htmlDoc) { - nsCOMPtr bodyElement; - htmlDoc->GetBody(getter_AddRefs(bodyElement)); - if (bodyElement) { - *aElement = bodyElement; - NS_ADDREF(*aElement); - } // Because of IE compatibility, return null when html document doesn't have // a body. - return NS_OK; + return static_cast(htmlDoc.get())->GetBody(); } // If we couldn't get a BODY, return the root element. - return GetDocumentElement(aElement); + return GetDocumentElement(); } NS_IMETHODIMP nsDocument::GetCurrentScript(nsIDOMElement **aElement) { - nsIScriptElement* script = mScriptLoader->GetCurrentScript(); - if (script) { - return CallQueryInterface(script, aElement); - } - - *aElement = nullptr; - + nsCOMPtr el(do_QueryInterface(nsIDocument::GetCurrentScript())); + el.forget(aElement); return NS_OK; } +Element* +nsIDocument::GetCurrentScript() +{ + nsCOMPtr el(do_QueryInterface(ScriptLoader()->GetCurrentScript())); + return el; +} + NS_IMETHODIMP nsDocument::ElementFromPoint(float aX, float aY, nsIDOMElement** aReturn) { - return ElementFromPointHelper(aX, aY, false, true, aReturn); + Element* el = nsIDocument::ElementFromPoint(aX, aY); + nsCOMPtr retval = do_QueryInterface(el); + retval.forget(aReturn); + return NS_OK; } -nsresult +Element* +nsIDocument::ElementFromPoint(float aX, float aY) +{ + return ElementFromPointHelper(aX, aY, false, true); +} + +Element* nsDocument::ElementFromPointHelper(float aX, float aY, bool aIgnoreRootScrollFrame, - bool aFlushLayout, - nsIDOMElement** aReturn) + bool aFlushLayout) { - NS_ENSURE_ARG_POINTER(aReturn); - *aReturn = nullptr; // As per the the spec, we return null if either coord is negative - if (!aIgnoreRootScrollFrame && (aX < 0 || aY < 0)) - return NS_OK; + if (!aIgnoreRootScrollFrame && (aX < 0 || aY < 0)) { + return nullptr; + } nscoord x = nsPresContext::CSSPixelsToAppUnits(aX); nscoord y = nsPresContext::CSSPixelsToAppUnits(aY); @@ -2748,26 +2783,27 @@ nsDocument::ElementFromPointHelper(float aX, float aY, FlushPendingNotifications(Flush_Layout); nsIPresShell *ps = GetShell(); - NS_ENSURE_STATE(ps); + if (!ps) { + return nullptr; + } nsIFrame *rootFrame = ps->GetRootFrame(); // XUL docs, unlike HTML, have no frame tree until everything's done loading - if (!rootFrame) - return NS_OK; // return null to premature XUL callers as a reminder to wait + if (!rootFrame) { + return nullptr; // return null to premature XUL callers as a reminder to wait + } nsIFrame *ptFrame = nsLayoutUtils::GetFrameForPoint(rootFrame, pt, true, aIgnoreRootScrollFrame); - if (!ptFrame) - return NS_OK; + if (!ptFrame) { + return nullptr; + } nsIContent* elem = GetContentInThisDocument(ptFrame); if (elem && !elem->IsElement()) { elem = elem->GetParent(); } - if (elem) { - CallQueryInterface(elem, aReturn); - } - return NS_OK; + return elem ? elem->AsElement() : nullptr; } nsresult @@ -2838,12 +2874,25 @@ NS_IMETHODIMP nsDocument::GetElementsByClassName(const nsAString& aClasses, nsIDOMNodeList** aReturn) { - *aReturn = nsContentUtils::GetElementsByClassName(this, aClasses).get(); + *aReturn = nsIDocument::GetElementsByClassName(aClasses).get(); return NS_OK; } +already_AddRefed +nsIDocument::GetElementsByClassName(const nsAString& aClasses) +{ + return nsContentUtils::GetElementsByClassName(this, aClasses); +} + NS_IMETHODIMP nsDocument::ReleaseCapture() +{ + nsIDocument::ReleaseCapture(); + return NS_OK; +} + +void +nsIDocument::ReleaseCapture() const { // only release the capture if the caller can access it. This prevents a // page from stopping a scrollbar grab for example. @@ -2851,7 +2900,6 @@ nsDocument::ReleaseCapture() if (node && nsContentUtils::CanCallerAccess(node)) { nsIPresShell::SetCapturingContent(nullptr, 0); } - return NS_OK; } nsresult @@ -3727,7 +3775,7 @@ nsDocument::GetScriptGlobalObject() const } nsIScriptGlobalObject* -nsDocument::GetScopeObject() +nsDocument::GetScopeObject() const { nsCOMPtr scope(do_QueryReferent(mScopeObject)); return scope; @@ -4097,23 +4145,30 @@ nsDocument::RemoveIDTargetObserver(nsIAtom* aID, IDTargetObserver aObserver, NS_IMETHODIMP nsDocument::MozSetImageElement(const nsAString& aImageElementId, nsIDOMElement* aImageElement) +{ + nsCOMPtr el = do_QueryInterface(aImageElement); + MozSetImageElement(aImageElementId, el); + return NS_OK; +} + +void +nsDocument::MozSetImageElement(const nsAString& aImageElementId, + Element* aElement) { if (aImageElementId.IsEmpty()) - return NS_OK; + return; // Hold a script blocker while calling SetImageElement since that can call // out to id-observers nsAutoScriptBlocker scriptBlocker; - nsCOMPtr content = do_QueryInterface(aImageElement); nsIdentifierMapEntry *entry = mIdentifierMap.PutEntry(aImageElementId); if (entry) { - entry->SetImageElement(content ? content->AsElement() : nullptr); + entry->SetImageElement(aElement); if (entry->IsEmpty()) { mIdentifierMap.RemoveEntry(aImageElementId); } } - return NS_OK; } Element* @@ -4293,45 +4348,62 @@ nsDocument::StyleRuleRemoved(nsIStyleSheet* aStyleSheet, // // nsIDOMDocument interface // -nsIContent* -nsIDocument::GetDocumentType() const +nsDOMDocumentType* +nsIDocument::GetDoctype() const { for (nsIContent* child = GetFirstChild(); child; child = child->GetNextSibling()) { if (child->NodeType() == nsIDOMNode::DOCUMENT_TYPE_NODE) { - return child; + return static_cast(child); } } - return NULL; + return nullptr; } NS_IMETHODIMP nsDocument::GetDoctype(nsIDOMDocumentType** aDoctype) { MOZ_ASSERT(aDoctype); - nsCOMPtr doctype = do_QueryInterface(GetDocumentType()); + nsCOMPtr doctype = nsIDocument::GetDoctype(); doctype.forget(aDoctype); return NS_OK; } NS_IMETHODIMP nsDocument::GetImplementation(nsIDOMDOMImplementation** aImplementation) +{ + ErrorResult rv; + *aImplementation = GetImplementation(rv); + if (rv.Failed()) { + MOZ_ASSERT(!*aImplementation); + return rv.ErrorCode(); + } + NS_ADDREF(*aImplementation); + return NS_OK; +} + +DOMImplementation* +nsDocument::GetImplementation(ErrorResult& rv) { if (!mDOMImplementation) { nsCOMPtr uri; NS_NewURI(getter_AddRefs(uri), "about:blank"); - NS_ENSURE_TRUE(uri, NS_ERROR_OUT_OF_MEMORY); + if (!uri) { + rv.Throw(NS_ERROR_OUT_OF_MEMORY); + return nullptr; + } bool hasHadScriptObject = true; nsIScriptGlobalObject* scriptObject = GetScriptHandlingObject(hasHadScriptObject); - NS_ENSURE_STATE(scriptObject || !hasHadScriptObject); + if (!scriptObject && hasHadScriptObject) { + rv.Throw(NS_ERROR_UNEXPECTED); + return nullptr; + } mDOMImplementation = new DOMImplementation(this, scriptObject, uri, uri); } - NS_ADDREF(*aImplementation = mDOMImplementation); - - return NS_OK; + return mDOMImplementation; } NS_IMETHODIMP @@ -4354,10 +4426,10 @@ nsDocument::CreateElement(const nsAString& aTagName, nsIDOMElement** aReturn) { *aReturn = nullptr; - nsCOMPtr content; - nsresult rv = CreateElement(aTagName, getter_AddRefs(content)); - NS_ENSURE_SUCCESS(rv, rv); - return CallQueryInterface(content, aReturn); + ErrorResult rv; + nsCOMPtr element = nsIDocument::CreateElement(aTagName, rv); + NS_ENSURE_FALSE(rv.Failed(), rv.ErrorCode()); + return CallQueryInterface(element, aReturn); } bool IsLowercaseASCII(const nsAString& aValue) @@ -4372,14 +4444,13 @@ bool IsLowercaseASCII(const nsAString& aValue) return true; } -nsresult -nsDocument::CreateElement(const nsAString& aTagName, - nsIContent** aReturn) +already_AddRefed +nsIDocument::CreateElement(const nsAString& aTagName, ErrorResult& rv) { - *aReturn = nullptr; - - nsresult rv = nsContentUtils::CheckQName(aTagName, false); - NS_ENSURE_SUCCESS(rv, rv); + rv = nsContentUtils::CheckQName(aTagName, false); + if (rv.Failed()) { + return nullptr; + } bool needsLowercase = IsHTML() && !IsLowercaseASCII(aTagName); nsAutoString lcTagName; @@ -4387,9 +4458,13 @@ nsDocument::CreateElement(const nsAString& aTagName, nsContentUtils::ASCIIToLower(aTagName, lcTagName); } + nsCOMPtr content; rv = CreateElem(needsLowercase ? lcTagName : aTagName, - nullptr, mDefaultElementType, aReturn); - return rv; + nullptr, mDefaultElementType, getter_AddRefs(content)); + if (rv.Failed()) { + return nullptr; + } + return content.forget().get()->AsElement(); } NS_IMETHODIMP @@ -4398,72 +4473,109 @@ nsDocument::CreateElementNS(const nsAString& aNamespaceURI, nsIDOMElement** aReturn) { *aReturn = nullptr; - nsCOMPtr content; - nsresult rv = CreateElementNS(aNamespaceURI, aQualifiedName, - getter_AddRefs(content)); - NS_ENSURE_SUCCESS(rv, rv); - return CallQueryInterface(content, aReturn); + ErrorResult rv; + nsCOMPtr element = + nsIDocument::CreateElementNS(aNamespaceURI, aQualifiedName, rv); + NS_ENSURE_FALSE(rv.Failed(), rv.ErrorCode()); + return CallQueryInterface(element, aReturn); } -nsresult -nsDocument::CreateElementNS(const nsAString& aNamespaceURI, - const nsAString& aQualifiedName, - nsIContent** aReturn) +already_AddRefed +nsIDocument::CreateElementNS(const nsAString& aNamespaceURI, + const nsAString& aQualifiedName, + ErrorResult& rv) { nsCOMPtr nodeInfo; - nsresult rv = nsContentUtils::GetNodeInfoFromQName(aNamespaceURI, - aQualifiedName, - mNodeInfoManager, - nsIDOMNode::ELEMENT_NODE, - getter_AddRefs(nodeInfo)); - NS_ENSURE_SUCCESS(rv, rv); + rv = nsContentUtils::GetNodeInfoFromQName(aNamespaceURI, + aQualifiedName, + mNodeInfoManager, + nsIDOMNode::ELEMENT_NODE, + getter_AddRefs(nodeInfo)); + if (rv.Failed()) { + return nullptr; + } - return NS_NewElement(aReturn, nodeInfo.forget(), NOT_FROM_PARSER); + nsCOMPtr content; + rv = NS_NewElement(getter_AddRefs(content), nodeInfo.forget(), + NOT_FROM_PARSER); + if (rv.Failed()) { + return nullptr; + } + return content.forget().get()->AsElement(); } NS_IMETHODIMP nsDocument::CreateTextNode(const nsAString& aData, nsIDOMText** aReturn) { - *aReturn = nullptr; - nsCOMPtr content; - nsresult rv = CreateTextNode(aData, getter_AddRefs(content)); - NS_ENSURE_SUCCESS(rv, rv); - return CallQueryInterface(content, aReturn); + ErrorResult rv; + *aReturn = nsIDocument::CreateTextNode(aData, rv).get(); + return rv.ErrorCode(); } nsresult nsDocument::CreateTextNode(const nsAString& aData, nsIContent** aReturn) { - nsresult rv = NS_NewTextNode(aReturn, mNodeInfoManager); - if (NS_SUCCEEDED(rv)) { - // Don't notify; this node is still being created. - (*aReturn)->SetText(aData, false); + ErrorResult rv; + *aReturn = nsIDocument::CreateTextNode(aData, rv).get(); + return rv.ErrorCode(); +} + +already_AddRefed +nsIDocument::CreateTextNode(const nsAString& aData, ErrorResult& rv) const +{ + nsCOMPtr content; + nsresult res = NS_NewTextNode(getter_AddRefs(content), mNodeInfoManager); + if (NS_FAILED(res)) { + rv.Throw(res); + return nullptr; } - return rv; + // Don't notify; this node is still being created. + content->SetText(aData, false); + return static_cast(content.forget().get()); } NS_IMETHODIMP nsDocument::CreateDocumentFragment(nsIDOMDocumentFragment** aReturn) { - return NS_NewDocumentFragment(aReturn, mNodeInfoManager); + ErrorResult rv; + *aReturn = nsIDocument::CreateDocumentFragment(rv).get(); + return rv.ErrorCode(); +} + +already_AddRefed +nsIDocument::CreateDocumentFragment(ErrorResult& rv) const +{ + nsCOMPtr frag; + nsresult res = NS_NewDocumentFragment(getter_AddRefs(frag), mNodeInfoManager); + if (NS_FAILED(res)) { + rv.Throw(res); + return nullptr; + } + return static_cast(frag.forget().get()); } NS_IMETHODIMP nsDocument::CreateComment(const nsAString& aData, nsIDOMComment** aReturn) { - *aReturn = nullptr; + ErrorResult rv; + *aReturn = nsIDocument::CreateComment(aData, rv).get(); + return rv.ErrorCode(); +} +// Unfortunately, bareword "Comment" is ambiguous with some Mac system headers. +already_AddRefed +nsIDocument::CreateComment(const nsAString& aData, ErrorResult& rv) const +{ nsCOMPtr comment; - nsresult rv = NS_NewCommentNode(getter_AddRefs(comment), mNodeInfoManager); - - if (NS_SUCCEEDED(rv)) { - // Don't notify; this node is still being created. - comment->SetText(aData, false); - - rv = CallQueryInterface(comment, aReturn); + nsresult res = NS_NewCommentNode(getter_AddRefs(comment), mNodeInfoManager); + if (NS_FAILED(res)) { + rv.Throw(res); + return nullptr; } - return rv; + // Don't notify; this node is still being created. + comment->SetText(aData, false); + return static_cast(comment.forget().get()); } NS_IMETHODIMP @@ -4471,28 +4583,38 @@ nsDocument::CreateCDATASection(const nsAString& aData, nsIDOMCDATASection** aReturn) { NS_ENSURE_ARG_POINTER(aReturn); - *aReturn = nullptr; + ErrorResult rv; + *aReturn = nsIDocument::CreateCDATASection(aData, rv).get(); + return rv.ErrorCode(); +} +already_AddRefed +nsIDocument::CreateCDATASection(const nsAString& aData, + ErrorResult& rv) +{ if (IsHTML()) { - return NS_ERROR_DOM_NOT_SUPPORTED_ERR; + rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); + return nullptr; } if (FindInReadable(NS_LITERAL_STRING("]]>"), aData)) { - return NS_ERROR_DOM_INVALID_CHARACTER_ERR; + rv.Throw(NS_ERROR_DOM_INVALID_CHARACTER_ERR); + return nullptr; } nsCOMPtr content; - nsresult rv = NS_NewXMLCDATASection(getter_AddRefs(content), - mNodeInfoManager); - - if (NS_SUCCEEDED(rv)) { - // Don't notify; this node is still being created. - content->SetText(aData, false); - - rv = CallQueryInterface(content, aReturn); + nsresult res = NS_NewXMLCDATASection(getter_AddRefs(content), + mNodeInfoManager); + if (NS_FAILED(res)) { + rv.Throw(res); + return nullptr; } - return rv; + // Don't notify; this node is still being created. + content->SetText(aData, false); + + nsCOMPtr section = do_QueryInterface(content); + return section.forget(); } NS_IMETHODIMP @@ -4500,49 +4622,75 @@ nsDocument::CreateProcessingInstruction(const nsAString& aTarget, const nsAString& aData, nsIDOMProcessingInstruction** aReturn) { - *aReturn = nullptr; + ErrorResult rv; + *aReturn = nsIDocument::CreateProcessingInstruction(aTarget, aData, rv).get(); + return rv.ErrorCode(); +} - nsresult rv = nsContentUtils::CheckQName(aTarget, false); - NS_ENSURE_SUCCESS(rv, rv); +already_AddRefed +nsIDocument::CreateProcessingInstruction(const nsAString& aTarget, + const nsAString& aData, + mozilla::ErrorResult& rv) const +{ + nsresult res = nsContentUtils::CheckQName(aTarget, false); + if (NS_FAILED(res)) { + rv.Throw(res); + return nullptr; + } if (FindInReadable(NS_LITERAL_STRING("?>"), aData)) { - return NS_ERROR_DOM_INVALID_CHARACTER_ERR; + rv.Throw(NS_ERROR_DOM_INVALID_CHARACTER_ERR); + return nullptr; } nsCOMPtr content; - rv = NS_NewXMLProcessingInstruction(getter_AddRefs(content), - mNodeInfoManager, aTarget, aData); - if (NS_FAILED(rv)) { - return rv; + res = NS_NewXMLProcessingInstruction(getter_AddRefs(content), + mNodeInfoManager, aTarget, aData); + if (NS_FAILED(res)) { + rv.Throw(res); + return nullptr; } - return CallQueryInterface(content, aReturn); + return static_cast(content.forget().get()); } NS_IMETHODIMP nsDocument::CreateAttribute(const nsAString& aName, nsIDOMAttr** aReturn) { - *aReturn = nullptr; + ErrorResult rv; + *aReturn = nsIDocument::CreateAttribute(aName, rv).get(); + return rv.ErrorCode(); +} +already_AddRefed +nsIDocument::CreateAttribute(const nsAString& aName, ErrorResult& rv) +{ WarnOnceAbout(eCreateAttribute); - NS_ENSURE_TRUE(mNodeInfoManager, NS_ERROR_NOT_INITIALIZED); + if (!mNodeInfoManager) { + rv.Throw(NS_ERROR_NOT_INITIALIZED); + return nullptr; + } - nsresult rv = nsContentUtils::CheckQName(aName, false); - NS_ENSURE_SUCCESS(rv, rv); + nsresult res = nsContentUtils::CheckQName(aName, false); + if (NS_FAILED(res)) { + rv.Throw(res); + return nullptr; + } nsCOMPtr nodeInfo; - rv = mNodeInfoManager->GetNodeInfo(aName, nullptr, kNameSpaceID_None, - nsIDOMNode::ATTRIBUTE_NODE, - getter_AddRefs(nodeInfo)); - NS_ENSURE_SUCCESS(rv, rv); + res = mNodeInfoManager->GetNodeInfo(aName, nullptr, kNameSpaceID_None, + nsIDOMNode::ATTRIBUTE_NODE, + getter_AddRefs(nodeInfo)); + if (NS_FAILED(res)) { + rv.Throw(res); + return nullptr; + } - nsAutoString value; nsCOMPtr attribute = - new nsDOMAttribute(nullptr, nodeInfo.forget(), value, false); - attribute.forget(aReturn); - return NS_OK; + new nsDOMAttribute(nullptr, nodeInfo.forget(), EmptyString(), false); + return attribute.forget(); } NS_IMETHODIMP @@ -4550,24 +4698,32 @@ nsDocument::CreateAttributeNS(const nsAString & aNamespaceURI, const nsAString & aQualifiedName, nsIDOMAttr **aResult) { - NS_ENSURE_ARG_POINTER(aResult); - *aResult = nullptr; + ErrorResult rv; + *aResult = + nsIDocument::CreateAttributeNS(aNamespaceURI, aQualifiedName, rv).get(); + return rv.ErrorCode(); +} +already_AddRefed +nsIDocument::CreateAttributeNS(const nsAString& aNamespaceURI, + const nsAString& aQualifiedName, + mozilla::ErrorResult& rv) +{ WarnOnceAbout(eCreateAttributeNS); nsCOMPtr nodeInfo; - nsresult rv = nsContentUtils::GetNodeInfoFromQName(aNamespaceURI, - aQualifiedName, - mNodeInfoManager, - nsIDOMNode::ATTRIBUTE_NODE, - getter_AddRefs(nodeInfo)); - NS_ENSURE_SUCCESS(rv, rv); + rv = nsContentUtils::GetNodeInfoFromQName(aNamespaceURI, + aQualifiedName, + mNodeInfoManager, + nsIDOMNode::ATTRIBUTE_NODE, + getter_AddRefs(nodeInfo)); + if (rv.Failed()) { + return nullptr; + } - nsAutoString value; nsCOMPtr attribute = - new nsDOMAttribute(nullptr, nodeInfo.forget(), value, true); - attribute.forget(aResult); - return NS_OK; + new nsDOMAttribute(nullptr, nodeInfo.forget(), EmptyString(), true); + return attribute.forget(); } NS_IMETHODIMP @@ -4583,8 +4739,8 @@ nsDocument::GetElementsByTagName(const nsAString& aTagname, } already_AddRefed -nsDocument::GetElementsByTagNameNS(const nsAString& aNamespaceURI, - const nsAString& aLocalName) +nsIDocument::GetElementsByTagNameNS(const nsAString& aNamespaceURI, + const nsAString& aLocalName) { int32_t nameSpaceId = kNameSpaceID_Wildcard; @@ -4605,8 +4761,8 @@ nsDocument::GetElementsByTagNameNS(const nsAString& aNamespaceURI, const nsAString& aLocalName, nsIDOMNodeList** aReturn) { - nsRefPtr list = GetElementsByTagNameNS(aNamespaceURI, - aLocalName); + nsRefPtr list = + nsIDocument::GetElementsByTagNameNS(aNamespaceURI, aLocalName); NS_ENSURE_TRUE(list, NS_ERROR_OUT_OF_MEMORY); // transfer ref to aReturn @@ -4641,21 +4797,28 @@ nsDocument::Load(const nsAString& aUrl, bool *aReturn) NS_IMETHODIMP nsDocument::GetStyleSheets(nsIDOMStyleSheetList** aStyleSheets) { - if (!mDOMStyleSheets) { - mDOMStyleSheets = new nsDOMStyleSheetList(this); - if (!mDOMStyleSheets) { - return NS_ERROR_OUT_OF_MEMORY; - } - } - - *aStyleSheets = mDOMStyleSheets; - NS_ADDREF(*aStyleSheets); - + NS_ADDREF(*aStyleSheets = StyleSheets()); return NS_OK; } +nsIDOMStyleSheetList* +nsDocument::StyleSheets() +{ + if (!mDOMStyleSheets) { + mDOMStyleSheets = new nsDOMStyleSheetList(this); + } + return mDOMStyleSheets; +} + NS_IMETHODIMP -nsDocument::GetSelectedStyleSheetSet(nsAString& aSheetSet) +nsDocument::GetMozSelectedStyleSheetSet(nsAString& aSheetSet) +{ + nsIDocument::GetSelectedStyleSheetSet(aSheetSet); + return NS_OK; +} + +void +nsIDocument::GetSelectedStyleSheetSet(nsAString& aSheetSet) { aSheetSet.Truncate(); @@ -4679,59 +4842,89 @@ nsDocument::GetSelectedStyleSheetSet(nsAString& aSheetSet) if (aSheetSet.IsEmpty()) { aSheetSet = title; - } else if (!title.IsEmpty() && !aSheetSet.Equals(title)) { + return; + } + + if (!title.IsEmpty() && !aSheetSet.Equals(title)) { // Sheets from multiple sets enabled; return null string, per spec. SetDOMStringToNull(aSheetSet); - break; + return; } } - - return NS_OK; } NS_IMETHODIMP +nsDocument::SetMozSelectedStyleSheetSet(const nsAString& aSheetSet) +{ + SetSelectedStyleSheetSet(aSheetSet); + return NS_OK; +} + +void nsDocument::SetSelectedStyleSheetSet(const nsAString& aSheetSet) { if (DOMStringIsNull(aSheetSet)) { - return NS_OK; + return; } // Must update mLastStyleSheetSet before doing anything else with stylesheets // or CSSLoaders. mLastStyleSheetSet = aSheetSet; EnableStyleSheetsForSetInternal(aSheetSet, true); - return NS_OK; } NS_IMETHODIMP nsDocument::GetLastStyleSheetSet(nsAString& aSheetSet) { - aSheetSet = mLastStyleSheetSet; + nsString sheetSet; + GetLastStyleSheetSet(sheetSet); + aSheetSet = sheetSet; return NS_OK; } +void +nsDocument::GetLastStyleSheetSet(nsString& aSheetSet) +{ + aSheetSet = mLastStyleSheetSet; +} + NS_IMETHODIMP nsDocument::GetPreferredStyleSheetSet(nsAString& aSheetSet) { - GetHeaderData(nsGkAtoms::headerDefaultStyle, aSheetSet); + nsIDocument::GetPreferredStyleSheetSet(aSheetSet); return NS_OK; } +void +nsIDocument::GetPreferredStyleSheetSet(nsAString& aSheetSet) +{ + GetHeaderData(nsGkAtoms::headerDefaultStyle, aSheetSet); +} + NS_IMETHODIMP nsDocument::GetStyleSheetSets(nsIDOMDOMStringList** aList) { - if (!mStyleSheetSetList) { - mStyleSheetSetList = new nsDOMStyleSheetSetList(this); - if (!mStyleSheetSetList) { - return NS_ERROR_OUT_OF_MEMORY; - } - } - - NS_ADDREF(*aList = mStyleSheetSetList); + NS_ADDREF(*aList = StyleSheetSets()); return NS_OK; } +nsIDOMDOMStringList* +nsDocument::StyleSheetSets() +{ + if (!mStyleSheetSetList) { + mStyleSheetSetList = new nsDOMStyleSheetSetList(this); + } + return mStyleSheetSetList; +} + NS_IMETHODIMP +nsDocument::MozEnableStyleSheetsForSet(const nsAString& aSheetSet) +{ + EnableStyleSheetsForSet(aSheetSet); + return NS_OK; +} + +void nsDocument::EnableStyleSheetsForSet(const nsAString& aSheetSet) { // Per spec, passing in null is a no-op. @@ -4742,8 +4935,6 @@ nsDocument::EnableStyleSheetsForSet(const nsAString& aSheetSet) // change either of those. EnableStyleSheetsForSetInternal(aSheetSet, false); } - - return NS_OK; } void @@ -4770,10 +4961,16 @@ nsDocument::EnableStyleSheetsForSetInternal(const nsAString& aSheetSet, NS_IMETHODIMP nsDocument::GetCharacterSet(nsAString& aCharacterSet) { - CopyASCIItoUTF16(GetDocumentCharacterSet(), aCharacterSet); + nsIDocument::GetCharacterSet(aCharacterSet); return NS_OK; } +void +nsIDocument::GetCharacterSet(nsAString& aCharacterSet) const +{ + CopyASCIItoUTF16(GetDocumentCharacterSet(), aCharacterSet); +} + NS_IMETHODIMP nsDocument::ImportNode(nsIDOMNode* aImportedNode, bool aDeep, @@ -4789,8 +4986,24 @@ nsDocument::ImportNode(nsIDOMNode* aImportedNode, nsCOMPtr imported = do_QueryInterface(aImportedNode); NS_ENSURE_TRUE(imported, NS_ERROR_UNEXPECTED); - nsresult rv = nsContentUtils::CheckSameOrigin(this, imported); - NS_ENSURE_SUCCESS(rv, rv); + ErrorResult rv; + nsCOMPtr result = nsIDocument::ImportNode(*imported, aDeep, rv); + if (rv.Failed()) { + return rv.ErrorCode(); + } + + NS_ADDREF(*aResult = result->AsDOMNode()); + return NS_OK; +} + +already_AddRefed +nsIDocument::ImportNode(nsINode& aNode, bool aDeep, ErrorResult& rv) const +{ + nsINode* imported = &aNode; + rv = nsContentUtils::CheckSameOrigin(this, imported); + if (rv.Failed()) { + return nullptr; + } switch (imported->NodeType()) { case nsIDOMNode::ATTRIBUTE_NODE: @@ -4806,42 +5019,53 @@ nsDocument::ImportNode(nsIDOMNode* aImportedNode, nsCOMArray nodesWithProperties; rv = nsNodeUtils::Clone(imported, aDeep, mNodeInfoManager, nodesWithProperties, getter_AddRefs(newNode)); - NS_ENSURE_SUCCESS(rv, rv); + if (rv.Failed()) { + return nullptr; + } nsIDocument *ownerDoc = imported->OwnerDoc(); rv = nsNodeUtils::CallUserDataHandlers(nodesWithProperties, ownerDoc, nsIDOMUserDataHandler::NODE_IMPORTED, true); - NS_ENSURE_SUCCESS(rv, rv); + if (rv.Failed()) { + return nullptr; + } - *aResult = newNode.forget().get()->AsDOMNode(); - return NS_OK; + return newNode.forget(); } default: { NS_WARNING("Don't know how to clone this nodetype for importNode."); - return NS_ERROR_DOM_NOT_SUPPORTED_ERR; + rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); } } + + return nullptr; } NS_IMETHODIMP nsDocument::AddBinding(nsIDOMElement* aContent, const nsAString& aURI) { - NS_ENSURE_ARG(aContent); + nsCOMPtr element = do_QueryInterface(aContent); + NS_ENSURE_ARG_POINTER(element); + ErrorResult rv; + nsIDocument::AddBinding(*element, aURI, rv); + return rv.ErrorCode(); +} - nsresult rv = nsContentUtils::CheckSameOrigin(this, aContent); - if (NS_FAILED(rv)) { - return rv; +void +nsIDocument::AddBinding(Element& aContent, const nsAString& aURI, ErrorResult& rv) +{ + rv = nsContentUtils::CheckSameOrigin(this, &aContent); + if (rv.Failed()) { + return; } - nsCOMPtr content(do_QueryInterface(aContent)); - nsCOMPtr uri; rv = NS_NewURI(getter_AddRefs(uri), aURI); - if (NS_FAILED(rv)) { - return rv; + if (rv.Failed()) { + return; } // Figure out the right principal to use @@ -4849,7 +5073,9 @@ nsDocument::AddBinding(nsIDOMElement* aContent, const nsAString& aURI) nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager(); if (secMan) { rv = secMan->GetSubjectPrincipal(getter_AddRefs(subject)); - NS_ENSURE_SUCCESS(rv, rv); + if (rv.Failed()) { + return; + } } if (!subject) { @@ -4858,44 +5084,64 @@ nsDocument::AddBinding(nsIDOMElement* aContent, const nsAString& aURI) subject = NodePrincipal(); } - return BindingManager()->AddLayeredBinding(content, uri, subject); + rv = BindingManager()->AddLayeredBinding(&aContent, uri, subject); } NS_IMETHODIMP nsDocument::RemoveBinding(nsIDOMElement* aContent, const nsAString& aURI) { - NS_ENSURE_ARG(aContent); + nsCOMPtr element = do_QueryInterface(aContent); + NS_ENSURE_ARG_POINTER(element); + ErrorResult rv; + nsIDocument::RemoveBinding(*element, aURI, rv); + return rv.ErrorCode(); +} - nsresult rv = nsContentUtils::CheckSameOrigin(this, aContent); - if (NS_FAILED(rv)) { - return rv; +void +nsIDocument::RemoveBinding(Element& aContent, const nsAString& aURI, + ErrorResult& rv) +{ + rv = nsContentUtils::CheckSameOrigin(this, &aContent); + if (rv.Failed()) { + return; } nsCOMPtr uri; rv = NS_NewURI(getter_AddRefs(uri), aURI); - if (NS_FAILED(rv)) { - return rv; + if (rv.Failed()) { + return; } - nsCOMPtr content(do_QueryInterface(aContent)); - return BindingManager()->RemoveLayeredBinding(content, uri); + rv = BindingManager()->RemoveLayeredBinding(&aContent, uri); } NS_IMETHODIMP nsDocument::LoadBindingDocument(const nsAString& aURI) +{ + ErrorResult rv; + nsIDocument::LoadBindingDocument(aURI, rv); + return rv.ErrorCode(); +} + +void +nsIDocument::LoadBindingDocument(const nsAString& aURI, ErrorResult& rv) { nsCOMPtr uri; - nsresult rv = NS_NewURI(getter_AddRefs(uri), aURI, - mCharacterSet.get(), - GetDocBaseURI()); - NS_ENSURE_SUCCESS(rv, rv); + rv = NS_NewURI(getter_AddRefs(uri), aURI, + mCharacterSet.get(), + GetDocBaseURI()); + if (rv.Failed()) { + return; + } // Figure out the right principal to use nsCOMPtr subject; nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager(); if (secMan) { rv = secMan->GetSubjectPrincipal(getter_AddRefs(subject)); - NS_ENSURE_SUCCESS(rv, rv); + if (rv.Failed()) { + return; + } } if (!subject) { @@ -4905,47 +5151,55 @@ nsDocument::LoadBindingDocument(const nsAString& aURI) } BindingManager()->LoadBindingDocument(this, uri, subject); - - return NS_OK; } NS_IMETHODIMP nsDocument::GetBindingParent(nsIDOMNode* aNode, nsIDOMElement** aResult) { - *aResult = nullptr; - nsCOMPtr content(do_QueryInterface(aNode)); - if (!content) - return NS_ERROR_FAILURE; + nsCOMPtr node = do_QueryInterface(aNode); + NS_ENSURE_ARG_POINTER(node); - nsCOMPtr elt(do_QueryInterface(content->GetBindingParent())); - NS_IF_ADDREF(*aResult = elt); + Element* bindingParent = nsIDocument::GetBindingParent(*node); + nsCOMPtr retval = do_QueryInterface(bindingParent); + retval.forget(aResult); return NS_OK; } -static nsIContent* +Element* +nsIDocument::GetBindingParent(nsINode& aNode) +{ + nsCOMPtr content(do_QueryInterface(&aNode)); + if (!content) + return nullptr; + + nsIContent* bindingParent = content->GetBindingParent(); + return bindingParent ? bindingParent->AsElement() : nullptr; +} + +static Element* GetElementByAttribute(nsIContent* aContent, nsIAtom* aAttrName, const nsAString& aAttrValue, bool aUniversalMatch) { if (aUniversalMatch ? aContent->HasAttr(kNameSpaceID_None, aAttrName) : aContent->AttrValueIs(kNameSpaceID_None, aAttrName, aAttrValue, eCaseMatters)) { - return aContent; + return aContent->AsElement(); } for (nsIContent* child = aContent->GetFirstChild(); child; child = child->GetNextSibling()) { - nsIContent* matchedContent = + Element* matchedElement = GetElementByAttribute(child, aAttrName, aAttrValue, aUniversalMatch); - if (matchedContent) - return matchedContent; + if (matchedElement) + return matchedElement; } return nullptr; } -nsIContent* +Element* nsDocument::GetAnonymousElementByAttribute(nsIContent* aElement, nsIAtom* aAttrName, const nsAString& aAttrValue) const @@ -4961,7 +5215,7 @@ nsDocument::GetAnonymousElementByAttribute(nsIContent* aElement, for (uint32_t i = 0; i < length; ++i) { nsIContent* current = nodeList->Item(i); - nsIContent* matchedElm = + Element* matchedElm = GetElementByAttribute(current, aAttrName, aAttrValue, universalMatch); if (matchedElm) return matchedElm; @@ -4976,14 +5230,25 @@ nsDocument::GetAnonymousElementByAttribute(nsIDOMElement* aElement, const nsAString& aAttrValue, nsIDOMElement** aResult) { - *aResult = nullptr; + nsCOMPtr element = do_QueryInterface(aElement); + NS_ENSURE_ARG_POINTER(element); + Element* anonEl = + nsIDocument::GetAnonymousElementByAttribute(*element, aAttrName, + aAttrValue); + nsCOMPtr retval = do_QueryInterface(anonEl); + retval.forget(aResult); + return NS_OK; +} + +Element* +nsIDocument::GetAnonymousElementByAttribute(Element& aElement, + const nsAString& aAttrName, + const nsAString& aAttrValue) +{ nsCOMPtr attribute = do_GetAtom(aAttrName); - nsCOMPtr content(do_QueryInterface(aElement)); - nsIContent* matchedContent = - GetAnonymousElementByAttribute(content, attribute, aAttrValue); - return matchedContent ? CallQueryInterface(matchedContent, aResult) : NS_OK; + return GetAnonymousElementByAttribute(&aElement, attribute, aAttrValue); } @@ -4997,15 +5262,31 @@ nsDocument::GetAnonymousNodes(nsIDOMElement* aElement, return BindingManager()->GetAnonymousNodesFor(content, aResult); } +nsINodeList* +nsIDocument::GetAnonymousNodes(Element& aElement) +{ + return BindingManager()->GetAnonymousNodesFor(&aElement); +} + NS_IMETHODIMP nsDocument::CreateRange(nsIDOMRange** aReturn) { - nsRefPtr range = new nsRange(); - nsresult rv = range->Set(this, 0, this, 0); - NS_ENSURE_SUCCESS(rv, rv); + ErrorResult rv; + *aReturn = nsIDocument::CreateRange(rv).get(); + return rv.ErrorCode(); +} - range.forget(aReturn); - return NS_OK; +already_AddRefed +nsIDocument::CreateRange(ErrorResult& rv) +{ + nsRefPtr range = new nsRange(); + nsresult res = range->Set(this, 0, this, 0); + if (NS_FAILED(res)) { + rv.Throw(res); + return nullptr; + } + + return range.forget(); } NS_IMETHODIMP @@ -5028,13 +5309,27 @@ nsDocument::CreateNodeIterator(nsIDOMNode *aRoot, nsCOMPtr root = do_QueryInterface(aRoot); NS_ENSURE_TRUE(root, NS_ERROR_UNEXPECTED); - nsresult rv = nsContentUtils::CheckSameOrigin(this, root); - NS_ENSURE_SUCCESS(rv, rv); + ErrorResult rv; + *_retval = nsIDocument::CreateNodeIterator(*root, aWhatToShow, aFilter, + rv).get(); + return rv.ErrorCode(); +} + +already_AddRefed +nsIDocument::CreateNodeIterator(nsINode& aRoot, uint32_t aWhatToShow, + nsIDOMNodeFilter* aFilter, + mozilla::ErrorResult& rv) const +{ + nsINode* root = &aRoot; + nsresult res = nsContentUtils::CheckSameOrigin(this, root); + if (NS_FAILED(res)) { + rv.Throw(res); + return nullptr; + } nsRefPtr iterator = new nsNodeIterator(root, aWhatToShow, aFilter); - iterator.forget(_retval); - return NS_OK; + return iterator.forget(); } NS_IMETHODIMP @@ -5050,25 +5345,29 @@ nsDocument::CreateTreeWalker(nsIDOMNode *aRoot, aWhatToShow = nsIDOMNodeFilter::SHOW_ALL; } - if (!aRoot) - return NS_ERROR_DOM_NOT_SUPPORTED_ERR; - - nsresult rv = nsContentUtils::CheckSameOrigin(this, aRoot); - NS_ENSURE_SUCCESS(rv, rv); - - NS_ENSURE_ARG_POINTER(_retval); - nsCOMPtr root = do_QueryInterface(aRoot); NS_ENSURE_TRUE(root, NS_ERROR_DOM_NOT_SUPPORTED_ERR); - nsTreeWalker* walker = new nsTreeWalker(root, - aWhatToShow, - aFilter); - NS_ENSURE_TRUE(walker, NS_ERROR_OUT_OF_MEMORY); + ErrorResult rv; + *_retval = nsIDocument::CreateTreeWalker(*root, aWhatToShow, aFilter, + rv).get(); + return rv.ErrorCode(); +} - NS_ADDREF(*_retval = walker); +already_AddRefed +nsIDocument::CreateTreeWalker(nsINode& aRoot, uint32_t aWhatToShow, + nsIDOMNodeFilter* aFilter, + mozilla::ErrorResult& rv) const +{ + nsINode* root = &aRoot; + nsresult res = nsContentUtils::CheckSameOrigin(this, root); + if (NS_FAILED(res)) { + rv.Throw(res); + return nullptr; + } - return NS_OK; + nsRefPtr walker = new nsTreeWalker(root, aWhatToShow, aFilter); + return walker.forget(); } @@ -5084,16 +5383,22 @@ nsDocument::GetDefaultView(nsIDOMWindow** aDefaultView) NS_IMETHODIMP nsDocument::GetLocation(nsIDOMLocation **_retval) { - NS_ENSURE_ARG_POINTER(_retval); - *_retval = nullptr; + *_retval = nsIDocument::GetLocation().get(); + return NS_OK; +} +already_AddRefed +nsIDocument::GetLocation() const +{ nsCOMPtr w = do_QueryInterface(mScriptGlobalObject); if (!w) { - return NS_OK; + return nullptr; } - return w->GetLocation(_retval); + nsCOMPtr loc; + w->GetLocation(getter_AddRefs(loc)); + return loc.forget(); } Element* @@ -5151,12 +5456,21 @@ nsDocument::GetTitleFromElement(uint32_t aNamespace, nsAString& aTitle) NS_IMETHODIMP nsDocument::GetTitle(nsAString& aTitle) +{ + nsString title; + GetTitle(title); + aTitle = title; + return NS_OK; +} + +void +nsDocument::GetTitle(nsString& aTitle) { aTitle.Truncate(); nsIContent *rootElement = GetRootElement(); if (!rootElement) - return NS_OK; + return; nsAutoString tmp; @@ -5178,7 +5492,6 @@ nsDocument::GetTitle(nsAString& aTitle) tmp.CompressWhitespace(); aTitle = tmp; - return NS_OK; } NS_IMETHODIMP @@ -5226,6 +5539,12 @@ nsDocument::SetTitle(const nsAString& aTitle) return nsContentUtils::SetNodeTextContent(title, aTitle, false); } +void +nsDocument::SetTitle(const nsAString& aTitle, ErrorResult& rv) +{ + rv = SetTitle(aTitle); +} + void nsDocument::NotifyPossibleTitleChange(bool aBoundTitleElement) { @@ -5563,16 +5882,21 @@ static const DirTable dirAttributes[] = { */ NS_IMETHODIMP nsDocument::GetDir(nsAString& aDirection) +{ + nsIDocument::GetDir(aDirection); + return NS_OK; +} + +void +nsIDocument::GetDir(nsAString& aDirection) const { uint32_t options = GetBidiOptions(); for (const DirTable* elt = dirAttributes; elt->mName; elt++) { if (GET_BIDI_OPTION_DIRECTION(options) == elt->mValue) { CopyASCIItoUTF16(elt->mName, aDirection); - break; + return; } } - - return NS_OK; } /** @@ -5582,6 +5906,14 @@ nsDocument::GetDir(nsAString& aDirection) */ NS_IMETHODIMP nsDocument::SetDir(const nsAString& aDirection) +{ + ErrorResult rv; + nsIDocument::SetDir(aDirection, rv); + return rv.ErrorCode(); +} + +void +nsIDocument::SetDir(const nsAString& aDirection, ErrorResult& rv) { uint32_t options = GetBidiOptions(); @@ -5592,7 +5924,10 @@ nsDocument::SetDir(const nsAString& aDirection) nsIPresShell *shell = GetShell(); if (shell) { nsPresContext *context = shell->GetPresContext(); - NS_ENSURE_TRUE(context, NS_ERROR_UNEXPECTED); + if (!context) { + rv.Throw(NS_ERROR_UNEXPECTED); + return; + } context->SetBidi(options, true); } else { // No presentation; just set it on ourselves @@ -5612,20 +5947,25 @@ nsDocument::SetDir(const nsAString& aDirection) break; } } - - return NS_OK; } NS_IMETHODIMP nsDocument::GetInputEncoding(nsAString& aInputEncoding) { + nsIDocument::GetInputEncoding(aInputEncoding); + return NS_OK; +} + +void +nsIDocument::GetInputEncoding(nsAString& aInputEncoding) +{ + // Not const function, because WarnOnceAbout is not a const method WarnOnceAbout(eInputEncoding); if (mHaveInputEncoding) { return GetCharacterSet(aInputEncoding); } SetDOMStringToNull(aInputEncoding); - return NS_OK; } NS_IMETHODIMP @@ -5637,6 +5977,15 @@ nsDocument::GetMozSyntheticDocument(bool *aSyntheticDocument) NS_IMETHODIMP nsDocument::GetDocumentURI(nsAString& aDocumentURI) +{ + nsString temp; + nsIDocument::GetDocumentURI(temp); + aDocumentURI = temp; + return NS_OK; +} + +void +nsIDocument::GetDocumentURI(nsString& aDocumentURI) const { if (mDocumentURI) { nsAutoCString uri; @@ -5645,8 +5994,6 @@ nsDocument::GetDocumentURI(nsAString& aDocumentURI) } else { aDocumentURI.Truncate(); } - - return NS_OK; } // Alias of above @@ -5656,12 +6003,27 @@ nsDocument::GetURL(nsAString& aURL) return GetDocumentURI(aURL); } +void +nsIDocument::GetURL(nsString& aURL) const +{ + return GetDocumentURI(aURL); +} + // readonly attribute DOMString compatMode; // Returns "BackCompat" if we are in quirks mode, "CSS1Compat" if we are // in almost standards or full standards mode. See bug 105640. This was // implemented to match MSIE's compatMode property. NS_IMETHODIMP nsDocument::GetCompatMode(nsAString& aCompatMode) +{ + nsString temp; + nsIDocument::GetCompatMode(temp); + aCompatMode = temp; + return NS_OK; +} + +void +nsIDocument::GetCompatMode(nsString& aCompatMode) const { NS_ASSERTION(mCompatMode == eCompatibility_NavQuirks || mCompatMode == eCompatibility_AlmostStandards || @@ -5673,8 +6035,6 @@ nsDocument::GetCompatMode(nsAString& aCompatMode) } else { aCompatMode.AssignLiteral("CSS1Compat"); } - - return NS_OK; } static void BlastSubtreeToPieces(nsINode *aNode); @@ -5820,15 +6180,29 @@ GetContextAndScope(nsIDocument* aOldDocument, nsIDocument* aNewDocument, NS_IMETHODIMP nsDocument::AdoptNode(nsIDOMNode *aAdoptedNode, nsIDOMNode **aResult) { - NS_ENSURE_ARG(aAdoptedNode); - *aResult = nullptr; nsCOMPtr adoptedNode = do_QueryInterface(aAdoptedNode); NS_ENSURE_TRUE(adoptedNode, NS_ERROR_UNEXPECTED); - nsresult rv = nsContentUtils::CheckSameOrigin(this, adoptedNode); - NS_ENSURE_SUCCESS(rv, rv); + ErrorResult rv; + nsINode* result = nsIDocument::AdoptNode(*adoptedNode, rv); + if (rv.Failed()) { + return rv.ErrorCode(); + } + + NS_ADDREF(*aResult = result->AsDOMNode()); + return NS_OK; +} + +nsINode* +nsIDocument::AdoptNode(nsINode& aAdoptedNode, ErrorResult& rv) +{ + nsINode* adoptedNode = &aAdoptedNode; + rv = nsContentUtils::CheckSameOrigin(this, adoptedNode); + if (rv.Failed()) { + return nullptr; + } // Scope firing mutation events so that we don't carry any state that // might be stale @@ -5846,18 +6220,22 @@ nsDocument::AdoptNode(nsIDOMNode *aAdoptedNode, nsIDOMNode **aResult) case nsIDOMNode::ATTRIBUTE_NODE: { // Remove from ownerElement. - nsCOMPtr adoptedAttr = do_QueryInterface(aAdoptedNode); + nsCOMPtr adoptedAttr = do_QueryInterface(adoptedNode); NS_ASSERTION(adoptedAttr, "Attribute not implementing nsIDOMAttr"); nsCOMPtr ownerElement; rv = adoptedAttr->GetOwnerElement(getter_AddRefs(ownerElement)); - NS_ENSURE_SUCCESS(rv, rv); + if (rv.Failed()) { + return nullptr; + } if (ownerElement) { nsCOMPtr newAttr; rv = ownerElement->RemoveAttributeNode(adoptedAttr, getter_AddRefs(newAttr)); - NS_ENSURE_SUCCESS(rv, rv); + if (rv.Failed()) { + return nullptr; + } newAttr.swap(adoptedAttr); } @@ -5884,7 +6262,8 @@ nsDocument::AdoptNode(nsIDOMNode *aAdoptedNode, nsIDOMNode **aResult) do_QueryInterface(win->GetFrameElementInternal()); if (node && nsContentUtils::ContentIsDescendantOf(node, adoptedNode)) { - return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR; + rv.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR); + return nullptr; } } } while ((doc = doc->GetParentDocument())); @@ -5899,13 +6278,15 @@ nsDocument::AdoptNode(nsIDOMNode *aAdoptedNode, nsIDOMNode **aResult) } case nsIDOMNode::DOCUMENT_NODE: { - return NS_ERROR_DOM_NOT_SUPPORTED_ERR; + rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); + return nullptr; } default: { NS_WARNING("Don't know how to adopt this nodetype for adoptNode."); - return NS_ERROR_DOM_NOT_SUPPORTED_ERR; + rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); + return nullptr; } } @@ -5916,13 +6297,15 @@ nsDocument::AdoptNode(nsIDOMNode *aAdoptedNode, nsIDOMNode **aResult) JSObject *newScope = nullptr; if (!sameDocument) { rv = GetContextAndScope(oldDocument, this, &cx, &newScope); - NS_ENSURE_SUCCESS(rv, rv); + if (rv.Failed()) { + return nullptr; + } } nsCOMArray nodesWithProperties; rv = nsNodeUtils::Adopt(adoptedNode, sameDocument ? nullptr : mNodeInfoManager, cx, newScope, nodesWithProperties); - if (NS_FAILED(rv)) { + if (rv.Failed()) { // Disconnect all nodes from their parents, since some have the old document // as their ownerDocument and some have this as their ownerDocument. BlastSubtreeToPieces(adoptedNode); @@ -5938,7 +6321,7 @@ nsDocument::AdoptNode(nsIDOMNode *aAdoptedNode, nsIDOMNode **aResult) } } - return rv; + return nullptr; } uint32_t count = nodesWithProperties.Count(); @@ -5947,20 +6330,16 @@ nsDocument::AdoptNode(nsIDOMNode *aAdoptedNode, nsIDOMNode **aResult) nsPropertyTable *oldTable = oldDocument->PropertyTable(j); nsPropertyTable *newTable = PropertyTable(j); for (uint32_t i = 0; i < count; ++i) { - if (NS_SUCCEEDED(rv)) { - rv = oldTable->TransferOrDeleteAllPropertiesFor(nodesWithProperties[i], - newTable); - } else { - oldTable->DeleteAllPropertiesFor(nodesWithProperties[i]); - } + rv = oldTable->TransferOrDeleteAllPropertiesFor(nodesWithProperties[i], + newTable); } } - if (NS_FAILED(rv)) { + if (rv.Failed()) { // Disconnect all nodes from their parents. BlastSubtreeToPieces(adoptedNode); - return rv; + return nullptr; } } @@ -5972,8 +6351,7 @@ nsDocument::AdoptNode(nsIDOMNode *aAdoptedNode, nsIDOMNode **aResult) NS_ASSERTION(adoptedNode->OwnerDoc() == this, "Should still be in the document we just got adopted into"); - NS_ADDREF(*aResult = aAdoptedNode); - return NS_OK; + return adoptedNode; } nsEventListenerManager* @@ -6009,10 +6387,14 @@ NS_IMETHODIMP nsDocument::CreateEvent(const nsAString& aEventType, nsIDOMEvent** aReturn) { NS_ENSURE_ARG_POINTER(aReturn); - *aReturn = nullptr; - - // Obtain a presentation shell + ErrorResult rv; + *aReturn = nsIDocument::CreateEvent(aEventType, rv).get(); + return rv.ErrorCode(); +} +already_AddRefed +nsIDocument::CreateEvent(const nsAString& aEventType, ErrorResult& rv) const +{ nsIPresShell *shell = GetShell(); nsPresContext *presContext = nullptr; @@ -6023,8 +6405,10 @@ nsDocument::CreateEvent(const nsAString& aEventType, nsIDOMEvent** aReturn) } // Create event even without presContext. - return nsEventDispatcher::CreateEvent(presContext, nullptr, - aEventType, aReturn); + nsCOMPtr ev; + rv = nsEventDispatcher::CreateEvent(presContext, nullptr, + aEventType, getter_AddRefs(ev)); + return ev.forget(); } void @@ -7378,14 +7762,15 @@ nsDocument::SetReadyStateInternal(ReadyState rs) } } -nsIDocument::ReadyState -nsDocument::GetReadyStateEnum() -{ - return mReadyState; -} - NS_IMETHODIMP nsDocument::GetReadyState(nsAString& aReadyState) +{ + nsIDocument::GetReadyState(aReadyState); + return NS_OK; +} + +void +nsIDocument::GetReadyState(nsAString& aReadyState) const { switch(mReadyState) { case READYSTATE_LOADING : @@ -7400,7 +7785,6 @@ nsDocument::GetReadyState(nsAString& aReadyState) default: aReadyState.Assign(NS_LITERAL_STRING("uninitialized")); } - return NS_OK; } static bool @@ -8217,21 +8601,36 @@ nsDocument::CreateTouch(nsIDOMWindow* aView, float aForce, nsIDOMTouch** aRetVal) { - NS_ADDREF(*aRetVal = new nsDOMTouch(aTarget, - aIdentifier, - aPageX, - aPageY, - aScreenX, - aScreenY, - aClientX, - aClientY, - aRadiusX, - aRadiusY, - aRotationAngle, - aForce)); + *aRetVal = nsIDocument::CreateTouch(aView, aTarget, aIdentifier, aPageX, + aPageY, aScreenX, aScreenY, aClientX, + aClientY, aRadiusX, aRadiusY, + aRotationAngle, aForce).get(); return NS_OK; } +already_AddRefed +nsIDocument::CreateTouch(nsIDOMWindow* aView, + nsISupports* aTarget, + int32_t aIdentifier, + int32_t aPageX, int32_t aPageY, + int32_t aScreenX, int32_t aScreenY, + int32_t aClientX, int32_t aClientY, + int32_t aRadiusX, int32_t aRadiusY, + float aRotationAngle, + float aForce) +{ + nsCOMPtr target = do_QueryInterface(aTarget); + nsCOMPtr touch = new nsDOMTouch(target, + aIdentifier, + aPageX, aPageY, + aScreenX, aScreenY, + aClientX, aClientY, + aRadiusX, aRadiusY, + aRotationAngle, + aForce); + return touch.forget(); +} + NS_IMETHODIMP nsDocument::CreateTouchList(nsIVariant* aPoints, nsIDOMTouchList** aRetVal) @@ -8273,6 +8672,24 @@ nsDocument::CreateTouchList(nsIVariant* aPoints, return NS_OK; } +already_AddRefed +nsIDocument::CreateTouchList(nsIDOMTouch* aTouch) +{ + nsRefPtr retval = new nsDOMTouchList(); + retval->Append(aTouch); + return retval.forget(); +} + +already_AddRefed +nsIDocument::CreateTouchList(const Sequence >& aTouches) +{ + nsRefPtr retval = new nsDOMTouchList(); + for (uint32_t i = 0; i < aTouches.Length(); ++i) { + retval->Append(aTouches[i]); + } + return retval.forget(); +} + static void DispatchFullScreenChange(nsIDocument* aTarget) { @@ -8286,6 +8703,13 @@ DispatchFullScreenChange(nsIDocument* aTarget) NS_IMETHODIMP nsDocument::MozCancelFullScreen() +{ + nsIDocument::MozCancelFullScreen(); + return NS_OK; +} + +void +nsIDocument::MozCancelFullScreen() { // Only perform fullscreen changes if we're running in a webapp // same-origin to the web app, or if we're in a user generated event @@ -8294,7 +8718,6 @@ nsDocument::MozCancelFullScreen() nsContentUtils::IsRequestFullScreenAllowed()) { RestorePreviousFullScreenState(); } - return NS_OK; } // Runnable to set window full-screen mode. Used as a script runner @@ -8987,14 +9410,28 @@ nsDocument::RequestFullScreen(Element* aElement, NS_IMETHODIMP nsDocument::GetMozFullScreenElement(nsIDOMElement **aFullScreenElement) { - NS_ENSURE_ARG_POINTER(aFullScreenElement); - *aFullScreenElement = nullptr; + ErrorResult rv; + Element* el = GetMozFullScreenElement(rv); + if (rv.Failed()) { + return rv.ErrorCode(); + } + nsCOMPtr retval = do_QueryInterface(el); + retval.forget(aFullScreenElement); + return NS_OK; +} + +Element* +nsDocument::GetMozFullScreenElement(ErrorResult& rv) +{ if (IsFullScreenDoc()) { // Must have a full-screen element while in full-screen mode. - NS_ENSURE_STATE(GetFullScreenElement()); - CallQueryInterface(GetFullScreenElement(), aFullScreenElement); + Element* el = GetFullScreenElement(); + if (!el) { + rv.Throw(NS_ERROR_UNEXPECTED); + } + return el; } - return NS_OK; + return nullptr; } Element* @@ -9009,8 +9446,7 @@ nsDocument::GetFullScreenElement() NS_IMETHODIMP nsDocument::GetMozFullScreen(bool *aFullScreen) { - NS_ENSURE_ARG_POINTER(aFullScreen); - *aFullScreen = IsFullScreenDoc(); + *aFullScreen = MozFullScreen(); return NS_OK; } @@ -9018,10 +9454,16 @@ NS_IMETHODIMP nsDocument::GetMozFullScreenEnabled(bool *aFullScreen) { NS_ENSURE_ARG_POINTER(aFullScreen); - *aFullScreen = IsFullScreenEnabled(nsContentUtils::IsCallerChrome(), false); + *aFullScreen = MozFullScreenEnabled(); return NS_OK; } +bool +nsDocument::MozFullScreenEnabled() +{ + return IsFullScreenEnabled(nsContentUtils::IsCallerChrome(), false); +} + static bool HasFullScreenSubDocument(nsIDocument* aDoc, void* aData) { @@ -9439,36 +9881,40 @@ nsIDocument::UnlockPointer() NS_IMETHODIMP nsDocument::MozExitPointerLock() { - UnlockPointer(); + nsIDocument::MozExitPointerLock(); return NS_OK; } NS_IMETHODIMP nsDocument::GetMozPointerLockElement(nsIDOMElement** aPointerLockedElement) { - NS_ENSURE_ARG_POINTER(aPointerLockedElement); - *aPointerLockedElement = nullptr; + Element* el = nsIDocument::GetMozPointerLockElement(); + nsCOMPtr retval = do_QueryInterface(el); + retval.forget(aPointerLockedElement); + return NS_OK; +} + +Element* +nsIDocument::GetMozPointerLockElement() +{ nsCOMPtr pointerLockedElement = do_QueryReferent(nsEventStateManager::sPointerLockedElement); if (!pointerLockedElement) { - return NS_OK; + return nullptr; } // Make sure pointer locked element is in the same document and domain. nsCOMPtr pointerLockedDoc = do_QueryReferent(nsEventStateManager::sPointerLockedDoc); - nsDocument* doc = static_cast(pointerLockedDoc.get()); - if (doc != this) { - return NS_OK; + if (pointerLockedDoc != this) { + return nullptr; } - nsCOMPtr pointerLockedNode = - do_QueryInterface(pointerLockedElement); - nsresult rv = nsContentUtils::CheckSameOrigin(this, pointerLockedNode.get()); + nsresult rv = nsContentUtils::CheckSameOrigin(this, pointerLockedElement); if (NS_FAILED(rv)) { - return NS_OK; + return nullptr; } - return CallQueryInterface(pointerLockedElement, aPointerLockedElement); + return pointerLockedElement; } #define EVENT(name_, id_, type_, struct_) \ @@ -9533,19 +9979,26 @@ nsDocument::PostVisibilityUpdateEvent() NS_IMETHODIMP nsDocument::GetMozHidden(bool* aHidden) { - WarnOnceAbout(ePrefixedVisibilityAPI); - return GetHidden(aHidden); + *aHidden = MozHidden(); + return NS_OK; } NS_IMETHODIMP nsDocument::GetHidden(bool* aHidden) { - *aHidden = mVisibilityState != eVisible; + *aHidden = Hidden(); return NS_OK; } NS_IMETHODIMP nsDocument::GetMozVisibilityState(nsAString& aState) +{ + nsIDocument::GetMozVisibilityState(aState); + return NS_OK; +} + +void +nsIDocument::GetMozVisibilityState(nsAString& aState) { WarnOnceAbout(ePrefixedVisibilityAPI); return GetVisibilityState(aState); @@ -9553,6 +10006,13 @@ nsDocument::GetMozVisibilityState(nsAString& aState) NS_IMETHODIMP nsDocument::GetVisibilityState(nsAString& aState) +{ + nsIDocument::GetVisibilityState(aState); + return NS_OK; +} + +void +nsIDocument::GetVisibilityState(nsAString& aState) { // This needs to stay in sync with the VisibilityState enum. static const char states[][8] = { @@ -9561,7 +10021,6 @@ nsDocument::GetVisibilityState(nsAString& aState) }; PR_STATIC_ASSERT(NS_ARRAY_LENGTH(states) == eVisibilityStateCount); aState.AssignASCII(states[mVisibilityState]); - return NS_OK; } /* virtual */ void @@ -9692,6 +10151,102 @@ nsDocument::DocSizeOfExcludingThis(nsWindowSizes* aWindowSizes) const // - many! } +already_AddRefed +nsIDocument::Constructor(nsISupports* aGlobal, ErrorResult& rv) +{ + nsCOMPtr global = do_QueryInterface(aGlobal); + if (!global) { + rv.Throw(NS_ERROR_UNEXPECTED); + return nullptr; + } + + nsCOMPtr prin = do_QueryInterface(aGlobal); + if (!prin) { + rv.Throw(NS_ERROR_UNEXPECTED); + return nullptr; + } + + nsCOMPtr uri; + NS_NewURI(getter_AddRefs(uri), "about:blank"); + if (!uri) { + rv.Throw(NS_ERROR_OUT_OF_MEMORY); + return nullptr; + } + + nsCOMPtr document; + nsresult res = + NS_NewDOMDocument(getter_AddRefs(document), + NullString(), + EmptyString(), + nullptr, + uri, + uri, + prin->GetPrincipal(), + true, + global, + DocumentFlavorLegacyGuess); + if (NS_FAILED(res)) { + rv.Throw(res); + return nullptr; + } + + nsCOMPtr doc = do_QueryInterface(document); + doc->SetReadyStateInternal(nsIDocument::READYSTATE_COMPLETE); + + return doc.forget(); +} + +already_AddRefed +nsIDocument::CreateExpression(const nsAString& aExpression, + nsIDOMXPathNSResolver* aResolver, + ErrorResult& rv) +{ + nsCOMPtr evaluator = do_QueryInterface(this); + if (!evaluator) { + rv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + + nsCOMPtr expr; + rv = evaluator->CreateExpression(aExpression, aResolver, getter_AddRefs(expr)); + return expr.forget(); +} + +already_AddRefed +nsIDocument::CreateNSResolver(nsINode* aNodeResolver, + ErrorResult& rv) +{ + nsCOMPtr evaluator = do_QueryInterface(this); + if (!evaluator) { + rv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + + nsCOMPtr nodeResolver = do_QueryInterface(aNodeResolver); + nsCOMPtr res; + rv = evaluator->CreateNSResolver(nodeResolver, getter_AddRefs(res)); + return res.forget(); +} + +already_AddRefed +nsIDocument::Evaluate(const nsAString& aExpression, nsINode* aContextNode, + nsIDOMXPathNSResolver* aResolver, uint16_t aType, + nsISupports* aResult, ErrorResult& rv) +{ + nsCOMPtr evaluator = do_QueryInterface(this); + if (!evaluator) { + rv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + + nsCOMPtr contextNode = do_QueryInterface(aContextNode); + nsCOMPtr res; + rv = evaluator->Evaluate(aExpression, contextNode, aResolver, aType, + aResult, getter_AddRefs(res)); + return res.forget(); +} + + bool MarkDocumentTreeToBeInSyncOperation(nsIDocument* aDoc, void* aData) { diff --git a/content/base/src/nsDocument.h b/content/base/src/nsDocument.h index 4c4cb78cdb4a..369d71d0068a 100644 --- a/content/base/src/nsDocument.h +++ b/content/base/src/nsDocument.h @@ -63,7 +63,7 @@ #include "nsISecurityEventSink.h" #include "nsIChannelEventSink.h" #include "imgIRequest.h" -#include "nsIDOMDOMImplementation.h" +#include "mozilla/dom/DOMImplementation.h" #include "nsIDOMTouchEvent.h" #include "nsIInlineEventHandlers.h" #include "nsDataHashtable.h" @@ -477,6 +477,7 @@ class nsDocument : public nsIDocument, { public: typedef mozilla::dom::Element Element; + using nsIDocument::GetElementsByTagName; NS_DECL_CYCLE_COLLECTING_ISUPPORTS @@ -624,7 +625,7 @@ public: virtual void SetScriptHandlingObject(nsIScriptGlobalObject* aScriptObject); - virtual nsIScriptGlobalObject* GetScopeObject(); + virtual nsIScriptGlobalObject* GetScopeObject() const; /** * Get the script loader for this document @@ -660,7 +661,6 @@ public: virtual void EndLoad(); virtual void SetReadyStateInternal(ReadyState rs); - virtual ReadyState GetReadyStateEnum(); virtual void ContentStateChanged(nsIContent* aContent, nsEventStates aStateMask); @@ -775,12 +775,6 @@ public: int32_t aNamespaceID, nsIContent **aResult); - nsresult CreateElement(const nsAString& aTagName, - nsIContent** aReturn); - nsresult CreateElementNS(const nsAString& aNamespaceURI, - const nsAString& aQualifiedName, - nsIContent** aReturn); - nsresult CreateTextNode(const nsAString& aData, nsIContent** aReturn); virtual NS_HIDDEN_(nsresult) Sanitize(); @@ -806,15 +800,14 @@ public: nsIDOMNodeList** aResult); virtual NS_HIDDEN_(nsresult) GetContentListFor(nsIContent* aContent, nsIDOMNodeList** aResult); - virtual NS_HIDDEN_(nsIContent*) + virtual NS_HIDDEN_(Element*) GetAnonymousElementByAttribute(nsIContent* aElement, nsIAtom* aAttrName, const nsAString& aAttrValue) const; - virtual NS_HIDDEN_(nsresult) ElementFromPointHelper(float aX, float aY, + virtual NS_HIDDEN_(Element*) ElementFromPointHelper(float aX, float aY, bool aIgnoreRootScrollFrame, - bool aFlushLayout, - nsIDOMElement** aReturn); + bool aFlushLayout); virtual NS_HIDDEN_(nsresult) NodesFromRectHelper(float aX, float aY, float aTopSize, float aRightSize, @@ -899,18 +892,12 @@ public: virtual void ResetScrolledToRefAlready(); virtual void SetChangeScrollPosWhenScrollingToRef(bool aValue); - already_AddRefed - GetElementsByTagName(const nsAString& aTagName) { - return NS_GetContentList(this, kNameSpaceID_Unknown, aTagName); - } - already_AddRefed - GetElementsByTagNameNS(const nsAString& aNamespaceURI, - const nsAString& aLocalName); - virtual Element *GetElementById(const nsAString& aElementId); virtual const nsSmallVoidArray* GetAllElementsForId(const nsAString& aElementId) const; virtual Element *LookupImageElement(const nsAString& aElementId); + virtual void MozSetImageElement(const nsAString& aImageElementId, + Element* aElement); virtual NS_HIDDEN_(nsresult) AddImage(imgIRequest* aImage); virtual NS_HIDDEN_(nsresult) RemoveImage(imgIRequest* aImage, uint32_t aFlags); @@ -990,6 +977,10 @@ public: // Returns the top element from the full-screen stack. Element* FullScreenStackTop(); + // DOM-exposed fullscreen API + virtual bool MozFullScreenEnabled(); + virtual Element* GetMozFullScreenElement(mozilla::ErrorResult& rv); + void RequestPointerLock(Element* aElement); bool ShouldLockPointer(Element* aElement); bool SetPointerLock(Element* aElement, int aCursorStyle); @@ -1005,6 +996,16 @@ public: // DocSizeOfIncludingThis is inherited from nsIDocument. virtual nsIDOMNode* AsDOMNode() { return this; } + + // WebIDL bits + virtual mozilla::dom::DOMImplementation* + GetImplementation(mozilla::ErrorResult& rv); + virtual nsIDOMStyleSheetList* StyleSheets(); + virtual void SetSelectedStyleSheetSet(const nsAString& aSheetSet); + virtual void GetLastStyleSheetSet(nsString& aSheetSet); + virtual nsIDOMDOMStringList* StyleSheetSets(); + virtual void EnableStyleSheetsForSet(const nsAString& aSheetSet); + protected: friend class nsNodeUtils; @@ -1052,12 +1053,6 @@ protected: nsIContent* GetFirstBaseNodeWithHref(); nsresult SetFirstBaseNodeWithHref(nsIContent *node); - inline void - SetDocumentDirectionality(mozilla::Directionality aDir) - { - mDirectionality = aDir; - } - // Get the first element with the given IsNodeOfType type, or // return null if there isn't one nsIContent* GetTitleContent(uint32_t aNodeType); @@ -1065,7 +1060,13 @@ protected: // append the concatenation of its text node children to aTitle. Do // nothing if there is no such element. void GetTitleFromElement(uint32_t aNodeType, nsAString& aTitle); +public: + // Get our title + virtual void GetTitle(nsString& aTitle); + // Set our title + virtual void SetTitle(const nsAString& aTitle, mozilla::ErrorResult& rv); +protected: nsresult doCreateShell(nsPresContext* aContext, nsIViewManager* aViewManager, nsStyleSet* aStyleSet, nsCompatibility aCompatMode, @@ -1101,9 +1102,6 @@ protected: void EnsureOnloadBlocker(); - nsCString mReferrer; - nsString mLastModified; - nsTArray<nsIObserver*> mCharSetObservers; PLDHashTable *mSubDocuments; @@ -1196,10 +1194,6 @@ protected: bool mSynchronousDOMContentLoaded:1; - // If true, we have an input encoding. If this is false, then the - // document was created entirely in memory - bool mHaveInputEncoding:1; - bool mInXBLUpdate:1; // Whether we're currently holding a lock on all of our images. @@ -1258,12 +1252,6 @@ protected: nsRefPtr<nsDOMNavigationTiming> mTiming; private: friend class nsUnblockOnloadEvent; - // This needs to stay in sync with the list in GetVisibilityState. - enum VisibilityState { - eHidden = 0, - eVisible, - eVisibilityStateCount - }; // Recomputes the visibility state but doesn't set the new value. VisibilityState GetVisibilityState() const; @@ -1322,7 +1310,6 @@ private: // Onload blockers which haven't been activated yet uint32_t mAsyncOnloadBlockCount; nsCOMPtr<nsIRequest> mOnloadBlocker; - ReadyState mReadyState; // A hashtable of styled links keyed by address pointer. nsTHashtable<nsPtrHashKey<mozilla::dom::Link> > mStyledLinks; @@ -1348,7 +1335,7 @@ private: // All images in process of being preloaded nsCOMArray<imgIRequest> mPreloadingImages; - nsCOMPtr<nsIDOMDOMImplementation> mDOMImplementation; + nsRefPtr<mozilla::dom::DOMImplementation> mDOMImplementation; nsRefPtr<nsContentList> mImageMaps; @@ -1362,8 +1349,6 @@ private: // Tracking for plugins in the document. nsTHashtable< nsPtrHashKey<nsIObjectLoadingContent> > mPlugins; - VisibilityState mVisibilityState; - #ifdef DEBUG protected: bool mWillReparent; diff --git a/content/base/src/nsINode.cpp b/content/base/src/nsINode.cpp index 430b4696149e..11f027496da5 100644 --- a/content/base/src/nsINode.cpp +++ b/content/base/src/nsINode.cpp @@ -103,6 +103,7 @@ #include "nsHTMLLegendElement.h" #include "nsWrapperCacheInlines.h" #include "WrapperFactory.h" +#include "nsDOMDocumentType.h" using namespace mozilla; using namespace mozilla::dom; @@ -1443,7 +1444,7 @@ bool IsAllowedAsChild(nsIContent* aNewChild, nsINode* aParent, return true; } - nsIContent* docTypeContent = parentDocument->GetDocumentType(); + nsIContent* docTypeContent = parentDocument->GetDoctype(); if (!docTypeContent) { // It's all good. return true; @@ -1466,7 +1467,7 @@ bool IsAllowedAsChild(nsIContent* aNewChild, nsINode* aParent, } nsIDocument* parentDocument = static_cast<nsIDocument*>(aParent); - nsIContent* docTypeContent = parentDocument->GetDocumentType(); + nsIContent* docTypeContent = parentDocument->GetDoctype(); if (docTypeContent) { // Already have a doctype, so this is only OK if we're replacing it return aIsReplace && docTypeContent == aRefChild; diff --git a/content/base/src/nsRange.h b/content/base/src/nsRange.h index e2c2d114caaf..7a84e41c5abf 100644 --- a/content/base/src/nsRange.h +++ b/content/base/src/nsRange.h @@ -243,4 +243,16 @@ protected: #endif }; +inline nsISupports* +ToCanonicalSupports(nsRange* aRange) +{ + return static_cast<nsIDOMRange*>(aRange); +} + +inline nsISupports* +ToSupports(nsRange* aRange) +{ + return static_cast<nsIDOMRange*>(aRange); +} + #endif /* nsRange_h___ */ diff --git a/content/events/src/nsContentEventHandler.cpp b/content/events/src/nsContentEventHandler.cpp index 8bf3eabfd121..98c1642dd6a3 100644 --- a/content/events/src/nsContentEventHandler.cpp +++ b/content/events/src/nsContentEventHandler.cpp @@ -26,6 +26,9 @@ #include "nsLayoutUtils.h" #include "nsIMEStateManager.h" #include "nsIObjectFrame.h" +#include "mozilla/dom/Element.h" + +using namespace mozilla::dom; /******************************************************************/ /* nsContentEventHandler */ @@ -870,10 +873,8 @@ nsContentEventHandler::OnQueryDOMWidgetHittest(nsQueryContentEvent* aEvent) eventLoc.x -= docFrameRect.x; eventLoc.y -= docFrameRect.y; - nsCOMPtr<nsIDOMElement> elementUnderMouse; - doc->ElementFromPointHelper(eventLoc.x, eventLoc.y, false, false, - getter_AddRefs(elementUnderMouse)); - nsCOMPtr<nsIContent> contentUnderMouse = do_QueryInterface(elementUnderMouse); + Element* contentUnderMouse = + doc->ElementFromPointHelper(eventLoc.x, eventLoc.y, false, false); if (contentUnderMouse) { nsIWidget* targetWidget = nullptr; nsIFrame* targetFrame = contentUnderMouse->GetPrimaryFrame(); diff --git a/content/html/document/src/nsHTMLDocument.cpp b/content/html/document/src/nsHTMLDocument.cpp index 18c8a733dd7f..ca90bc16d699 100644 --- a/content/html/document/src/nsHTMLDocument.cpp +++ b/content/html/document/src/nsHTMLDocument.cpp @@ -1025,7 +1025,7 @@ nsHTMLDocument::SetDomain(const nsAString& aDomain) return NodePrincipal()->SetDomain(newURI); } -nsIContent* +Element* nsHTMLDocument::GetBody() { Element* body = GetBodyElement(); @@ -1040,7 +1040,7 @@ nsHTMLDocument::GetBody() nsRefPtr<nsContentList> nodeList = NS_GetContentList(this, kNameSpaceID_XHTML, NS_LITERAL_STRING("frameset")); - return nodeList->Item(0); + return nodeList->GetElementAt(0); } NS_IMETHODIMP diff --git a/content/html/document/src/nsHTMLDocument.h b/content/html/document/src/nsHTMLDocument.h index 944b3575a45c..d882f52491c5 100644 --- a/content/html/document/src/nsHTMLDocument.h +++ b/content/html/document/src/nsHTMLDocument.h @@ -86,6 +86,14 @@ public: // nsIDOMDocument interface NS_FORWARD_NSIDOMDOCUMENT(nsDocument::) + // And explicitly import the things from nsDocument that we just shadowed + using nsDocument::GetImplementation; + using nsDocument::GetTitle; + using nsDocument::SetTitle; + using nsDocument::GetLastStyleSheetSet; + using nsDocument::MozSetImageElement; + using nsDocument::GetMozFullScreenElement; + // nsIDOMNode interface NS_FORWARD_NSIDOMNODE_TO_NSINODE @@ -101,7 +109,7 @@ public: nsWrapperCache **aCache, nsresult *aResult); - nsIContent *GetBody(); + Element *GetBody(); Element *GetHead() { return GetHeadElement(); } already_AddRefed<nsContentList> GetElementsByName(const nsAString & aName) { diff --git a/content/svg/document/src/nsSVGDocument.h b/content/svg/document/src/nsSVGDocument.h index 8020ba7670c1..804267058f1f 100644 --- a/content/svg/document/src/nsSVGDocument.h +++ b/content/svg/document/src/nsSVGDocument.h @@ -20,6 +20,14 @@ public: NS_DECL_NSIDOMSVGDOCUMENT NS_FORWARD_NSIDOMDOCUMENT(nsXMLDocument::) + // And explicitly import the things from nsDocument that we just shadowed + using nsDocument::GetImplementation; + using nsDocument::GetTitle; + using nsDocument::SetTitle; + using nsDocument::GetLastStyleSheetSet; + using nsDocument::MozSetImageElement; + using nsDocument::GetMozFullScreenElement; + NS_FORWARD_NSIDOMNODE_TO_NSINODE NS_DECL_ISUPPORTS_INHERITED virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const; diff --git a/content/xul/document/src/nsXULDocument.h b/content/xul/document/src/nsXULDocument.h index 8052519de72a..7024c32d122e 100644 --- a/content/xul/document/src/nsXULDocument.h +++ b/content/xul/document/src/nsXULDocument.h @@ -140,6 +140,13 @@ public: // nsIDOMDocument interface NS_FORWARD_NSIDOMDOCUMENT(nsXMLDocument::) + // And explicitly import the things from nsDocument that we just shadowed + using nsDocument::GetImplementation; + using nsDocument::GetTitle; + using nsDocument::SetTitle; + using nsDocument::GetLastStyleSheetSet; + using nsDocument::MozSetImageElement; + using nsDocument::GetMozFullScreenElement; // nsDocument interface overrides virtual mozilla::dom::Element* GetElementById(const nsAString & elementId); diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp index 7dfb8b42e290..4a492de1a772 100644 --- a/dom/base/nsDOMWindowUtils.cpp +++ b/dom/base/nsDOMWindowUtils.cpp @@ -1215,8 +1215,11 @@ nsDOMWindowUtils::ElementFromPoint(float aX, float aY, nsCOMPtr<nsIDocument> doc(do_QueryInterface(window->GetExtantDocument())); NS_ENSURE_STATE(doc); - return doc->ElementFromPointHelper(aX, aY, aIgnoreRootScrollFrame, aFlushLayout, - aReturn); + Element* el = + doc->ElementFromPointHelper(aX, aY, aIgnoreRootScrollFrame, aFlushLayout); + nsCOMPtr<nsIDOMElement> retval = do_QueryInterface(el); + retval.forget(aReturn); + return NS_OK; } NS_IMETHODIMP diff --git a/dom/bindings/Bindings.conf b/dom/bindings/Bindings.conf index 6d76af984348..c07b0b0afb75 100644 --- a/dom/bindings/Bindings.conf +++ b/dom/bindings/Bindings.conf @@ -173,6 +173,14 @@ DOMInterfaces = { 'Document': [ { 'nativeType': 'nsIDocument', + 'resultNotAddRefed': [ 'implementation', 'doctype', 'documentElement', + 'getElementById', 'adoptNode', 'defaultView', + 'activeElement', 'currentScript', + 'mozFullScreenElement', 'mozPointerLockElement', + 'styleSheets', 'styleSheetSets', 'elementFromPoint', + 'querySelector', 'getAnonymousNodes', + 'getAnonymousElementByAtribute', 'getBindingParent' + ] }, { 'nativeType': 'JSObject', @@ -330,6 +338,14 @@ DOMInterfaces = { 'workers': True, }], +'Location': { + # NOTE: Before you turn on codegen for Location, make sure all the + # Unforgeable stuff is dealt with. + 'nativeType': 'nsIDOMLocation', + 'skipGen': True, + 'register': False +}, + 'MediaStreamList': { 'headerFile': 'MediaStreamList.h', 'wrapperCache': False, @@ -772,7 +788,7 @@ DOMInterfaces = { 'TestExampleProxyInterface' : { 'headerFile': 'TestExampleProxyInterface-example.h', - 'register': False + 'register': False } } @@ -808,35 +824,47 @@ addExternalHTMLElement('HTMLVideoElement') addExternalIface('Attr') addExternalIface('CanvasGradient', headerFile='nsIDOMCanvasRenderingContext2D.h') addExternalIface('CanvasPattern', headerFile='nsIDOMCanvasRenderingContext2D.h') +addExternalIface('CDATASection') addExternalIface('ClientRect') +addExternalIface('Comment', nativeType='mozilla::dom::Comment') addExternalIface("Counter") addExternalIface('CSSRule') -addExternalIface('DocumentType', nativeType='nsIDOMDocumentType') +addExternalIface('DocumentFragment', nativeType='mozilla::dom::DocumentFragment') +addExternalIface('DocumentType', headerFile="nsDOMDocumentType.h") addExternalIface('DOMRequest') -addExternalIface('DOMStringList', nativeType='nsDOMStringList', - headerFile='nsDOMLists.h') +addExternalIface('DOMStringList') addExternalIface('File') addExternalIface('HitRegionOptions', nativeType='nsISupports') addExternalIface('LockedFile') addExternalIface('MediaStream') addExternalIface('NamedNodeMap') +addExternalIface('NodeIterator') addExternalIface('OutputStream', nativeType='nsIOutputStream', notflattened=True) addExternalIface('PaintRequest') addExternalIface('Principal', nativeType='nsIPrincipal', headerFile='nsIPrincipal.h', notflattened=True) +addExternalIface('ProcessingInstruction', nativeType='nsXMLProcessingInstruction') +addExternalIface('Range', nativeType='nsRange') +addExternalIface("Rect") +addExternalIface('StyleSheetList') addExternalIface('SVGLength') addExternalIface('SVGMatrix') addExternalIface('SVGNumber') addExternalIface('SVGPathSeg') addExternalIface('SVGPoint') addExternalIface('SVGTransform') -addExternalIface("Rect") +addExternalIface('Text', nativeType='nsTextNode') addExternalIface('TextMetrics', headerFile='nsIDOMCanvasRenderingContext2D.h') +addExternalIface('TreeWalker') addExternalIface('Touch', headerFile='nsIDOMTouchEvent.h') +addExternalIface('TouchList', headerFile='nsIDOMTouchEvent.h') addExternalIface('URI', nativeType='nsIURI', headerFile='nsIURI.h', notflattened=True) addExternalIface('UserDataHandler') addExternalIface('Window') +addExternalIface('WindowProxy', nativeType='nsIDOMWindow') addExternalIface('XPathResult', nativeType='nsISupports') +addExternalIface('XPathExpression') +addExternalIface('XPathNSResolver') addExternalIface('XULElement') diff --git a/dom/bindings/Makefile.in b/dom/bindings/Makefile.in index 93c3b05e8e64..a02be12352cb 100644 --- a/dom/bindings/Makefile.in +++ b/dom/bindings/Makefile.in @@ -81,6 +81,7 @@ LOCAL_INCLUDES += -I$(topsrcdir)/js/xpconnect/src \ -I$(topsrcdir)/dom/base \ -I$(topsrcdir)/content/xslt/src/base \ -I$(topsrcdir)/content/xslt/src/xpath \ + -I$(topsrcdir)/content/xml/content/src \ $(NULL) include $(topsrcdir)/config/rules.mk diff --git a/dom/interfaces/core/nsIDOMDocument.idl b/dom/interfaces/core/nsIDOMDocument.idl index 8bfc6ba833a1..6868a274057e 100644 --- a/dom/interfaces/core/nsIDOMDocument.idl +++ b/dom/interfaces/core/nsIDOMDocument.idl @@ -201,6 +201,7 @@ interface nsIDOMDocument : nsIDOMNode * * @see <http://dev.w3.org/csswg/cssom/#dom-document-selectedStyleSheetSet> */ + [binaryname(MozSelectedStyleSheetSet)] attribute DOMString selectedStyleSheetSet; /* @@ -241,6 +242,7 @@ interface nsIDOMDocument : nsIDOMNode * * @see <http://dev.w3.org/csswg/cssom/#dom-document-enableStyleSheetsForSet> */ + [binaryname(MozEnableStyleSheetsForSet)] void enableStyleSheetsForSet(in DOMString name); diff --git a/dom/webidl/Document.webidl b/dom/webidl/Document.webidl index 9134290c4005..bac55ea087dc 100644 --- a/dom/webidl/Document.webidl +++ b/dom/webidl/Document.webidl @@ -3,14 +3,36 @@ * 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://www.w3.org/TR/2012/WD-dom-20120105/ + * The origin of this IDL file is: + * http://dom.spec.whatwg.org/#interface-document + * http://www.whatwg.org/specs/web-apps/current-work/#the-document-object + * http://dvcs.w3.org/hg/fullscreen/raw-file/tip/Overview.html#api + * http://dvcs.w3.org/hg/pointerlock/raw-file/default/index.html#extensions-to-the-document-interface + * http://dvcs.w3.org/hg/webperf/raw-file/tip/specs/PageVisibility/Overview.html#sec-document-interface + * http://dev.w3.org/csswg/cssom/#extensions-to-the-document-interface + * http://dev.w3.org/csswg/cssom-view/#extensions-to-the-document-interface * - * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C - * liability, trademark and document use rules apply. + * http://mxr.mozilla.org/mozilla-central/source/dom/interfaces/core/nsIDOMDocument.idl */ +interface Attr; +interface CDATASection; +interface DocumentFragment; +interface Comment; +interface NodeIterator; +interface ProcessingInstruction; +interface Range; +interface StyleSheetList; +interface Text; +interface Touch; +interface TouchList; +interface TreeWalker; +interface WindowProxy; + +/* http://dom.spec.whatwg.org/#interface-document */ +[Constructor] interface Document : Node { + [Throws, Constant] readonly attribute DOMImplementation implementation; readonly attribute DOMString URL; readonly attribute DOMString documentURI; @@ -20,31 +42,408 @@ interface Document : Node { readonly attribute DocumentType? doctype; readonly attribute Element? documentElement; - NodeList getElementsByTagName(DOMString qualifiedName); - NodeList getElementsByTagNameNS(DOMString? namespace, DOMString localName); - NodeList getElementsByClassName(DOMString classNames); + HTMLCollection getElementsByTagName(DOMString localName); + HTMLCollection getElementsByTagNameNS(DOMString? namespace, DOMString localName); + HTMLCollection getElementsByClassName(DOMString classNames); Element? getElementById(DOMString elementId); + [Creator, Throws] Element createElement(DOMString localName); + [Creator, Throws] Element createElementNS(DOMString? namespace, DOMString qualifiedName); + [Creator, Throws] DocumentFragment createDocumentFragment(); + [Creator, Throws] Text createTextNode(DOMString data); + [Creator, Throws] Comment createComment(DOMString data); + [Creator, Throws] ProcessingInstruction createProcessingInstruction(DOMString target, DOMString data); - Node importNode(Node node, optional boolean deep); + [Throws] + Node importNode(Node node, optional boolean deep = true); + [Throws] Node adoptNode(Node node); - Event createEvent(DOMString eventInterfaceName); + [Creator, Throws] + Event createEvent(DOMString interface); + [Creator, Throws] Range createRange(); - NodeIterator createNodeIterator(Node root, optional unsigned long whatToShow, optional NodeFilter? filter); - TreeWalker createTreeWalker(Node root, optional unsigned long whatToShow, optional NodeFilter? filter); + // NodeFilter.SHOW_ALL = 0xFFFFFFFF + [Creator, Throws] + NodeIterator createNodeIterator(Node root, optional unsigned long whatToShow = 0xFFFFFFFF, optional NodeFilter? filter = null); + [Creator, Throws] + TreeWalker createTreeWalker(Node root, optional unsigned long whatToShow = 0xFFFFFFFF, optional NodeFilter? filter = null); // NEW - void prepend((Node or DOMString)... nodes); - void append((Node or DOMString)... nodes); + // No support for prepend/append yet + // void prepend((Node or DOMString)... nodes); + // void append((Node or DOMString)... nodes); + + // These are not in the spec, but leave them for now for backwards compat. + // So sort of like Gecko extensions + [Creator, Throws] + CDATASection createCDATASection(DOMString data); + [Creator, Throws] + Attr createAttribute(DOMString name); + [Creator, Throws] + Attr createAttributeNS(DOMString? namespace, DOMString name); + readonly attribute DOMString? inputEncoding; +/* }; -interface XMLDocument : Document {}; +http://www.whatwg.org/specs/web-apps/current-work/#the-document-object +partial interface Document { +*/ + [PutForwards=href, Unforgeable] readonly attribute Location? location; + //(HTML only) attribute DOMString domain; + readonly attribute DOMString referrer; + //(HTML only) attribute DOMString cookie; + readonly attribute DOMString lastModified; + readonly attribute DOMString readyState; + + // DOM tree accessors + //(Not proxy yet)getter object (DOMString name); + [SetterThrows] + attribute DOMString title; + [SetterThrows] + attribute DOMString dir; + //(HTML only) attribute HTMLElement? body; + //(HTML only)readonly attribute HTMLHeadElement? head; + //(HTML only)readonly attribute HTMLCollection images; + //(HTML only)readonly attribute HTMLCollection embeds; + //(HTML only)readonly attribute HTMLCollection plugins; + //(HTML only)readonly attribute HTMLCollection links; + //(HTML only)readonly attribute HTMLCollection forms; + //(HTML only)readonly attribute HTMLCollection scripts; + //(HTML only)NodeList getElementsByName(DOMString elementName); + //(HTML only)NodeList getItems(optional DOMString typeNames); // microdata + //(Not implemented)readonly attribute DOMElementMap cssElementMap; + + // dynamic markup insertion + //(HTML only)Document open(optional DOMString type, optional DOMString replace); + //(HTML only)WindowProxy open(DOMString url, DOMString name, DOMString features, optional boolean replace); + //(HTML only)void close(); + //(HTML only)void write(DOMString... text); + //(HTML only)void writeln(DOMString... text); + + // user interaction + readonly attribute WindowProxy? defaultView; + readonly attribute Element? activeElement; + [Throws] + boolean hasFocus(); + //(HTML only) attribute DOMString designMode; + //(HTML only)boolean execCommand(DOMString commandId); + //(HTML only)boolean execCommand(DOMString commandId, boolean showUI); + //(HTML only)boolean execCommand(DOMString commandId, boolean showUI, DOMString value); + //(HTML only)boolean queryCommandEnabled(DOMString commandId); + //(HTML only)boolean queryCommandIndeterm(DOMString commandId); + //(HTML only)boolean queryCommandState(DOMString commandId); + //(HTML only)boolean queryCommandSupported(DOMString commandId); + //(HTML only)DOMString queryCommandValue(DOMString commandId); + //(Not implemented)readonly attribute HTMLCollection commands; + + // event handler IDL attributes + [SetterThrows] + attribute EventHandler onabort; + [SetterThrows] + attribute EventHandler onblur; + //(Not implemented) attribute EventHandler oncancel; + [SetterThrows] + attribute EventHandler oncanplay; + [SetterThrows] + attribute EventHandler oncanplaythrough; + [SetterThrows] + attribute EventHandler onchange; + [SetterThrows] + attribute EventHandler onclick; + //(Not implemented) attribute EventHandler onclose; + [SetterThrows] + attribute EventHandler oncontextmenu; + //(Not implemented) attribute EventHandler oncuechange; + [SetterThrows] + attribute EventHandler ondblclick; + [SetterThrows] + attribute EventHandler ondrag; + [SetterThrows] + attribute EventHandler ondragend; + [SetterThrows] + attribute EventHandler ondragenter; + [SetterThrows] + attribute EventHandler ondragleave; + [SetterThrows] + attribute EventHandler ondragover; + [SetterThrows] + attribute EventHandler ondragstart; + [SetterThrows] + attribute EventHandler ondrop; + [SetterThrows] + attribute EventHandler ondurationchange; + [SetterThrows] + attribute EventHandler onemptied; + [SetterThrows] + attribute EventHandler onended; + [SetterThrows] + attribute EventHandler onerror; + [SetterThrows] + attribute EventHandler onfocus; + [SetterThrows] + attribute EventHandler oninput; + [SetterThrows] + attribute EventHandler oninvalid; + [SetterThrows] + attribute EventHandler onkeydown; + [SetterThrows] + attribute EventHandler onkeypress; + [SetterThrows] + attribute EventHandler onkeyup; + [SetterThrows] + attribute EventHandler onload; + [SetterThrows] + attribute EventHandler onloadeddata; + [SetterThrows] + attribute EventHandler onloadedmetadata; + [SetterThrows] + attribute EventHandler onloadstart; + [SetterThrows] + attribute EventHandler onmousedown; + [SetterThrows] + attribute EventHandler onmousemove; + [SetterThrows] + attribute EventHandler onmouseout; + [SetterThrows] + attribute EventHandler onmouseover; + [SetterThrows] + attribute EventHandler onmouseup; + //(Not implemented) attribute EventHandler onmousewheel; + [SetterThrows] + attribute EventHandler onpause; + [SetterThrows] + attribute EventHandler onplay; + [SetterThrows] + attribute EventHandler onplaying; + [SetterThrows] + attribute EventHandler onprogress; + [SetterThrows] + attribute EventHandler onratechange; + [SetterThrows] + attribute EventHandler onreset; + [SetterThrows] + attribute EventHandler onscroll; + [SetterThrows] + attribute EventHandler onseeked; + [SetterThrows] + attribute EventHandler onseeking; + [SetterThrows] + attribute EventHandler onselect; + [SetterThrows] + attribute EventHandler onshow; + [SetterThrows] + attribute EventHandler onstalled; + [SetterThrows] + attribute EventHandler onsubmit; + [SetterThrows] + attribute EventHandler onsuspend; + [SetterThrows] + attribute EventHandler ontimeupdate; + [SetterThrows] + attribute EventHandler onvolumechange; + [SetterThrows] + attribute EventHandler onwaiting; + + // special event handler IDL attributes that only apply to Document objects + [LenientThis, SetterThrows] attribute EventHandler onreadystatechange; + + // Gecko extensions? + [LenientThis, SetterThrows] attribute EventHandler onmouseenter; + [LenientThis, SetterThrows] attribute EventHandler onmouseleave; + [SetterThrows] attribute EventHandler onmozfullscreenchange; + [SetterThrows] attribute EventHandler onmozfullscreenerror; + [SetterThrows] attribute EventHandler onmozpointerlockchange; + [SetterThrows] attribute EventHandler onmozpointerlockerror; + [SetterThrows] attribute EventHandler onwheel; + [SetterThrows] attribute EventHandler oncopy; + [SetterThrows] attribute EventHandler oncut; + [SetterThrows] attribute EventHandler onpaste; + [SetterThrows] attribute EventHandler onbeforescriptexecute; + [SetterThrows] attribute EventHandler onafterscriptexecute; + /** + * True if this document is synthetic : stand alone image, video, audio file, + * etc. + */ + [ChromeOnly] readonly attribute boolean mozSyntheticDocument; + /** + * Returns the script element whose script is currently being processed. + * + * @see <https://developer.mozilla.org/en/DOM/document.currentScript> + */ + readonly attribute Element? currentScript; + /** + * Release the current mouse capture if it is on an element within this + * document. + * + * @see <https://developer.mozilla.org/en/DOM/document.releaseCapture> + */ + void releaseCapture(); + /** + * Use the given DOM element as the source image of target |-moz-element()|. + * + * This function introduces a new special ID (called "image element ID"), + * which is only used by |-moz-element()|, and associates it with the given + * DOM element. Image elements ID's have the higher precedence than general + * HTML id's, so if |document.mozSetImageElement(<id>, <element>)| is called, + * |-moz-element(#<id>)| uses |<element>| as the source image even if there + * is another element with id attribute = |<id>|. To unregister an image + * element ID |<id>|, call |document.mozSetImageElement(<id>, null)|. + * + * Example: + * <script> + * canvas = document.createElement("canvas"); + * canvas.setAttribute("width", 100); + * canvas.setAttribute("height", 100); + * // draw to canvas + * document.mozSetImageElement("canvasbg", canvas); + * </script> + * <div style="background-image: -moz-element(#canvasbg);"></div> + * + * @param aImageElementId an image element ID to associate with + * |aImageElement| + * @param aImageElement a DOM element to be used as the source image of + * |-moz-element(#aImageElementId)|. If this is null, the function will + * unregister the image element ID |aImageElementId|. + * + * @see <https://developer.mozilla.org/en/DOM/document.mozSetImageElement> + */ + void mozSetImageElement(DOMString aImageElementId, + Element? aImageElement); + +/* +}; + +http://dvcs.w3.org/hg/fullscreen/raw-file/tip/Overview.html#api +partial interface Document { +*/ + // Note: Per spec the 'S' in these two is lowercase, but the "Moz" + // versions hve it uppercase. + readonly attribute boolean mozFullScreenEnabled; + [Throws] + readonly attribute Element? mozFullScreenElement; + + //(Renamed?)void exitFullscreen(); + + // Gecko-specific fullscreen bits + readonly attribute boolean mozFullScreen; + void mozCancelFullScreen(); +/* +}; + +http://dvcs.w3.org/hg/pointerlock/raw-file/default/index.html#extensions-to-the-document-interface +partial interface Document { +*/ + readonly attribute Element? mozPointerLockElement; + void mozExitPointerLock (); +/* +}; + +http://dvcs.w3.org/hg/webperf/raw-file/tip/specs/PageVisibility/Overview.html#sec-document-interface +partial interface Document { +*/ + readonly attribute boolean hidden; + readonly attribute boolean mozHidden; + readonly attribute DOMString visibilityState; + readonly attribute DOMString mozVisibilityState; + // "hidden", "visible", "prerender", "unloaded" +/* +}; + +http://dev.w3.org/csswg/cssom/#extensions-to-the-document-interface +partial interface Document { +*/ + [Constant] + readonly attribute StyleSheetList styleSheets; + attribute DOMString? selectedStyleSheetSet; + readonly attribute DOMString? lastStyleSheetSet; + readonly attribute DOMString? preferredStyleSheetSet; + [Constant] + readonly attribute DOMStringList styleSheetSets; + void enableStyleSheetsForSet (DOMString? name); +/* +}; + +http://dev.w3.org/csswg/cssom-view/#extensions-to-the-document-interface +partial interface Document { +*/ + Element? elementFromPoint (float x, float y); + //(Not implemented)CaretPosition? caretPositionFromPoint (float x, float y); +/*}; + +http://dev.w3.org/2006/webapi/selectors-api2/#interface-definitions +partial interface Document { +*/ + [Throws] + Element? querySelector(DOMString selectors); + [Throws] + NodeList querySelectorAll(DOMString selectors); + + //(Not implemented)Element? find(DOMString selectors, optional (Element or sequence<Node>)? refNodes); + //(Not implemented)NodeList findAll(DOMString selectors, optional (Element or sequence<Node>)? refNodes); +/*}; + + Mozilla extensions of various sorts +*/ + + // nsIDOMDocumentXBL. Wish we could make these [ChromeOnly], but + // that would likely break bindings running with the page principal. + NodeList? getAnonymousNodes(Element elt); + Element? getAnonymousElementByAttribute(Element elt, DOMString attrName, + DOMString attrValue); + [Throws] + void addBinding(Element elt, DOMString bindingURL); + [Throws] + void removeBinding(Element elt, DOMString bindingURL); + Element? getBindingParent(Node node); + [Throws] + void loadBindingDocument(DOMString documentURL); + + // nsIDOMDocumentTouch + // XXXbz I can't find the sane spec for this stuff, so just cribbing + // from our xpidl for now. + [SetterThrows, Pref="dom.w3c_touch_events.expose"] + attribute EventHandler ontouchstart; + [SetterThrows, Pref="dom.w3c_touch_events.expose"] + attribute EventHandler ontouchend; + [SetterThrows, Pref="dom.w3c_touch_events.expose"] + attribute EventHandler ontouchmove; + [SetterThrows, Pref="dom.w3c_touch_events.expose"] + attribute EventHandler ontouchenter; + [SetterThrows, Pref="dom.w3c_touch_events.expose"] + attribute EventHandler ontouchleave; + [SetterThrows, Pref="dom.w3c_touch_events.expose"] + attribute EventHandler ontouchcancel; + [Creator, Pref="dom.w3c_touch_events.expose"] + Touch createTouch(optional Window? view = null, + // Nasty hack, because we can't do EventTarget arguments yet + // (they would need to be non-castable, but trying to do + // XPConnect unwrapping with nsDOMEventTargetHelper fails). + // optional EventTarget? target = null, + optional nsISupports? target = null, + optional long identifier = 0, + optional long pageX = 0, + optional long pageY = 0, + optional long screenX = 0, + optional long screenY = 0, + optional long clientX = 0, + optional long clientY = 0, + optional long radiusX = 0, + optional long radiusY = 0, + optional float rotationAngle = 0, + optional float force = 0); + [Creator, Pref="dom.w3c_touch_events.expose"] + TouchList createTouchList(Touch touch); + [Creator, Pref="dom.w3c_touch_events.expose"] + TouchList createTouchList(sequence<Touch> touches); +}; + +Document implements XPathEvaluator; diff --git a/dom/webidl/Location.webidl b/dom/webidl/Location.webidl new file mode 100644 index 000000000000..8d8d3dd9b33e --- /dev/null +++ b/dom/webidl/Location.webidl @@ -0,0 +1,28 @@ +/* -*- 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://www.whatwg.org/specs/web-apps/current-work/#the-location-interface + * + * Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and + * Opera Software ASA. You are granted a license to use, reproduce + * and create derivative works of this document. + */ + +[Unforgeable] interface Location { + stringifier attribute DOMString href; + void assign(DOMString url); + void replace(DOMString url); + void reload(); + + // URL decomposition IDL attributes + attribute DOMString protocol; + attribute DOMString host; + attribute DOMString hostname; + attribute DOMString port; + attribute DOMString pathname; + attribute DOMString search; + attribute DOMString hash; +}; diff --git a/dom/webidl/WebIDL.mk b/dom/webidl/WebIDL.mk index 5ed6f4027983..514023babc34 100644 --- a/dom/webidl/WebIDL.mk +++ b/dom/webidl/WebIDL.mk @@ -49,6 +49,7 @@ webidl_files = \ HTMLOptionsCollection.webidl \ HTMLPropertiesCollection.webidl \ ImageData.webidl \ + Location.webidl \ MutationObserver.webidl \ Node.webidl \ NodeFilter.webidl \ diff --git a/js/xpconnect/src/dom_quickstubs.qsconf b/js/xpconnect/src/dom_quickstubs.qsconf index 4788cc07f746..3d47a06963f8 100644 --- a/js/xpconnect/src/dom_quickstubs.qsconf +++ b/js/xpconnect/src/dom_quickstubs.qsconf @@ -523,18 +523,20 @@ customMethodCalls = { 'nsIDOMDocument_GetElementsByTagNameNS': { 'thisType': 'nsDocument', 'code': ' nsRefPtr<nsContentList> result =' - 'self->GetElementsByTagNameNS(arg0, arg1);', + 'self->nsIDocument::GetElementsByTagNameNS(arg0, arg1);', 'canFail': False }, 'nsIDOMDocument_CreateElement': { 'thisType': 'nsDocument', - 'code': ' nsCOMPtr<nsIContent> result;\n' - ' rv = self->CreateElement(arg0, getter_AddRefs(result));' + 'code': ' mozilla::ErrorResult error;\n' + ' nsCOMPtr<mozilla::dom::Element> result = self->nsIDocument::CreateElement(arg0, error);\n' + ' rv = error.ErrorCode();' }, 'nsIDOMDocument_CreateElementNS': { 'thisType': 'nsDocument', - 'code': ' nsCOMPtr<nsIContent> result;\n' - ' rv = self->CreateElementNS(arg0, arg1, getter_AddRefs(result));' + 'code': ' mozilla::ErrorResult error;\n' + ' nsCOMPtr<mozilla::dom::Element> result = self->nsIDocument::CreateElementNS(arg0, arg1, error);\n' + ' rv = error.ErrorCode();' }, 'nsIDOMDocument_CreateTextNode': { 'thisType': 'nsDocument', @@ -565,6 +567,12 @@ customMethodCalls = { 'thisType' : 'nsDocument', 'unwrapThisFailureFatal' : False }, + 'nsIDOMDocument_GetTitle' : { + 'thisType' : 'nsDocument', + 'code': ' nsString result;\n' + ' self->GetTitle(result);', + 'canFail': False + }, 'nsIDOMWindow_GetOnmouseenter' : { 'thisType' : 'nsIDOMWindow', 'unwrapThisFailureFatal' : False From ecdc94030a6acdfd31b57e726e6b27785c81ffb6 Mon Sep 17 00:00:00 2001 From: "Zane U. Ji" <ZaneUJi@gmail.com> Date: Sat, 22 Dec 2012 17:54:00 +0900 Subject: [PATCH 061/469] Bug 493544 - Don't decode the encoded text until it ends. r=smontagu --- netwerk/mime/nsMIMEHeaderParamImpl.cpp | 149 ++++++++++++++++++------- 1 file changed, 106 insertions(+), 43 deletions(-) diff --git a/netwerk/mime/nsMIMEHeaderParamImpl.cpp b/netwerk/mime/nsMIMEHeaderParamImpl.cpp index 42c75cd0664a..454e0b23a24b 100644 --- a/netwerk/mime/nsMIMEHeaderParamImpl.cpp +++ b/netwerk/mime/nsMIMEHeaderParamImpl.cpp @@ -1091,6 +1091,43 @@ void CopyRawHeader(const char *aInput, uint32_t aLen, } } +nsresult DecodeQOrBase64Str(const char *aEncoded, size_t aLen, char aQOrBase64, + const char *aCharset, nsACString &aResult) +{ + char *decodedText; + NS_ASSERTION(aQOrBase64 == 'Q' || aQOrBase64 == 'B', "Should be 'Q' or 'B'"); + if(aQOrBase64 == 'Q') + decodedText = DecodeQ(aEncoded, aLen); + else if (aQOrBase64 == 'B') { + decodedText = PL_Base64Decode(aEncoded, aLen, nullptr); + } else { + return NS_ERROR_INVALID_ARG; + } + + if (!decodedText) { + return NS_ERROR_INVALID_ARG; + } + + nsresult rv; + nsCOMPtr<nsIUTF8ConverterService> + cvtUTF8(do_GetService(NS_UTF8CONVERTERSERVICE_CONTRACTID, &rv)); + nsAutoCString utf8Text; + if (NS_SUCCEEDED(rv)) { + // skip ASCIIness/UTF8ness test if aCharset is 7bit non-ascii charset. + rv = cvtUTF8->ConvertStringToUTF8(nsDependentCString(decodedText), + aCharset, + IS_7BIT_NON_ASCII_CHARSET(aCharset), + true, 1, utf8Text); + } + PR_Free(decodedText); + if (NS_FAILED(rv)) { + return rv; + } + aResult.Append(utf8Text); + + return NS_OK; +} + static const char especials[] = "()<>@,;:\\\"/[]?.="; // |decode_mime_part2_str| taken from comi18n.c @@ -1103,14 +1140,13 @@ nsresult DecodeRFC2047Str(const char *aHeader, const char *aDefaultCharset, bool aOverrideCharset, nsACString &aResult) { const char *p, *q = nullptr, *r; - char *decodedText; const char *begin; // tracking pointer for where we are in the input buffer int32_t isLastEncodedWord = 0; const char *charsetStart, *charsetEnd; - char charset[80]; - - // initialize charset name to an empty string - charset[0] = '\0'; + nsAutoCString prevCharset, curCharset; + nsAutoCString encodedText; + char prevEncoding = '\0', curEncoding; + nsresult rv; begin = aHeader; @@ -1155,15 +1191,9 @@ nsresult DecodeRFC2047Str(const char *aHeader, const char *aDefaultCharset, charsetEnd = q; } - // Check for too-long charset name - if (uint32_t(charsetEnd - charsetStart) >= sizeof(charset)) - goto badsyntax; - - memcpy(charset, charsetStart, charsetEnd - charsetStart); - charset[charsetEnd - charsetStart] = 0; - q++; - if (*q != 'Q' && *q != 'q' && *q != 'B' && *q != 'b') + curEncoding = nsCRT::ToUpper(*q); + if (curEncoding != 'Q' && curEncoding != 'B') goto badsyntax; if (q[1] != '?') @@ -1182,55 +1212,88 @@ nsresult DecodeRFC2047Str(const char *aHeader, const char *aDefaultCharset, continue; } - if(*q == 'Q' || *q == 'q') - decodedText = DecodeQ(q + 2, r - (q + 2)); - else { + curCharset.Assign(charsetStart, charsetEnd - charsetStart); + // Override charset if requested. Never override labeled UTF-8. + // Use default charset instead of UNKNOWN-8BIT + if ((aOverrideCharset && 0 != nsCRT::strcasecmp(curCharset.get(), "UTF-8")) + || (aDefaultCharset && 0 == nsCRT::strcasecmp(curCharset.get(), "UNKNOWN-8BIT")) + ) { + curCharset = aDefaultCharset; + } + + const char *R; + R = r; + if (curEncoding == 'B') { // bug 227290. ignore an extraneous '=' at the end. // (# of characters in B-encoded part has to be a multiple of 4) int32_t n = r - (q + 2); - n -= (n % 4 == 1 && !PL_strncmp(r - 3, "===", 3)) ? 1 : 0; - decodedText = PL_Base64Decode(q + 2, n, nullptr); + R -= (n % 4 == 1 && !PL_strncmp(r - 3, "===", 3)) ? 1 : 0; + } + // Bug 493544. Don't decode the encoded text until it ends + if (R[-1] != '=' + && (prevCharset.IsEmpty() + || (curCharset == prevCharset && curEncoding == prevEncoding)) + ) { + encodedText.Append(q + 2, R - (q + 2)); + prevCharset = curCharset; + prevEncoding = curEncoding; + + begin = r + 2; + isLastEncodedWord = 1; + continue; } - if (decodedText == nullptr) - goto badsyntax; - - // Override charset if requested. Never override labeled UTF-8. - // Use default charset instead of UNKNOWN-8BIT - if ((aOverrideCharset && 0 != nsCRT::strcasecmp(charset, "UTF-8")) || - (aDefaultCharset && 0 == nsCRT::strcasecmp(charset, "UNKNOWN-8BIT"))) { - PL_strncpy(charset, aDefaultCharset, sizeof(charset) - 1); - charset[sizeof(charset) - 1] = '\0'; + bool bDecoded; // If the current line has been decoded. + bDecoded = false; + if (!encodedText.IsEmpty()) { + if (curCharset == prevCharset && curEncoding == prevEncoding) { + encodedText.Append(q + 2, R - (q + 2)); + bDecoded = true; + } + rv = DecodeQOrBase64Str(encodedText.get(), encodedText.Length(), + prevEncoding, prevCharset.get(), aResult); + if (NS_FAILED(rv)) { + aResult.Append(encodedText); + } + encodedText.Truncate(); + prevCharset.Truncate(); } - - { - nsCOMPtr<nsIUTF8ConverterService> - cvtUTF8(do_GetService(NS_UTF8CONVERTERSERVICE_CONTRACTID)); - nsAutoCString utf8Text; - // skip ASCIIness/UTF8ness test if aCharset is 7bit non-ascii charset. - if (cvtUTF8 && - NS_SUCCEEDED( - cvtUTF8->ConvertStringToUTF8(nsDependentCString(decodedText), - charset, - IS_7BIT_NON_ASCII_CHARSET(charset), - true, 1, utf8Text))) { - aResult.Append(utf8Text); - } else { - aResult.Append(REPLACEMENT_CHAR); + if (!bDecoded) { + rv = DecodeQOrBase64Str(q + 2, R - (q + 2), curEncoding, + curCharset.get(), aResult); + if (NS_FAILED(rv)) { + aResult.Append(encodedText); } } - PR_Free(decodedText); + begin = r + 2; isLastEncodedWord = 1; continue; badsyntax: + if (!encodedText.IsEmpty()) { + rv = DecodeQOrBase64Str(encodedText.get(), encodedText.Length(), + prevEncoding, prevCharset.get(), aResult); + if (NS_FAILED(rv)) { + aResult.Append(encodedText); + } + encodedText.Truncate(); + prevCharset.Truncate(); + } // copy the part before the encoded-word aResult.Append(begin, p - begin); begin = p; isLastEncodedWord = 0; } + if (!encodedText.IsEmpty()) { + rv = DecodeQOrBase64Str(encodedText.get(), encodedText.Length(), + prevEncoding, prevCharset.get(), aResult); + if (NS_FAILED(rv)) { + aResult.Append(encodedText); + } + } + // put the tail back CopyRawHeader(begin, strlen(begin), aDefaultCharset, aResult); From cb1444bc4cf3bd653eb30bb075bc2d41cc493a4e Mon Sep 17 00:00:00 2001 From: Mark Banner <bugzilla@standard8.plus.com> Date: Sat, 22 Dec 2012 08:59:22 +0000 Subject: [PATCH 062/469] Bug 823932 Change leaksoup.cpp to use nsAutoTArray rather than nsAutoVoidArray. r=dbaron --- tools/trace-malloc/leaksoup.cpp | 55 ++++++++++++++++----------------- 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/tools/trace-malloc/leaksoup.cpp b/tools/trace-malloc/leaksoup.cpp index 7d3f21196d36..d42aeefef2d6 100644 --- a/tools/trace-malloc/leaksoup.cpp +++ b/tools/trace-malloc/leaksoup.cpp @@ -7,10 +7,12 @@ #include <stdio.h> #include "plhash.h" -#include "nsVoidArray.h" +#include "nsTArray.h" #include "nsQuickSort.h" #include "nsXPCOM.h" +const uint32_t kPointersDefaultSize = 8; + /* * Read in an allocation dump, presumably one taken at shutdown (using * the --shutdown-leaks=file option, which must be used along with @@ -25,10 +27,10 @@ struct AllocationNode { // Other |AllocationNode| objects whose memory has a pointer to // this object. - nsAutoVoidArray pointers_to; + nsAutoTArray<AllocationNode*, kPointersDefaultSize> pointers_to; // The reverse. - nsAutoVoidArray pointers_from; + nsAutoTArray<AllocationNode*, kPointersDefaultSize> pointers_from; // Early on in the algorithm, the pre-order index from a DFS. // Later on, set to the index of the strongly connected component to @@ -165,7 +167,7 @@ int main(int argc, char **argv) // |pointers_to|) and assign the post-order index to |index|. { uint32_t dfs_index = 0; - nsVoidArray stack; + nsTArray<AllocationNode*> stack; for (AllocationNode *n = nodes, *n_end = nodes+count; n != n_end; ++n) { if (n->reached) { @@ -174,9 +176,8 @@ int main(int argc, char **argv) stack.AppendElement(n); do { - uint32_t pos = stack.Count() - 1; - AllocationNode *n = - static_cast<AllocationNode*>(stack[pos]); + uint32_t pos = stack.Length() - 1; + AllocationNode *n = stack[pos]; if (n->reached) { n->index = dfs_index++; stack.RemoveElementAt(pos); @@ -185,14 +186,14 @@ int main(int argc, char **argv) // When doing post-order processing, we have to be // careful not to put reached nodes into the stack. - nsVoidArray &pt = n->pointers_to; - for (int32_t i = pt.Count() - 1; i >= 0; --i) { - if (!static_cast<AllocationNode*>(pt[i])->reached) { - stack.AppendElement(pt[i]); + for (int32_t i = n->pointers_to.Length() - 1; i >= 0; --i) { + AllocationNode* e = n->pointers_to[i]; + if (!e->reached) { + stack.AppendElement(e); } } } - } while (stack.Count() > 0); + } while (stack.Length() > 0); } } @@ -218,7 +219,7 @@ int main(int argc, char **argv) for (size_t i = 0; i < count; ++i) { nodes[i].reached = false; } - nsVoidArray stack; + nsTArray<AllocationNode*> stack; for (AllocationNode **sn = sorted_nodes, **sn_end = sorted_nodes + count; sn != sn_end; ++sn) { if ((*sn)->reached) { @@ -228,9 +229,8 @@ int main(int argc, char **argv) // We found a new strongly connected index. stack.AppendElement(*sn); do { - uint32_t pos = stack.Count() - 1; - AllocationNode *n = - static_cast<AllocationNode*>(stack[pos]); + uint32_t pos = stack.Length() - 1; + AllocationNode *n = stack[pos]; stack.RemoveElementAt(pos); if (!n->reached) { @@ -238,7 +238,7 @@ int main(int argc, char **argv) n->index = num_sccs; stack.AppendElements(n->pointers_from); } - } while (stack.Count() > 0); + } while (stack.Length() > 0); ++num_sccs; } } @@ -251,7 +251,7 @@ int main(int argc, char **argv) nodes[i].is_root = true; } - nsVoidArray stack; + nsTArray<AllocationNode*> stack; for (AllocationNode *n = nodes, *n_end = nodes+count; n != n_end; ++n) { if (!n->is_root) { continue; @@ -259,18 +259,16 @@ int main(int argc, char **argv) // Loop through pointers_to, and add any that are in a // different SCC to stack: - for (int i = n->pointers_to.Count() - 1; i >= 0; --i) { - AllocationNode *target = - static_cast<AllocationNode*>(n->pointers_to[i]); + for (int i = n->pointers_to.Length() - 1; i >= 0; --i) { + AllocationNode *target = n->pointers_to[i]; if (n->index != target->index) { stack.AppendElement(target); } } - while (stack.Count() > 0) { - uint32_t pos = stack.Count() - 1; - AllocationNode *n = - static_cast<AllocationNode*>(stack[pos]); + while (stack.Length() > 0) { + uint32_t pos = stack.Length() - 1; + AllocationNode *n = stack[pos]; stack.RemoveElementAt(pos); if (n->is_root) { @@ -368,12 +366,11 @@ int main(int argc, char **argv) } } - if (n->pointers_from.Count()) { + if (n->pointers_from.Length()) { printf("\nPointers from:\n"); - for (uint32_t i = 0, i_end = n->pointers_from.Count(); + for (uint32_t i = 0, i_end = n->pointers_from.Length(); i != i_end; ++i) { - AllocationNode *t = static_cast<AllocationNode*> - (n->pointers_from[i]); + AllocationNode *t = n->pointers_from[i]; const ADLog::Entry *te = t->entry; printf(" <a href=\"#o%d\">%s</a> (Object %d, ", t - nodes, te->type, t - nodes); From 0527db678b4db6ebb1e90fec02d4d306c744e333 Mon Sep 17 00:00:00 2001 From: Mark Banner <bugzilla@standard8.plus.com> Date: Sat, 22 Dec 2012 09:00:15 +0000 Subject: [PATCH 063/469] Bug 823940 Remove unused nsAutoVoidArray, and cleanup nsVoidArray's support for it. r=bsmedberg. --- xpcom/glue/nsVoidArray.cpp | 64 ++++++-------------------------------- xpcom/glue/nsVoidArray.h | 50 +++-------------------------- 2 files changed, 13 insertions(+), 101 deletions(-) diff --git a/xpcom/glue/nsVoidArray.cpp b/xpcom/glue/nsVoidArray.cpp index d1287c5f0ef7..3c2342be0d85 100644 --- a/xpcom/glue/nsVoidArray.cpp +++ b/xpcom/glue/nsVoidArray.cpp @@ -107,16 +107,13 @@ VoidStats gVoidStats; #endif void -nsVoidArray::SetArray(Impl *newImpl, int32_t aSize, int32_t aCount, - bool aOwner, bool aHasAuto) +nsVoidArray::SetArray(Impl *newImpl, int32_t aSize, int32_t aCount) { // old mImpl has been realloced and so we don't free/delete it NS_PRECONDITION(newImpl, "can't set size"); mImpl = newImpl; mImpl->mCount = aCount; - mImpl->mBits = static_cast<uint32_t>(aSize & kArraySizeMask) | - (aOwner ? kArrayOwnerMask : 0) | - (aHasAuto ? kArrayHasAutoBufferMask : 0); + mImpl->mSize = aSize; } // This does all allocation/reallocation of the array. @@ -125,8 +122,6 @@ nsVoidArray::SetArray(Impl *newImpl, int32_t aSize, int32_t aCount, bool nsVoidArray::SizeTo(int32_t aSize) { uint32_t oldsize = GetArraySize(); - bool isOwner = IsArrayOwner(); - bool hasAuto = HasAutoBuffer(); if (aSize == (int32_t) oldsize) return true; // no change @@ -136,25 +131,13 @@ bool nsVoidArray::SizeTo(int32_t aSize) // free the array if allocated if (mImpl) { - if (isOwner) - { - free(reinterpret_cast<char *>(mImpl)); - if (hasAuto) { - static_cast<nsAutoVoidArray*>(this)->ResetToAutoBuffer(); - } - else { - mImpl = nullptr; - } - } - else - { - mImpl->mCount = 0; // nsAutoVoidArray - } + free(reinterpret_cast<char *>(mImpl)); + mImpl = nullptr; } return true; } - if (mImpl && isOwner) + if (mImpl) { // We currently own an array impl. Resize it appropriately. if (aSize < mImpl->mCount) @@ -185,7 +168,7 @@ bool nsVoidArray::SizeTo(int32_t aSize) } } #endif - SetArray(newImpl, aSize, newImpl->mCount, true, hasAuto); + SetArray(newImpl, aSize, newImpl->mCount); return true; } @@ -225,7 +208,7 @@ bool nsVoidArray::SizeTo(int32_t aSize) mImpl->mCount * sizeof(mImpl->mArray[0])); } - SetArray(newImpl, aSize, mImpl ? mImpl->mCount : 0, true, hasAuto); + SetArray(newImpl, aSize, mImpl ? mImpl->mCount : 0); // no memset; handled later in ReplaceElementAt if needed return true; } @@ -340,7 +323,7 @@ nsVoidArray& nsVoidArray::operator=(const nsVoidArray& other) nsVoidArray::~nsVoidArray() { MOZ_COUNT_DTOR(nsVoidArray); - if (mImpl && IsArrayOwner()) + if (mImpl) free(reinterpret_cast<char*>(mImpl)); } @@ -623,12 +606,6 @@ void nsVoidArray::Clear() if (mImpl) { mImpl->mCount = 0; - // We don't have to free on Clear, but if we have a built-in buffer, - // it's worth considering. - if (HasAutoBuffer() && IsArrayOwner() && - GetArraySize() > kAutoClearCompactSizeFactor * kAutoBufSize) { - SizeTo(0); - } } } @@ -639,15 +616,7 @@ void nsVoidArray::Compact() // XXX NOTE: this is quite inefficient in many cases if we're only // compacting by a little, but some callers care more about memory use. int32_t count = Count(); - if (HasAutoBuffer() && count <= kAutoBufSize) - { - Impl* oldImpl = mImpl; - static_cast<nsAutoVoidArray*>(this)->ResetToAutoBuffer(); - memcpy(mImpl->mArray, oldImpl->mArray, - count * sizeof(mImpl->mArray[0])); - free(reinterpret_cast<char *>(oldImpl)); - } - else if (GetArraySize() > count) + if (GetArraySize() > count) { SizeTo(Count()); } @@ -758,21 +727,6 @@ nsVoidArray::SizeOfExcludingThis( return n; } -//---------------------------------------------------------------- -// nsAutoVoidArray - -nsAutoVoidArray::nsAutoVoidArray() - : nsVoidArray() -{ - // Don't need to clear it. Some users just call ReplaceElementAt(), - // but we'll clear it at that time if needed to save CPU cycles. -#if DEBUG_VOIDARRAY - mIsAuto = true; - ADD_TO_STATS(MaxAuto,0); -#endif - ResetToAutoBuffer(); -} - //---------------------------------------------------------------------- // NOTE: nsSmallVoidArray elements MUST all have the low bit as 0. // This means that normally it's only used for pointers, and in particular diff --git a/xpcom/glue/nsVoidArray.h b/xpcom/glue/nsVoidArray.h index c34aaaa0ae23..672f051d9fec 100644 --- a/xpcom/glue/nsVoidArray.h +++ b/xpcom/glue/nsVoidArray.h @@ -40,7 +40,7 @@ public: bool SetCount(int32_t aNewCount); // returns the max number that can be held without allocating inline int32_t GetArraySize() const { - return mImpl ? (int32_t(mImpl->mBits) & kArraySizeMask) : 0; + return mImpl ? mImpl->mSize : 0; } void* FastElementAt(int32_t aIndex) const @@ -118,12 +118,9 @@ protected: struct Impl { /** - * Packed bits. The low 30 bits are the array's size. - * The two highest bits indicate whether or not we "own" mImpl and - * must free() it when destroyed, and whether we have a preallocated - * nsAutoVoidArray buffer. + * The actual array size. */ - uint32_t mBits; + int32_t mSize; /** * The number of elements in the array @@ -143,53 +140,14 @@ protected: bool mIsAuto; #endif - enum { - kArrayOwnerMask = 1 << 31, - kArrayHasAutoBufferMask = 1 << 30, - kArraySizeMask = ~(kArrayOwnerMask | kArrayHasAutoBufferMask) - }; - enum { kAutoBufSize = 8 }; - - // bit twiddlers - void SetArray(Impl *newImpl, int32_t aSize, int32_t aCount, bool aOwner, - bool aHasAuto); - inline bool IsArrayOwner() const { - return mImpl && (mImpl->mBits & kArrayOwnerMask); - } - inline bool HasAutoBuffer() const { - return mImpl && (mImpl->mBits & kArrayHasAutoBufferMask); - } + void SetArray(Impl *newImpl, int32_t aSize, int32_t aCount); private: /// Copy constructors are not allowed nsVoidArray(const nsVoidArray& other); }; - -// A zero-based array with a bit of automatic internal storage -class NS_COM_GLUE nsAutoVoidArray : public nsVoidArray { -public: - nsAutoVoidArray(); - - void ResetToAutoBuffer() - { - SetArray(reinterpret_cast<Impl*>(mAutoBuf), kAutoBufSize, 0, false, - true); - } - - nsAutoVoidArray& operator=(const nsVoidArray& other) - { - nsVoidArray::operator=(other); - return *this; - } - -protected: - // The internal storage - char mAutoBuf[sizeof(Impl) + (kAutoBufSize - 1) * sizeof(void*)]; -}; - - //=================================================================== // nsSmallVoidArray is not a general-purpose replacement for // ns(Auto)VoidArray because there is (some) extra CPU overhead for arrays From a76332437fdb3d9b94af066c9a2e68ebb4edba96 Mon Sep 17 00:00:00 2001 From: Jonathan Kew <jfkthame@gmail.com> Date: Sat, 22 Dec 2012 10:07:00 +0000 Subject: [PATCH 064/469] Bug 823964 - Wrong bounds for scaled images. r=longsonr --- content/svg/content/test/bbox-helper.svg | 1 + content/svg/content/test/bounds-helper.svg | 1 + content/svg/content/test/test_bbox.xhtml | 1 + content/svg/content/test/test_bounds.html | 7 +++++++ layout/svg/nsSVGImageFrame.cpp | 4 +++- 5 files changed, 13 insertions(+), 1 deletion(-) diff --git a/content/svg/content/test/bbox-helper.svg b/content/svg/content/test/bbox-helper.svg index 470aa25e1660..6aa2798129e0 100644 --- a/content/svg/content/test/bbox-helper.svg +++ b/content/svg/content/test/bbox-helper.svg @@ -2,6 +2,7 @@ <svg xmlns="http://www.w3.org/2000/svg"> <g transform="scale(0.5)"> <foreignObject id="fO" x="10" y="10" width="100" height="100"/> + <image id="i" x="10" y="10" width="100" height="100"/> </g> <text id="b" x="20" y="20">b</text> <text id="a" x="20" y="30">a</text> diff --git a/content/svg/content/test/bounds-helper.svg b/content/svg/content/test/bounds-helper.svg index 1364c105db02..599918dbf998 100644 --- a/content/svg/content/test/bounds-helper.svg +++ b/content/svg/content/test/bounds-helper.svg @@ -21,6 +21,7 @@ text { font: 20px monospace; } <rect id="rect3" x="25" y="80" width="50" height="50" fill="green"/> <rect id="rect3a" x="25" y="80" width="50" height="50" fill="none" stroke-width="4" stroke="blue"/> <rect id="rect3b" vector-effect="non-scaling-stroke" x="100" y="100" width="25" height="25" fill="orange" stroke-width="4" stroke="yellow"/> + <image id="i" x="10" y="10" width="100" height="100"/> </g> <g transform="scale(2) rotate(45 175 75)"> <rect id="rect4" x="150" y="50" width="50" height="50" fill="yellow"/> diff --git a/content/svg/content/test/test_bbox.xhtml b/content/svg/content/test/test_bbox.xhtml index e7dd5c7e5e55..e19b94e88c46 100644 --- a/content/svg/content/test/test_bbox.xhtml +++ b/content/svg/content/test/test_bbox.xhtml @@ -48,6 +48,7 @@ function run() } checkBBox("fO", 10, 10, 100, 100); + checkBBox("i", 10, 10, 100, 100); compareBBoxHeight("a", "b"); compareBBoxHeight("a", "y"); compareBBox("b", "tspan"); diff --git a/content/svg/content/test/test_bounds.html b/content/svg/content/test/test_bounds.html index aee5582d859c..a742f4b6890c 100644 --- a/content/svg/content/test/test_bounds.html +++ b/content/svg/content/test/test_bounds.html @@ -134,6 +134,13 @@ function runTest() is(text2aBounds.left, text1aBounds.left + 100 - 3, "text2a.getBoundingClientRect().left"); is(text2aBounds.width, text1aBounds.width + 6, "text2a.getBoundingClientRect().width"); + var i = doc.getElementById("i"); + var iBounds = i.getBoundingClientRect(); + is(iBounds.left, 20, "i.getBoundingClientRect().left"); + is(iBounds.top, 20, "i.getBoundingClientRect().top"); + is(iBounds.width, 200, "i.getBoundingClientRect().width"); + is(iBounds.height, 200, "i.getBoundingClientRect().height"); + SimpleTest.finish(); } diff --git a/layout/svg/nsSVGImageFrame.cpp b/layout/svg/nsSVGImageFrame.cpp index 2ebcf3296483..d2eb7dac9b7c 100644 --- a/layout/svg/nsSVGImageFrame.cpp +++ b/layout/svg/nsSVGImageFrame.cpp @@ -485,8 +485,10 @@ nsSVGImageFrame::ReflowSVG() gfxMatrix scaling; if (applyScaling) { scaling.Scale(scaleFactors.width, scaleFactors.height); - } + } + tmpCtx.Save(); GeneratePath(&tmpCtx, scaling); + tmpCtx.Restore(); gfxRect extent = tmpCtx.GetUserPathExtent(); if (applyScaling) { extent.Scale(1 / scaleFactors.width, 1 / scaleFactors.height); From 83166588ed6f04b9ca722543505109e575e07682 Mon Sep 17 00:00:00 2001 From: Jason Duell <jduell.mcbugs@gmail.com> Date: Sat, 22 Dec 2012 03:53:04 -0800 Subject: [PATCH 065/469] Bug 821160 - remove accidentally commited .orig/.rej files r=jduell DONTBUILD --- .../froyo/stagefright/DataSource.h.orig | 83 ------------------- .../froyo/stagefright/DataSource.h.rej | 24 ------ 2 files changed, 107 deletions(-) delete mode 100644 media/omx-plugin/include/froyo/stagefright/DataSource.h.orig delete mode 100644 media/omx-plugin/include/froyo/stagefright/DataSource.h.rej diff --git a/media/omx-plugin/include/froyo/stagefright/DataSource.h.orig b/media/omx-plugin/include/froyo/stagefright/DataSource.h.orig deleted file mode 100644 index 6f7dc38c3cc1..000000000000 --- a/media/omx-plugin/include/froyo/stagefright/DataSource.h.orig +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef DATA_SOURCE_H_ - -#define DATA_SOURCE_H_ - -#include <sys/types.h> - -#include <utils/Errors.h> -#include <utils/KeyedVector.h> -#include <utils/List.h> -#include <utils/RefBase.h> -#include <utils/threads.h> - -namespace android { - -class String8; - -class DataSource : public RefBase { -public: - enum Flags { - kWantsPrefetching = 1, - kStreamedFromLocalHost = 2, - }; - - static sp<DataSource> CreateFromURI( - const char *uri, - const KeyedVector<String8, String8> *headers = NULL); - - DataSource() {} - - virtual status_t initCheck() const = 0; - - virtual ssize_t readAt(off_t offset, void *data, size_t size) = 0; - - // Convenience methods: - bool getUInt16(off_t offset, uint16_t *x); - - // May return ERROR_UNSUPPORTED. - virtual status_t getSize(off_t *size); - - virtual uint32_t flags() { - return 0; - } - - //////////////////////////////////////////////////////////////////////////// - - bool sniff(String8 *mimeType, float *confidence); - - typedef bool (*SnifferFunc)( - const sp<DataSource> &source, String8 *mimeType, float *confidence); - - static void RegisterSniffer(SnifferFunc func); - static void RegisterDefaultSniffers(); - -protected: - virtual ~DataSource() {} - -private: - static Mutex gSnifferMutex; - static List<SnifferFunc> gSniffers; - - DataSource(const DataSource &); - DataSource &operator=(const DataSource &); -}; - -} // namespace android - -#endif // DATA_SOURCE_H_ diff --git a/media/omx-plugin/include/froyo/stagefright/DataSource.h.rej b/media/omx-plugin/include/froyo/stagefright/DataSource.h.rej deleted file mode 100644 index 7c00d2dbb10c..000000000000 --- a/media/omx-plugin/include/froyo/stagefright/DataSource.h.rej +++ /dev/null @@ -1,24 +0,0 @@ ---- stagefright/DataSource.h -+++ stagefright/DataSource.h -@@ -26,12 +26,20 @@ - #include <utils/RefBase.h> - #include <utils/threads.h> - -+#if !defined(STAGEFRIGHT_EXPORT) -+#define STAGEFRIGHT_EXPORT -+#endif -+ -+#if !defined(MOZ_STAGEFRIGHT_OFF_T) -+#define MOZ_STAGEFRIGHT_OFF_T off64_t -+#endif -+ - namespace android { - - struct AMessage; - class String8; - --class DataSource : public RefBase { -+class STAGEFRIGHT_EXPORT DataSource : public RefBase { - public: - enum Flags { - kWantsPrefetching = 1, From d3be2bc9c404f0a17fb2b2da3bd80425db7f4d5f Mon Sep 17 00:00:00 2001 From: Georg Fritzsche <georg.fritzsche@googlemail.com> Date: Thu, 20 Dec 2012 21:30:19 +0100 Subject: [PATCH 066/469] Bug 823533 - Reject plugins with a different architecture in 32bit Mac builds. r=bsmedberg,smichaud --- dom/plugins/base/nsPluginsDirDarwin.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/dom/plugins/base/nsPluginsDirDarwin.cpp b/dom/plugins/base/nsPluginsDirDarwin.cpp index 494874441d6e..4fe5e38e5470 100644 --- a/dom/plugins/base/nsPluginsDirDarwin.cpp +++ b/dom/plugins/base/nsPluginsDirDarwin.cpp @@ -380,10 +380,15 @@ static bool IsCompatibleArch(nsIFile *file) return false; } - uint32_t containerArchitectures = mozilla::ipc::GeckoChildProcessHost::GetSupportedArchitecturesForProcessType(GeckoProcessType_Plugin); + uint32_t supportedArchitectures = +#ifdef __LP64__ + mozilla::ipc::GeckoChildProcessHost::GetSupportedArchitecturesForProcessType(GeckoProcessType_Plugin); +#else + base::GetCurrentProcessArchitecture(); +#endif // Consider the plugin architecture valid if there is any overlap in the masks. - isPluginFile = !!(containerArchitectures & pluginLibArchitectures); + isPluginFile = !!(supportedArchitectures & pluginLibArchitectures); } ::CFRelease(pluginBundle); } From 8658387d975c9e411794dd81d13aaadfc796bc4d Mon Sep 17 00:00:00 2001 From: Josh Matthews <josh@joshmatthews.net> Date: Fri, 7 Dec 2012 17:12:02 -0500 Subject: [PATCH 067/469] Bug 815523. patches stolen from 782542 Parts 1,2,3: Necko IPC security pref, and disable for xpcshell tests, r=ted,jdm --- modules/libpref/src/init/all.js | 3 +++ netwerk/ipc/NeckoChild.cpp | 5 +++++ netwerk/ipc/NeckoParent.cpp | 5 +++++ testing/xpcshell/head.js | 39 +++++++++++++++++++-------------- 4 files changed, 35 insertions(+), 17 deletions(-) diff --git a/modules/libpref/src/init/all.js b/modules/libpref/src/init/all.js index f3680aa1e1cf..cd6f4a10a1ff 100644 --- a/modules/libpref/src/init/all.js +++ b/modules/libpref/src/init/all.js @@ -773,6 +773,9 @@ pref("security.fileuri.strict_origin_policy", true); // the results pref("network.allow-experiments", true); +// Turn off interprocess security checks. Needed to run xpcshell tests. +pref("network.disable.ipc.security", false); + // Default action for unlisted external protocol handlers pref("network.protocol-handler.external-default", true); // OK to load pref("network.protocol-handler.warn-external-default", true); // warn before load diff --git a/netwerk/ipc/NeckoChild.cpp b/netwerk/ipc/NeckoChild.cpp index d47242928604..74fcc5a0ee4b 100644 --- a/netwerk/ipc/NeckoChild.cpp +++ b/netwerk/ipc/NeckoChild.cpp @@ -14,17 +14,22 @@ #include "mozilla/net/FTPChannelChild.h" #include "mozilla/net/WebSocketChannelChild.h" #include "mozilla/dom/network/TCPSocketChild.h" +#include "mozilla/Preferences.h" using mozilla::dom::TCPSocketChild; namespace mozilla { namespace net { +static bool gDisableIPCSecurity = false; +static const char kPrefDisableIPCSecurity[] = "network.disable.ipc.security"; + PNeckoChild *gNeckoChild = nullptr; // C++ file contents NeckoChild::NeckoChild() { + Preferences::AddBoolVarCache(&gDisableIPCSecurity, kPrefDisableIPCSecurity); } NeckoChild::~NeckoChild() diff --git a/netwerk/ipc/NeckoParent.cpp b/netwerk/ipc/NeckoParent.cpp index ae43859f493c..e62d5b9a702b 100644 --- a/netwerk/ipc/NeckoParent.cpp +++ b/netwerk/ipc/NeckoParent.cpp @@ -14,6 +14,7 @@ #include "mozilla/net/WebSocketChannelParent.h" #include "mozilla/dom/TabParent.h" #include "mozilla/dom/network/TCPSocketParent.h" +#include "mozilla/Preferences.h" #include "nsHTMLDNSPrefetch.h" @@ -24,9 +25,13 @@ using mozilla::dom::TCPSocketParent; namespace mozilla { namespace net { +static bool gDisableIPCSecurity = false; +static const char kPrefDisableIPCSecurity[] = "network.disable.ipc.security"; + // C++ file contents NeckoParent::NeckoParent() { + Preferences::AddBoolVarCache(&gDisableIPCSecurity, kPrefDisableIPCSecurity); } NeckoParent::~NeckoParent() diff --git a/testing/xpcshell/head.js b/testing/xpcshell/head.js index c7885111e920..016e3dd6cf66 100644 --- a/testing/xpcshell/head.js +++ b/testing/xpcshell/head.js @@ -36,16 +36,27 @@ let (ios = Components.classes["@mozilla.org/network/io-service;1"] ios.offline = false; } -// Disable IPv6 lookups for 'localhost' on windows. +// Determine if we're running on parent or child +let runningInParent = true; try { - if ("@mozilla.org/windows-registry-key;1" in Components.classes) { - let processType = Components.classes["@mozilla.org/xre/runtime;1"]. - getService(Components.interfaces.nsIXULRuntime).processType; - if (processType == Components.interfaces.nsIXULRuntime.PROCESS_TYPE_DEFAULT) { - let (prefs = Components.classes["@mozilla.org/preferences-service;1"] - .getService(Components.interfaces.nsIPrefBranch)) { - prefs.setCharPref("network.dns.ipv4OnlyDomains", "localhost"); - } + runningInParent = Components.classes["@mozilla.org/xre/runtime;1"]. + getService(Components.interfaces.nsIXULRuntime).processType + == Components.interfaces.nsIXULRuntime.PROCESS_TYPE_DEFAULT; +} +catch (e) { } + +try { + if (runningInParent) { + let prefs = Components.classes["@mozilla.org/preferences-service;1"] + .getService(Components.interfaces.nsIPrefBranch); + + // disable necko IPC security checks for xpcshell, as they lack the + // docshells needed to pass them + prefs.setBoolPref("network.disable.ipc.security", true); + + // Disable IPv6 lookups for 'localhost' on windows. + if ("@mozilla.org/windows-registry-key;1" in Components.classes) { + prefs.setCharPref("network.dns.ipv4OnlyDomains", "localhost"); } } } @@ -57,9 +68,7 @@ catch (e) { } // Note that if we're in a child process, we don't want to init the // crashreporter component. try { // nsIXULRuntime is not available in some configurations. - let processType = Components.classes["@mozilla.org/xre/runtime;1"]. - getService(Components.interfaces.nsIXULRuntime).processType; - if (processType == Components.interfaces.nsIXULRuntime.PROCESS_TYPE_DEFAULT && + if (runningInParent && "@mozilla.org/toolkit/crash-reporter;1" in Components.classes) { // Remember to update </toolkit/crashreporter/test/unit/test_crashreporter.js> // too if you change this initial setting. @@ -800,11 +809,7 @@ function do_get_profile() { function do_load_child_test_harness() { // Make sure this isn't called from child process - var runtime = Components.classes["@mozilla.org/xre/app-info;1"] - .getService(Components.interfaces.nsIXULRuntime); - if (runtime.processType != - Components.interfaces.nsIXULRuntime.PROCESS_TYPE_DEFAULT) - { + if (!runningInParent) { do_throw("run_test_in_child cannot be called from child!"); } From 1403709ff411396eb2d9aaff61c7fc16ef2a59e6 Mon Sep 17 00:00:00 2001 From: Jason Duell <jduell.mcbugs@gmail.com> Date: Sat, 22 Dec 2012 05:56:21 -0800 Subject: [PATCH 068/469] Bug 815523 - Remote the app: and jar: protocols. r=fabrice,mwu,jdm --- dom/apps/src/AppsService.js | 10 + dom/apps/src/AppsServiceChild.jsm | 9 + dom/apps/src/AppsUtils.jsm | 2 + dom/apps/src/Webapps.jsm | 25 +- dom/interfaces/apps/mozIApplication.idl | 10 +- dom/interfaces/apps/nsIAppsService.idl | 12 +- modules/libjar/nsIZipReader.idl | 7 +- modules/libjar/nsJAR.cpp | 21 + modules/libjar/nsJARChannel.cpp | 94 ++- modules/libjar/nsJARChannel.h | 4 + modules/libjar/test/unit/head_ipc.js | 17 + modules/libjar/test/unit/test_jarchannel.js | 197 +++--- .../libjar/test/unit/test_jarchannel_e10s.js | 7 + modules/libjar/test/unit/xpcshell.ini | 4 +- netwerk/ipc/Makefile.in | 9 + netwerk/ipc/NeckoChild.cpp | 18 + netwerk/ipc/NeckoChild.h | 3 + netwerk/ipc/NeckoParent.cpp | 129 ++++ netwerk/ipc/NeckoParent.h | 8 + netwerk/ipc/PNecko.ipdl | 4 + netwerk/ipc/PRemoteOpenFile.ipdl | 35 + netwerk/ipc/RemoteOpenFileChild.cpp | 644 ++++++++++++++++++ netwerk/ipc/RemoteOpenFileChild.h | 86 +++ netwerk/ipc/RemoteOpenFileParent.cpp | 69 ++ netwerk/ipc/RemoteOpenFileParent.h | 38 ++ netwerk/ipc/ipdl.mk | 1 + netwerk/ipc/nsIRemoteOpenFileListener.idl | 30 + netwerk/protocol/app/AppProtocolHandler.js | 26 +- 28 files changed, 1398 insertions(+), 121 deletions(-) create mode 100644 modules/libjar/test/unit/head_ipc.js create mode 100644 modules/libjar/test/unit/test_jarchannel_e10s.js create mode 100644 netwerk/ipc/PRemoteOpenFile.ipdl create mode 100644 netwerk/ipc/RemoteOpenFileChild.cpp create mode 100644 netwerk/ipc/RemoteOpenFileChild.h create mode 100644 netwerk/ipc/RemoteOpenFileParent.cpp create mode 100644 netwerk/ipc/RemoteOpenFileParent.h create mode 100644 netwerk/ipc/nsIRemoteOpenFileListener.idl diff --git a/dom/apps/src/AppsService.js b/dom/apps/src/AppsService.js index 2baacb1c2fe4..bc6f2863c9b3 100644 --- a/dom/apps/src/AppsService.js +++ b/dom/apps/src/AppsService.js @@ -58,6 +58,16 @@ AppsService.prototype = { return DOMApplicationRegistry.getAppFromObserverMessage(aMessage); }, + getCoreAppsBasePath: function getCoreAppsBasePath() { + debug("getCoreAppsBasePath()"); + return DOMApplicationRegistry.getCoreAppsBasePath(); + }, + + getWebAppsBasePath: function getWebAppsBasePath() { + debug("getWebAppsBasePath()"); + return DOMApplicationRegistry.getWebAppsBasePath(); + }, + classID : APPS_SERVICE_CID, QueryInterface : XPCOMUtils.generateQI([Ci.nsIAppsService]) } diff --git a/dom/apps/src/AppsServiceChild.jsm b/dom/apps/src/AppsServiceChild.jsm index 950c83acfbe0..7cbf4a56b1f5 100644 --- a/dom/apps/src/AppsServiceChild.jsm +++ b/dom/apps/src/AppsServiceChild.jsm @@ -86,6 +86,15 @@ this.DOMApplicationRegistry = { getAppFromObserverMessage: function getAppFromObserverMessage(aMessage) { debug("getAppFromObserverMessage " + aMessage); return AppsUtils.getAppFromObserverMessage(this.webapps. aMessage); + }, + getCoreAppsBasePath: function getCoreAppsBasePath() { + debug("getCoreAppsBasePath() not yet supported on child!"); + return null; + }, + + getWebAppsBasePath: function getWebAppsBasePath() { + debug("getWebAppsBasePath() not yet supported on child!"); + return null; } } diff --git a/dom/apps/src/AppsUtils.jsm b/dom/apps/src/AppsUtils.jsm index 5530820a782b..eb7fcd65c3d0 100644 --- a/dom/apps/src/AppsUtils.jsm +++ b/dom/apps/src/AppsUtils.jsm @@ -38,7 +38,9 @@ this.AppsUtils = { manifestURL: aApp.manifestURL, appStatus: aApp.appStatus, removable: aApp.removable, + id: aApp.id, localId: aApp.localId, + basePath: aApp.basePath, progress: aApp.progress || 0.0, installState: aApp.installState || "installed", downloadAvailable: aApp.downloadAvailable, diff --git a/dom/apps/src/Webapps.jsm b/dom/apps/src/Webapps.jsm index 127d4152d326..5ca18421dd49 100644 --- a/dom/apps/src/Webapps.jsm +++ b/dom/apps/src/Webapps.jsm @@ -75,7 +75,7 @@ this.DOMApplicationRegistry = { "Webapps:GetSelf", "Webapps:CheckInstalled", "Webapps:GetInstalled", "Webapps:GetNotInstalled", "Webapps:Launch", "Webapps:GetAll", - "Webapps:InstallPackage", "Webapps:GetBasePath", + "Webapps:InstallPackage", "Webapps:GetAppInfo", "Webapps:GetList", "Webapps:RegisterForMessages", "Webapps:UnregisterForMessages", "Webapps:CancelDownload", "Webapps:CheckForUpdate", @@ -110,6 +110,9 @@ this.DOMApplicationRegistry = { this.webapps = aData; let appDir = FileUtils.getDir(DIRECTORY_NAME, ["webapps"], false); for (let id in this.webapps) { + + this.webapps[id].id = id; + // Make sure we have a localId if (this.webapps[id].localId === undefined) { this.webapps[id].localId = this._nextLocalId(); @@ -215,7 +218,7 @@ this.DOMApplicationRegistry = { let app = this.webapps[aId]; let baseDir; try { - baseDir = FileUtils.getDir("coreAppsDir", ["webapps", aId], true, true); + baseDir = FileUtils.getDir("coreAppsDir", ["webapps", aId], false); } catch(e) { // In ENG builds, we don't have apps in coreAppsDir. return; @@ -320,6 +323,8 @@ this.DOMApplicationRegistry = { this.webapps[id] = aData[id]; this.webapps[id].basePath = appDir.path; + this.webapps[id].id = id; + // Create a new localId. this.webapps[id].localId = this._nextLocalId(); @@ -779,12 +784,13 @@ this.DOMApplicationRegistry = { case "Webapps:InstallPackage": this.doInstallPackage(msg, mm); break; - case "Webapps:GetBasePath": + case "Webapps:GetAppInfo": if (!this.webapps[msg.id]) { debug("No webapp for " + msg.id); return null; } - return this.webapps[msg.id].basePath; + return { "basePath": this.webapps[msg.id].basePath + "/", + "isCoreApp": !this.webapps[msg.id].removable }; break; case "Webapps:RegisterForMessages": this.addMessageListener(msg, mm); @@ -1479,9 +1485,9 @@ this.DOMApplicationRegistry = { } } else { id = this.makeAppId(); - app.id = id; localId = this._nextLocalId(); } + app.id = id; let manifestName = "manifest.webapp"; if (aData.isPackage) { @@ -1506,6 +1512,7 @@ this.DOMApplicationRegistry = { let appNote = JSON.stringify(appObject); appNote.id = id; + appObject.id = id; appObject.localId = localId; appObject.basePath = FileUtils.getDir(DIRECTORY_NAME, ["webapps"], true, true).path; let dir = FileUtils.getDir(DIRECTORY_NAME, ["webapps", id], true, true); @@ -2189,6 +2196,14 @@ this.DOMApplicationRegistry = { return AppsUtils.getAppFromObserverMessage(this.webapps, aMessage); }, + getCoreAppsBasePath: function() { + return FileUtils.getDir("coreAppsDir", ["webapps"], false).path; + }, + + getWebAppsBasePath: function getWebAppsBasePath() { + return FileUtils.getDir(DIRECTORY_NAME, ["webapps"], false).path; + }, + getAllWithoutManifests: function(aCallback) { let result = {}; for (let id in this.webapps) { diff --git a/dom/interfaces/apps/mozIApplication.idl b/dom/interfaces/apps/mozIApplication.idl index d284f0ab439e..737f5e622ed3 100644 --- a/dom/interfaces/apps/mozIApplication.idl +++ b/dom/interfaces/apps/mozIApplication.idl @@ -11,7 +11,7 @@ * We expose Gecko-internal helpers related to "web apps" through this * sub-interface. */ -[scriptable, uuid(8ac7827f-f982-40fb-be11-ba16dd665635)] +[scriptable, uuid(cfa75628-4d31-481f-b51e-fe0ce18fa98f)] interface mozIApplication: mozIDOMApplication { /* Return true if this app has |permission|. */ @@ -20,9 +20,15 @@ interface mozIApplication: mozIDOMApplication /* Application status as defined in nsIPrincipal. */ readonly attribute unsigned short appStatus; - /* Returns the local id of the app (not the uuid used for sync). */ + /* Returns the uuid of the app. */ + readonly attribute DOMString id; + + /* Returns the local id of the app. */ readonly attribute unsigned long localId; + /* Returns the base directory for the app */ + readonly attribute DOMString basePath; + /* Name copied from the manifest */ readonly attribute DOMString name; diff --git a/dom/interfaces/apps/nsIAppsService.idl b/dom/interfaces/apps/nsIAppsService.idl index f6ca6797e438..8349e4b6e332 100644 --- a/dom/interfaces/apps/nsIAppsService.idl +++ b/dom/interfaces/apps/nsIAppsService.idl @@ -16,7 +16,7 @@ interface mozIApplication; * This service allows accessing some DOMApplicationRegistry methods from * non-javascript code. */ -[scriptable, uuid(4a182c18-dbdf-4f9c-93a0-0f0cffb88ed0)] +[scriptable, uuid(e65f9397-e191-4273-aa5f-f13c185ce63b)] interface nsIAppsService : nsISupports { mozIDOMApplication getAppByManifestURL(in DOMString manifestURL); @@ -50,4 +50,14 @@ interface nsIAppsService : nsISupports * Returns the CSP associated to this localId. */ DOMString getCSPByLocalId(in unsigned long localId); + + /** + * Returns the basepath for core apps + */ + DOMString getCoreAppsBasePath(); + + /** + * Returns the basepath for regular packaged apps + */ + DOMString getWebAppsBasePath(); }; diff --git a/modules/libjar/nsIZipReader.idl b/modules/libjar/nsIZipReader.idl index 2aa89eddf5e5..1df6e32875c0 100644 --- a/modules/libjar/nsIZipReader.idl +++ b/modules/libjar/nsIZipReader.idl @@ -185,7 +185,7 @@ interface nsIZipReader : nsISupports //////////////////////////////////////////////////////////////////////////////// // nsIZipReaderCache -[scriptable, uuid(72fc56e5-3e6e-4d11-8967-26ab96071032)] +[scriptable, uuid(748050ac-3ab6-4472-bc2a-cb1564ac6a81)] interface nsIZipReaderCache : nsISupports { /** @@ -210,6 +210,11 @@ interface nsIZipReaderCache : nsISupports */ nsIZipReader getZip(in nsIFile zipFile); + /** + * returns true if this zipreader already has this file cached + */ + bool isCached(in nsIFile zipFile); + /** * Returns a (possibly shared) nsIZipReader for a zip inside another zip * diff --git a/modules/libjar/nsJAR.cpp b/modules/libjar/nsJAR.cpp index 97c5f347c1d7..38f4b1ce849c 100644 --- a/modules/libjar/nsJAR.cpp +++ b/modules/libjar/nsJAR.cpp @@ -1062,6 +1062,27 @@ nsZipReaderCache::~nsZipReaderCache() #endif } +NS_IMETHODIMP +nsZipReaderCache::IsCached(nsIFile* zipFile, bool* aResult) +{ + NS_ENSURE_ARG_POINTER(zipFile); + nsresult rv; + nsCOMPtr<nsIZipReader> antiLockZipGrip; + MutexAutoLock lock(mLock); + + nsAutoCString uri; + rv = zipFile->GetNativePath(uri); + if (NS_FAILED(rv)) + return rv; + + uri.Insert(NS_LITERAL_CSTRING("file:"), 0); + + nsCStringKey key(uri); + + *aResult = mZips.Exists(&key); + return NS_OK; +} + NS_IMETHODIMP nsZipReaderCache::GetZip(nsIFile* zipFile, nsIZipReader* *result) { diff --git a/modules/libjar/nsJARChannel.cpp b/modules/libjar/nsJARChannel.cpp index 1d704d383f59..348ebbc7a38d 100644 --- a/modules/libjar/nsJARChannel.cpp +++ b/modules/libjar/nsJARChannel.cpp @@ -1,6 +1,6 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * - * This Source Code Form is subject to the terms of the Mozilla Public +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* vim: set sw=4 ts=8 et tw=80 : */ +/* 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/. */ @@ -18,10 +18,14 @@ #include "nsIScriptSecurityManager.h" #include "nsIPrincipal.h" #include "nsIFileURL.h" +#include "nsXULAppAPI.h" #include "mozilla/Preferences.h" +#include "mozilla/net/RemoteOpenFileChild.h" +#include "nsITabChild.h" using namespace mozilla; +using namespace mozilla::net; static NS_DEFINE_CID(kZipReaderCID, NS_ZIPREADER_CID); @@ -188,6 +192,7 @@ nsJARChannel::nsJARChannel() , mStatus(NS_OK) , mIsPending(false) , mIsUnsafe(true) + , mOpeningRemote(false) { #if defined(PR_LOGGING) if (!gJarProtocolLog) @@ -205,13 +210,14 @@ nsJARChannel::~nsJARChannel() NS_RELEASE(handler); // NULL parameter } -NS_IMPL_ISUPPORTS_INHERITED6(nsJARChannel, +NS_IMPL_ISUPPORTS_INHERITED7(nsJARChannel, nsHashPropertyBag, nsIRequest, nsIChannel, nsIStreamListener, nsIRequestObserver, nsIDownloadObserver, + nsIRemoteOpenFileListener, nsIJARChannel) nsresult @@ -263,9 +269,9 @@ nsJARChannel::CreateJarInput(nsIZipReaderCache *jarCache, nsJARInputThunk **resu nsCOMPtr<nsIZipReader> reader; if (jarCache) { if (mInnerJarEntry.IsEmpty()) - rv = jarCache->GetZip(mJarFile, getter_AddRefs(reader)); + rv = jarCache->GetZip(clonedFile, getter_AddRefs(reader)); else - rv = jarCache->GetInnerZip(mJarFile, mInnerJarEntry, + rv = jarCache->GetInnerZip(clonedFile, mInnerJarEntry, getter_AddRefs(reader)); } else { // create an uncached jar reader @@ -273,7 +279,7 @@ nsJARChannel::CreateJarInput(nsIZipReaderCache *jarCache, nsJARInputThunk **resu if (NS_FAILED(rv)) return rv; - rv = outerReader->Open(mJarFile); + rv = outerReader->Open(clonedFile); if (NS_FAILED(rv)) return rv; @@ -334,6 +340,37 @@ nsJARChannel::LookupFile() if (fileURL) fileURL->GetFile(getter_AddRefs(mJarFile)); } + // if we're in child process and have special "remoteopenfile:://" scheme, + // create special nsIFile that gets file handle from parent when opened. + if (!mJarFile && XRE_GetProcessType() != GeckoProcessType_Default) { + nsAutoCString scheme; + nsresult rv = mJarBaseURI->GetScheme(scheme); + if (NS_SUCCEEDED(rv) && scheme.EqualsLiteral("remoteopenfile")) { + nsRefPtr<RemoteOpenFileChild> remoteFile = new RemoteOpenFileChild(); + rv = remoteFile->Init(mJarBaseURI); + NS_ENSURE_SUCCESS(rv, rv); + mJarFile = remoteFile; + + nsIZipReaderCache *jarCache = gJarHandler->JarCache(); + if (jarCache) { + bool cached = false; + rv = jarCache->IsCached(mJarFile, &cached); + if (NS_SUCCEEDED(rv) && cached) { + // zipcache already has file mmapped: don't open on parent, + // just return and proceed to cache hit in CreateJarInput() + return NS_OK; + } + } + + // Open file on parent: OnRemoteFileOpenComplete called when done + nsCOMPtr<nsITabChild> tabChild; + NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup, tabChild); + rv = remoteFile->AsyncRemoteFileOpen(PR_RDONLY, this, tabChild.get()); + NS_ENSURE_SUCCESS(rv, rv); + + mOpeningRemote = true; + } + } // try to handle a nested jar if (!mJarFile) { nsCOMPtr<nsIJARURI> jarURI = do_QueryInterface(mJarBaseURI); @@ -655,7 +692,7 @@ nsJARChannel::Open(nsIInputStream **stream) return NS_ERROR_NOT_IMPLEMENTED; } - nsCOMPtr<nsJARInputThunk> input; + nsRefPtr<nsJARInputThunk> input; rv = CreateJarInput(gJarHandler->JarCache(), getter_AddRefs(input)); if (NS_FAILED(rv)) return rv; @@ -702,12 +739,13 @@ nsJARChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctx) rv = NS_OpenURI(mDownloader, nullptr, mJarBaseURI, nullptr, mLoadGroup, mCallbacks, mLoadFlags & ~(LOAD_DOCUMENT_URI | LOAD_CALL_CONTENT_SNIFFERS)); - } - else { + } else if (mOpeningRemote) { + // nothing to do: already asked parent to open file. + } else { // local files are always considered safe mIsUnsafe = false; - nsCOMPtr<nsJARInputThunk> input; + nsRefPtr<nsJARInputThunk> input; rv = CreateJarInput(gJarHandler->JarCache(), getter_AddRefs(input)); if (NS_SUCCEEDED(rv)) { // create input stream pump and call AsyncRead as a block @@ -845,7 +883,7 @@ nsJARChannel::OnDownloadComplete(nsIDownloader *downloader, if (NS_SUCCEEDED(status)) { mJarFile = file; - nsCOMPtr<nsJARInputThunk> input; + nsRefPtr<nsJARInputThunk> input; rv = CreateJarInput(nullptr, getter_AddRefs(input)); if (NS_SUCCEEDED(rv)) { // create input stream pump @@ -865,6 +903,38 @@ nsJARChannel::OnDownloadComplete(nsIDownloader *downloader, return NS_OK; } +//----------------------------------------------------------------------------- +// nsIRemoteOpenFileListener +//----------------------------------------------------------------------------- +nsresult +nsJARChannel::OnRemoteFileOpenComplete(nsresult aOpenStatus) +{ + nsresult rv = aOpenStatus; + + if (NS_SUCCEEDED(rv)) { + // files on parent are always considered safe + mIsUnsafe = false; + + nsRefPtr<nsJARInputThunk> input; + rv = CreateJarInput(gJarHandler->JarCache(), getter_AddRefs(input)); + if (NS_SUCCEEDED(rv)) { + // create input stream pump and call AsyncRead as a block + rv = NS_NewInputStreamPump(getter_AddRefs(mPump), input); + if (NS_SUCCEEDED(rv)) + rv = mPump->AsyncRead(this, nullptr); + } + } + + if (NS_FAILED(rv)) { + mStatus = rv; + OnStartRequest(nullptr, nullptr); + OnStopRequest(nullptr, nullptr, mStatus); + } + + return NS_OK; +} + + //----------------------------------------------------------------------------- // nsIStreamListener //----------------------------------------------------------------------------- diff --git a/modules/libjar/nsJARChannel.h b/modules/libjar/nsJARChannel.h index 96d4f3b90ace..baddcd54f77e 100644 --- a/modules/libjar/nsJARChannel.h +++ b/modules/libjar/nsJARChannel.h @@ -12,6 +12,7 @@ #include "nsIInterfaceRequestor.h" #include "nsIProgressEventSink.h" #include "nsIStreamListener.h" +#include "nsIRemoteOpenFileListener.h" #include "nsIZipReader.h" #include "nsIDownloader.h" #include "nsILoadGroup.h" @@ -29,6 +30,7 @@ class nsJARInputThunk; class nsJARChannel : public nsIJARChannel , public nsIDownloadObserver , public nsIStreamListener + , public nsIRemoteOpenFileListener , public nsHashPropertyBag { public: @@ -39,6 +41,7 @@ public: NS_DECL_NSIDOWNLOADOBSERVER NS_DECL_NSIREQUESTOBSERVER NS_DECL_NSISTREAMLISTENER + NS_DECL_NSIREMOTEOPENFILELISTENER nsJARChannel(); virtual ~nsJARChannel(); @@ -76,6 +79,7 @@ private: nsresult mStatus; bool mIsPending; bool mIsUnsafe; + bool mOpeningRemote; nsCOMPtr<nsIStreamListener> mDownloader; nsCOMPtr<nsIInputStreamPump> mPump; diff --git a/modules/libjar/test/unit/head_ipc.js b/modules/libjar/test/unit/head_ipc.js new file mode 100644 index 000000000000..5b752316a83c --- /dev/null +++ b/modules/libjar/test/unit/head_ipc.js @@ -0,0 +1,17 @@ +/* + * If we're running in e10s, determines whether we're in child directory or + * not. + */ + +var inChild = false; +var filePrefix = ""; +try { + inChild = Components.classes["@mozilla.org/xre/runtime;1"]. + getService(Components.interfaces.nsIXULRuntime).processType + != Components.interfaces.nsIXULRuntime.PROCESS_TYPE_DEFAULT; + if (inChild) { + // use "jar:remoteopenfile://" in child instead of "jar:file://" + filePrefix = "remoteopen"; + } +} +catch (e) { } diff --git a/modules/libjar/test/unit/test_jarchannel.js b/modules/libjar/test/unit/test_jarchannel.js index 9f0c82204460..1720e881cfe6 100644 --- a/modules/libjar/test/unit/test_jarchannel.js +++ b/modules/libjar/test/unit/test_jarchannel.js @@ -27,7 +27,8 @@ const nsIBinaryInputStream = ctor("@mozilla.org/binaryinputstream;1", const fileBase = "test_bug637286.zip"; const file = do_get_file("data/" + fileBase); -const jarBase = "jar:" + ios.newFileURI(file).spec + "!"; +// on child we'll test with jar:remoteopenfile:// instead of jar:file:// +const jarBase = "jar:" + filePrefix + ios.newFileURI(file).spec + "!"; const tmpDir = dirSvc.get("TmpD", Ci.nsIFile); function Listener(callback) { @@ -65,25 +66,10 @@ Listener.prototype = { } }; -/** - * Basic reading test for synchronously opened jar channels - */ -add_test(function testSync() { - var uri = jarBase + "/inner40.zip"; - var chan = ios.newChannel(uri, null, null); - var stream = chan.open(); - do_check_true(chan.contentLength > 0); - do_check_eq(stream.available(), chan.contentLength); - stream.close(); - stream.close(); // should still not throw - - run_next_test(); -}); - /** * Basic reading test for asynchronously opened jar channel */ -add_test(function testAsync() { +function testAsync() { var uri = jarBase + "/inner40.zip"; var chan = ios.newChannel(uri, null, null); do_check_true(chan.contentLength < 0); @@ -95,93 +81,122 @@ add_test(function testAsync() { run_next_test(); }), null); -}); +} -/** - * Basic reading test for synchronously opened, nested jar channels - */ -add_test(function testSyncNested() { - var uri = "jar:" + jarBase + "/inner40.zip!/foo"; - var chan = ios.newChannel(uri, null, null); - var stream = chan.open(); - do_check_true(chan.contentLength > 0); - do_check_eq(stream.available(), chan.contentLength); - stream.close(); - stream.close(); // should still not throw +add_test(testAsync); +// Run same test again so we test the codepath for a zipcache hit +add_test(testAsync); - run_next_test(); -}); -/** - * Basic reading test for asynchronously opened, nested jar channels - */ -add_test(function testAsyncNested(next) { - var uri = "jar:" + jarBase + "/inner40.zip!/foo"; - var chan = ios.newChannel(uri, null, null); - chan.asyncOpen(new Listener(function(l) { - do_check_true(chan.contentLength > 0); - do_check_true(l.gotStartRequest); - do_check_true(l.gotStopRequest); - do_check_eq(l.available, chan.contentLength); +// In e10s child processes we don't currently support +// 1) synchronously opening jar files on parent +// 2) nested jar channels in e10s: (app:// doesn't use them). +// 3) we can't do file lock checks on android, so skip those tests too. +if (!inChild) { - run_next_test(); - }), null); -}); + /** + * Basic reading test for synchronously opened jar channels + */ + add_test(function testSync() { + var uri = jarBase + "/inner40.zip"; + var chan = ios.newChannel(uri, null, null); + var stream = chan.open(); + do_check_true(chan.contentLength > 0); + do_check_eq(stream.available(), chan.contentLength); + stream.close(); + stream.close(); // should still not throw -/** - * Verify that file locks are released when closing a synchronously - * opened jar channel stream - */ -add_test(function testSyncCloseUnlocks() { - var copy = tmpDir.clone(); - copy.append(fileBase); - file.copyTo(copy.parent, copy.leafName); + run_next_test(); + }); - var uri = "jar:" + ios.newFileURI(copy).spec + "!/inner40.zip"; - var chan = ios.newChannel(uri, null, null); - var stream = chan.open(); - do_check_true(chan.contentLength > 0); - stream.close(); - // Drop any jar caches - obs.notifyObservers(null, "chrome-flush-caches", null); + /** + * Basic reading test for synchronously opened, nested jar channels + */ + add_test(function testSyncNested() { + var uri = "jar:" + jarBase + "/inner40.zip!/foo"; + var chan = ios.newChannel(uri, null, null); + var stream = chan.open(); + do_check_true(chan.contentLength > 0); + do_check_eq(stream.available(), chan.contentLength); + stream.close(); + stream.close(); // should still not throw - try { - copy.remove(false); - } - catch (ex) { - do_throw(ex); - } + run_next_test(); + }); - run_next_test(); -}); + /** + * Basic reading test for asynchronously opened, nested jar channels + */ + add_test(function testAsyncNested(next) { + var uri = "jar:" + jarBase + "/inner40.zip!/foo"; + var chan = ios.newChannel(uri, null, null); + chan.asyncOpen(new Listener(function(l) { + do_check_true(chan.contentLength > 0); + do_check_true(l.gotStartRequest); + do_check_true(l.gotStopRequest); + do_check_eq(l.available, chan.contentLength); -/** - * Verify that file locks are released when closing an asynchronously - * opened jar channel stream - */ -add_test(function testAsyncCloseUnlocks() { - var copy = tmpDir.clone(); - copy.append(fileBase); - file.copyTo(copy.parent, copy.leafName); + run_next_test(); + }), null); + }); - var uri = "jar:" + ios.newFileURI(copy).spec + "!/inner40.zip"; - var chan = ios.newChannel(uri, null, null); - chan.asyncOpen(new Listener(function (l) { - do_check_true(chan.contentLength > 0); + /** + * Verify that file locks are released when closing a synchronously + * opened jar channel stream + */ + add_test(function testSyncCloseUnlocks() { + var copy = tmpDir.clone(); + copy.append(fileBase); + file.copyTo(copy.parent, copy.leafName); - // Drop any jar caches - obs.notifyObservers(null, "chrome-flush-caches", null); + var uri = "jar:" + ios.newFileURI(copy).spec + "!/inner40.zip"; + var chan = ios.newChannel(uri, null, null); + var stream = chan.open(); + do_check_true(chan.contentLength > 0); + stream.close(); - try { - copy.remove(false); - } - catch (ex) { - do_throw(ex); - } + // Drop any jar caches + obs.notifyObservers(null, "chrome-flush-caches", null); - run_next_test(); - }), null); -}); + try { + copy.remove(false); + } + catch (ex) { + do_throw(ex); + } + + run_next_test(); + }); + + /** + * Verify that file locks are released when closing an asynchronously + * opened jar channel stream + */ + add_test(function testAsyncCloseUnlocks() { + var copy = tmpDir.clone(); + copy.append(fileBase); + file.copyTo(copy.parent, copy.leafName); + + var uri = "jar:" + ios.newFileURI(copy).spec + "!/inner40.zip"; + var chan = ios.newChannel(uri, null, null); + chan.asyncOpen(new Listener(function (l) { + do_check_true(chan.contentLength > 0); + + // Drop any jar caches + obs.notifyObservers(null, "chrome-flush-caches", null); + + try { + copy.remove(false); + } + catch (ex) { + do_throw(ex); + } + + run_next_test(); + }), null); + }); + +} // if !inChild function run_test() run_next_test(); diff --git a/modules/libjar/test/unit/test_jarchannel_e10s.js b/modules/libjar/test/unit/test_jarchannel_e10s.js new file mode 100644 index 000000000000..b77ebc5c2df8 --- /dev/null +++ b/modules/libjar/test/unit/test_jarchannel_e10s.js @@ -0,0 +1,7 @@ +// +// Run test script in content process instead of chrome (xpcshell's default) +// + +function run_test() { + run_test_in_child("../unit/test_jarchannel.js"); +} diff --git a/modules/libjar/test/unit/xpcshell.ini b/modules/libjar/test/unit/xpcshell.ini index 864bfe7d6005..e46b01058883 100644 --- a/modules/libjar/test/unit/xpcshell.ini +++ b/modules/libjar/test/unit/xpcshell.ini @@ -1,8 +1,10 @@ [DEFAULT] -head = +head = head_ipc.js tail = [test_jarchannel.js] +[test_jarchannel_e10s.js] +skip-if = os == "mac" || os == "windows" [test_bug278262.js] [test_bug333423.js] [test_bug336691.js] diff --git a/netwerk/ipc/Makefile.in b/netwerk/ipc/Makefile.in index 3c312dd436ed..1f46764c8a4f 100644 --- a/netwerk/ipc/Makefile.in +++ b/netwerk/ipc/Makefile.in @@ -16,6 +16,11 @@ LIBRARY_NAME = neckoipc_s LIBXUL_LIBRARY = 1 FORCE_STATIC_LIB = 1 EXPORT_LIBRARY = 1 +XPIDL_MODULE = necko_ipc + +XPIDLSRCS = \ + nsIRemoteOpenFileListener.idl \ + $(NULL) EXPORTS_NAMESPACES = mozilla/net @@ -25,12 +30,16 @@ EXPORTS_mozilla/net = \ NeckoCommon.h \ NeckoMessageUtils.h \ ChannelEventQueue.h \ + RemoteOpenFileParent.h \ + RemoteOpenFileChild.h \ $(NULL) CPPSRCS = \ NeckoChild.cpp \ NeckoParent.cpp \ ChannelEventQueue.cpp \ + RemoteOpenFileParent.cpp \ + RemoteOpenFileChild.cpp \ $(NULL) LOCAL_INCLUDES += \ diff --git a/netwerk/ipc/NeckoChild.cpp b/netwerk/ipc/NeckoChild.cpp index 74fcc5a0ee4b..2eaa36849e11 100644 --- a/netwerk/ipc/NeckoChild.cpp +++ b/netwerk/ipc/NeckoChild.cpp @@ -13,6 +13,7 @@ #include "mozilla/net/WyciwygChannelChild.h" #include "mozilla/net/FTPChannelChild.h" #include "mozilla/net/WebSocketChannelChild.h" +#include "mozilla/net/RemoteOpenFileChild.h" #include "mozilla/dom/network/TCPSocketChild.h" #include "mozilla/Preferences.h" @@ -172,5 +173,22 @@ NeckoChild::DeallocPTCPSocket(PTCPSocketChild* child) return true; } +PRemoteOpenFileChild* +NeckoChild::AllocPRemoteOpenFile(const URIParams&, PBrowserChild*) +{ + // We don't allocate here: instead we always use IPDL constructor that takes + // an existing RemoteOpenFileChild + NS_NOTREACHED("AllocPRemoteOpenFile should not be called on child"); + return nullptr; +} + +bool +NeckoChild::DeallocPRemoteOpenFile(PRemoteOpenFileChild* aChild) +{ + RemoteOpenFileChild *p = static_cast<RemoteOpenFileChild*>(aChild); + p->ReleaseIPDLReference(); + return true; +} + }} // mozilla::net diff --git a/netwerk/ipc/NeckoChild.h b/netwerk/ipc/NeckoChild.h index 8006c4c86937..1b3455a4c72d 100644 --- a/netwerk/ipc/NeckoChild.h +++ b/netwerk/ipc/NeckoChild.h @@ -43,6 +43,9 @@ protected: const nsString& aBinaryType, PBrowserChild* aBrowser); virtual bool DeallocPTCPSocket(PTCPSocketChild*); + virtual PRemoteOpenFileChild* AllocPRemoteOpenFile(const URIParams&, + PBrowserChild*); + virtual bool DeallocPRemoteOpenFile(PRemoteOpenFileChild*); }; /** diff --git a/netwerk/ipc/NeckoParent.cpp b/netwerk/ipc/NeckoParent.cpp index e62d5b9a702b..9c5e80739a7f 100644 --- a/netwerk/ipc/NeckoParent.cpp +++ b/netwerk/ipc/NeckoParent.cpp @@ -12,11 +12,15 @@ #include "mozilla/net/WyciwygChannelParent.h" #include "mozilla/net/FTPChannelParent.h" #include "mozilla/net/WebSocketChannelParent.h" +#include "mozilla/net/RemoteOpenFileParent.h" #include "mozilla/dom/TabParent.h" #include "mozilla/dom/network/TCPSocketParent.h" +#include "mozilla/ipc/URIUtils.h" #include "mozilla/Preferences.h" #include "nsHTMLDNSPrefetch.h" +#include "nsIAppsService.h" +#include "nsEscape.h" using mozilla::dom::TabParent; using mozilla::net::PTCPSocketParent; @@ -32,6 +36,21 @@ static const char kPrefDisableIPCSecurity[] = "network.disable.ipc.security"; NeckoParent::NeckoParent() { Preferences::AddBoolVarCache(&gDisableIPCSecurity, kPrefDisableIPCSecurity); + + if (!gDisableIPCSecurity) { + // cache values for core/packaged apps basepaths + nsAutoString corePath, webPath; + nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID); + if (appsService) { + appsService->GetCoreAppsBasePath(corePath); + appsService->GetWebAppsBasePath(webPath); + } + // corePath may be empty: we don't use it for all build types + MOZ_ASSERT(!webPath.IsEmpty()); + + LossyCopyUTF16toASCII(corePath, mCoreAppsBasePath); + LossyCopyUTF16toASCII(webPath, mWebAppsBasePath); + } } NeckoParent::~NeckoParent() @@ -149,6 +168,116 @@ NeckoParent::DeallocPTCPSocket(PTCPSocketParent* actor) return true; } +PRemoteOpenFileParent* +NeckoParent::AllocPRemoteOpenFile(const URIParams& aURI, + PBrowserParent* aBrowser) +{ + nsCOMPtr<nsIURI> uri = DeserializeURI(aURI); + nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(uri); + if (!fileURL) { + return nullptr; + } + + // security checks + if (!gDisableIPCSecurity) { + if (!aBrowser) { + NS_WARNING("NeckoParent::AllocPRemoteOpenFile: " + "FATAL error: missing TabParent: KILLING CHILD PROCESS\n"); + return nullptr; + } + nsRefPtr<TabParent> tabParent = static_cast<TabParent*>(aBrowser); + uint32_t appId = tabParent->OwnOrContainingAppId(); + nsCOMPtr<nsIAppsService> appsService = + do_GetService(APPS_SERVICE_CONTRACTID); + if (!appsService) { + return nullptr; + } + nsCOMPtr<mozIDOMApplication> domApp; + nsresult rv = appsService->GetAppByLocalId(appId, getter_AddRefs(domApp)); + if (!domApp) { + return nullptr; + } + nsCOMPtr<mozIApplication> mozApp = do_QueryInterface(domApp); + if (!mozApp) { + return nullptr; + } + bool hasManage = false; + rv = mozApp->HasPermission("webapps-manage", &hasManage); + if (NS_FAILED(rv)) { + return nullptr; + } + + nsAutoCString requestedPath; + fileURL->GetPath(requestedPath); + NS_UnescapeURL(requestedPath); + + if (hasManage) { + // webapps-manage permission means allow reading any application.zip file + // in either the regular webapps directory, or the core apps directory (if + // we're using one). + NS_NAMED_LITERAL_CSTRING(appzip, "/application.zip"); + nsAutoCString pathEnd; + requestedPath.Right(pathEnd, appzip.Length()); + if (!pathEnd.Equals(appzip)) { + return nullptr; + } + nsAutoCString pathStart; + requestedPath.Left(pathStart, mWebAppsBasePath.Length()); + if (!pathStart.Equals(mWebAppsBasePath)) { + if (mCoreAppsBasePath.IsEmpty()) { + return nullptr; + } + requestedPath.Left(pathStart, mCoreAppsBasePath.Length()); + if (!pathStart.Equals(mCoreAppsBasePath)) { + return nullptr; + } + } + // Finally: make sure there are no "../" in URI. + // Note: not checking for symlinks (would cause I/O for each path + // component). So it's up to us to avoid creating symlinks that could + // provide attack vectors. + if (PL_strnstr(requestedPath.BeginReading(), "/../", + requestedPath.Length())) { + NS_WARNING("NeckoParent::AllocPRemoteOpenFile: " + "FATAL error: requested file URI contains '/../' " + "KILLING CHILD PROCESS\n"); + return nullptr; + } + } else { + // regular packaged apps can only access their own application.zip file + nsAutoString basePath; + rv = mozApp->GetBasePath(basePath); + if (NS_FAILED(rv)) { + return nullptr; + } + nsAutoString uuid; + rv = mozApp->GetId(uuid); + if (NS_FAILED(rv)) { + return nullptr; + } + nsPrintfCString mustMatch("%s/%s/application.zip", + NS_LossyConvertUTF16toASCII(basePath).get(), + NS_LossyConvertUTF16toASCII(uuid).get()); + if (!requestedPath.Equals(mustMatch)) { + NS_WARNING("NeckoParent::AllocPRemoteOpenFile: " + "FATAL error: requesting file other than application.zip: " + "KILLING CHILD PROCESS\n"); + return nullptr; + } + } + } + + RemoteOpenFileParent* parent = new RemoteOpenFileParent(fileURL); + return parent; +} + +bool +NeckoParent::DeallocPRemoteOpenFile(PRemoteOpenFileParent* actor) +{ + delete actor; + return true; +} + bool NeckoParent::RecvHTMLDNSPrefetch(const nsString& hostname, const uint16_t& flags) diff --git a/netwerk/ipc/NeckoParent.h b/netwerk/ipc/NeckoParent.h index 1112e1046a10..df22267e8e96 100644 --- a/netwerk/ipc/NeckoParent.h +++ b/netwerk/ipc/NeckoParent.h @@ -39,6 +39,11 @@ protected: const bool& useSSL, const nsString& aBinaryType, PBrowserParent* aBrowser); + virtual PRemoteOpenFileParent* AllocPRemoteOpenFile( + const URIParams& fileuri, + PBrowserParent* browser); + virtual bool DeallocPRemoteOpenFile(PRemoteOpenFileParent* actor); + virtual bool RecvPTCPSocketConstructor(PTCPSocketParent*, const nsString& aHost, const uint16_t& aPort, @@ -52,6 +57,9 @@ protected: const uint16_t& flags, const nsresult& reason); +private: + nsCString mCoreAppsBasePath; + nsCString mWebAppsBasePath; }; } // namespace net diff --git a/netwerk/ipc/PNecko.ipdl b/netwerk/ipc/PNecko.ipdl index 9330fb01fe3b..a1c12ba47b1d 100644 --- a/netwerk/ipc/PNecko.ipdl +++ b/netwerk/ipc/PNecko.ipdl @@ -13,6 +13,8 @@ include protocol PWyciwygChannel; include protocol PFTPChannel; include protocol PWebSocket; include protocol PTCPSocket; +include protocol PRemoteOpenFile; +include URIParams; include "SerializedLoadContext.h"; @@ -32,6 +34,7 @@ sync protocol PNecko manages PFTPChannel; manages PWebSocket; manages PTCPSocket; + manages PRemoteOpenFile; parent: __delete__(); @@ -44,6 +47,7 @@ parent: PWebSocket(PBrowser browser); PTCPSocket(nsString host, uint16_t port, bool useSSL, nsString binaryType, nullable PBrowser browser); + PRemoteOpenFile(URIParams fileuri, nullable PBrowser browser); HTMLDNSPrefetch(nsString hostname, uint16_t flags); CancelHTMLDNSPrefetch(nsString hostname, uint16_t flags, nsresult reason); diff --git a/netwerk/ipc/PRemoteOpenFile.ipdl b/netwerk/ipc/PRemoteOpenFile.ipdl new file mode 100644 index 000000000000..89d22079d72a --- /dev/null +++ b/netwerk/ipc/PRemoteOpenFile.ipdl @@ -0,0 +1,35 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set sw=2 ts=8 et tw=80 ft=cpp : */ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +include protocol PNecko; + +namespace mozilla { +namespace net { + +/** + * Protocol to support RemoteOpenFile, an nsIFile that opens it's file handle on + * the parent instead of the child (since child lacks permission to do so). + */ +protocol PRemoteOpenFile +{ + manager PNecko; + +parent: + // Tell parent to open file. URI to open was passed and vetted for security in + // IPDL constructor: see NeckoParent::AllocPRemoteOpenFile() + AsyncOpenFile(); + + __delete__(); + +child: + // success/failure code, and if NS_SUCCEEDED(rv), an open file descriptor + FileOpened(FileDescriptor fd, nsresult rv); +}; + + +} // namespace net +} // namespace mozilla diff --git a/netwerk/ipc/RemoteOpenFileChild.cpp b/netwerk/ipc/RemoteOpenFileChild.cpp new file mode 100644 index 000000000000..9cddaf82ab4e --- /dev/null +++ b/netwerk/ipc/RemoteOpenFileChild.cpp @@ -0,0 +1,644 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set sw=2 ts=8 et tw=80 : */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/net/NeckoChild.h" +#include "mozilla/net/RemoteOpenFileChild.h" +#include "nsIRemoteOpenFileListener.h" +#include "mozilla/ipc/URIUtils.h" + +// needed to alloc/free NSPR file descriptors +#include "private/pprio.h" + +using namespace mozilla::ipc; + +namespace mozilla { +namespace net { + +NS_IMPL_THREADSAFE_ISUPPORTS2(RemoteOpenFileChild, + nsIFile, + nsIHashable) + + +RemoteOpenFileChild::RemoteOpenFileChild(const RemoteOpenFileChild& other) + : mNSPRFileDesc(other.mNSPRFileDesc) + , mAsyncOpenCalled(other.mAsyncOpenCalled) + , mNSPROpenCalled(other.mNSPROpenCalled) +{ + // Note: don't clone mListener or we'll have a refcount leak. + other.mURI->Clone(getter_AddRefs(mURI)); + other.mFile->Clone(getter_AddRefs(mFile)); +} + +RemoteOpenFileChild::~RemoteOpenFileChild() +{ + if (mNSPRFileDesc) { + // If we handed out fd we shouldn't have pointer to it any more. + MOZ_ASSERT(!mNSPROpenCalled); + // PR_Close both closes the file and deallocates the PRFileDesc + PR_Close(mNSPRFileDesc); + } +} + +nsresult +RemoteOpenFileChild::Init(nsIURI* aRemoteOpenUri) +{ + if (!aRemoteOpenUri) { + return NS_ERROR_INVALID_ARG; + } + + nsAutoCString scheme; + nsresult rv = aRemoteOpenUri->GetScheme(scheme); + NS_ENSURE_SUCCESS(rv, rv); + + if (!scheme.EqualsLiteral("remoteopenfile")) { + return NS_ERROR_INVALID_ARG; + } + + // scheme of URI is not file:// so this is not a nsIFileURL. Convert to one. + nsCOMPtr<nsIURI> clonedURI; + rv = aRemoteOpenUri->Clone(getter_AddRefs(clonedURI)); + NS_ENSURE_SUCCESS(rv, rv); + + clonedURI->SetScheme(NS_LITERAL_CSTRING("file")); + nsAutoCString spec; + clonedURI->GetSpec(spec); + + rv = NS_NewURI(getter_AddRefs(mURI), spec); + NS_ENSURE_SUCCESS(rv, rv); + + // Get nsIFile + nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(mURI); + if (!fileURL) { + return NS_ERROR_UNEXPECTED; + } + + rv = fileURL->GetFile(getter_AddRefs(mFile)); + NS_ENSURE_SUCCESS(rv, rv); + + return NS_OK; +} + +nsresult +RemoteOpenFileChild::AsyncRemoteFileOpen(int32_t aFlags, + nsIRemoteOpenFileListener* aListener, + nsITabChild* aTabChild) +{ + if (!mFile) { + return NS_ERROR_NOT_INITIALIZED; + } + + if (!aListener) { + return NS_ERROR_INVALID_ARG; + } + + if (mAsyncOpenCalled) { + return NS_ERROR_ALREADY_OPENED; + } + + if (aFlags != PR_RDONLY) { + return NS_ERROR_NOT_AVAILABLE; + } + + mozilla::dom::TabChild* tabChild = nullptr; + if (aTabChild) { + tabChild = static_cast<mozilla::dom::TabChild*>(aTabChild); + } + +#if defined(XP_WIN) || defined(MOZ_WIDGET_COCOA) + // we do nothing on these platforms: we'll just open file locally when asked + // for NSPR handle + mListener->OnRemoteFileOpenComplete(NS_OK); + mListener = nullptr; + mAsyncOpenCalled = true; + return NS_OK; + +#else + URIParams uri; + SerializeURI(mURI, uri); + + gNeckoChild->SendPRemoteOpenFileConstructor(this, uri, tabChild); + + // Can't seem to reply from within IPDL Parent constructor, so send open as + // separate message + SendAsyncOpenFile(); + + // The chrome process now has a logical ref to us until we call Send__delete + AddIPDLReference(); + + mListener = aListener; + mAsyncOpenCalled = true; + return NS_OK; +#endif +} + + +//----------------------------------------------------------------------------- +// RemoteOpenFileChild::PRemoteOpenFileChild +//----------------------------------------------------------------------------- + +bool +RemoteOpenFileChild::RecvFileOpened(const FileDescriptor& aFD, + const nsresult& aRV) +{ +#if defined(XP_WIN) || defined(MOZ_WIDGET_COCOA) + NS_NOTREACHED("osX and Windows shouldn't be doing IPDL here"); +#else + if (NS_SUCCEEDED(aRV)) { + mNSPRFileDesc = PR_AllocFileDesc(aFD.PlatformHandle(), PR_GetFileMethods()); + } + + MOZ_ASSERT(mListener); + + mListener->OnRemoteFileOpenComplete(aRV); + + mListener = nullptr; // release ref to listener + + // This calls NeckoChild::DeallocPRemoteOpenFile(), which deletes |this| if + // IPDL holds the last reference. Don't rely on |this| existing after here! + Send__delete__(this); + +#endif + + return true; +} + +void +RemoteOpenFileChild::AddIPDLReference() +{ + AddRef(); +} + +void +RemoteOpenFileChild::ReleaseIPDLReference() +{ + // if we haven't gotten fd from parent yet, we're not going to. + if (mListener) { + mListener->OnRemoteFileOpenComplete(NS_ERROR_UNEXPECTED); + mListener = nullptr; + } + + Release(); +} + +//----------------------------------------------------------------------------- +// RemoteOpenFileChild::nsIFile functions that we override logic for +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +RemoteOpenFileChild::Clone(nsIFile **file) +{ + *file = new RemoteOpenFileChild(*this); + NS_ADDREF(*file); + + // if we transferred ownership of file to clone, forget our pointer. + if (mNSPRFileDesc) { + mNSPRFileDesc = nullptr; + } + + return NS_OK; +} + +/* The main event: get file descriptor from parent process + */ +NS_IMETHODIMP +RemoteOpenFileChild::OpenNSPRFileDesc(int32_t aFlags, int32_t aMode, + PRFileDesc **aRetval) +{ +#if defined(XP_WIN) || defined(MOZ_WIDGET_COCOA) + // Windows and OSX builds: just open nsIFile locally. + return mFile->OpenNSPRFileDesc(aFlags, aMode, aRetval); + +#else + if (aFlags != PR_RDONLY) { + return NS_ERROR_NOT_AVAILABLE; + } + + // Unlike regular nsIFile we can't (easily) support multiple open()s. + if (mNSPROpenCalled) { + return NS_ERROR_ALREADY_OPENED; + } + + if (!mNSPRFileDesc) { + // client skipped AsyncRemoteFileOpen() or didn't wait for result, or this + // object has been cloned + return NS_ERROR_NOT_AVAILABLE; + } + + // hand off ownership (i.e responsibility to PR_Close() file handle) to caller + *aRetval = mNSPRFileDesc; + mNSPRFileDesc = nullptr; + mNSPROpenCalled = true; + + return NS_OK; +#endif +} + + +//----------------------------------------------------------------------------- +// RemoteOpenFileChild::nsIFile functions that we delegate to underlying nsIFile +//----------------------------------------------------------------------------- + +nsresult +RemoteOpenFileChild::GetLeafName(nsAString &aLeafName) +{ + return mFile->GetLeafName(aLeafName); +} + +NS_IMETHODIMP +RemoteOpenFileChild::GetNativeLeafName(nsACString &aLeafName) +{ + return mFile->GetNativeLeafName(aLeafName); +} + +nsresult +RemoteOpenFileChild::GetTarget(nsAString &_retval) +{ + return mFile->GetTarget(_retval); +} + +NS_IMETHODIMP +RemoteOpenFileChild::GetNativeTarget(nsACString &_retval) +{ + return mFile->GetNativeTarget(_retval); +} + +nsresult +RemoteOpenFileChild::GetPath(nsAString &_retval) +{ + return mFile->GetPath(_retval); +} + +NS_IMETHODIMP +RemoteOpenFileChild::GetNativePath(nsACString &_retval) +{ + return mFile->GetNativePath(_retval); +} + +NS_IMETHODIMP +RemoteOpenFileChild::Equals(nsIFile *inFile, bool *_retval) +{ + return mFile->Equals(inFile, _retval); +} + +NS_IMETHODIMP +RemoteOpenFileChild::Contains(nsIFile *inFile, bool recur, bool *_retval) +{ + return mFile->Contains(inFile, recur, _retval); +} + +NS_IMETHODIMP +RemoteOpenFileChild::GetParent(nsIFile **aParent) +{ + return mFile->GetParent(aParent); +} + +NS_IMETHODIMP +RemoteOpenFileChild::GetFollowLinks(bool *aFollowLinks) +{ + return mFile->GetFollowLinks(aFollowLinks); +} + +//----------------------------------------------------------------------------- +// RemoteOpenFileChild::nsIFile functions that are not currently supported +//----------------------------------------------------------------------------- + +nsresult +RemoteOpenFileChild::Append(const nsAString &node) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +RemoteOpenFileChild::AppendNative(const nsACString &fragment) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +RemoteOpenFileChild::Normalize() +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +RemoteOpenFileChild::Create(uint32_t type, uint32_t permissions) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult +RemoteOpenFileChild::SetLeafName(const nsAString &aLeafName) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +RemoteOpenFileChild::SetNativeLeafName(const nsACString &aLeafName) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult +RemoteOpenFileChild::InitWithPath(const nsAString &filePath) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +RemoteOpenFileChild::InitWithNativePath(const nsACString &filePath) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +RemoteOpenFileChild::InitWithFile(nsIFile *aFile) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +RemoteOpenFileChild::SetFollowLinks(bool aFollowLinks) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult +RemoteOpenFileChild::AppendRelativePath(const nsAString &node) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +RemoteOpenFileChild::AppendRelativeNativePath(const nsACString &fragment) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +RemoteOpenFileChild::GetPersistentDescriptor(nsACString &aPersistentDescriptor) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +RemoteOpenFileChild::SetPersistentDescriptor(const nsACString &aPersistentDescriptor) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +RemoteOpenFileChild::GetRelativeDescriptor(nsIFile *fromFile, nsACString& _retval) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +RemoteOpenFileChild::SetRelativeDescriptor(nsIFile *fromFile, + const nsACString& relativeDesc) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult +RemoteOpenFileChild::CopyTo(nsIFile *newParentDir, const nsAString &newName) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +RemoteOpenFileChild::CopyToNative(nsIFile *newParent, const nsACString &newName) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult +RemoteOpenFileChild::CopyToFollowingLinks(nsIFile *newParentDir, + const nsAString &newName) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +RemoteOpenFileChild::CopyToFollowingLinksNative(nsIFile *newParent, + const nsACString &newName) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult +RemoteOpenFileChild::MoveTo(nsIFile *newParentDir, const nsAString &newName) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +RemoteOpenFileChild::MoveToNative(nsIFile *newParent, const nsACString &newName) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +RemoteOpenFileChild::Remove(bool recursive) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +RemoteOpenFileChild::GetPermissions(uint32_t *aPermissions) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +RemoteOpenFileChild::SetPermissions(uint32_t aPermissions) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +RemoteOpenFileChild::GetPermissionsOfLink(uint32_t *aPermissionsOfLink) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +RemoteOpenFileChild::SetPermissionsOfLink(uint32_t aPermissions) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +RemoteOpenFileChild::GetLastModifiedTime(PRTime *aLastModTime) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +RemoteOpenFileChild::SetLastModifiedTime(PRTime aLastModTime) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +RemoteOpenFileChild::GetLastModifiedTimeOfLink(PRTime *aLastModTimeOfLink) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +RemoteOpenFileChild::SetLastModifiedTimeOfLink(PRTime aLastModTimeOfLink) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +RemoteOpenFileChild::GetFileSize(int64_t *aFileSize) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +RemoteOpenFileChild::SetFileSize(int64_t aFileSize) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +RemoteOpenFileChild::GetFileSizeOfLink(int64_t *aFileSize) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +RemoteOpenFileChild::Exists(bool *_retval) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +RemoteOpenFileChild::IsWritable(bool *_retval) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +RemoteOpenFileChild::IsReadable(bool *_retval) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +RemoteOpenFileChild::IsExecutable(bool *_retval) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +RemoteOpenFileChild::IsHidden(bool *_retval) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +RemoteOpenFileChild::IsDirectory(bool *_retval) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +RemoteOpenFileChild::IsFile(bool *_retval) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +RemoteOpenFileChild::IsSymlink(bool *_retval) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +RemoteOpenFileChild::IsSpecial(bool *_retval) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +RemoteOpenFileChild::CreateUnique(uint32_t type, uint32_t attributes) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +RemoteOpenFileChild::GetDirectoryEntries(nsISimpleEnumerator **entries) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +RemoteOpenFileChild::OpenANSIFileDesc(const char *mode, FILE **_retval) +{ + // TODO: can implement using fdopen()? + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +RemoteOpenFileChild::Load(PRLibrary **_retval) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +RemoteOpenFileChild::GetDiskSpaceAvailable(int64_t *aDiskSpaceAvailable) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +RemoteOpenFileChild::Reveal() +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +RemoteOpenFileChild::Launch() +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +//----------------------------------------------------------------------------- +// RemoteOpenFileChild::nsIHashable functions that we delegate to underlying nsIFile +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +RemoteOpenFileChild::Equals(nsIHashable* aOther, bool *aResult) +{ + nsCOMPtr<nsIHashable> hashable = do_QueryInterface(mFile); + + MOZ_ASSERT(hashable); + + if (hashable) { + return hashable->Equals(aOther, aResult); + } + return NS_ERROR_UNEXPECTED; +} + +NS_IMETHODIMP +RemoteOpenFileChild::GetHashCode(uint32_t *aResult) +{ + nsCOMPtr<nsIHashable> hashable = do_QueryInterface(mFile); + + MOZ_ASSERT(hashable); + + if (hashable) { + return hashable->GetHashCode(aResult); + } + return NS_ERROR_UNEXPECTED; +} + +} // namespace net +} // namespace mozilla + diff --git a/netwerk/ipc/RemoteOpenFileChild.h b/netwerk/ipc/RemoteOpenFileChild.h new file mode 100644 index 000000000000..260718572d91 --- /dev/null +++ b/netwerk/ipc/RemoteOpenFileChild.h @@ -0,0 +1,86 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set sw=2 ts=8 et tw=80 : */ +/* 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/. */ + +#ifndef _RemoteOpenFileChild_h +#define _RemoteOpenFileChild_h + +#include "mozilla/dom/TabChild.h" +#include "mozilla/net/PRemoteOpenFileChild.h" +#include "nsILocalFile.h" +#include "nsIRemoteOpenFileListener.h" + +namespace mozilla { +namespace net { + +/** + * RemoteOpenFileChild: a thin wrapper around regular nsIFile classes that does + * IPC to open a file handle on parent instead of child. Used when we can't + * open file handle on child (don't have permission), but we don't want the + * overhead of shipping all I/O traffic across IPDL. Example: JAR files. + * + * To open a file handle with this class, AsyncRemoteFileOpen() must be called + * first. After the listener's OnRemoteFileOpenComplete() is called, if the + * result is NS_OK, nsIFile.OpenNSPRFileDesc() may be called--once--to get the + * file handle. + * + * Note that calling Clone() on this class results in the filehandle ownership + * being passed on to the new RemoteOpenFileChild. I.e. if + * OnRemoteFileOpenComplete is called and then Clone(), OpenNSPRFileDesc() will + * work in the cloned object, but not in the original. + * + * This class should only be instantiated in a child process. + * + */ +class RemoteOpenFileChild MOZ_FINAL + : public PRemoteOpenFileChild + , public nsIFile + , public nsIHashable +{ +public: + RemoteOpenFileChild() + : mNSPRFileDesc(nullptr) + , mAsyncOpenCalled(false) + , mNSPROpenCalled(false) + {} + + virtual ~RemoteOpenFileChild(); + + NS_DECL_ISUPPORTS + NS_DECL_NSIFILE + NS_DECL_NSIHASHABLE + + // URI must be scheme 'remoteopenfile://': otherwise looks like a file:// uri. + nsresult Init(nsIURI* aRemoteOpenUri); + + void AddIPDLReference(); + void ReleaseIPDLReference(); + + // Send message to parent to tell it to open file handle for file. + // TabChild is required, for IPC security. + // Note: currently only PR_RDONLY is supported for 'flags' + nsresult AsyncRemoteFileOpen(int32_t aFlags, + nsIRemoteOpenFileListener* aListener, + nsITabChild* aTabChild); +private: + RemoteOpenFileChild(const RemoteOpenFileChild& other); + +protected: + virtual bool RecvFileOpened(const FileDescriptor&, const nsresult&); + + // regular nsIFile object, that we forward most calls to. + nsCOMPtr<nsIFile> mFile; + nsCOMPtr<nsIURI> mURI; + nsCOMPtr<nsIRemoteOpenFileListener> mListener; + PRFileDesc* mNSPRFileDesc; + bool mAsyncOpenCalled; + bool mNSPROpenCalled; +}; + +} // namespace net +} // namespace mozilla + +#endif // _RemoteOpenFileChild_h + diff --git a/netwerk/ipc/RemoteOpenFileParent.cpp b/netwerk/ipc/RemoteOpenFileParent.cpp new file mode 100644 index 000000000000..2f4311c0c3b0 --- /dev/null +++ b/netwerk/ipc/RemoteOpenFileParent.cpp @@ -0,0 +1,69 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set sw=2 ts=8 et tw=80 : */ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/net/RemoteOpenFileParent.h" +#include "mozilla/unused.h" +#include "nsEscape.h" + +#if !defined(XP_WIN) && !defined(MOZ_WIDGET_COCOA) +#include <fcntl.h> +#endif + +namespace mozilla { +namespace net { + +RemoteOpenFileParent::RemoteOpenFileParent(nsIFileURL *aURI) + : mURI(aURI) +#if !defined(XP_WIN) && !defined(MOZ_WIDGET_COCOA) + , mFd(-1) +#endif +{} + +RemoteOpenFileParent::~RemoteOpenFileParent() +{ +#if !defined(XP_WIN) && !defined(MOZ_WIDGET_COCOA) + if (mFd != -1) { + // close file handle now that other process has it open, else we'll leak + // file handles in parent process + close(mFd); + } +#endif +} + +bool +RemoteOpenFileParent::RecvAsyncOpenFile() +{ +#if defined(XP_WIN) || defined(MOZ_WIDGET_COCOA) + NS_NOTREACHED("osX and Windows shouldn't be doing IPDL here"); +#else + + // TODO: make this async! + + nsAutoCString path; + nsresult rv = mURI->GetFilePath(path); + NS_UnescapeURL(path); + if (NS_SUCCEEDED(rv)) { + int fd = open(path.get(), O_RDONLY); + if (fd != -1) { + unused << SendFileOpened(FileDescriptor(fd), NS_OK); + // file handle needs to stay open until it's shared with child (and IPDL + // is async, so hasn't happened yet). Close in destructor. + mFd = fd; + return true; + } + } + + // Note: sending an invalid file descriptor currently kills the child process: + // but that's ok for our use case (failing to open application.jar). + unused << SendFileOpened(FileDescriptor(mFd), NS_ERROR_NOT_AVAILABLE); +#endif // OS_TYPE + + return true; +} + +} // namespace net +} // namespace mozilla diff --git a/netwerk/ipc/RemoteOpenFileParent.h b/netwerk/ipc/RemoteOpenFileParent.h new file mode 100644 index 000000000000..e56f1a081270 --- /dev/null +++ b/netwerk/ipc/RemoteOpenFileParent.h @@ -0,0 +1,38 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set sw=2 ts=8 et tw=80 : */ + +/* 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/. */ + +#ifndef mozilla_net_RemoteOpenFileParent_h +#define mozilla_net_RemoteOpenFileParent_h + +#include "mozilla/net/PRemoteOpenFileParent.h" +#include "mozilla/net/NeckoCommon.h" +#include "nsIFileURL.h" + +namespace mozilla { +namespace net { + +class RemoteOpenFileParent : public PRemoteOpenFileParent +{ +public: + RemoteOpenFileParent(nsIFileURL* aURI); + + ~RemoteOpenFileParent(); + + virtual bool RecvAsyncOpenFile(); + +private: + nsCOMPtr<nsIFileURL> mURI; + +#if !defined(XP_WIN) && !defined(MOZ_WIDGET_COCOA) + int mFd; +#endif +}; + +} // namespace net +} // namespace mozilla + +#endif // mozilla_net_RemoteOpenFileParent_h diff --git a/netwerk/ipc/ipdl.mk b/netwerk/ipc/ipdl.mk index bdc4d60dd16d..8b1da9f059ff 100644 --- a/netwerk/ipc/ipdl.mk +++ b/netwerk/ipc/ipdl.mk @@ -4,5 +4,6 @@ IPDLSRCS = \ PNecko.ipdl \ + PRemoteOpenFile.ipdl \ $(NULL) diff --git a/netwerk/ipc/nsIRemoteOpenFileListener.idl b/netwerk/ipc/nsIRemoteOpenFileListener.idl new file mode 100644 index 000000000000..1ecf53a08c62 --- /dev/null +++ b/netwerk/ipc/nsIRemoteOpenFileListener.idl @@ -0,0 +1,30 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* vim: set sw=4 ts=4 et tw=80 : */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsISupports.idl" + +/** + * nsIRemoteOpenFileListener: passed to RemoteOpenFileChild::AsyncRemoteFileOpen. + * + * Interface for notifying when the file has been opened and is available in + * child. + */ +[uuid(5c89208c-fe2b-4e04-9783-93bcf5c3b783)] +interface nsIRemoteOpenFileListener : nsISupports +{ + /** + * Called when result of opening RemoteOpenFileChild:AsyncRemoteFileOpen() + * is available in child. + * + * @param aOpenStatus: nsresult from opening file in parent. If NS_OK, + * then a following call to RemoteOpenFileChild::OpenNSPRFileDesc that + * passes the same flags as were passed to + * RemoteOpenFileChild::AsyncRemoteFileOpen is guaranteed to succeed. If + * !NS_OK or if different flags were passed, the call will fail. + */ + void onRemoteFileOpenComplete(in nsresult aOpenStatus); +}; + diff --git a/netwerk/protocol/app/AppProtocolHandler.js b/netwerk/protocol/app/AppProtocolHandler.js index 089a549218ec..8a9504122d90 100644 --- a/netwerk/protocol/app/AppProtocolHandler.js +++ b/netwerk/protocol/app/AppProtocolHandler.js @@ -16,7 +16,10 @@ XPCOMUtils.defineLazyServiceGetter(this, "cpmm", "nsISyncMessageSender"); function AppProtocolHandler() { - this._basePath = []; + this._appInfo = []; + this._runningInParent = Cc["@mozilla.org/xre/runtime;1"] + .getService(Ci.nsIXULRuntime) + .processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT; } AppProtocolHandler.prototype = { @@ -30,14 +33,13 @@ AppProtocolHandler.prototype = { Ci.nsIProtocolHandler.URI_DANGEROUS_TO_LOAD | Ci.nsIProtocolHandler.URI_CROSS_ORIGIN_NEEDS_WEBAPPS_PERM, - getBasePath: function app_phGetBasePath(aId) { + getAppInfo: function app_phGetAppInfo(aId) { - if (!this._basePath[aId]) { - this._basePath[aId] = cpmm.sendSyncMessage("Webapps:GetBasePath", - { id: aId })[0] + "/"; + if (!this._appInfo[aId]) { + let reply = cpmm.sendSyncMessage("Webapps:GetAppInfo", { id: aId }); + this._appInfo[aId] = reply[0]; } - - return this._basePath[aId]; + return this._appInfo[aId]; }, newURI: function app_phNewURI(aSpec, aOriginCharset, aBaseURI) { @@ -62,7 +64,15 @@ AppProtocolHandler.prototype = { } // Build a jar channel and masquerade as an app:// URI. - let uri = "jar:file://" + this.getBasePath(appId) + appId + "/application.zip!" + fileSpec; + let appInfo = this.getAppInfo(appId); + let uri; + if (this._runningInParent || appInfo.isCoreApp) { + // In-parent and CoreApps can directly access files, so use jar:file:// + uri = "jar:file://" + appInfo.basePath + appId + "/application.zip!" + fileSpec; + } else { + // non-CoreApps in child need to ask parent for file handle, use jar:ipcfile:// + uri = "jar:remoteopenfile://" + appInfo.basePath + appId + "/application.zip!" + fileSpec; + } let channel = Services.io.newChannel(uri, null, null); channel.QueryInterface(Ci.nsIJARChannel).setAppURI(aURI); channel.QueryInterface(Ci.nsIChannel).originalURI = aURI; From 80e620d390bfc851f4806bb717d4ef0558d677ab Mon Sep 17 00:00:00 2001 From: Trevor Saunders <trev.saunders@gmail.com> Date: Wed, 24 Oct 2012 19:38:52 -0400 Subject: [PATCH 069/469] bug 821593 - add downcasting from CSSValue to nsROCSSPrimitiveValue r=bz --- layout/style/CSSValue.h | 8 ++++++++ layout/style/nsROCSSPrimitiveValue.h | 6 ++++++ 2 files changed, 14 insertions(+) diff --git a/layout/style/CSSValue.h b/layout/style/CSSValue.h index e189c1bfd1aa..d58c58f38561 100644 --- a/layout/style/CSSValue.h +++ b/layout/style/CSSValue.h @@ -31,6 +31,14 @@ public: virtual void GetCssText(nsString& aText, mozilla::ErrorResult& aRv) = 0; virtual void SetCssText(const nsAString& aText, mozilla::ErrorResult& aRv) = 0; virtual uint16_t CssValueType() const = 0; + + // Downcasting + + /** + * Return this as a nsROCSSPrimitiveValue* if its a primitive value, and null + * otherwise. + */ + nsROCSSPrimitiveValue *AsPrimitiveValue(); }; } diff --git a/layout/style/nsROCSSPrimitiveValue.h b/layout/style/nsROCSSPrimitiveValue.h index 527ad8164873..1c4ce744a0e1 100644 --- a/layout/style/nsROCSSPrimitiveValue.h +++ b/layout/style/nsROCSSPrimitiveValue.h @@ -99,5 +99,11 @@ private: } mValue; }; +inline nsROCSSPrimitiveValue *mozilla::dom::CSSValue::AsPrimitiveValue() +{ + return CssValueType() == nsIDOMCSSValue::CSS_PRIMITIVE_VALUE ? + static_cast<nsROCSSPrimitiveValue*>(this) : nullptr; +} + #endif /* nsROCSSPrimitiveValue_h___ */ From a92084f8ed4f5f63f3fac90df7d95437e87efbd2 Mon Sep 17 00:00:00 2001 From: Trevor Saunders <trev.saunders@gmail.com> Date: Fri, 14 Dec 2012 04:14:21 -0500 Subject: [PATCH 070/469] bug 821593 - stop using nsIDOMCSSValue / nsIDOMRGBColor in editor r=bz --- editor/libeditor/html/nsHTMLAbsPosition.cpp | 66 +++++++++------------ 1 file changed, 27 insertions(+), 39 deletions(-) diff --git a/editor/libeditor/html/nsHTMLAbsPosition.cpp b/editor/libeditor/html/nsHTMLAbsPosition.cpp index a8e95e371d56..8e4aee2d1b0c 100644 --- a/editor/libeditor/html/nsHTMLAbsPosition.cpp +++ b/editor/libeditor/html/nsHTMLAbsPosition.cpp @@ -26,14 +26,13 @@ #include "nsHTMLEditor.h" #include "nsHTMLObjectResizer.h" #include "nsIContent.h" -#include "nsIDOMCSSPrimitiveValue.h" +#include "nsROCSSPrimitiveValue.h" #include "nsIDOMCSSStyleDeclaration.h" -#include "nsIDOMCSSValue.h" #include "nsIDOMElement.h" #include "nsIDOMEventListener.h" #include "nsIDOMEventTarget.h" #include "nsIDOMNode.h" -#include "nsIDOMRGBColor.h" +#include "nsDOMCSSRGBColor.h" #include "nsIDOMWindow.h" #include "nsIEditor.h" #include "nsIHTMLEditor.h" @@ -661,43 +660,32 @@ nsHTMLEditor::CheckPositionedElementBGandFG(nsIDOMElement * aElement, NS_ENSURE_STATE(cssDecl); // from these declarations, get the one we want and that one only - nsCOMPtr<nsIDOMCSSValue> colorCssValue; - res = cssDecl->GetPropertyCSSValue(NS_LITERAL_STRING("color"), getter_AddRefs(colorCssValue)); - NS_ENSURE_SUCCESS(res, res); + ErrorResult error; + nsRefPtr<dom::CSSValue> cssVal = cssDecl->GetPropertyCSSValue(NS_LITERAL_STRING("color"), error); + NS_ENSURE_SUCCESS(error.ErrorCode(), error.ErrorCode()); - uint16_t type; - res = colorCssValue->GetCssValueType(&type); - NS_ENSURE_SUCCESS(res, res); - if (nsIDOMCSSValue::CSS_PRIMITIVE_VALUE == type) { - nsCOMPtr<nsIDOMCSSPrimitiveValue> val = do_QueryInterface(colorCssValue); - res = val->GetPrimitiveType(&type); - NS_ENSURE_SUCCESS(res, res); - if (nsIDOMCSSPrimitiveValue::CSS_RGBCOLOR == type) { - nsCOMPtr<nsIDOMRGBColor> rgbColor; - res = val->GetRGBColorValue(getter_AddRefs(rgbColor)); - NS_ENSURE_SUCCESS(res, res); - nsCOMPtr<nsIDOMCSSPrimitiveValue> red, green, blue; - float r, g, b; - res = rgbColor->GetRed(getter_AddRefs(red)); - NS_ENSURE_SUCCESS(res, res); - res = rgbColor->GetGreen(getter_AddRefs(green)); - NS_ENSURE_SUCCESS(res, res); - res = rgbColor->GetBlue(getter_AddRefs(blue)); - NS_ENSURE_SUCCESS(res, res); - res = red->GetFloatValue(nsIDOMCSSPrimitiveValue::CSS_NUMBER, &r); - NS_ENSURE_SUCCESS(res, res); - res = green->GetFloatValue(nsIDOMCSSPrimitiveValue::CSS_NUMBER, &g); - NS_ENSURE_SUCCESS(res, res); - res = blue->GetFloatValue(nsIDOMCSSPrimitiveValue::CSS_NUMBER, &b); - NS_ENSURE_SUCCESS(res, res); - if (r >= BLACK_BG_RGB_TRIGGER && - g >= BLACK_BG_RGB_TRIGGER && - b >= BLACK_BG_RGB_TRIGGER) - aReturn.AssignLiteral("black"); - else - aReturn.AssignLiteral("white"); - return NS_OK; - } + nsROCSSPrimitiveValue* val = cssVal->AsPrimitiveValue(); + NS_ENSURE_TRUE(val); + + if (nsIDOMCSSPrimitiveValue::CSS_RGBCOLOR == val->PrimitiveType()) { + nsDOMCSSRGBColor* rgbVal = val->GetRGBColorValue(error); + NS_ENSURE_SUCCESS(error.ErrorCode(), error.ErrorCode()); + float r = rgbVal->Red()-> + GetFloatValue(nsIDOMCSSPrimitiveValue::CSS_NUMBER, error); + NS_ENSURE_SUCCESS(error.ErrorCode(), error.ErrorCode()); + float g = rgbVal->Green()-> + GetFloatValue(nsIDOMCSSPrimitiveValue::CSS_NUMBER, error); + NS_ENSURE_SUCCESS(error.ErrorCode(), error.ErrorCode()); + float b = rgbVal->Blue()-> + GetFloatValue(nsIDOMCSSPrimitiveValue::CSS_NUMBER, error); + NS_ENSURE_SUCCESS(error.ErrorCode(), error.ErrorCode()); + if (r >= BLACK_BG_RGB_TRIGGER && + g >= BLACK_BG_RGB_TRIGGER && + b >= BLACK_BG_RGB_TRIGGER) + aReturn.AssignLiteral("black"); + else + aReturn.AssignLiteral("white"); + return NS_OK; } } } From 3c0622ef7d8bd71357949b7c9a75b5db1c40c657 Mon Sep 17 00:00:00 2001 From: Trevor Saunders <trev.saunders@gmail.com> Date: Fri, 14 Dec 2012 04:18:40 -0500 Subject: [PATCH 071/469] bug 821593 - remove nsIDOMCSSPrimitiveValue:::GetRGBColor() r=bz --- dom/interfaces/css/nsIDOMCSSPrimitiveValue.idl | 4 +--- layout/style/nsROCSSPrimitiveValue.cpp | 8 -------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/dom/interfaces/css/nsIDOMCSSPrimitiveValue.idl b/dom/interfaces/css/nsIDOMCSSPrimitiveValue.idl index 84a09b8d8aba..c34e38aca2f6 100644 --- a/dom/interfaces/css/nsIDOMCSSPrimitiveValue.idl +++ b/dom/interfaces/css/nsIDOMCSSPrimitiveValue.idl @@ -13,7 +13,7 @@ * http://www.w3.org/TR/DOM-Level-2-Style */ -[scriptable, uuid(e249031f-8df9-4e7a-b644-18946dce0019)] +[scriptable, uuid(f6df7293-2dc9-4cb9-9531-778caf4370e0)] interface nsIDOMCSSPrimitiveValue : nsIDOMCSSValue { // UnitTypes @@ -59,6 +59,4 @@ interface nsIDOMCSSPrimitiveValue : nsIDOMCSSValue raises(DOMException); nsIDOMRect getRectValue() raises(DOMException); - nsIDOMRGBColor getRGBColorValue() - raises(DOMException); }; diff --git a/layout/style/nsROCSSPrimitiveValue.cpp b/layout/style/nsROCSSPrimitiveValue.cpp index a26c97c3c7b1..77e9f3b88bf9 100644 --- a/layout/style/nsROCSSPrimitiveValue.cpp +++ b/layout/style/nsROCSSPrimitiveValue.cpp @@ -479,14 +479,6 @@ nsROCSSPrimitiveValue::GetRectValue(nsIDOMRect** aRect) return error.ErrorCode(); } -NS_IMETHODIMP -nsROCSSPrimitiveValue::GetRGBColorValue(nsIDOMRGBColor** aColor) -{ - ErrorResult error; - NS_IF_ADDREF(*aColor = GetRGBColorValue(error)); - return error.ErrorCode(); -} - nsDOMCSSRGBColor* nsROCSSPrimitiveValue::GetRGBColorValue(ErrorResult& aRv) { From d5b38a13744ca3f952f0daf84c88b4eabfc51ec8 Mon Sep 17 00:00:00 2001 From: Trevor Saunders <trev.saunders@gmail.com> Date: Fri, 14 Dec 2012 04:51:06 -0500 Subject: [PATCH 072/469] bug 821593 - remove the nsIDOMRGBColor xpidl now that nothing uses it r=bz --- dom/interfaces/base/domstubs.idl | 1 - dom/interfaces/css/Makefile.in | 2 -- dom/interfaces/css/nsIDOMNSRGBAColor.idl | 12 -------- dom/interfaces/css/nsIDOMRGBColor.idl | 14 --------- layout/style/nsDOMCSSRGBColor.cpp | 38 ------------------------ layout/style/nsDOMCSSRGBColor.h | 5 +--- 6 files changed, 1 insertion(+), 71 deletions(-) delete mode 100644 dom/interfaces/css/nsIDOMNSRGBAColor.idl delete mode 100644 dom/interfaces/css/nsIDOMRGBColor.idl diff --git a/dom/interfaces/base/domstubs.idl b/dom/interfaces/base/domstubs.idl index e95254b8f95a..a9aa2bf39f1e 100644 --- a/dom/interfaces/base/domstubs.idl +++ b/dom/interfaces/base/domstubs.idl @@ -75,7 +75,6 @@ interface nsIDOMCSSStyleSheet; interface nsIDOMCSSStyleDeclaration; interface nsIDOMCounter; interface nsIDOMRect; -interface nsIDOMRGBColor; interface nsIDOMCSSStyleRule; interface nsIDOMCSSStyleRuleCollection; interface nsIDOMHTMLTableCaptionElement; diff --git a/dom/interfaces/css/Makefile.in b/dom/interfaces/css/Makefile.in index 6c2f9893bbd8..fd02cb727c51 100644 --- a/dom/interfaces/css/Makefile.in +++ b/dom/interfaces/css/Makefile.in @@ -39,9 +39,7 @@ XPIDLSRCS = \ nsIDOMCSSStyleRule.idl \ nsIDOMCSSUnknownRule.idl \ nsIDOMCounter.idl \ - nsIDOMRGBColor.idl \ nsIDOMRect.idl \ - nsIDOMNSRGBAColor.idl \ $(NULL) include $(topsrcdir)/config/rules.mk diff --git a/dom/interfaces/css/nsIDOMNSRGBAColor.idl b/dom/interfaces/css/nsIDOMNSRGBAColor.idl deleted file mode 100644 index f27d94454cfe..000000000000 --- a/dom/interfaces/css/nsIDOMNSRGBAColor.idl +++ /dev/null @@ -1,12 +0,0 @@ -/* -*- 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/. */ - -#include "nsIDOMRGBColor.idl" - -[scriptable, uuid(742dc816-5134-4214-adfa-cad9dd3377cd)] -interface nsIDOMNSRGBAColor : nsIDOMRGBColor -{ - readonly attribute nsIDOMCSSPrimitiveValue alpha; -}; diff --git a/dom/interfaces/css/nsIDOMRGBColor.idl b/dom/interfaces/css/nsIDOMRGBColor.idl deleted file mode 100644 index db5011193bc6..000000000000 --- a/dom/interfaces/css/nsIDOMRGBColor.idl +++ /dev/null @@ -1,14 +0,0 @@ -/* -*- 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/. */ - -#include "domstubs.idl" - -[scriptable, uuid(6aff3102-320d-4986-9790-12316bb87cf9)] -interface nsIDOMRGBColor : nsISupports -{ - readonly attribute nsIDOMCSSPrimitiveValue red; - readonly attribute nsIDOMCSSPrimitiveValue green; - readonly attribute nsIDOMCSSPrimitiveValue blue; -}; diff --git a/layout/style/nsDOMCSSRGBColor.cpp b/layout/style/nsDOMCSSRGBColor.cpp index 39b67f7880ba..5a0882975e93 100644 --- a/layout/style/nsDOMCSSRGBColor.cpp +++ b/layout/style/nsDOMCSSRGBColor.cpp @@ -32,8 +32,6 @@ nsDOMCSSRGBColor::~nsDOMCSSRGBColor(void) } NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMCSSRGBColor) - NS_INTERFACE_MAP_ENTRY(nsIDOMRGBColor) - NS_INTERFACE_MAP_ENTRY(nsIDOMNSRGBAColor) NS_INTERFACE_MAP_ENTRY(nsISupports) NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY NS_INTERFACE_MAP_END @@ -48,39 +46,3 @@ nsDOMCSSRGBColor::WrapObject(JSContext *aCx, JSObject *aScope, bool *aTried) return dom::RGBColorBinding::Wrap(aCx, aScope, this, aTried); } - -NS_IMETHODIMP -nsDOMCSSRGBColor::GetRed(nsIDOMCSSPrimitiveValue** aRed) -{ - NS_ENSURE_TRUE(mRed, NS_ERROR_NOT_INITIALIZED); - *aRed = mRed; - NS_ADDREF(*aRed); - return NS_OK; -} - -NS_IMETHODIMP -nsDOMCSSRGBColor::GetGreen(nsIDOMCSSPrimitiveValue** aGreen) -{ - NS_ENSURE_TRUE(mGreen, NS_ERROR_NOT_INITIALIZED); - *aGreen = mGreen; - NS_ADDREF(*aGreen); - return NS_OK; -} - -NS_IMETHODIMP -nsDOMCSSRGBColor::GetBlue(nsIDOMCSSPrimitiveValue** aBlue) -{ - NS_ENSURE_TRUE(mBlue, NS_ERROR_NOT_INITIALIZED); - *aBlue = mBlue; - NS_ADDREF(*aBlue); - return NS_OK; -} - -NS_IMETHODIMP -nsDOMCSSRGBColor::GetAlpha(nsIDOMCSSPrimitiveValue** aAlpha) -{ - NS_ENSURE_TRUE(mAlpha, NS_ERROR_NOT_INITIALIZED); - *aAlpha = mAlpha; - NS_ADDREF(*aAlpha); - return NS_OK; -} diff --git a/layout/style/nsDOMCSSRGBColor.h b/layout/style/nsDOMCSSRGBColor.h index 1b1d86459b24..cf8360d5d660 100644 --- a/layout/style/nsDOMCSSRGBColor.h +++ b/layout/style/nsDOMCSSRGBColor.h @@ -11,12 +11,11 @@ #include "mozilla/Attributes.h" #include "nsAutoPtr.h" #include "nsISupports.h" -#include "nsIDOMNSRGBAColor.h" #include "nsWrapperCache.h" class nsROCSSPrimitiveValue; -class nsDOMCSSRGBColor : public nsIDOMNSRGBAColor, +class nsDOMCSSRGBColor : public nsISupports, public nsWrapperCache { public: @@ -29,8 +28,6 @@ public: virtual ~nsDOMCSSRGBColor(void); NS_DECL_CYCLE_COLLECTING_ISUPPORTS - NS_DECL_NSIDOMRGBCOLOR - NS_DECL_NSIDOMNSRGBACOLOR NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsDOMCSSRGBColor) From 527b4acbd2ed9fb1c1692f3196ef3fa13c204a53 Mon Sep 17 00:00:00 2001 From: Ms2ger <ms2ger@gmail.com> Date: Sat, 22 Dec 2012 15:33:46 +0100 Subject: [PATCH 073/469] Backout bug 821593 for bustage. --- dom/interfaces/base/domstubs.idl | 1 + dom/interfaces/css/Makefile.in | 2 + .../css/nsIDOMCSSPrimitiveValue.idl | 4 +- dom/interfaces/css/nsIDOMNSRGBAColor.idl | 12 ++++ dom/interfaces/css/nsIDOMRGBColor.idl | 14 ++++ editor/libeditor/html/nsHTMLAbsPosition.cpp | 66 +++++++++++-------- layout/style/CSSValue.h | 8 --- layout/style/nsDOMCSSRGBColor.cpp | 38 +++++++++++ layout/style/nsDOMCSSRGBColor.h | 5 +- layout/style/nsROCSSPrimitiveValue.cpp | 8 +++ layout/style/nsROCSSPrimitiveValue.h | 6 -- 11 files changed, 121 insertions(+), 43 deletions(-) create mode 100644 dom/interfaces/css/nsIDOMNSRGBAColor.idl create mode 100644 dom/interfaces/css/nsIDOMRGBColor.idl diff --git a/dom/interfaces/base/domstubs.idl b/dom/interfaces/base/domstubs.idl index a9aa2bf39f1e..e95254b8f95a 100644 --- a/dom/interfaces/base/domstubs.idl +++ b/dom/interfaces/base/domstubs.idl @@ -75,6 +75,7 @@ interface nsIDOMCSSStyleSheet; interface nsIDOMCSSStyleDeclaration; interface nsIDOMCounter; interface nsIDOMRect; +interface nsIDOMRGBColor; interface nsIDOMCSSStyleRule; interface nsIDOMCSSStyleRuleCollection; interface nsIDOMHTMLTableCaptionElement; diff --git a/dom/interfaces/css/Makefile.in b/dom/interfaces/css/Makefile.in index fd02cb727c51..6c2f9893bbd8 100644 --- a/dom/interfaces/css/Makefile.in +++ b/dom/interfaces/css/Makefile.in @@ -39,7 +39,9 @@ XPIDLSRCS = \ nsIDOMCSSStyleRule.idl \ nsIDOMCSSUnknownRule.idl \ nsIDOMCounter.idl \ + nsIDOMRGBColor.idl \ nsIDOMRect.idl \ + nsIDOMNSRGBAColor.idl \ $(NULL) include $(topsrcdir)/config/rules.mk diff --git a/dom/interfaces/css/nsIDOMCSSPrimitiveValue.idl b/dom/interfaces/css/nsIDOMCSSPrimitiveValue.idl index c34e38aca2f6..84a09b8d8aba 100644 --- a/dom/interfaces/css/nsIDOMCSSPrimitiveValue.idl +++ b/dom/interfaces/css/nsIDOMCSSPrimitiveValue.idl @@ -13,7 +13,7 @@ * http://www.w3.org/TR/DOM-Level-2-Style */ -[scriptable, uuid(f6df7293-2dc9-4cb9-9531-778caf4370e0)] +[scriptable, uuid(e249031f-8df9-4e7a-b644-18946dce0019)] interface nsIDOMCSSPrimitiveValue : nsIDOMCSSValue { // UnitTypes @@ -59,4 +59,6 @@ interface nsIDOMCSSPrimitiveValue : nsIDOMCSSValue raises(DOMException); nsIDOMRect getRectValue() raises(DOMException); + nsIDOMRGBColor getRGBColorValue() + raises(DOMException); }; diff --git a/dom/interfaces/css/nsIDOMNSRGBAColor.idl b/dom/interfaces/css/nsIDOMNSRGBAColor.idl new file mode 100644 index 000000000000..f27d94454cfe --- /dev/null +++ b/dom/interfaces/css/nsIDOMNSRGBAColor.idl @@ -0,0 +1,12 @@ +/* -*- 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/. */ + +#include "nsIDOMRGBColor.idl" + +[scriptable, uuid(742dc816-5134-4214-adfa-cad9dd3377cd)] +interface nsIDOMNSRGBAColor : nsIDOMRGBColor +{ + readonly attribute nsIDOMCSSPrimitiveValue alpha; +}; diff --git a/dom/interfaces/css/nsIDOMRGBColor.idl b/dom/interfaces/css/nsIDOMRGBColor.idl new file mode 100644 index 000000000000..db5011193bc6 --- /dev/null +++ b/dom/interfaces/css/nsIDOMRGBColor.idl @@ -0,0 +1,14 @@ +/* -*- 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/. */ + +#include "domstubs.idl" + +[scriptable, uuid(6aff3102-320d-4986-9790-12316bb87cf9)] +interface nsIDOMRGBColor : nsISupports +{ + readonly attribute nsIDOMCSSPrimitiveValue red; + readonly attribute nsIDOMCSSPrimitiveValue green; + readonly attribute nsIDOMCSSPrimitiveValue blue; +}; diff --git a/editor/libeditor/html/nsHTMLAbsPosition.cpp b/editor/libeditor/html/nsHTMLAbsPosition.cpp index 8e4aee2d1b0c..a8e95e371d56 100644 --- a/editor/libeditor/html/nsHTMLAbsPosition.cpp +++ b/editor/libeditor/html/nsHTMLAbsPosition.cpp @@ -26,13 +26,14 @@ #include "nsHTMLEditor.h" #include "nsHTMLObjectResizer.h" #include "nsIContent.h" -#include "nsROCSSPrimitiveValue.h" +#include "nsIDOMCSSPrimitiveValue.h" #include "nsIDOMCSSStyleDeclaration.h" +#include "nsIDOMCSSValue.h" #include "nsIDOMElement.h" #include "nsIDOMEventListener.h" #include "nsIDOMEventTarget.h" #include "nsIDOMNode.h" -#include "nsDOMCSSRGBColor.h" +#include "nsIDOMRGBColor.h" #include "nsIDOMWindow.h" #include "nsIEditor.h" #include "nsIHTMLEditor.h" @@ -660,32 +661,43 @@ nsHTMLEditor::CheckPositionedElementBGandFG(nsIDOMElement * aElement, NS_ENSURE_STATE(cssDecl); // from these declarations, get the one we want and that one only - ErrorResult error; - nsRefPtr<dom::CSSValue> cssVal = cssDecl->GetPropertyCSSValue(NS_LITERAL_STRING("color"), error); - NS_ENSURE_SUCCESS(error.ErrorCode(), error.ErrorCode()); + nsCOMPtr<nsIDOMCSSValue> colorCssValue; + res = cssDecl->GetPropertyCSSValue(NS_LITERAL_STRING("color"), getter_AddRefs(colorCssValue)); + NS_ENSURE_SUCCESS(res, res); - nsROCSSPrimitiveValue* val = cssVal->AsPrimitiveValue(); - NS_ENSURE_TRUE(val); - - if (nsIDOMCSSPrimitiveValue::CSS_RGBCOLOR == val->PrimitiveType()) { - nsDOMCSSRGBColor* rgbVal = val->GetRGBColorValue(error); - NS_ENSURE_SUCCESS(error.ErrorCode(), error.ErrorCode()); - float r = rgbVal->Red()-> - GetFloatValue(nsIDOMCSSPrimitiveValue::CSS_NUMBER, error); - NS_ENSURE_SUCCESS(error.ErrorCode(), error.ErrorCode()); - float g = rgbVal->Green()-> - GetFloatValue(nsIDOMCSSPrimitiveValue::CSS_NUMBER, error); - NS_ENSURE_SUCCESS(error.ErrorCode(), error.ErrorCode()); - float b = rgbVal->Blue()-> - GetFloatValue(nsIDOMCSSPrimitiveValue::CSS_NUMBER, error); - NS_ENSURE_SUCCESS(error.ErrorCode(), error.ErrorCode()); - if (r >= BLACK_BG_RGB_TRIGGER && - g >= BLACK_BG_RGB_TRIGGER && - b >= BLACK_BG_RGB_TRIGGER) - aReturn.AssignLiteral("black"); - else - aReturn.AssignLiteral("white"); - return NS_OK; + uint16_t type; + res = colorCssValue->GetCssValueType(&type); + NS_ENSURE_SUCCESS(res, res); + if (nsIDOMCSSValue::CSS_PRIMITIVE_VALUE == type) { + nsCOMPtr<nsIDOMCSSPrimitiveValue> val = do_QueryInterface(colorCssValue); + res = val->GetPrimitiveType(&type); + NS_ENSURE_SUCCESS(res, res); + if (nsIDOMCSSPrimitiveValue::CSS_RGBCOLOR == type) { + nsCOMPtr<nsIDOMRGBColor> rgbColor; + res = val->GetRGBColorValue(getter_AddRefs(rgbColor)); + NS_ENSURE_SUCCESS(res, res); + nsCOMPtr<nsIDOMCSSPrimitiveValue> red, green, blue; + float r, g, b; + res = rgbColor->GetRed(getter_AddRefs(red)); + NS_ENSURE_SUCCESS(res, res); + res = rgbColor->GetGreen(getter_AddRefs(green)); + NS_ENSURE_SUCCESS(res, res); + res = rgbColor->GetBlue(getter_AddRefs(blue)); + NS_ENSURE_SUCCESS(res, res); + res = red->GetFloatValue(nsIDOMCSSPrimitiveValue::CSS_NUMBER, &r); + NS_ENSURE_SUCCESS(res, res); + res = green->GetFloatValue(nsIDOMCSSPrimitiveValue::CSS_NUMBER, &g); + NS_ENSURE_SUCCESS(res, res); + res = blue->GetFloatValue(nsIDOMCSSPrimitiveValue::CSS_NUMBER, &b); + NS_ENSURE_SUCCESS(res, res); + if (r >= BLACK_BG_RGB_TRIGGER && + g >= BLACK_BG_RGB_TRIGGER && + b >= BLACK_BG_RGB_TRIGGER) + aReturn.AssignLiteral("black"); + else + aReturn.AssignLiteral("white"); + return NS_OK; + } } } } diff --git a/layout/style/CSSValue.h b/layout/style/CSSValue.h index d58c58f38561..e189c1bfd1aa 100644 --- a/layout/style/CSSValue.h +++ b/layout/style/CSSValue.h @@ -31,14 +31,6 @@ public: virtual void GetCssText(nsString& aText, mozilla::ErrorResult& aRv) = 0; virtual void SetCssText(const nsAString& aText, mozilla::ErrorResult& aRv) = 0; virtual uint16_t CssValueType() const = 0; - - // Downcasting - - /** - * Return this as a nsROCSSPrimitiveValue* if its a primitive value, and null - * otherwise. - */ - nsROCSSPrimitiveValue *AsPrimitiveValue(); }; } diff --git a/layout/style/nsDOMCSSRGBColor.cpp b/layout/style/nsDOMCSSRGBColor.cpp index 5a0882975e93..39b67f7880ba 100644 --- a/layout/style/nsDOMCSSRGBColor.cpp +++ b/layout/style/nsDOMCSSRGBColor.cpp @@ -32,6 +32,8 @@ nsDOMCSSRGBColor::~nsDOMCSSRGBColor(void) } NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMCSSRGBColor) + NS_INTERFACE_MAP_ENTRY(nsIDOMRGBColor) + NS_INTERFACE_MAP_ENTRY(nsIDOMNSRGBAColor) NS_INTERFACE_MAP_ENTRY(nsISupports) NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY NS_INTERFACE_MAP_END @@ -46,3 +48,39 @@ nsDOMCSSRGBColor::WrapObject(JSContext *aCx, JSObject *aScope, bool *aTried) return dom::RGBColorBinding::Wrap(aCx, aScope, this, aTried); } + +NS_IMETHODIMP +nsDOMCSSRGBColor::GetRed(nsIDOMCSSPrimitiveValue** aRed) +{ + NS_ENSURE_TRUE(mRed, NS_ERROR_NOT_INITIALIZED); + *aRed = mRed; + NS_ADDREF(*aRed); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMCSSRGBColor::GetGreen(nsIDOMCSSPrimitiveValue** aGreen) +{ + NS_ENSURE_TRUE(mGreen, NS_ERROR_NOT_INITIALIZED); + *aGreen = mGreen; + NS_ADDREF(*aGreen); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMCSSRGBColor::GetBlue(nsIDOMCSSPrimitiveValue** aBlue) +{ + NS_ENSURE_TRUE(mBlue, NS_ERROR_NOT_INITIALIZED); + *aBlue = mBlue; + NS_ADDREF(*aBlue); + return NS_OK; +} + +NS_IMETHODIMP +nsDOMCSSRGBColor::GetAlpha(nsIDOMCSSPrimitiveValue** aAlpha) +{ + NS_ENSURE_TRUE(mAlpha, NS_ERROR_NOT_INITIALIZED); + *aAlpha = mAlpha; + NS_ADDREF(*aAlpha); + return NS_OK; +} diff --git a/layout/style/nsDOMCSSRGBColor.h b/layout/style/nsDOMCSSRGBColor.h index cf8360d5d660..1b1d86459b24 100644 --- a/layout/style/nsDOMCSSRGBColor.h +++ b/layout/style/nsDOMCSSRGBColor.h @@ -11,11 +11,12 @@ #include "mozilla/Attributes.h" #include "nsAutoPtr.h" #include "nsISupports.h" +#include "nsIDOMNSRGBAColor.h" #include "nsWrapperCache.h" class nsROCSSPrimitiveValue; -class nsDOMCSSRGBColor : public nsISupports, +class nsDOMCSSRGBColor : public nsIDOMNSRGBAColor, public nsWrapperCache { public: @@ -28,6 +29,8 @@ public: virtual ~nsDOMCSSRGBColor(void); NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_NSIDOMRGBCOLOR + NS_DECL_NSIDOMNSRGBACOLOR NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsDOMCSSRGBColor) diff --git a/layout/style/nsROCSSPrimitiveValue.cpp b/layout/style/nsROCSSPrimitiveValue.cpp index 77e9f3b88bf9..a26c97c3c7b1 100644 --- a/layout/style/nsROCSSPrimitiveValue.cpp +++ b/layout/style/nsROCSSPrimitiveValue.cpp @@ -479,6 +479,14 @@ nsROCSSPrimitiveValue::GetRectValue(nsIDOMRect** aRect) return error.ErrorCode(); } +NS_IMETHODIMP +nsROCSSPrimitiveValue::GetRGBColorValue(nsIDOMRGBColor** aColor) +{ + ErrorResult error; + NS_IF_ADDREF(*aColor = GetRGBColorValue(error)); + return error.ErrorCode(); +} + nsDOMCSSRGBColor* nsROCSSPrimitiveValue::GetRGBColorValue(ErrorResult& aRv) { diff --git a/layout/style/nsROCSSPrimitiveValue.h b/layout/style/nsROCSSPrimitiveValue.h index 1c4ce744a0e1..527ad8164873 100644 --- a/layout/style/nsROCSSPrimitiveValue.h +++ b/layout/style/nsROCSSPrimitiveValue.h @@ -99,11 +99,5 @@ private: } mValue; }; -inline nsROCSSPrimitiveValue *mozilla::dom::CSSValue::AsPrimitiveValue() -{ - return CssValueType() == nsIDOMCSSValue::CSS_PRIMITIVE_VALUE ? - static_cast<nsROCSSPrimitiveValue*>(this) : nullptr; -} - #endif /* nsROCSSPrimitiveValue_h___ */ From 50b95c94b2961cf8e85f43006feeebdd92393f45 Mon Sep 17 00:00:00 2001 From: Honza Bambas <honzab.moz@firemni.cz> Date: Sat, 22 Dec 2012 15:46:14 +0100 Subject: [PATCH 074/469] Bug 765215 - Firefox 13 hangs on resuming from sleep, introduced wake up adjust for QueryPerformanceCounter, r=ehsan --- xpcom/ds/TimeStamp_windows.cpp | 50 ++++++++++++++++++++++++++++------ 1 file changed, 41 insertions(+), 9 deletions(-) diff --git a/xpcom/ds/TimeStamp_windows.cpp b/xpcom/ds/TimeStamp_windows.cpp index b099f2dd90c1..52f80ef494cc 100644 --- a/xpcom/ds/TimeStamp_windows.cpp +++ b/xpcom/ds/TimeStamp_windows.cpp @@ -133,6 +133,9 @@ static const ULONGLONG kOverflowLimit = 100; // which is the most usual increment. static const DWORD kDefaultTimeIncrement = 156001; +// Time since GTC fallback after we forbid recalibration on wake up [ms] +static const DWORD kForbidRecalibrationTime = 2000; + // ---------------------------------------------------------------------------- // Global variables, not changing at runtime // ---------------------------------------------------------------------------- @@ -168,6 +171,12 @@ static LONGLONG sFrequencyPerSec = 0; static LONGLONG sUnderrunThreshold; static LONGLONG sOverrunThreshold; +// QPC may be reset after wake up. But because we may return GTC + sSkew +// for a short time before we reclibrate after wakeup, result of +// CalibratedPerformanceCounter may go radically backwrads. We have +// to compensate this jump. +static LONGLONG sWakeupAdjust = 0; + // ---------------------------------------------------------------------------- // Global lock // ---------------------------------------------------------------------------- @@ -207,6 +216,11 @@ static ULONGLONG sLastResult = 0; // Kept in [ms] static ULONGLONG sLastCalibrated; +// Time of fallback to GTC +// +// Kept in [ms] and filled only with value of GTC +static ULONGLONG sFallbackTime = 0; + // The following variable stores two booleans, both initialized to false. // // The lower word is fallbackToGTC: @@ -327,11 +341,19 @@ StandbyObserver::Observe(nsISupports *subject, { AutoCriticalSection lock(&sTimeStampLock); + CalibrationFlags value; + value.dwordValue = sCalibrationFlags.dwordValue; + + if (value.flags.fallBackToGTC && + ((sGetTickCount64() - sFallbackTime) > kForbidRecalibrationTime)) { + LOG(("Disallowing recalibration since the time from fallback is too long")); + return NS_OK; + } + // Clear the potentiall fallback flag now and try using // QPC again after wake up. - CalibrationFlags value; + value.flags.forceRecalibrate = value.flags.fallBackToGTC; value.flags.fallBackToGTC = false; - value.flags.forceRecalibrate = true; sCalibrationFlags.dwordValue = value.dwordValue; // aligned 32-bit writes are atomic LOG(("TimeStamp: system has woken up, reset GTC fallback")); @@ -465,11 +487,12 @@ PerformanceCounter() // Called when we detect a larger deviation of QPC to disable it. static inline void -RecordFlaw() +RecordFlaw(ULONGLONG gtc) { sCalibrationFlags.flags.fallBackToGTC = true; + sFallbackTime = gtc; - LOG(("TimeStamp: falling back to GTC :(")); + LOG(("TimeStamp: falling back to GTC at %llu :(", gtc)); #if 0 // This code has been disabled, because we: @@ -526,7 +549,7 @@ CheckCalibration(LONGLONG overflow, ULONGLONG qpc, ULONGLONG gtc) // This sets fallBackToGTC, we have detected // an unreliability of QPC, stop using it. AutoCriticalSection lock(&sTimeStampLock); - RecordFlaw(); + RecordFlaw(gtc); return false; } } @@ -534,10 +557,19 @@ CheckCalibration(LONGLONG overflow, ULONGLONG qpc, ULONGLONG gtc) if (sinceLastCalibration > kCalibrationInterval || value.flags.forceRecalibrate) { // Recalculate the skew now AutoCriticalSection lock(&sTimeStampLock); + + // If this is forced recalibration after wakeup, we have to take care of any large + // QPC jumps from GTC + current skew. It can happen that QPC after waking up is + // reset or jumps a lot to the past. When we would start using QPC again + // the result of CalibratedPerformanceCounter would go radically back - actually + // stop increasing since there is a simple MAX(last, now) protection. + if (value.flags.forceRecalibrate) + sWakeupAdjust += sSkew - (qpc - ms2mt(gtc)); + sSkew = qpc - ms2mt(gtc); sLastCalibrated = gtc; - LOG(("TimeStamp: new skew is %1.2fms (force:%d)", - mt2ms_d(sSkew), value.flags.forceRecalibrate)); + LOG(("TimeStamp: new skew is %1.2fms, wakeup adjust is %1.2fms (force:%d)", + mt2ms_d(sSkew), mt2ms_d(sWakeupAdjust), value.flags.forceRecalibrate)); sCalibrationFlags.flags.forceRecalibrate = false; } @@ -588,7 +620,7 @@ CalibratedPerformanceCounter() // the largest bottleneck, let threads read the value concurently to have // possibly a better performance. - ULONGLONG qpc = PerformanceCounter(); + ULONGLONG qpc = PerformanceCounter() + sWakeupAdjust; // Rollover protection ULONGLONG gtc = sGetTickCount64(); @@ -707,7 +739,7 @@ TimeStamp::Startup() sHasStableTSC = HasStableTSC(); - LOG(("TimeStamp: initial skew is %1.2fms", mt2ms_d(sSkew))); + LOG(("TimeStamp: initial skew is %1.2fms, sHasStableTSC=%d", mt2ms_d(sSkew), sHasStableTSC)); return NS_OK; } From 574decbf047cdacd5b93f914745bc759db4b3356 Mon Sep 17 00:00:00 2001 From: Hannes Verschore <hv1989@gmail.com> Date: Sat, 22 Dec 2012 17:09:32 +0100 Subject: [PATCH 075/469] Bug 824005: Fix for v8-richards regression introduced in bug 813784, r=nbp --- js/src/jsanalyze.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/js/src/jsanalyze.cpp b/js/src/jsanalyze.cpp index d6c2c7167a6c..6f6e474a931f 100644 --- a/js/src/jsanalyze.cpp +++ b/js/src/jsanalyze.cpp @@ -593,9 +593,10 @@ ScriptAnalysis::analyzeBytecode(JSContext *cx) break; default: - if (!(js_CodeSpec[op].format & JOF_DECOMPOSE)) + if (!(js_CodeSpec[op].format & JOF_DECOMPOSE)) { isJaegerCompileable = false; isJaegerInlineable = isIonInlineable = false; + } break; } From fd8f18bdbfbb81aaa4776086a4170d72715583ee Mon Sep 17 00:00:00 2001 From: Jonathan Watt <jwatt@jwatt.org> Date: Sat, 22 Dec 2012 16:43:20 +0000 Subject: [PATCH 076/469] Regression reftests for bug 822014 to let us know if the behavior of clip-path on outer-<svg> with a border changes. --- .../svg-integration/clipPath-html-07-ref.svg | 4 +++ .../svg-integration/clipPath-html-07.xhtml | 31 +++++++++++++++++++ .../svg-integration/clipPath-html-08.xhtml | 26 ++++++++++++++++ .../reftests/svg/svg-integration/reftest.list | 2 ++ 4 files changed, 63 insertions(+) create mode 100644 layout/reftests/svg/svg-integration/clipPath-html-07-ref.svg create mode 100644 layout/reftests/svg/svg-integration/clipPath-html-07.xhtml create mode 100644 layout/reftests/svg/svg-integration/clipPath-html-08.xhtml diff --git a/layout/reftests/svg/svg-integration/clipPath-html-07-ref.svg b/layout/reftests/svg/svg-integration/clipPath-html-07-ref.svg new file mode 100644 index 000000000000..4d7153968a5d --- /dev/null +++ b/layout/reftests/svg/svg-integration/clipPath-html-07-ref.svg @@ -0,0 +1,4 @@ +<svg xmlns="http://www.w3.org/2000/svg"> + <rect x="100" y="100" width="100" height="100" fill="black"/> + <rect x="150" y="150" width="50" height="50" fill="yellow"/> +</svg> diff --git a/layout/reftests/svg/svg-integration/clipPath-html-07.xhtml b/layout/reftests/svg/svg-integration/clipPath-html-07.xhtml new file mode 100644 index 000000000000..8391ad01e6cd --- /dev/null +++ b/layout/reftests/svg/svg-integration/clipPath-html-07.xhtml @@ -0,0 +1,31 @@ +<!DOCTYPE html> +<!-- + Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ +--> +<html xmlns="http://www.w3.org/1999/xhtml"> + <!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=822014 --> + <head> + <title>Test clip-path on outer-<svg> with border + + + + + + + + + + + + + + diff --git a/layout/reftests/svg/svg-integration/clipPath-html-08.xhtml b/layout/reftests/svg/svg-integration/clipPath-html-08.xhtml new file mode 100644 index 000000000000..3eb0dfa3c347 --- /dev/null +++ b/layout/reftests/svg/svg-integration/clipPath-html-08.xhtml @@ -0,0 +1,26 @@ + + + + + + Test clip-path on <div> with border + + + +
+ + + + + + + diff --git a/layout/reftests/svg/svg-integration/reftest.list b/layout/reftests/svg/svg-integration/reftest.list index 6976977d89a9..42bac63f7037 100644 --- a/layout/reftests/svg/svg-integration/reftest.list +++ b/layout/reftests/svg/svg-integration/reftest.list @@ -10,6 +10,8 @@ fuzzy-if(true,140,70) == clipPath-html-05.xhtml clipPath-html-05-ref.xhtml # Bug fuzzy-if(true,140,70) == clipPath-html-05-extref.xhtml clipPath-html-05-ref.xhtml # Bug 776089 == clipPath-html-06.xhtml clipPath-html-06-ref.xhtml == clipPath-html-06-extref.xhtml clipPath-html-06-ref.xhtml +== clipPath-html-07.xhtml clipPath-html-07-ref.svg +== clipPath-html-08.xhtml clipPath-html-07-ref.svg # reuse 07-ref.svg == clipPath-html-zoomed-01.xhtml clipPath-html-01-ref.svg == clipPath-transformed-html-01.xhtml ../pass.svg == clipPath-transformed-html-02.xhtml ../pass.svg From 42c96d1ff89c0d87785d91aec4cf6b6365332f13 Mon Sep 17 00:00:00 2001 From: Jason Duell Date: Sat, 22 Dec 2012 09:44:38 -0800 Subject: [PATCH 077/469] Bug 815523. Fix syntax of skip-if to skip xpcshell test on windows. r==orangefix --- modules/libjar/test/unit/xpcshell.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/libjar/test/unit/xpcshell.ini b/modules/libjar/test/unit/xpcshell.ini index e46b01058883..1dc4446df439 100644 --- a/modules/libjar/test/unit/xpcshell.ini +++ b/modules/libjar/test/unit/xpcshell.ini @@ -4,7 +4,7 @@ tail = [test_jarchannel.js] [test_jarchannel_e10s.js] -skip-if = os == "mac" || os == "windows" +skip-if = os == "mac" || os == "win" [test_bug278262.js] [test_bug333423.js] [test_bug336691.js] From effe344f4528f216080b9539af79b008e9bbbc56 Mon Sep 17 00:00:00 2001 From: Michael Wu Date: Sat, 22 Dec 2012 13:01:07 -0500 Subject: [PATCH 078/469] Bug 824090 - Fix gl config selection in boot animation, r=cjones --- b2g/app/BootAnimation.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/b2g/app/BootAnimation.cpp b/b2g/app/BootAnimation.cpp index 56c0de3e879c..ef87120cff70 100644 --- a/b2g/app/BootAnimation.cpp +++ b/b2g/app/BootAnimation.cpp @@ -363,9 +363,8 @@ AnimationThread(void *) ANativeWindow const * const window = gNativeWindow.get(); window->query(window, NATIVE_WINDOW_FORMAT, &format); - EGLConfig config = NULL; - CreateConfig(&config, display, format); - if (!config) { + EGLConfig config; + if (!CreateConfig(&config, display, format)) { LOGW("Could not find config for pixel format"); return nullptr; } From 2bb8a2cfbe5697d0053dd97da9822c5e91ad4af5 Mon Sep 17 00:00:00 2001 From: Daniel Holbert Date: Sat, 22 Dec 2012 10:08:33 -0800 Subject: [PATCH 079/469] Bug 823286: Fix incorrect kDefaultRemainingTime value in GeckoBatteryManager.java, to be consistent with dom/battery/Constants.h (and actually use it, instead of hardcoding 0). r=mounir --- mobile/android/base/GeckoBatteryManager.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mobile/android/base/GeckoBatteryManager.java b/mobile/android/base/GeckoBatteryManager.java index b8dc56726a79..85e7bd22c9e5 100644 --- a/mobile/android/base/GeckoBatteryManager.java +++ b/mobile/android/base/GeckoBatteryManager.java @@ -21,14 +21,14 @@ public class GeckoBatteryManager extends BroadcastReceiver { // dom/battery/Constants.h private final static double kDefaultLevel = 1.0; private final static boolean kDefaultCharging = true; - private final static double kDefaultRemainingTime = -1.0; + private final static double kDefaultRemainingTime = 0.0; private final static double kUnknownRemainingTime = -1.0; private static long sLastLevelChange = 0; private static boolean sNotificationsEnabled = false; private static double sLevel = kDefaultLevel; private static boolean sCharging = kDefaultCharging; - private static double sRemainingTime = kDefaultRemainingTime;; + private static double sRemainingTime = kDefaultRemainingTime; private static GeckoBatteryManager sInstance = new GeckoBatteryManager(); @@ -113,7 +113,7 @@ public class GeckoBatteryManager extends BroadcastReceiver { } if (sLevel == 1.0 && sCharging) { - sRemainingTime = 0.0; + sRemainingTime = kDefaultRemainingTime; } else if (sLevel != previousLevel) { // Estimate remaining time. if (sLastLevelChange != 0) { @@ -147,7 +147,7 @@ public class GeckoBatteryManager extends BroadcastReceiver { } else { sLevel = kDefaultLevel; sCharging = kDefaultCharging; - sRemainingTime = 0; + sRemainingTime = kDefaultRemainingTime; } /* From 66407bcd3f996540f3efd7ccb9d08fd4d639815a Mon Sep 17 00:00:00 2001 From: Asaf Romano Date: Sat, 22 Dec 2012 22:13:25 +0200 Subject: [PATCH 080/469] Bug 822343 - Downloads view takes far too long to render. Part 4 - Cache the download state so command-updating doesn't check the file size over and over. r=mconley. --- .../content/allDownloadsViewOverlay.js | 81 +++++++++++-------- 1 file changed, 46 insertions(+), 35 deletions(-) diff --git a/browser/components/downloads/content/allDownloadsViewOverlay.js b/browser/components/downloads/content/allDownloadsViewOverlay.js index 3f7cd8448bd1..92a5e7a1852e 100644 --- a/browser/components/downloads/content/allDownloadsViewOverlay.js +++ b/browser/components/downloads/content/allDownloadsViewOverlay.js @@ -96,7 +96,7 @@ DownloadElementShell.prototype = { } else if (this._placesNode) { this._wasInProgress = false; - this._wasDone = this._state == nsIDM.DOWNLOAD_FINISHED; + this._wasDone = this.getDownloadState(true) == nsIDM.DOWNLOAD_FINISHED; } this._updateStatusUI(); @@ -115,7 +115,7 @@ DownloadElementShell.prototype = { this._placesNode = aNode; if (!this._dataItem && this._placesNode) { this._wasInProgress = false; - this._wasDone = this._state == nsIDM.DOWNLOAD_FINISHED; + this._wasDone = this.getDownloadState(true) == nsIDM.DOWNLOAD_FINISHED; this._updateStatusUI(); } } @@ -216,42 +216,53 @@ DownloadElementShell.prototype = { // The target's file size in bytes. If there's no target file, or If we // cannot determine its size, 0 is returned. get _fileSize() { - if (!this._file || !this._file.exists()) - return 0; - try { - return this._file.fileSize; - } - catch(ex) { - Cu.reportError(ex); - return 0; + if (!("__fileSize" in this)) { + if (!this._file || !this._file.exists()) + this.__fileSize = 0; + try { + this.__fileSize = this._file.fileSize; + } + catch(ex) { + Cu.reportError(ex); + this.__fileSize = 0; + } } + return this.__fileSize; }, + /** + * Get the state of the download + * @param [optional] aForceUpdate + * Whether to force update the cached download state. Default: false. + */ // The download state (see nsIDownloadManager). - get _state() { - if (this._dataItem) - return this._dataItem.state; - - let state = -1; - try { - return this._getAnnotation(DOWNLOAD_STATE_ANNO); - } - catch (ex) { - // The state annotation didn't exist in past releases. - if (!this._file) { - state = nsIDM.DOWNLOAD_FAILED; - } - else if (this._file.exists()) { - state = this._fileSize > 0 ? - nsIDM.DOWNLOAD_FINISHED : nsIDM.DOWNLOAD_FAILED; + getDownloadState: function DES_getDownloadState(aForceUpdate = false) { + if (aForceUpdate || !("_state" in this)) { + if (this._dataItem) { + this._state = this._dataItem.state; } else { - // XXXmano I'm not sure if this right. We should probably show no - // status text at all in this case. - state = nsIDM.DOWNLOAD_CANCELED; + try { + this._state = this._getAnnotation(DOWNLOAD_STATE_ANNO); + } + catch (ex) { + // The state annotation didn't exist in past releases. + if (!this._file) { + this._state = nsIDM.DOWNLOAD_FAILED; + } + else if (this._file.exists()) { + this._state = this._fileSize > 0 ? + nsIDM.DOWNLOAD_FINISHED : nsIDM.DOWNLOAD_FAILED; + } + else { + // XXXmano I'm not sure if this right. We should probably show no + // status text at all in this case. + this._state = nsIDM.DOWNLOAD_CANCELED; + } + } } } - return state; + return this._state; }, // The status text for the download @@ -292,7 +303,7 @@ DownloadElementShell.prototype = { return s.statusSeparator(fullHost, fullDate); } - switch (this._state) { + switch (this.getDownloadState()) { case nsIDM.DOWNLOAD_FAILED: return s.stateFailed; case nsIDM.DOWNLOAD_CANCELED: @@ -331,7 +342,7 @@ DownloadElementShell.prototype = { // appropriate buttons and context menu items), the status text label, // and the progress meter. _updateDownloadStatusUI: function DES__updateDownloadStatusUI() { - this._element.setAttribute("state", this._state); + this._element.setAttribute("state", this.getDownloadState(true)); this._element.setAttribute("status", this._statusText); // For past-downloads, we're done. For session-downloads, we may also need @@ -429,7 +440,7 @@ DownloadElementShell.prototype = { case "downloadsCmd_open": { return this._file.exists() && ((this._dataItem && this._dataItem.openable) || - (this._state == nsIDM.DOWNLOAD_FINISHED)); + (this.getDownloadState() == nsIDM.DOWNLOAD_FINISHED)); } case "downloadsCmd_show": { return this._getTargetFileOrPartFileIfExists() != null; @@ -547,7 +558,7 @@ DownloadElementShell.prototype = { } return ""; } - let command = getDefaultCommandForState(this._state); + let command = getDefaultCommandForState(this.getDownloadState()); if (this.isCommandEnabled(command)) this.doCommand(command); } @@ -1079,7 +1090,7 @@ DownloadsPlacesView.prototype = { // Set the state attribute so that only the appropriate items are displayed. let contextMenu = document.getElementById("downloadsContextMenu"); - contextMenu.setAttribute("state", element._shell._state); + contextMenu.setAttribute("state", element._shell.getDownloadState()); return true; }, From 3fc031f3f1eaac003ed7878afa16cd3723db8382 Mon Sep 17 00:00:00 2001 From: Masatoshi Kimura Date: Sun, 23 Dec 2012 05:13:02 +0900 Subject: [PATCH 081/469] Bug 804834 - Part 3: Add a regression test. r=waldo --- dom/base/test/Makefile.in | 1 + dom/base/test/test_e4x_for_each.html | 55 ++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 dom/base/test/test_e4x_for_each.html diff --git a/dom/base/test/Makefile.in b/dom/base/test/Makefile.in index 78aef4d9392c..ea6167e78aa9 100644 --- a/dom/base/test/Makefile.in +++ b/dom/base/test/Makefile.in @@ -13,6 +13,7 @@ include $(DEPTH)/config/autoconf.mk MOCHITEST_FILES = \ test_document.all_unqualified.html \ test_domrequest.html \ + test_e4x_for_each.html \ test_gsp-standards.html \ test_gsp-quirks.html \ test_gsp-qualified.html \ diff --git a/dom/base/test/test_e4x_for_each.html b/dom/base/test/test_e4x_for_each.html new file mode 100644 index 000000000000..3d1ffa57a7c5 --- /dev/null +++ b/dom/base/test/test_e4x_for_each.html @@ -0,0 +1,55 @@ + + + + Test for E4X "for each" syntax + + + + +

+ + +
+
+
+ + From 41d5c4cd99f61042bc0355cc528918261f0a8e75 Mon Sep 17 00:00:00 2001 From: Neil Rashbrook Date: Sat, 22 Dec 2012 20:40:37 +0000 Subject: [PATCH 082/469] Bug 818861 Shouldn't allow promising a flat string from a flat string r=dbaron --- content/base/src/nsFrameMessageManager.cpp | 4 +-- content/canvas/src/WebGLContextGL.cpp | 11 +++---- dom/plugins/base/nsPluginInstanceOwner.cpp | 2 +- dom/plugins/ipc/PluginProcessChild.cpp | 2 +- gfx/thebes/gfxGDIFontList.cpp | 7 ++-- image/decoders/icon/mac/nsIconChannelCocoa.mm | 2 +- .../dirserviceprovider/src/nsProfileLock.cpp | 6 ++-- toolkit/components/alerts/nsAlertsService.cpp | 10 +++--- toolkit/components/places/History.cpp | 2 +- toolkit/xre/nsAppRunner.cpp | 3 +- xpcom/base/nsCycleCollector.cpp | 3 +- xpcom/base/nsMemoryInfoDumper.cpp | 3 +- xpcom/string/public/nsTPromiseFlatString.h | 32 ++++++++----------- 13 files changed, 38 insertions(+), 49 deletions(-) diff --git a/content/base/src/nsFrameMessageManager.cpp b/content/base/src/nsFrameMessageManager.cpp index ffa6c27b03b9..c72d2e33cbed 100644 --- a/content/base/src/nsFrameMessageManager.cpp +++ b/content/base/src/nsFrameMessageManager.cpp @@ -231,7 +231,7 @@ GetParamsForMessage(JSContext* aCx, NS_ENSURE_TRUE(!json.IsEmpty(), false); jsval val = JSVAL_NULL; - NS_ENSURE_TRUE(JS_ParseJSON(aCx, static_cast(PromiseFlatString(json).get()), + NS_ENSURE_TRUE(JS_ParseJSON(aCx, static_cast(json.get()), json.Length(), &val), false); return WriteStructuredClone(aCx, val, aBuffer, aClosure); @@ -535,7 +535,7 @@ nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget, } JSString* jsMessage = JS_NewUCStringCopyN(ctx, - static_cast(PromiseFlatString(aMessage).get()), + static_cast(aMessage.BeginReading()), aMessage.Length()); NS_ENSURE_TRUE(jsMessage, NS_ERROR_OUT_OF_MEMORY); JS_DefineProperty(ctx, param, "target", targetv, NULL, NULL, JSPROP_ENUMERATE); diff --git a/content/canvas/src/WebGLContextGL.cpp b/content/canvas/src/WebGLContextGL.cpp index 0dffcd6dc9fe..d003dd359d3f 100644 --- a/content/canvas/src/WebGLContextGL.cpp +++ b/content/canvas/src/WebGLContextGL.cpp @@ -4169,15 +4169,13 @@ WebGLContext::CompileShader(WebGLShader *shader) // cleanSource nsAString instance will be destroyed before the reference is // actually used. StripComments stripComments(shader->Source()); - const nsAString& cleanSource = nsString(stripComments.result().Elements(), stripComments.length()); + const nsAString& cleanSource = Substring(stripComments.result().Elements(), stripComments.length()); if (!ValidateGLSLString(cleanSource, "compileShader")) return; - const nsPromiseFlatString& flatSource = PromiseFlatString(cleanSource); - // shaderSource() already checks that the source stripped of comments is in the // 7-bit ASCII range, so we can skip the NS_IsAscii() check. - const nsCString& sourceCString = NS_LossyConvertUTF16toASCII(flatSource); + NS_LossyConvertUTF16toASCII sourceCString(cleanSource); if (gl->WorkAroundDriverBugs()) { const uint32_t maxSourceLength = 0x3ffff; @@ -4298,8 +4296,7 @@ WebGLContext::CompileShader(WebGLShader *shader) translatedSrc.SetLength(len); ShGetObjectCode(compiler, translatedSrc.BeginWriting()); - nsPromiseFlatCString translatedSrc2(translatedSrc); - const char *ts = translatedSrc2.get(); + const char *ts = translatedSrc.get(); gl->fShaderSource(shadername, 1, &ts, NULL); } else { // not useShaderSourceTranslation @@ -4613,7 +4610,7 @@ WebGLContext::ShaderSource(WebGLShader *shader, const nsAString& source) // cleanSource nsAString instance will be destroyed before the reference is // actually used. StripComments stripComments(source); - const nsAString& cleanSource = nsString(stripComments.result().Elements(), stripComments.length()); + const nsAString& cleanSource = Substring(stripComments.result().Elements(), stripComments.length()); if (!ValidateGLSLString(cleanSource, "compileShader")) return; diff --git a/dom/plugins/base/nsPluginInstanceOwner.cpp b/dom/plugins/base/nsPluginInstanceOwner.cpp index b8ca99df6c92..c6707a1dc033 100644 --- a/dom/plugins/base/nsPluginInstanceOwner.cpp +++ b/dom/plugins/base/nsPluginInstanceOwner.cpp @@ -1018,7 +1018,7 @@ NS_IMETHODIMP nsPluginInstanceOwner::GetDocumentEncoding(const char* *result) if (charset.EqualsLiteral("us-ascii")) { *result = PL_strdup("US_ASCII"); } else if (charset.EqualsLiteral("ISO-8859-1") || - !nsCRT::strncmp(PromiseFlatCString(charset).get(), "UTF", 3)) { + !nsCRT::strncmp(charset.get(), "UTF", 3)) { *result = ToNewCString(charset); } else { if (!gCharsetMap) { diff --git a/dom/plugins/ipc/PluginProcessChild.cpp b/dom/plugins/ipc/PluginProcessChild.cpp index ba6c9819ab51..9649421a73be 100644 --- a/dom/plugins/ipc/PluginProcessChild.cpp +++ b/dom/plugins/ipc/PluginProcessChild.cpp @@ -70,7 +70,7 @@ PluginProcessChild::Init() setInterpose.Append(interpose); } // Values passed to PR_SetEnv() must be seperately allocated. - char* setInterposePtr = strdup(PromiseFlatCString(setInterpose).get()); + char* setInterposePtr = strdup(setInterpose.get()); PR_SetEnv(setInterposePtr); } } diff --git a/gfx/thebes/gfxGDIFontList.cpp b/gfx/thebes/gfxGDIFontList.cpp index 4466c91eb5d8..94daf4169fb4 100644 --- a/gfx/thebes/gfxGDIFontList.cpp +++ b/gfx/thebes/gfxGDIFontList.cpp @@ -427,7 +427,7 @@ GDIFontEntry::InitLogFont(const nsAString& aName, mLogFont.lfWeight = mWeight; int len = NS_MIN(aName.Length(), LF_FACESIZE - 1); - memcpy(&mLogFont.lfFaceName, nsPromiseFlatString(aName).get(), len * 2); + memcpy(&mLogFont.lfFaceName, aName.BeginReading(), len * sizeof(PRUnichar)); mLogFont.lfFaceName[len] = '\0'; } @@ -560,10 +560,7 @@ GDIFontFamily::FindStyleVariations() logFont.lfCharSet = DEFAULT_CHARSET; logFont.lfPitchAndFamily = 0; uint32_t l = NS_MIN(mName.Length(), LF_FACESIZE - 1); - memcpy(logFont.lfFaceName, - nsPromiseFlatString(mName).get(), - l * sizeof(PRUnichar)); - logFont.lfFaceName[l] = 0; + memcpy(logFont.lfFaceName, mName.get(), l * sizeof(PRUnichar)); EnumFontFamiliesExW(hdc, &logFont, (FONTENUMPROCW)GDIFontFamily::FamilyAddStylesProc, diff --git a/image/decoders/icon/mac/nsIconChannelCocoa.mm b/image/decoders/icon/mac/nsIconChannelCocoa.mm index 39b0a9d72ab3..d53177b0fb03 100644 --- a/image/decoders/icon/mac/nsIconChannelCocoa.mm +++ b/image/decoders/icon/mac/nsIconChannelCocoa.mm @@ -233,7 +233,7 @@ nsresult nsIconChannel::MakeInputStream(nsIInputStream** _retval, bool nonBlocki // if we don't have an icon yet try to get one by extension if (!iconImage && !fileExt.IsEmpty()) { - NSString* fileExtension = [NSString stringWithUTF8String:PromiseFlatCString(fileExt).get()]; + NSString* fileExtension = [NSString stringWithUTF8String:fileExt.get()]; iconImage = [[NSWorkspace sharedWorkspace] iconForFileType:fileExtension]; } diff --git a/profile/dirserviceprovider/src/nsProfileLock.cpp b/profile/dirserviceprovider/src/nsProfileLock.cpp index 879a0beb5ef6..e875908afdc0 100644 --- a/profile/dirserviceprovider/src/nsProfileLock.cpp +++ b/profile/dirserviceprovider/src/nsProfileLock.cpp @@ -208,8 +208,7 @@ nsresult nsProfileLock::LockWithFcntl(nsIFile *aLockFile) aLockFile->GetLastModifiedTime(&mReplacedLockTime); - mLockFileDesc = open(PromiseFlatCString(lockFilePath).get(), - O_WRONLY | O_CREAT | O_TRUNC, 0666); + mLockFileDesc = open(lockFilePath.get(), O_WRONLY | O_CREAT | O_TRUNC, 0666); if (mLockFileDesc != -1) { struct flock lock; @@ -336,8 +335,7 @@ nsresult nsProfileLock::LockWithSymlink(nsIFile *aLockFile, bool aHaveFcntlLock) char *signature = PR_smprintf("%s:%s%lu", inet_ntoa(inaddr), aHaveFcntlLock ? "+" : "", (unsigned long)getpid()); - const nsPromiseFlatCString& flat = PromiseFlatCString(lockFilePath); - const char *fileName = flat.get(); + const char *fileName = lockFilePath.get(); int symlink_rv, symlink_errno = 0, tries = 0; // use ns4.x-compatible symlinks if the FS supports them diff --git a/toolkit/components/alerts/nsAlertsService.cpp b/toolkit/components/alerts/nsAlertsService.cpp index 40b851be2aa0..a58a1ee0d36a 100644 --- a/toolkit/components/alerts/nsAlertsService.cpp +++ b/toolkit/components/alerts/nsAlertsService.cpp @@ -78,12 +78,12 @@ NS_IMETHODIMP nsAlertsService::ShowAlertNotification(const nsAString & aImageUrl if (aAlertListener) cpc->AddRemoteAlertObserver(PromiseFlatString(aAlertCookie), aAlertListener); - cpc->SendShowAlertNotification(nsAutoString(aImageUrl), - nsAutoString(aAlertTitle), - nsAutoString(aAlertText), + cpc->SendShowAlertNotification(PromiseFlatString(aImageUrl), + PromiseFlatString(aAlertTitle), + PromiseFlatString(aAlertText), aAlertTextClickable, - nsAutoString(aAlertCookie), - nsAutoString(aAlertName)); + PromiseFlatString(aAlertCookie), + PromiseFlatString(aAlertName)); return NS_OK; } diff --git a/toolkit/components/places/History.cpp b/toolkit/components/places/History.cpp index f2044d9b4b7f..f8146d683f83 100644 --- a/toolkit/components/places/History.cpp +++ b/toolkit/components/places/History.cpp @@ -2020,7 +2020,7 @@ History::SetURITitle(nsIURI* aURI, const nsAString& aTitle) mozilla::dom::ContentChild * cpc = mozilla::dom::ContentChild::GetSingleton(); NS_ASSERTION(cpc, "Content Protocol is NULL!"); - (void)cpc->SendSetURITitle(uri, nsString(aTitle)); + (void)cpc->SendSetURITitle(uri, PromiseFlatString(aTitle)); return NS_OK; } diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp index 3c7cf9136e62..0eded02be323 100644 --- a/toolkit/xre/nsAppRunner.cpp +++ b/toolkit/xre/nsAppRunner.cpp @@ -3807,8 +3807,7 @@ XREMain::XRE_mainRun() if (!mDisableRemote) mRemoteService = do_GetService("@mozilla.org/toolkit/remote-service;1"); if (mRemoteService) - mRemoteService->Startup(mAppData->name, - PromiseFlatCString(mProfileName).get()); + mRemoteService->Startup(mAppData->name, mProfileName.get()); #endif /* MOZ_ENABLE_XREMOTE */ mNativeApp->Enable(); diff --git a/xpcom/base/nsCycleCollector.cpp b/xpcom/base/nsCycleCollector.cpp index 6371e77e4de5..95e5499ba556 100644 --- a/xpcom/base/nsCycleCollector.cpp +++ b/xpcom/base/nsCycleCollector.cpp @@ -1615,10 +1615,11 @@ private: // On android the default system umask is 0077 which makes these files // unreadable to the shell user. In order to pull the dumps off a non-rooted // device we need to chmod them to something world-readable. + // XXX why not logFile->SetPermissions(0644); nsAutoCString path; rv = logFile->GetNativePath(path); if (NS_SUCCEEDED(rv)) { - chmod(PromiseFlatCString(path).get(), 0644); + chmod(path.get(), 0644); } } #endif diff --git a/xpcom/base/nsMemoryInfoDumper.cpp b/xpcom/base/nsMemoryInfoDumper.cpp index e6b44fbece9b..9032f24d854a 100644 --- a/xpcom/base/nsMemoryInfoDumper.cpp +++ b/xpcom/base/nsMemoryInfoDumper.cpp @@ -498,10 +498,11 @@ OpenTempFile(const nsACString &aFilename, nsIFile* *aFile) // On android the default system umask is 0077 which makes these files // unreadable to the shell user. In order to pull the dumps off a non-rooted // device we need to chmod them to something world-readable. + // XXX why not logFile->SetPermissions(0644); nsAutoCString path; rv = file->GetNativePath(path); if (NS_SUCCEEDED(rv)) { - chmod(PromiseFlatCString(path).get(), 0644); + chmod(path.get(), 0644); } } #endif diff --git a/xpcom/string/public/nsTPromiseFlatString.h b/xpcom/string/public/nsTPromiseFlatString.h index f2913e79e9d0..ce7b298b8221 100644 --- a/xpcom/string/public/nsTPromiseFlatString.h +++ b/xpcom/string/public/nsTPromiseFlatString.h @@ -28,11 +28,11 @@ * promises. You must never use it to promise characters out of a string * with a shorter lifespan. The typical use will be something like this: * - * SomeOSFunction( PromiseFlatCString(aCString).get() ); // GOOD + * SomeOSFunction( PromiseFlatCString(aCSubstring).get() ); // GOOD * * Here's a BAD use: * - * const char* buffer = PromiseFlatCString(aCString).get(); + * const char* buffer = PromiseFlatCString(aCSubstring).get(); * SomeOSFunction(buffer); // BAD!! |buffer| is a dangling pointer * * The only way to make one is with the function |PromiseFlat[C]String|, @@ -40,9 +40,9 @@ * around for a little while?'' you might ask. In that case, you can keep a * reference, like so * - * const nsPromiseFlatString& flat = PromiseFlatString(aString); + * const nsCString& flat = PromiseFlatString(aCSubstring); * // this reference holds the anonymous temporary alive, but remember, - * // it must _still_ have a lifetime shorter than that of |aString| + * // it must _still_ have a lifetime shorter than that of |aCSubstring| * * SomeOSFunction(flat.get()); * SomeOtherOSFunction(flat.get()); @@ -69,10 +69,13 @@ class nsTPromiseFlatString_CharT : public nsTString_CharT void Init( const substring_type& ); // NOT TO BE IMPLEMENTED - void operator=( const self_type& ); + void operator=( const self_type& ) MOZ_DELETE; // NOT TO BE IMPLEMENTED - nsTPromiseFlatString_CharT(); + nsTPromiseFlatString_CharT() MOZ_DELETE; + + // NOT TO BE IMPLEMENTED + nsTPromiseFlatString_CharT( const string_type& str ) MOZ_DELETE; public: @@ -93,18 +96,11 @@ class nsTPromiseFlatString_CharT : public nsTString_CharT } }; - // e.g., PromiseFlatCString(Substring(s)) -inline +// We template this so that the constructor is chosen based on the type of the +// parameter. This allows us to reject attempts to promise a flat flat string. +template const nsTPromiseFlatString_CharT -TPromiseFlatString_CharT( const nsTSubstring_CharT& frag ) +TPromiseFlatString_CharT( const T& string ) { - return nsTPromiseFlatString_CharT(frag); - } - - // e.g., PromiseFlatCString(a + b) -inline -const nsTPromiseFlatString_CharT -TPromiseFlatString_CharT( const nsTSubstringTuple_CharT& tuple ) - { - return nsTPromiseFlatString_CharT(tuple); + return nsTPromiseFlatString_CharT(string); } From 73aa7b095caaef824a890bcf1352ee3f298b1eb2 Mon Sep 17 00:00:00 2001 From: Hannes Verschore Date: Sat, 22 Dec 2012 23:07:59 +0100 Subject: [PATCH 083/469] Bug 777262: IonMonkey: Inline more compare operations, r=jandem --- js/src/ion/CodeGenerator.cpp | 22 +- js/src/ion/CodeGenerator.h | 2 +- js/src/ion/IonAnalysis.cpp | 2 +- js/src/ion/LIR-Common.h | 157 ++++++++----- js/src/ion/LOpcodes.h | 8 +- js/src/ion/Lowering.cpp | 178 +++++++++------ js/src/ion/MIR.cpp | 207 +++++++++++++----- js/src/ion/MIR.h | 53 ++++- js/src/ion/TypePolicy.cpp | 45 ++-- js/src/ion/TypePolicy.h | 8 - js/src/ion/arm/CodeGenerator-arm.cpp | 53 +++++ js/src/ion/arm/CodeGenerator-arm.h | 2 + .../ion/shared/CodeGenerator-x86-shared.cpp | 8 +- js/src/ion/shared/CodeGenerator-x86-shared.h | 2 +- js/src/ion/x64/CodeGenerator-x64.cpp | 31 +++ js/src/ion/x64/CodeGenerator-x64.h | 2 + js/src/ion/x86/CodeGenerator-x86.cpp | 54 +++++ js/src/ion/x86/CodeGenerator-x86.h | 2 + js/src/jsinfer.h | 10 + 19 files changed, 619 insertions(+), 227 deletions(-) diff --git a/js/src/ion/CodeGenerator.cpp b/js/src/ion/CodeGenerator.cpp index 1c49d35e7a83..8e7c85406b5f 100644 --- a/js/src/ion/CodeGenerator.cpp +++ b/js/src/ion/CodeGenerator.cpp @@ -2410,7 +2410,7 @@ static const VMFunction GtInfo = FunctionInfo(ion::GreaterThan); static const VMFunction GeInfo = FunctionInfo(ion::GreaterThanOrEqual); bool -CodeGenerator::visitCompareV(LCompareV *lir) +CodeGenerator::visitCompareVM(LCompareVM *lir) { pushArg(ToValue(lir, LBinaryV::RhsInput)); pushArg(ToValue(lir, LBinaryV::LhsInput)); @@ -2450,8 +2450,9 @@ bool CodeGenerator::visitIsNullOrLikeUndefined(LIsNullOrLikeUndefined *lir) { JSOp op = lir->mir()->jsop(); - MIRType specialization = lir->mir()->specialization(); - JS_ASSERT(IsNullOrUndefined(specialization)); + MCompare::CompareType compareType = lir->mir()->compareType(); + JS_ASSERT(compareType == MCompare::Compare_Undefined || + compareType == MCompare::Compare_Null); const ValueOperand value = ToValue(lir, LIsNullOrLikeUndefined::Value); Register output = ToRegister(lir->output()); @@ -2512,7 +2513,7 @@ CodeGenerator::visitIsNullOrLikeUndefined(LIsNullOrLikeUndefined *lir) JS_ASSERT(op == JSOP_STRICTEQ || op == JSOP_STRICTNE); Assembler::Condition cond = JSOpToCondition(op); - if (specialization == MIRType_Null) + if (compareType == MCompare::Compare_Null) cond = masm.testNull(cond, value); else cond = masm.testUndefined(cond, value); @@ -2525,8 +2526,9 @@ bool CodeGenerator::visitIsNullOrLikeUndefinedAndBranch(LIsNullOrLikeUndefinedAndBranch *lir) { JSOp op = lir->mir()->jsop(); - MIRType specialization = lir->mir()->specialization(); - JS_ASSERT(IsNullOrUndefined(specialization)); + MCompare::CompareType compareType = lir->mir()->compareType(); + JS_ASSERT(compareType == MCompare::Compare_Undefined || + compareType == MCompare::Compare_Null); const ValueOperand value = ToValue(lir, LIsNullOrLikeUndefinedAndBranch::Value); @@ -2577,7 +2579,7 @@ CodeGenerator::visitIsNullOrLikeUndefinedAndBranch(LIsNullOrLikeUndefinedAndBran JS_ASSERT(op == JSOP_STRICTEQ || op == JSOP_STRICTNE); Assembler::Condition cond = JSOpToCondition(op); - if (specialization == MIRType_Null) + if (compareType == MCompare::MCompare::Compare_Null) cond = masm.testNull(cond, value); else cond = masm.testUndefined(cond, value); @@ -2592,7 +2594,8 @@ static const VMFunction ConcatStringsInfo = FunctionInfo(js_Con bool CodeGenerator::visitEmulatesUndefined(LEmulatesUndefined *lir) { - MOZ_ASSERT(IsNullOrUndefined(lir->mir()->specialization())); + MOZ_ASSERT(lir->mir()->compareType() == MCompare::Compare_Undefined || + lir->mir()->compareType() == MCompare::Compare_Null); MOZ_ASSERT(lir->mir()->lhs()->type() == MIRType_Object); MOZ_ASSERT(lir->mir()->operandMightEmulateUndefined(), "If the object couldn't emulate undefined, this should have been folded."); @@ -2626,7 +2629,8 @@ CodeGenerator::visitEmulatesUndefined(LEmulatesUndefined *lir) bool CodeGenerator::visitEmulatesUndefinedAndBranch(LEmulatesUndefinedAndBranch *lir) { - MOZ_ASSERT(IsNullOrUndefined(lir->mir()->specialization())); + MOZ_ASSERT(lir->mir()->compareType() == MCompare::Compare_Undefined || + lir->mir()->compareType() == MCompare::Compare_Null); MOZ_ASSERT(lir->mir()->operandMightEmulateUndefined(), "Operands which can't emulate undefined should have been folded"); diff --git a/js/src/ion/CodeGenerator.h b/js/src/ion/CodeGenerator.h index 3a23a8da5b03..00416baf3988 100644 --- a/js/src/ion/CodeGenerator.h +++ b/js/src/ion/CodeGenerator.h @@ -128,7 +128,7 @@ class CodeGenerator : public CodeGeneratorSpecific bool visitMinMaxI(LMinMaxI *lir); bool visitBinaryV(LBinaryV *lir); bool visitCompareS(LCompareS *lir); - bool visitCompareV(LCompareV *lir); + bool visitCompareVM(LCompareVM *lir); bool visitIsNullOrLikeUndefined(LIsNullOrLikeUndefined *lir); bool visitIsNullOrLikeUndefinedAndBranch(LIsNullOrLikeUndefinedAndBranch *lir); bool visitEmulatesUndefined(LEmulatesUndefined *lir); diff --git a/js/src/ion/IonAnalysis.cpp b/js/src/ion/IonAnalysis.cpp index 245ef97435f0..4c2e23199ad3 100644 --- a/js/src/ion/IonAnalysis.cpp +++ b/js/src/ion/IonAnalysis.cpp @@ -1087,7 +1087,7 @@ ion::ExtractLinearInequality(MTest *test, BranchDirection direction, MDefinition *lhs = compare->getOperand(0); MDefinition *rhs = compare->getOperand(1); - if (compare->specialization() != MIRType_Int32) + if (compare->compareType() != MCompare::Compare_Int32) return false; JS_ASSERT(lhs->type() == MIRType_Int32); diff --git a/js/src/ion/LIR-Common.h b/js/src/ion/LIR-Common.h index 2c9977526244..9766c589fa40 100644 --- a/js/src/ion/LIR-Common.h +++ b/js/src/ion/LIR-Common.h @@ -959,7 +959,6 @@ class LPolyInlineDispatch : public LInstructionHelper<0, 1, 1> } }; - // Compares two integral values of the same JS type, either integer or object. // For objects, both operands are in registers. class LCompare : public LInstructionHelper<1, 2, 0> @@ -989,64 +988,6 @@ class LCompare : public LInstructionHelper<1, 2, 0> } }; -class LCompareD : public LInstructionHelper<1, 2, 0> -{ - public: - LIR_HEADER(CompareD) - LCompareD(const LAllocation &left, const LAllocation &right) { - setOperand(0, left); - setOperand(1, right); - } - - const LAllocation *left() { - return getOperand(0); - } - const LAllocation *right() { - return getOperand(1); - } - MCompare *mir() { - return mir_->toCompare(); - } -}; - -class LCompareS : public LInstructionHelper<1, 2, 1> -{ - public: - LIR_HEADER(CompareS) - LCompareS(const LAllocation &left, const LAllocation &right, - const LDefinition &temp) { - setOperand(0, left); - setOperand(1, right); - setTemp(0, temp); - } - - const LAllocation *left() { - return getOperand(0); - } - const LAllocation *right() { - return getOperand(1); - } - const LDefinition *temp() { - return getTemp(0); - } - MCompare *mir() { - return mir_->toCompare(); - } -}; - -class LCompareV : public LCallInstructionHelper<1, 2 * BOX_PIECES, 0> -{ - public: - LIR_HEADER(CompareV) - - static const size_t LhsInput = 0; - static const size_t RhsInput = BOX_PIECES; - - MCompare *mir() const { - return mir_->toCompare(); - } -}; - // Compares two integral values of the same JS type, either integer or object. // For objects, both operands are in registers. class LCompareAndBranch : public LInstructionHelper<0, 2, 0> @@ -1087,6 +1028,26 @@ class LCompareAndBranch : public LInstructionHelper<0, 2, 0> } }; +class LCompareD : public LInstructionHelper<1, 2, 0> +{ + public: + LIR_HEADER(CompareD) + LCompareD(const LAllocation &left, const LAllocation &right) { + setOperand(0, left); + setOperand(1, right); + } + + const LAllocation *left() { + return getOperand(0); + } + const LAllocation *right() { + return getOperand(1); + } + MCompare *mir() { + return mir_->toCompare(); + } +}; + class LCompareDAndBranch : public LInstructionHelper<0, 2, 0> { MBasicBlock *ifTrue_; @@ -1120,6 +1081,31 @@ class LCompareDAndBranch : public LInstructionHelper<0, 2, 0> } }; +class LCompareS : public LInstructionHelper<1, 2, 1> +{ + public: + LIR_HEADER(CompareS) + LCompareS(const LAllocation &left, const LAllocation &right, + const LDefinition &temp) { + setOperand(0, left); + setOperand(1, right); + setTemp(0, temp); + } + + const LAllocation *left() { + return getOperand(0); + } + const LAllocation *right() { + return getOperand(1); + } + const LDefinition *temp() { + return getTemp(0); + } + MCompare *mir() { + return mir_->toCompare(); + } +}; + // Used for strict-equality comparisons where one side is a boolean // and the other is a value. Note that CompareI is used to compare // two booleans. @@ -1174,6 +1160,59 @@ class LCompareBAndBranch : public LInstructionHelper<0, BOX_PIECES + 1, 0> } }; +class LCompareV : public LInstructionHelper<1, 2 * BOX_PIECES, 0> +{ + public: + LIR_HEADER(CompareV) + + static const size_t LhsInput = 0; + static const size_t RhsInput = BOX_PIECES; + + MCompare *mir() const { + return mir_->toCompare(); + } +}; + +class LCompareVAndBranch : public LInstructionHelper<0, 2 * BOX_PIECES, 0> +{ + MBasicBlock *ifTrue_; + MBasicBlock *ifFalse_; + + public: + LIR_HEADER(CompareVAndBranch) + + static const size_t LhsInput = 0; + static const size_t RhsInput = BOX_PIECES; + + LCompareVAndBranch(MBasicBlock *ifTrue, MBasicBlock *ifFalse) + : ifTrue_(ifTrue), + ifFalse_(ifFalse) + { } + + MBasicBlock *ifTrue() const { + return ifTrue_; + } + MBasicBlock *ifFalse() const { + return ifFalse_; + } + MCompare *mir() { + return mir_->toCompare(); + } +}; + +class LCompareVM : public LCallInstructionHelper<1, 2 * BOX_PIECES, 0> +{ + public: + LIR_HEADER(CompareVM) + + static const size_t LhsInput = 0; + static const size_t RhsInput = BOX_PIECES; + + MCompare *mir() const { + return mir_->toCompare(); + } +}; + class LIsNullOrLikeUndefined : public LInstructionHelper<1, BOX_PIECES, 2> { public: diff --git a/js/src/ion/LOpcodes.h b/js/src/ion/LOpcodes.h index 6eda32fbaf4f..f51f9f3f4ed1 100644 --- a/js/src/ion/LOpcodes.h +++ b/js/src/ion/LOpcodes.h @@ -57,13 +57,15 @@ _(TestOAndBranch) \ _(PolyInlineDispatch) \ _(Compare) \ - _(CompareD) \ - _(CompareS) \ - _(CompareV) \ _(CompareAndBranch) \ + _(CompareD) \ _(CompareDAndBranch) \ + _(CompareS) \ _(CompareB) \ _(CompareBAndBranch) \ + _(CompareV) \ + _(CompareVAndBranch) \ + _(CompareVM) \ _(IsNullOrLikeUndefined) \ _(IsNullOrLikeUndefinedAndBranch)\ _(EmulatesUndefined) \ diff --git a/js/src/ion/Lowering.cpp b/js/src/ion/Lowering.cpp index 0a2f117f0dad..66efaf78b55e 100644 --- a/js/src/ion/Lowering.cpp +++ b/js/src/ion/Lowering.cpp @@ -431,21 +431,14 @@ LIRGenerator::visitTest(MTest *test) if (comp->tryFold(&result)) return add(new LGoto(result ? ifTrue : ifFalse)); - if (comp->specialization() == MIRType_Int32 || comp->specialization() == MIRType_Object) { - JSOp op = ReorderComparison(comp->jsop(), &left, &right); - LAllocation rhs = comp->specialization() == MIRType_Object - ? useRegister(right) - : useAnyOrConstant(right); - return add(new LCompareAndBranch(op, useRegister(left), rhs, ifTrue, ifFalse), comp); - } - if (comp->specialization() == MIRType_Double) { - return add(new LCompareDAndBranch(useRegister(left), useRegister(right), ifTrue, - ifFalse), comp); - } + // Emit LCompare*AndBranch. - // The second operand has known null/undefined type, so just test the - // first operand. - if (IsNullOrUndefined(comp->specialization())) { + // Compare and branch null/undefined. + // The second operand has known null/undefined type, + // so just test the first operand. + if (comp->compareType() == MCompare::Compare_Null || + comp->compareType() == MCompare::Compare_Undefined) + { if (left->type() == MIRType_Object) { MOZ_ASSERT(comp->operandMightEmulateUndefined(), "MCompare::tryFold should handle the never-emulates-undefined case"); @@ -471,16 +464,48 @@ LIRGenerator::visitTest(MTest *test) return add(lir, comp); } - if (comp->specialization() == MIRType_Boolean) { + // Compare and branch booleans. + if (comp->compareType() == MCompare::Compare_Boolean) { JS_ASSERT(left->type() == MIRType_Value); JS_ASSERT(right->type() == MIRType_Boolean); - LCompareBAndBranch *lir = new LCompareBAndBranch(useRegisterOrConstant(right), - ifTrue, ifFalse); + LAllocation rhs = useRegisterOrConstant(right); + LCompareBAndBranch *lir = new LCompareBAndBranch(rhs, ifTrue, ifFalse); if (!useBox(lir, LCompareBAndBranch::Lhs, left)) return false; return add(lir, comp); } + + // Compare and branch Int32 or Object pointers. + if (comp->compareType() == MCompare::Compare_Int32 || + comp->compareType() == MCompare::Compare_Object) + { + JSOp op = ReorderComparison(comp->jsop(), &left, &right); + LAllocation lhs = useRegister(left); + LAllocation rhs = useRegister(right); + if (comp->compareType() == MCompare::Compare_Int32) + rhs = useAnyOrConstant(right); + LCompareAndBranch *lir = new LCompareAndBranch(op, lhs, rhs, ifTrue, ifFalse); + return add(lir, comp); + } + + // Compare and branch doubles. + if (comp->compareType() == MCompare::Compare_Double) { + LAllocation lhs = useRegister(left); + LAllocation rhs = useRegister(right); + LCompareDAndBranch *lir = new LCompareDAndBranch(lhs, rhs, ifTrue, ifFalse); + return add(lir, comp); + } + + // Compare values. + if (comp->compareType() == MCompare::Compare_Value) { + LCompareVAndBranch *lir = new LCompareVAndBranch(ifTrue, ifFalse); + if (!useBoxAtStart(lir, LCompareVAndBranch::LhsInput, left)) + return false; + if (!useBoxAtStart(lir, LCompareVAndBranch::RhsInput, right)) + return false; + return add(lir, comp); + } } if (opd->type() == MIRType_Double) @@ -526,52 +551,42 @@ LIRGenerator::visitCompare(MCompare *comp) MDefinition *left = comp->lhs(); MDefinition *right = comp->rhs(); - if (comp->specialization() != MIRType_None) { - // Try to fold the comparison so that we don't have to handle all cases. - bool result; - if (comp->tryFold(&result)) - return define(new LInteger(result), comp); + // Try to fold the comparison so that we don't have to handle all cases. + bool result; + if (comp->tryFold(&result)) + return define(new LInteger(result), comp); - // Move below the emitAtUses call if we ever implement - // LCompareSAndBranch. Doing this now wouldn't be wrong, but doesn't - // make sense and avoids confusion. - if (comp->specialization() == MIRType_String) { - LCompareS *lir = new LCompareS(useRegister(left), useRegister(right), temp()); - if (!define(lir, comp)) - return false; - return assignSafepoint(lir, comp); - } + // Move below the emitAtUses call if we ever implement + // LCompareSAndBranch. Doing this now wouldn't be wrong, but doesn't + // make sense and avoids confusion. + if (comp->compareType() == MCompare::Compare_String) { + LCompareS *lir = new LCompareS(useRegister(left), useRegister(right), temp()); + if (!define(lir, comp)) + return false; + return assignSafepoint(lir, comp); + } - // Sniff out if the output of this compare is used only for a branching. - // If it is, then we will emit an LCompare*AndBranch instruction in place - // of this compare and any test that uses this compare. Thus, we can - // ignore this Compare. - if (CanEmitCompareAtUses(comp)) - return emitAtUses(comp); + // Unknown/unspecialized compare use a VM call. + if (comp->compareType() == MCompare::Compare_Unknown) { + LCompareVM *lir = new LCompareVM(); + if (!useBoxAtStart(lir, LCompareVM::LhsInput, left)) + return false; + if (!useBoxAtStart(lir, LCompareVM::RhsInput, right)) + return false; + return defineReturn(lir, comp) && assignSafepoint(lir, comp); + } - if (comp->specialization() == MIRType_Int32 || comp->specialization() == MIRType_Object) { - JSOp op = ReorderComparison(comp->jsop(), &left, &right); - LAllocation rhs = comp->specialization() == MIRType_Object - ? useRegister(right) - : useAnyOrConstant(right); - return define(new LCompare(op, useRegister(left), rhs), comp); - } - - if (comp->specialization() == MIRType_Double) - return define(new LCompareD(useRegister(left), useRegister(right)), comp); - - if (comp->specialization() == MIRType_Boolean) { - JS_ASSERT(left->type() == MIRType_Value); - JS_ASSERT(right->type() == MIRType_Boolean); - - LCompareB *lir = new LCompareB(useRegisterOrConstant(right)); - if (!useBox(lir, LCompareB::Lhs, left)) - return false; - return define(lir, comp); - } - - JS_ASSERT(IsNullOrUndefined(comp->specialization())); + // Sniff out if the output of this compare is used only for a branching. + // If it is, then we will emit an LCompare*AndBranch instruction in place + // of this compare and any test that uses this compare. Thus, we can + // ignore this Compare. + if (CanEmitCompareAtUses(comp)) + return emitAtUses(comp); + // Compare Null and Undefined. + if (comp->compareType() == MCompare::Compare_Null || + comp->compareType() == MCompare::Compare_Undefined) + { if (left->type() == MIRType_Object) { MOZ_ASSERT(comp->operandMightEmulateUndefined(), "MCompare::tryFold should have folded this away"); @@ -594,12 +609,45 @@ LIRGenerator::visitCompare(MCompare *comp) return define(lir, comp); } - LCompareV *lir = new LCompareV(); - if (!useBoxAtStart(lir, LCompareV::LhsInput, left)) - return false; - if (!useBoxAtStart(lir, LCompareV::RhsInput, right)) - return false; - return defineReturn(lir, comp) && assignSafepoint(lir, comp); + // Compare booleans. + if (comp->compareType() == MCompare::Compare_Boolean) { + JS_ASSERT(left->type() == MIRType_Value); + JS_ASSERT(right->type() == MIRType_Boolean); + + LCompareB *lir = new LCompareB(useRegisterOrConstant(right)); + if (!useBox(lir, LCompareB::Lhs, left)) + return false; + return define(lir, comp); + } + + // Compare Int32 or Object pointers. + if (comp->compareType() == MCompare::Compare_Int32 || + comp->compareType() == MCompare::Compare_Object) + { + JSOp op = ReorderComparison(comp->jsop(), &left, &right); + LAllocation lhs = useRegister(left); + LAllocation rhs = useRegister(right); + if (comp->compareType() == MCompare::Compare_Int32) + rhs = useAnyOrConstant(right); + return define(new LCompare(op, lhs, rhs), comp); + } + + // Compare doubles. + if (comp->compareType() == MCompare::Compare_Double) + return define(new LCompareD(useRegister(left), useRegister(right)), comp); + + // Compare values. + if (comp->compareType() == MCompare::Compare_Value) { + LCompareV *lir = new LCompareV(); + if (!useBoxAtStart(lir, LCompareV::LhsInput, left)) + return false; + if (!useBoxAtStart(lir, LCompareV::RhsInput, right)) + return false; + return define(lir, comp); + } + + JS_NOT_REACHED("Unrecognized compare type."); + return false; } static void diff --git a/js/src/ion/MIR.cpp b/js/src/ion/MIR.cpp index 764aa7ad2983..b57f0a50bbe7 100644 --- a/js/src/ion/MIR.cpp +++ b/js/src/ion/MIR.cpp @@ -1084,6 +1084,100 @@ SafelyCoercesToDouble(JSContext *cx, types::StackTypeSet *types) return false; } +static bool +CanDoValueBitwiseCmp(JSContext *cx, types::StackTypeSet *lhs, types::StackTypeSet *rhs, bool looseEq) +{ + // Only primitive (not double/string) or objects are supported. + // I.e. Undefined/Null/Boolean/Int32 and Object + if (!lhs->knownPrimitiveOrObject() || + lhs->hasAnyFlag(types::TYPE_FLAG_STRING) || + lhs->hasAnyFlag(types::TYPE_FLAG_DOUBLE) || + !rhs->knownPrimitiveOrObject() || + rhs->hasAnyFlag(types::TYPE_FLAG_STRING) || + rhs->hasAnyFlag(types::TYPE_FLAG_DOUBLE)) + { + return false; + } + + // Objects with special equality or that emulates undefined are not supported. + if (lhs->maybeObject() && + (lhs->hasObjectFlags(cx, types::OBJECT_FLAG_SPECIAL_EQUALITY) || + lhs->hasObjectFlags(cx, types::OBJECT_FLAG_EMULATES_UNDEFINED))) + { + return false; + } + if (rhs->maybeObject() && + (rhs->hasObjectFlags(cx, types::OBJECT_FLAG_SPECIAL_EQUALITY) || + rhs->hasObjectFlags(cx, types::OBJECT_FLAG_EMULATES_UNDEFINED))) + { + return false; + } + + // In the loose comparison more values could be the same, + // but value comparison reporting otherwise. + if (looseEq) { + + // Undefined compared loosy to Null is not supported, + // because tag is different, but value can be the same (undefined == null). + if ((lhs->hasAnyFlag(types::TYPE_FLAG_UNDEFINED) && + rhs->hasAnyFlag(types::TYPE_FLAG_NULL)) || + (lhs->hasAnyFlag(types::TYPE_FLAG_NULL) && + rhs->hasAnyFlag(types::TYPE_FLAG_UNDEFINED))) + { + return false; + } + + // Int32 compared loosy to Boolean is not supported, + // because tag is different, but value can be the same (1 == true). + if ((lhs->hasAnyFlag(types::TYPE_FLAG_INT32) && + rhs->hasAnyFlag(types::TYPE_FLAG_BOOLEAN)) || + (lhs->hasAnyFlag(types::TYPE_FLAG_BOOLEAN) && + rhs->hasAnyFlag(types::TYPE_FLAG_INT32))) + { + return false; + } + + // For loosy comparison of an object with a Boolean/Number/String + // the valueOf the object is taken. Therefore not supported. + types::TypeFlags numbers = types::TYPE_FLAG_BOOLEAN | + types::TYPE_FLAG_INT32; + if ((lhs->maybeObject() && rhs->hasAnyFlag(numbers)) || + (rhs->maybeObject() && lhs->hasAnyFlag(numbers))) + { + return false; + } + } + + return true; +} + +MIRType +MCompare::inputType() +{ + switch(compareType_) { + case Compare_Undefined: + return MIRType_Undefined; + case Compare_Null: + return MIRType_Null; + case Compare_Boolean: + return MIRType_Boolean; + case Compare_Int32: + return MIRType_Int32; + case Compare_Double: + return MIRType_Double; + case Compare_String: + return MIRType_String; + case Compare_Object: + return MIRType_Object; + case Compare_Unknown: + case Compare_Value: + return MIRType_Value; + default: + JS_NOT_REACHED("No known conversion"); + return MIRType_None; + } +} + void MCompare::infer(const TypeOracle::BinaryTypes &b, JSContext *cx) { @@ -1098,86 +1192,95 @@ MCompare::infer(const TypeOracle::BinaryTypes &b, JSContext *cx) MIRType lhs = MIRTypeFromValueType(b.lhsTypes->getKnownTypeTag()); MIRType rhs = MIRTypeFromValueType(b.rhsTypes->getKnownTypeTag()); - // Strict integer or boolean comparisons may be treated as Int32. + bool looseEq = jsop() == JSOP_EQ || jsop() == JSOP_NE; + bool strictEq = jsop() == JSOP_STRICTEQ || jsop() == JSOP_STRICTNE; + bool relationalEq = !(looseEq || strictEq); + + // Integer to integer or boolean to boolean comparisons may be treated as Int32. if ((lhs == MIRType_Int32 && rhs == MIRType_Int32) || (lhs == MIRType_Boolean && rhs == MIRType_Boolean)) { - specialization_ = MIRType_Int32; + compareType_ = Compare_Int32; return; } - // Loose cross-integer/boolean comparisons may be treated as Int32. - if (jsop() != JSOP_STRICTEQ && jsop() != JSOP_STRICTNE && + // Loose/relational cross-integer/boolean comparisons may be treated as Int32. + if (!strictEq && (lhs == MIRType_Int32 || lhs == MIRType_Boolean) && (rhs == MIRType_Int32 || rhs == MIRType_Boolean)) { - specialization_ = MIRType_Int32; + compareType_ = Compare_Int32; return; } // Numeric comparisons against a double coerce to double. if (IsNumberType(lhs) && IsNumberType(rhs)) { - specialization_ = MIRType_Double; + compareType_ = Compare_Double; return; } - // Handle double comparisons against something that safely coerces to double. - if (jsop() != JSOP_STRICTEQ && jsop() != JSOP_STRICTNE && + // Any comparison is allowed except strict eq. + if (!strictEq && ((lhs == MIRType_Double && SafelyCoercesToDouble(cx, b.rhsTypes)) || (rhs == MIRType_Double && SafelyCoercesToDouble(cx, b.lhsTypes)))) { - specialization_ = MIRType_Double; + compareType_ = Compare_Double; return; } - if (jsop() == JSOP_STRICTEQ || jsop() == JSOP_EQ || - jsop() == JSOP_STRICTNE || jsop() == JSOP_NE) - { - if (lhs == MIRType_Object && rhs == MIRType_Object) { - if (b.lhsTypes->hasObjectFlags(cx, types::OBJECT_FLAG_SPECIAL_EQUALITY) || - b.rhsTypes->hasObjectFlags(cx, types::OBJECT_FLAG_SPECIAL_EQUALITY)) - { - return; - } - specialization_ = MIRType_Object; + // Handle object comparison. + if (!relationalEq && lhs == MIRType_Object && rhs == MIRType_Object) { + if (b.lhsTypes->hasObjectFlags(cx, types::OBJECT_FLAG_SPECIAL_EQUALITY) || + b.rhsTypes->hasObjectFlags(cx, types::OBJECT_FLAG_SPECIAL_EQUALITY)) + { return; } - if (lhs == MIRType_String && rhs == MIRType_String) { - // We don't yet want to optimize relational string compares. - specialization_ = MIRType_String; - return; - } - - // Swap null/undefined lhs to rhs so we can test for it only on lhs. - if (IsNullOrUndefined(lhs)) { - MIRType tmp = lhs; - lhs = rhs; - rhs = tmp; - swapOperands(); - } - - if (IsNullOrUndefined(rhs)) { - specialization_ = rhs; - return; - } + compareType_ = Compare_Object; + return; } - if (jsop() == JSOP_STRICTEQ || jsop() == JSOP_STRICTNE) { + // Handle string comparisons. (Relational string compares are still unsupported). + if (!relationalEq && lhs == MIRType_String && rhs == MIRType_String) { + compareType_ = Compare_String; + return; + } + + // Handle compare with lhs being Undefined or Null. + if (!relationalEq && IsNullOrUndefined(lhs)) { + // Lowering expects the rhs to be null/undefined, so we have to + // swap the operands. This is necessary since we may not know which + // operand was null/undefined during lowering (both operands may have + // MIRType_Value). + compareType_ = (lhs == MIRType_Null) ? Compare_Null : Compare_Undefined; + swapOperands(); + return; + } + + // Handle compare with rhs being Undefined or Null. + if (!relationalEq && IsNullOrUndefined(rhs)) { + compareType_ = (rhs == MIRType_Null) ? Compare_Null : Compare_Undefined; + return; + } + + // Handle strict comparison with lhs/rhs being typed Boolean. + if (strictEq && (lhs == MIRType_Boolean || rhs == MIRType_Boolean)) { // bool/bool case got an int32 specialization earlier. JS_ASSERT(!(lhs == MIRType_Boolean && rhs == MIRType_Boolean)); - if (lhs == MIRType_Boolean) { - // Ensure the boolean is on the right so that the type policy knows - // which side to unbox. - swapOperands(); - specialization_ = MIRType_Boolean; - return; - } - if (rhs == MIRType_Boolean) { - specialization_ = MIRType_Boolean; - return; - } + // Ensure the boolean is on the right so that the type policy knows + // which side to unbox. + if (lhs == MIRType_Boolean) + swapOperands(); + + compareType_ = Compare_Boolean; + return; + } + + // Determine if we can do the compare based on a quick value check. + if (!relationalEq && CanDoValueBitwiseCmp(cx, b.lhsTypes, b.rhsTypes, looseEq)) { + compareType_ = Compare_Value; + return; } } @@ -1395,7 +1498,7 @@ MCompare::tryFold(bool *result) { JSOp op = jsop(); - if (IsNullOrUndefined(specialization())) { + if (compareType_ == Compare_Null || compareType_ == Compare_Undefined) { JS_ASSERT(op == JSOP_EQ || op == JSOP_STRICTEQ || op == JSOP_NE || op == JSOP_STRICTNE); @@ -1405,7 +1508,7 @@ MCompare::tryFold(bool *result) return false; case MIRType_Undefined: case MIRType_Null: - if (lhs()->type() == specialization()) { + if (lhs()->type() == inputType()) { // Both sides have the same type, null or undefined. *result = (op == JSOP_EQ || op == JSOP_STRICTEQ); } else { @@ -1430,7 +1533,7 @@ MCompare::tryFold(bool *result) } } - if (specialization_ == MIRType_Boolean) { + if (compareType_ == Compare_Boolean) { JS_ASSERT(op == JSOP_STRICTEQ || op == JSOP_STRICTNE); JS_ASSERT(rhs()->type() == MIRType_Boolean); diff --git a/js/src/ion/MIR.h b/js/src/ion/MIR.h index ecc6963946bb..de1c2157e10a 100644 --- a/js/src/ion/MIR.h +++ b/js/src/ion/MIR.h @@ -1382,11 +1382,51 @@ class MCompare : public MBinaryInstruction, public ComparePolicy { + public: + enum CompareType { + + // Anything compared to Undefined + Compare_Undefined, + + // Anything compared to Null + Compare_Null, + + // Undefined compared to Boolean + // Null compared to Boolean + // Double compared to Boolean + // String compared to Boolean + // Object compared to Boolean + // Value compared to Boolean + Compare_Boolean, + + // Int32 compared to Int32 + // Boolean compared to Boolean + Compare_Int32, + + // Double compared to Double + Compare_Double, + + // String compared to String + Compare_String, + + // Object compared to Object + Compare_Object, + + // Compare 2 values bitwise + Compare_Value, + + // All other possible compares + Compare_Unknown + }; + + private: + CompareType compareType_; JSOp jsop_; bool operandMightEmulateUndefined_; MCompare(MDefinition *left, MDefinition *right, JSOp jsop) : MBinaryInstruction(left, right), + compareType_(Compare_Unknown), jsop_(jsop), operandMightEmulateUndefined_(true) { @@ -1396,6 +1436,7 @@ class MCompare public: INSTRUCTION_HEADER(Compare) + static MCompare *New(MDefinition *left, MDefinition *right, JSOp op); bool tryFold(bool *result); @@ -1403,9 +1444,13 @@ class MCompare MDefinition *foldsTo(bool useValueNumbers); void infer(const TypeOracle::BinaryTypes &b, JSContext *cx); - MIRType specialization() const { - return specialization_; + CompareType compareType() const { + return compareType_; } + void setCompareType(CompareType type) { + compareType_ = type; + } + MIRType inputType(); JSOp jsop() const { return jsop_; @@ -1423,9 +1468,9 @@ class MCompare // Strict equality is never effectful. if (jsop_ == JSOP_STRICTEQ || jsop_ == JSOP_STRICTNE) return AliasSet::None(); - if (specialization_ == MIRType_None) + if (compareType_ == Compare_Unknown) return AliasSet::Store(AliasSet::Any); - JS_ASSERT(specialization_ <= MIRType_Object); + JS_ASSERT(compareType_ <= Compare_Object); return AliasSet::None(); } diff --git a/js/src/ion/TypePolicy.cpp b/js/src/ion/TypePolicy.cpp index 8d45e6f8842f..6dadabcbdbc4 100644 --- a/js/src/ion/TypePolicy.cpp +++ b/js/src/ion/TypePolicy.cpp @@ -96,16 +96,31 @@ BinaryStringPolicy::adjustInputs(MInstruction *ins) bool ComparePolicy::adjustInputs(MInstruction *def) { - if (specialization_ == MIRType_None) + JS_ASSERT(def->isCompare()); + MCompare *compare = def->toCompare(); + MIRType type = compare->inputType(); + + // Box inputs to get value + if (type == MIRType_Value) return BoxInputsPolicy::adjustInputs(def); - if (IsNullOrUndefined(specialization_)) { - // Nothing to do, lowering handles all types. + // Nothing to do for undefined and null, lowering handles all types. + if (type == MIRType_Undefined || type == MIRType_Null) return true; + + // MIRType_Boolean specialization is done for "Anything === Bool" + // If the LHS is boolean, we set the specialization to Compare_Int32. + // This matches other comparisons of the form bool === bool and + // generated code of Compare_Int32 is more efficient. + if (type == MIRType_Boolean && def->getOperand(0)->type() == MIRType_Boolean) { + compare->setCompareType(MCompare::Compare_Int32); + type = compare->inputType(); } - if (specialization_ == MIRType_Boolean) { - // The RHS is boolean, unbox if needed. + // MIRType_Boolean specialization is done for "Anything === Bool" + // As of previous line Anything can't be Boolean + if (type == MIRType_Boolean) { + // Unbox rhs that is definitely Boolean MDefinition *rhs = def->getOperand(1); if (rhs->type() == MIRType_Value) { @@ -114,24 +129,15 @@ ComparePolicy::adjustInputs(MInstruction *def) def->replaceOperand(1, unbox); } + JS_ASSERT(def->getOperand(0)->type() != MIRType_Boolean); JS_ASSERT(def->getOperand(1)->type() == MIRType_Boolean); - - // Allow the LHS to have any type other than boolean. Value === boolean - // is handled by LCompareB, comparisons with other non-boolean types are - // folded. - if (def->getOperand(0)->type() != MIRType_Boolean) - return true; - - // If the LHS is boolean, we set the specialization to int32 and - // fall-through. This matches other comparisons of the form - // bool === bool and allows us to use LCompare, which is much more - // efficient than LCompareB. - specialization_ = MIRType_Int32; + return true; } + // Convert all inputs to the right input type for (size_t i = 0; i < 2; i++) { MDefinition *in = def->getOperand(i); - if (in->type() == specialization_) + if (in->type() == type) continue; MInstruction *replace; @@ -140,12 +146,11 @@ ComparePolicy::adjustInputs(MInstruction *def) if (in->type() == MIRType_Object || in->type() == MIRType_String) in = boxAt(def, in); - switch (specialization_) { + switch (type) { case MIRType_Double: replace = MToDouble::New(in); break; case MIRType_Int32: - case MIRType_Boolean: replace = MToInt32::New(in); break; case MIRType_Object: diff --git a/js/src/ion/TypePolicy.h b/js/src/ion/TypePolicy.h index 77d7eda0d411..fcd773b98e97 100644 --- a/js/src/ion/TypePolicy.h +++ b/js/src/ion/TypePolicy.h @@ -77,14 +77,6 @@ class BitwisePolicy : public BoxInputsPolicy class ComparePolicy : public BoxInputsPolicy { - protected: - MIRType specialization_; - - public: - ComparePolicy() - : specialization_(MIRType_None) - { } - bool adjustInputs(MInstruction *def); }; diff --git a/js/src/ion/arm/CodeGenerator-arm.cpp b/js/src/ion/arm/CodeGenerator-arm.cpp index b34d961eec80..8bb7fe5bbed3 100644 --- a/js/src/ion/arm/CodeGenerator-arm.cpp +++ b/js/src/ion/arm/CodeGenerator-arm.cpp @@ -1230,6 +1230,59 @@ CodeGeneratorARM::visitCompareBAndBranch(LCompareBAndBranch *lir) return true; } +bool +CodeGeneratorARM::visitCompareV(LCompareV *lir) +{ + MCompare *mir = lir->mir(); + Assembler::Condition cond = JSOpToCondition(mir->jsop()); + const ValueOperand lhs = ToValue(lir, LCompareV::LhsInput); + const ValueOperand rhs = ToValue(lir, LCompareV::RhsInput); + const Register output = ToRegister(lir->output()); + + JS_ASSERT(mir->jsop() == JSOP_EQ || mir->jsop() == JSOP_STRICTEQ || + mir->jsop() == JSOP_NE || mir->jsop() == JSOP_STRICTNE); + + Label notEqual, done; + masm.cmp32(lhs.typeReg(), rhs.typeReg()); + masm.j(Assembler::NotEqual, ¬Equal); + { + masm.cmp32(lhs.payloadReg(), rhs.payloadReg()); + emitSet(cond, output); + masm.jump(&done); + } + masm.bind(¬Equal); + { + masm.move32(Imm32(cond == Assembler::NotEqual), output); + } + + masm.bind(&done); + return true; +} + +bool +CodeGeneratorARM::visitCompareVAndBranch(LCompareVAndBranch *lir) +{ + MCompare *mir = lir->mir(); + Assembler::Condition cond = JSOpToCondition(mir->jsop()); + const ValueOperand lhs = ToValue(lir, LCompareVAndBranch::LhsInput); + const ValueOperand rhs = ToValue(lir, LCompareVAndBranch::RhsInput); + + JS_ASSERT(mir->jsop() == JSOP_EQ || mir->jsop() == JSOP_STRICTEQ || + mir->jsop() == JSOP_NE || mir->jsop() == JSOP_STRICTNE); + + Label *notEqual; + if (cond == Assembler::Equal) + notEqual = lir->ifFalse()->lir()->label(); + else + notEqual = lir->ifTrue()->lir()->label(); + + masm.cmp32(lhs.typeReg(), rhs.typeReg()); + masm.j(Assembler::NotEqual, notEqual); + masm.cmp32(lhs.payloadReg(), rhs.payloadReg()); + emitBranch(cond, lir->ifTrue(), lir->ifFalse()); + + return true; +} bool CodeGeneratorARM::visitNotI(LNotI *ins) { diff --git a/js/src/ion/arm/CodeGenerator-arm.h b/js/src/ion/arm/CodeGenerator-arm.h index 2790eada731b..96c95c3a2636 100644 --- a/js/src/ion/arm/CodeGenerator-arm.h +++ b/js/src/ion/arm/CodeGenerator-arm.h @@ -95,6 +95,8 @@ class CodeGeneratorARM : public CodeGeneratorShared virtual bool visitCompareDAndBranch(LCompareDAndBranch *comp); virtual bool visitCompareB(LCompareB *lir); virtual bool visitCompareBAndBranch(LCompareBAndBranch *lir); + virtual bool visitCompareV(LCompareV *lir); + virtual bool visitCompareVAndBranch(LCompareVAndBranch *lir); virtual bool visitNotI(LNotI *ins); virtual bool visitNotD(LNotD *ins); diff --git a/js/src/ion/shared/CodeGenerator-x86-shared.cpp b/js/src/ion/shared/CodeGenerator-x86-shared.cpp index c0d2071431e9..168c71037adb 100644 --- a/js/src/ion/shared/CodeGenerator-x86-shared.cpp +++ b/js/src/ion/shared/CodeGenerator-x86-shared.cpp @@ -180,10 +180,10 @@ CodeGeneratorX86Shared::emitSet(Assembler::Condition cond, const Register &dest, } void -CodeGeneratorX86Shared::emitCompare(MIRType type, const LAllocation *left, const LAllocation *right) +CodeGeneratorX86Shared::emitCompare(MCompare::CompareType type, const LAllocation *left, const LAllocation *right) { #ifdef JS_CPU_X64 - if (type == MIRType_Object) { + if (type == MCompare::Compare_Object) { masm.cmpq(ToRegister(left), ToOperand(right)); return; } @@ -198,7 +198,7 @@ CodeGeneratorX86Shared::emitCompare(MIRType type, const LAllocation *left, const bool CodeGeneratorX86Shared::visitCompare(LCompare *comp) { - emitCompare(comp->mir()->specialization(), comp->left(), comp->right()); + emitCompare(comp->mir()->compareType(), comp->left(), comp->right()); emitSet(JSOpToCondition(comp->jsop()), ToRegister(comp->output())); return true; } @@ -206,7 +206,7 @@ CodeGeneratorX86Shared::visitCompare(LCompare *comp) bool CodeGeneratorX86Shared::visitCompareAndBranch(LCompareAndBranch *comp) { - emitCompare(comp->mir()->specialization(), comp->left(), comp->right()); + emitCompare(comp->mir()->compareType(), comp->left(), comp->right()); Assembler::Condition cond = JSOpToCondition(comp->jsop()); emitBranch(cond, comp->ifTrue(), comp->ifFalse()); return true; diff --git a/js/src/ion/shared/CodeGenerator-x86-shared.h b/js/src/ion/shared/CodeGenerator-x86-shared.h index 097bda5dfd7f..15e63b13b87e 100644 --- a/js/src/ion/shared/CodeGenerator-x86-shared.h +++ b/js/src/ion/shared/CodeGenerator-x86-shared.h @@ -63,7 +63,7 @@ class CodeGeneratorX86Shared : public CodeGeneratorShared Operand createArrayElementOperand(Register elements, const LAllocation *index); - void emitCompare(MIRType type, const LAllocation *left, const LAllocation *right); + void emitCompare(MCompare::CompareType type, const LAllocation *left, const LAllocation *right); // Emits a conditional set. void emitSet(Assembler::Condition cond, const Register &dest, diff --git a/js/src/ion/x64/CodeGenerator-x64.cpp b/js/src/ion/x64/CodeGenerator-x64.cpp index a447ae493c4f..654d9edf8181 100644 --- a/js/src/ion/x64/CodeGenerator-x64.cpp +++ b/js/src/ion/x64/CodeGenerator-x64.cpp @@ -361,3 +361,34 @@ CodeGeneratorX64::visitCompareBAndBranch(LCompareBAndBranch *lir) emitBranch(JSOpToCondition(mir->jsop()), lir->ifTrue(), lir->ifFalse()); return true; } +bool +CodeGeneratorX64::visitCompareV(LCompareV *lir) +{ + MCompare *mir = lir->mir(); + const ValueOperand lhs = ToValue(lir, LCompareV::LhsInput); + const ValueOperand rhs = ToValue(lir, LCompareV::RhsInput); + const Register output = ToRegister(lir->output()); + + JS_ASSERT(mir->jsop() == JSOP_EQ || mir->jsop() == JSOP_STRICTEQ || + mir->jsop() == JSOP_NE || mir->jsop() == JSOP_STRICTNE); + + masm.cmpq(lhs.valueReg(), rhs.valueReg()); + emitSet(JSOpToCondition(mir->jsop()), output); + return true; +} + +bool +CodeGeneratorX64::visitCompareVAndBranch(LCompareVAndBranch *lir) +{ + MCompare *mir = lir->mir(); + + const ValueOperand lhs = ToValue(lir, LCompareVAndBranch::LhsInput); + const ValueOperand rhs = ToValue(lir, LCompareVAndBranch::RhsInput); + + JS_ASSERT(mir->jsop() == JSOP_EQ || mir->jsop() == JSOP_STRICTEQ || + mir->jsop() == JSOP_NE || mir->jsop() == JSOP_STRICTNE); + + masm.cmpq(lhs.valueReg(), rhs.valueReg()); + emitBranch(JSOpToCondition(mir->jsop()), lir->ifTrue(), lir->ifFalse()); + return true; +} diff --git a/js/src/ion/x64/CodeGenerator-x64.h b/js/src/ion/x64/CodeGenerator-x64.h index a1af4e602d8e..f3b4e871f1d5 100644 --- a/js/src/ion/x64/CodeGenerator-x64.h +++ b/js/src/ion/x64/CodeGenerator-x64.h @@ -51,6 +51,8 @@ class CodeGeneratorX64 : public CodeGeneratorX86Shared bool visitInterruptCheck(LInterruptCheck *lir); bool visitCompareB(LCompareB *lir); bool visitCompareBAndBranch(LCompareBAndBranch *lir); + bool visitCompareV(LCompareV *lir); + bool visitCompareVAndBranch(LCompareVAndBranch *lir); }; typedef CodeGeneratorX64 CodeGeneratorSpecific; diff --git a/js/src/ion/x86/CodeGenerator-x86.cpp b/js/src/ion/x86/CodeGenerator-x86.cpp index cbd925e57057..f2688ffe4a81 100644 --- a/js/src/ion/x86/CodeGenerator-x86.cpp +++ b/js/src/ion/x86/CodeGenerator-x86.cpp @@ -370,3 +370,57 @@ CodeGeneratorX86::visitCompareBAndBranch(LCompareBAndBranch *lir) emitBranch(JSOpToCondition(mir->jsop()), lir->ifTrue(), lir->ifFalse()); return true; } + +bool +CodeGeneratorX86::visitCompareV(LCompareV *lir) +{ + MCompare *mir = lir->mir(); + Assembler::Condition cond = JSOpToCondition(mir->jsop()); + const ValueOperand lhs = ToValue(lir, LCompareV::LhsInput); + const ValueOperand rhs = ToValue(lir, LCompareV::RhsInput); + const Register output = ToRegister(lir->output()); + + JS_ASSERT(mir->jsop() == JSOP_EQ || mir->jsop() == JSOP_STRICTEQ || + mir->jsop() == JSOP_NE || mir->jsop() == JSOP_STRICTNE); + + Label notEqual, done; + masm.cmp32(lhs.typeReg(), rhs.typeReg()); + masm.j(Assembler::NotEqual, ¬Equal); + { + masm.cmp32(lhs.payloadReg(), rhs.payloadReg()); + emitSet(cond, output); + masm.jump(&done); + } + masm.bind(¬Equal); + { + masm.move32(Imm32(cond == Assembler::NotEqual), output); + } + + masm.bind(&done); + return true; +} + +bool +CodeGeneratorX86::visitCompareVAndBranch(LCompareVAndBranch *lir) +{ + MCompare *mir = lir->mir(); + Assembler::Condition cond = JSOpToCondition(mir->jsop()); + const ValueOperand lhs = ToValue(lir, LCompareVAndBranch::LhsInput); + const ValueOperand rhs = ToValue(lir, LCompareVAndBranch::RhsInput); + + JS_ASSERT(mir->jsop() == JSOP_EQ || mir->jsop() == JSOP_STRICTEQ || + mir->jsop() == JSOP_NE || mir->jsop() == JSOP_STRICTNE); + + Label *notEqual; + if (cond == Assembler::Equal) + notEqual = lir->ifFalse()->lir()->label(); + else + notEqual = lir->ifTrue()->lir()->label(); + + masm.cmp32(lhs.typeReg(), rhs.typeReg()); + masm.j(Assembler::NotEqual, notEqual); + masm.cmp32(lhs.payloadReg(), rhs.payloadReg()); + emitBranch(cond, lir->ifTrue(), lir->ifFalse()); + + return true; +} diff --git a/js/src/ion/x86/CodeGenerator-x86.h b/js/src/ion/x86/CodeGenerator-x86.h index 009f337b0b16..c1a710d031cf 100644 --- a/js/src/ion/x86/CodeGenerator-x86.h +++ b/js/src/ion/x86/CodeGenerator-x86.h @@ -70,6 +70,8 @@ class CodeGeneratorX86 : public CodeGeneratorX86Shared bool visitInterruptCheck(LInterruptCheck *lir); bool visitCompareB(LCompareB *lir); bool visitCompareBAndBranch(LCompareBAndBranch *lir); + bool visitCompareV(LCompareV *lir); + bool visitCompareVAndBranch(LCompareVAndBranch *lir); }; typedef CodeGeneratorX86 CodeGeneratorSpecific; diff --git a/js/src/jsinfer.h b/js/src/jsinfer.h index 087e68939840..a3b512286e03 100644 --- a/js/src/jsinfer.h +++ b/js/src/jsinfer.h @@ -609,6 +609,16 @@ class StackTypeSet : public TypeSet * null/undefined/int/double, or some combination of those. */ bool knownNonStringPrimitive(); + + bool knownPrimitiveOrObject() { + TypeFlags flags = TYPE_FLAG_UNDEFINED | TYPE_FLAG_NULL | TYPE_FLAG_DOUBLE | + TYPE_FLAG_INT32 | TYPE_FLAG_BOOLEAN | TYPE_FLAG_STRING | + TYPE_FLAG_ANYOBJECT; + if (baseFlags() & (~flags & TYPE_FLAG_BASE_MASK)) + return false; + + return true; + } }; /* From db0eb7997328f2899097abbc4eb94b2732c99b93 Mon Sep 17 00:00:00 2001 From: Hannes Verschore Date: Sat, 22 Dec 2012 23:40:55 +0100 Subject: [PATCH 084/469] Bug 777262: Fix windows bustage, r=bustage --- js/src/ion/CodeGenerator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/ion/CodeGenerator.cpp b/js/src/ion/CodeGenerator.cpp index 8e7c85406b5f..a00ccaa90791 100644 --- a/js/src/ion/CodeGenerator.cpp +++ b/js/src/ion/CodeGenerator.cpp @@ -2579,7 +2579,7 @@ CodeGenerator::visitIsNullOrLikeUndefinedAndBranch(LIsNullOrLikeUndefinedAndBran JS_ASSERT(op == JSOP_STRICTEQ || op == JSOP_STRICTNE); Assembler::Condition cond = JSOpToCondition(op); - if (compareType == MCompare::MCompare::Compare_Null) + if (compareType == MCompare::Compare_Null) cond = masm.testNull(cond, value); else cond = masm.testUndefined(cond, value); From 22cf1a556805a18f2fa88901238620f47a83513e Mon Sep 17 00:00:00 2001 From: Peter Van der Beken Date: Fri, 21 Dec 2012 15:06:49 +0100 Subject: [PATCH 085/469] Fix for bug 824007 (Convert HTMLBodyElement, HTMLDataListElement, HTMLFontElement, HTMLFrameSetElement and HTMLLabelElement to new DOM bindings) - make NS_IMPL_NS_NEW_HTML_ELEMENT macros work with HTML element classes in mozilla::dom. r=bz. --HG-- rename : dom/encoding/TextDecoderBase.h => dom/encoding/TextDecoder.h rename : dom/encoding/TextEncoderBase.h => dom/encoding/TextEncoder.h extra : rebase_source : c6c3c3e702fd2c6081869f1f2cf88bbf6b10b293 --- .../html/content/src/nsGenericHTMLElement.h | 64 ++++++++++++++++++- 1 file changed, 62 insertions(+), 2 deletions(-) diff --git a/content/html/content/src/nsGenericHTMLElement.h b/content/html/content/src/nsGenericHTMLElement.h index 58949650c94f..424a9b6a0f66 100644 --- a/content/html/content/src/nsGenericHTMLElement.h +++ b/content/html/content/src/nsGenericHTMLElement.h @@ -1817,6 +1817,12 @@ protected: * A macro to declare the NS_NewHTMLXXXElement() functions. */ #define NS_DECLARE_NS_NEW_HTML_ELEMENT(_elementName) \ +class nsHTML##_elementName##Element; \ +namespace mozilla { \ +namespace dom { \ +class HTML##_elementName##Element; \ +} \ +} \ nsGenericHTMLElement* \ NS_NewHTML##_elementName##Element(already_AddRefed aNodeInfo, \ mozilla::dom::FromParser aFromParser = mozilla::dom::NOT_FROM_PARSER); @@ -1829,6 +1835,55 @@ NS_NewHTML##_elementName##Element(already_AddRefed aNodeInfo, \ return NS_NewHTMLSharedElement(aNodeInfo, aFromParser); \ } +namespace mozilla { +namespace dom { + +// A helper struct to automatically detect whether HTMLFooElement is implemented +// as nsHTMLFooElement or as mozilla::dom::HTMLFooElement by using SFINAE to +// look for the InNavQuirksMode function (which lives on nsGenericHTMLElement) +// on both types and using whichever one the substitution succeeds with. + +struct NewHTMLElementHelper +{ + template struct SFINAE; + typedef bool (*InNavQuirksMode)(nsIDocument*); + + template + static nsGenericHTMLElement* + Create(already_AddRefed aNodeInfo, + SFINAE* dummy=nullptr) + { + return new T(aNodeInfo); + } + template + static nsGenericHTMLElement* + Create(already_AddRefed aNodeInfo, + SFINAE* dummy=nullptr) + { + return new U(aNodeInfo); + } + + template + static nsGenericHTMLElement* + Create(already_AddRefed aNodeInfo, + mozilla::dom::FromParser aFromParser, + SFINAE* dummy=nullptr) + { + return new U(aNodeInfo, aFromParser); + } + template + static nsGenericHTMLElement* + Create(already_AddRefed aNodeInfo, + mozilla::dom::FromParser aFromParser, + SFINAE* dummy=nullptr) + { + return new T(aNodeInfo, aFromParser); + } +}; + +} +} + /** * A macro to implement the NS_NewHTMLXXXElement() functions. */ @@ -1837,7 +1892,9 @@ nsGenericHTMLElement* \ NS_NewHTML##_elementName##Element(already_AddRefed aNodeInfo, \ mozilla::dom::FromParser aFromParser) \ { \ - return new nsHTML##_elementName##Element(aNodeInfo); \ + return mozilla::dom::NewHTMLElementHelper:: \ + Create(aNodeInfo); \ } #define NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(_elementName) \ @@ -1845,7 +1902,10 @@ nsGenericHTMLElement* \ NS_NewHTML##_elementName##Element(already_AddRefed aNodeInfo, \ mozilla::dom::FromParser aFromParser) \ { \ - return new nsHTML##_elementName##Element(aNodeInfo, aFromParser); \ + return mozilla::dom::NewHTMLElementHelper:: \ + Create(aNodeInfo, \ + aFromParser); \ } // Here, we expand 'NS_DECLARE_NS_NEW_HTML_ELEMENT()' by hand. From d837e37c502587a71cb229e77c9a60b48ae34527 Mon Sep 17 00:00:00 2001 From: Peter Van der Beken Date: Fri, 21 Dec 2012 15:06:50 +0100 Subject: [PATCH 086/469] Fix for bug 824007 (Convert HTMLBodyElement, HTMLDataListElement, HTMLFontElement, HTMLFrameSetElement and HTMLLabelElement to new DOM bindings) - move some HTML element classes to mozilla::dom. r=bz. --HG-- rename : content/html/content/src/nsHTMLBodyElement.cpp => content/html/content/src/HTMLBodyElement.cpp rename : content/html/content/src/nsHTMLDataListElement.cpp => content/html/content/src/HTMLDataListElement.cpp rename : content/html/content/src/nsHTMLDivElement.cpp => content/html/content/src/HTMLDivElement.cpp rename : content/html/content/src/nsHTMLDivElement.h => content/html/content/src/HTMLDivElement.h rename : content/html/content/src/nsHTMLElement.cpp => content/html/content/src/HTMLElement.cpp rename : content/html/content/src/nsHTMLFontElement.cpp => content/html/content/src/HTMLFontElement.cpp rename : content/html/content/src/nsHTMLFrameSetElement.cpp => content/html/content/src/HTMLFrameSetElement.cpp rename : content/html/content/src/nsHTMLFrameSetElement.h => content/html/content/src/HTMLFrameSetElement.h rename : content/html/content/src/nsHTMLLabelElement.cpp => content/html/content/src/HTMLLabelElement.cpp rename : content/html/content/src/nsHTMLLabelElement.h => content/html/content/src/HTMLLabelElement.h rename : content/html/content/src/nsHTMLUnknownElement.cpp => content/html/content/src/HTMLUnknownElement.cpp rename : content/html/content/src/nsHTMLUnknownElement.h => content/html/content/src/HTMLUnknownElement.h extra : rebase_source : 99a2b1764bfd34db1375939b967f816dc2a42a91 --- content/base/public/nsINode.h | 6 +- content/events/src/nsEventStateManager.cpp | 5 +- ...TMLBodyElement.cpp => HTMLBodyElement.cpp} | 247 ++++++------------ content/html/content/src/HTMLBodyElement.h | 97 +++++++ .../html/content/src/HTMLDataListElement.cpp | 64 +++++ .../html/content/src/HTMLDataListElement.h | 60 +++++ ...sHTMLDivElement.cpp => HTMLDivElement.cpp} | 49 ++-- .../{nsHTMLDivElement.h => HTMLDivElement.h} | 30 ++- .../{nsHTMLElement.cpp => HTMLElement.cpp} | 64 ++--- ...TMLFontElement.cpp => HTMLFontElement.cpp} | 94 ++----- content/html/content/src/HTMLFontElement.h | 53 ++++ ...SetElement.cpp => HTMLFrameSetElement.cpp} | 174 ++++++------ ...rameSetElement.h => HTMLFrameSetElement.h} | 36 ++- ...LLabelElement.cpp => HTMLLabelElement.cpp} | 102 ++------ ...sHTMLLabelElement.h => HTMLLabelElement.h} | 43 ++- ...nownElement.cpp => HTMLUnknownElement.cpp} | 30 ++- ...LUnknownElement.h => HTMLUnknownElement.h} | 18 +- content/html/content/src/Makefile.in | 27 +- .../html/content/src/nsGenericHTMLElement.cpp | 4 +- .../content/src/nsHTMLDataListElement.cpp | 112 -------- dom/bindings/Bindings.conf | 8 - js/xpconnect/src/nsDOMQS.h | 2 - layout/generic/nsFrameSetFrame.cpp | 11 +- layout/generic/nsFrameSetFrame.h | 2 +- 24 files changed, 667 insertions(+), 671 deletions(-) rename content/html/content/src/{nsHTMLBodyElement.cpp => HTMLBodyElement.cpp} (74%) create mode 100644 content/html/content/src/HTMLBodyElement.h create mode 100644 content/html/content/src/HTMLDataListElement.cpp create mode 100644 content/html/content/src/HTMLDataListElement.h rename content/html/content/src/{nsHTMLDivElement.cpp => HTMLDivElement.cpp} (72%) rename content/html/content/src/{nsHTMLDivElement.h => HTMLDivElement.h} (72%) rename content/html/content/src/{nsHTMLElement.cpp => HTMLElement.cpp} (65%) rename content/html/content/src/{nsHTMLFontElement.cpp => HTMLFontElement.cpp} (61%) create mode 100644 content/html/content/src/HTMLFontElement.h rename content/html/content/src/{nsHTMLFrameSetElement.cpp => HTMLFrameSetElement.cpp} (76%) rename content/html/content/src/{nsHTMLFrameSetElement.h => HTMLFrameSetElement.h} (85%) rename content/html/content/src/{nsHTMLLabelElement.cpp => HTMLLabelElement.cpp} (74%) rename content/html/content/src/{nsHTMLLabelElement.h => HTMLLabelElement.h} (58%) rename content/html/content/src/{nsHTMLUnknownElement.cpp => HTMLUnknownElement.cpp} (53%) rename content/html/content/src/{nsHTMLUnknownElement.h => HTMLUnknownElement.h} (73%) delete mode 100644 content/html/content/src/nsHTMLDataListElement.cpp diff --git a/content/base/public/nsINode.h b/content/base/public/nsINode.h index b343b385847c..447bb45175c0 100644 --- a/content/base/public/nsINode.h +++ b/content/base/public/nsINode.h @@ -277,11 +277,11 @@ public: // worthwhile: // - nsGenericHTMLElement: mForm, mFieldSet // - nsGenericHTMLFrameElement: mFrameLoader (bug 672539), mTitleChangedListener - // - nsHTMLBodyElement: mContentStyleRule - // - nsHTMLDataListElement: mOptions + // - HTMLBodyElement: mContentStyleRule + // - HTMLDataListElement: mOptions // - nsHTMLFieldSetElement: mElements, mDependentElements, mFirstLegend // - nsHTMLFormElement: many! - // - nsHTMLFrameSetElement: mRowSpecs, mColSpecs + // - HTMLFrameSetElement: mRowSpecs, mColSpecs // - nsHTMLInputElement: mInputData, mFiles, mFileList, mStaticDocfileList // - nsHTMLMapElement: mAreas // - nsHTMLMediaElement: many! diff --git a/content/events/src/nsEventStateManager.cpp b/content/events/src/nsEventStateManager.cpp index 19577429db34..ba3c31037fbb 100644 --- a/content/events/src/nsEventStateManager.cpp +++ b/content/events/src/nsEventStateManager.cpp @@ -92,7 +92,7 @@ #include "nsICommandParams.h" #include "mozilla/Services.h" #include "mozAutoDocUpdate.h" -#include "nsHTMLLabelElement.h" +#include "mozilla/dom/HTMLLabelElement.h" #include "mozilla/Preferences.h" #include "mozilla/LookAndFeel.h" @@ -4613,7 +4613,8 @@ nsEventStateManager::GetEventTargetContent(nsEvent* aEvent) static Element* GetLabelTarget(nsIContent* aPossibleLabel) { - nsHTMLLabelElement* label = nsHTMLLabelElement::FromContent(aPossibleLabel); + mozilla::dom::HTMLLabelElement* label = + mozilla::dom::HTMLLabelElement::FromContent(aPossibleLabel); if (!label) return nullptr; diff --git a/content/html/content/src/nsHTMLBodyElement.cpp b/content/html/content/src/HTMLBodyElement.cpp similarity index 74% rename from content/html/content/src/nsHTMLBodyElement.cpp rename to content/html/content/src/HTMLBodyElement.cpp index a90e5eaad656..aafe54616a69 100644 --- a/content/html/content/src/nsHTMLBodyElement.cpp +++ b/content/html/content/src/HTMLBodyElement.cpp @@ -5,10 +5,7 @@ #include "mozilla/Util.h" -#include "nscore.h" -#include "nsCOMPtr.h" -#include "nsIDOMHTMLBodyElement.h" -#include "nsGenericHTMLElement.h" +#include "HTMLBodyElement.h" #include "nsAttrValueInlines.h" #include "nsGkAtoms.h" #include "nsStyleConsts.h" @@ -22,92 +19,17 @@ #include "nsIDocShell.h" #include "nsIEditorDocShell.h" #include "nsRuleWalker.h" -#include "jspubtd.h" #include "mozilla/dom/EventHandlerBinding.h" -//---------------------------------------------------------------------- +NS_IMPL_NS_NEW_HTML_ELEMENT(Body) +DOMCI_NODE_DATA(HTMLBodyElement, mozilla::dom::HTMLBodyElement) -using namespace mozilla; -using namespace mozilla::dom; - -class nsHTMLBodyElement; - -class BodyRule: public nsIStyleRule { -public: - BodyRule(nsHTMLBodyElement* aPart); - virtual ~BodyRule(); - - NS_DECL_ISUPPORTS - - // nsIStyleRule interface - virtual void MapRuleInfoInto(nsRuleData* aRuleData); -#ifdef DEBUG - virtual void List(FILE* out = stdout, int32_t aIndent = 0) const; -#endif - - nsHTMLBodyElement* mPart; // not ref-counted, cleared by content -}; +namespace mozilla { +namespace dom { //---------------------------------------------------------------------- -class nsHTMLBodyElement : public nsGenericHTMLElement, - public nsIDOMHTMLBodyElement -{ -public: - using Element::GetText; - using Element::SetText; - - nsHTMLBodyElement(already_AddRefed aNodeInfo); - virtual ~nsHTMLBodyElement(); - - // nsISupports - NS_DECL_ISUPPORTS_INHERITED - - // nsIDOMNode - NS_FORWARD_NSIDOMNODE_TO_NSINODE - - // nsIDOMElement - NS_FORWARD_NSIDOMELEMENT_TO_GENERIC - - // nsIDOMHTMLElement - NS_FORWARD_NSIDOMHTMLELEMENT_TO_GENERIC - - // nsIDOMHTMLBodyElement - NS_DECL_NSIDOMHTMLBODYELEMENT - - // Event listener stuff; we need to declare only the ones we need to - // forward to window that don't come from nsIDOMHTMLBodyElement. -#define EVENT(name_, id_, type_, struct_) /* nothing; handled by the shim */ -#define FORWARDED_EVENT(name_, id_, type_, struct_) \ - NS_IMETHOD GetOn##name_(JSContext *cx, jsval *vp); \ - NS_IMETHOD SetOn##name_(JSContext *cx, const jsval &v); -#include "nsEventNameList.h" -#undef FORWARDED_EVENT -#undef EVENT - - virtual bool ParseAttribute(int32_t aNamespaceID, - nsIAtom* aAttribute, - const nsAString& aValue, - nsAttrValue& aResult); - virtual void UnbindFromTree(bool aDeep = true, - bool aNullParent = true); - virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const; - NS_IMETHOD WalkContentStyleRules(nsRuleWalker* aRuleWalker); - NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const; - virtual already_AddRefed GetAssociatedEditor(); - virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const; - virtual nsXPCClassInfo* GetClassInfo(); - virtual nsIDOMNode* AsDOMNode() { return this; } -private: - nsresult GetColorHelper(nsIAtom* aAtom, nsAString& aColor); - -protected: - BodyRule* mContentStyleRule; -}; - -//---------------------------------------------------------------------- - -BodyRule::BodyRule(nsHTMLBodyElement* aPart) +BodyRule::BodyRule(HTMLBodyElement* aPart) { mPart = aPart; } @@ -264,17 +186,7 @@ BodyRule::List(FILE* out, int32_t aIndent) const //---------------------------------------------------------------------- - -NS_IMPL_NS_NEW_HTML_ELEMENT(Body) - - -nsHTMLBodyElement::nsHTMLBodyElement(already_AddRefed aNodeInfo) - : nsGenericHTMLElement(aNodeInfo), - mContentStyleRule(nullptr) -{ -} - -nsHTMLBodyElement::~nsHTMLBodyElement() +HTMLBodyElement::~HTMLBodyElement() { if (mContentStyleRule) { mContentStyleRule->mPart = nullptr; @@ -283,33 +195,31 @@ nsHTMLBodyElement::~nsHTMLBodyElement() } -NS_IMPL_ADDREF_INHERITED(nsHTMLBodyElement, Element) -NS_IMPL_RELEASE_INHERITED(nsHTMLBodyElement, Element) +NS_IMPL_ADDREF_INHERITED(HTMLBodyElement, Element) +NS_IMPL_RELEASE_INHERITED(HTMLBodyElement, Element) -DOMCI_NODE_DATA(HTMLBodyElement, nsHTMLBodyElement) - -// QueryInterface implementation for nsHTMLBodyElement -NS_INTERFACE_TABLE_HEAD(nsHTMLBodyElement) - NS_HTML_CONTENT_INTERFACE_TABLE1(nsHTMLBodyElement, nsIDOMHTMLBodyElement) - NS_HTML_CONTENT_INTERFACE_TABLE_TO_MAP_SEGUE(nsHTMLBodyElement, +// QueryInterface implementation for HTMLBodyElement +NS_INTERFACE_TABLE_HEAD(HTMLBodyElement) + NS_HTML_CONTENT_INTERFACE_TABLE1(HTMLBodyElement, nsIDOMHTMLBodyElement) + NS_HTML_CONTENT_INTERFACE_TABLE_TO_MAP_SEGUE(HTMLBodyElement, nsGenericHTMLElement) NS_HTML_CONTENT_INTERFACE_TABLE_TAIL_CLASSINFO(HTMLBodyElement) -NS_IMPL_ELEMENT_CLONE(nsHTMLBodyElement) +NS_IMPL_ELEMENT_CLONE(HTMLBodyElement) -NS_IMPL_STRING_ATTR(nsHTMLBodyElement, Background, background) -NS_IMPL_STRING_ATTR(nsHTMLBodyElement, VLink, vlink) -NS_IMPL_STRING_ATTR(nsHTMLBodyElement, ALink, alink) -NS_IMPL_STRING_ATTR(nsHTMLBodyElement, Link, link) -NS_IMPL_STRING_ATTR(nsHTMLBodyElement, Text, text) -NS_IMPL_STRING_ATTR(nsHTMLBodyElement, BgColor, bgcolor) +NS_IMPL_STRING_ATTR(HTMLBodyElement, Background, background) +NS_IMPL_STRING_ATTR(HTMLBodyElement, VLink, vlink) +NS_IMPL_STRING_ATTR(HTMLBodyElement, ALink, alink) +NS_IMPL_STRING_ATTR(HTMLBodyElement, Link, link) +NS_IMPL_STRING_ATTR(HTMLBodyElement, Text, text) +NS_IMPL_STRING_ATTR(HTMLBodyElement, BgColor, bgcolor) bool -nsHTMLBodyElement::ParseAttribute(int32_t aNamespaceID, - nsIAtom* aAttribute, - const nsAString& aValue, - nsAttrValue& aResult) +HTMLBodyElement::ParseAttribute(int32_t aNamespaceID, + nsIAtom* aAttribute, + const nsAString& aValue, + nsAttrValue& aResult) { if (aNamespaceID == kNameSpaceID_None) { if (aAttribute == nsGkAtoms::bgcolor || @@ -337,7 +247,7 @@ nsHTMLBodyElement::ParseAttribute(int32_t aNamespaceID, } void -nsHTMLBodyElement::UnbindFromTree(bool aDeep, bool aNullParent) +HTMLBodyElement::UnbindFromTree(bool aDeep, bool aNullParent) { if (mContentStyleRule) { mContentStyleRule->mPart = nullptr; @@ -398,13 +308,13 @@ void MapAttributesIntoRule(const nsMappedAttributes* aAttributes, nsRuleData* aD } nsMapRuleToAttributesFunc -nsHTMLBodyElement::GetAttributeMappingFunction() const +HTMLBodyElement::GetAttributeMappingFunction() const { return &MapAttributesIntoRule; } NS_IMETHODIMP -nsHTMLBodyElement::WalkContentStyleRules(nsRuleWalker* aRuleWalker) +HTMLBodyElement::WalkContentStyleRules(nsRuleWalker* aRuleWalker) { nsGenericHTMLElement::WalkContentStyleRules(aRuleWalker); @@ -421,7 +331,7 @@ nsHTMLBodyElement::WalkContentStyleRules(nsRuleWalker* aRuleWalker) } NS_IMETHODIMP_(bool) -nsHTMLBodyElement::IsAttributeMapped(const nsIAtom* aAttribute) const +HTMLBodyElement::IsAttributeMapped(const nsIAtom* aAttribute) const { static const MappedAttributeEntry attributes[] = { { &nsGkAtoms::link }, @@ -447,7 +357,7 @@ nsHTMLBodyElement::IsAttributeMapped(const nsIAtom* aAttribute) const } already_AddRefed -nsHTMLBodyElement::GetAssociatedEditor() +HTMLBodyElement::GetAssociatedEditor() { nsIEditor* editor = nullptr; if (NS_SUCCEEDED(GetEditorInternal(&editor)) && editor) { @@ -479,55 +389,59 @@ nsHTMLBodyElement::GetAssociatedEditor() // nsGenericHTMLElement::GetOnError returns // already_AddRefed while other getters return // EventHandlerNonNull*, so allow passing in the type to use here. -#define FORWARDED_EVENT_HELPER(name_, getter_type_) \ - NS_IMETHODIMP nsHTMLBodyElement::GetOn##name_(JSContext *cx, \ - jsval *vp) { \ - getter_type_ h = nsGenericHTMLElement::GetOn##name_(); \ - vp->setObjectOrNull(h ? h->Callable() : nullptr); \ - return NS_OK; \ - } \ - NS_IMETHODIMP nsHTMLBodyElement::SetOn##name_(JSContext *cx, \ - const jsval &v) { \ - JSObject *obj = GetWrapper(); \ - if (!obj) { \ - /* Just silently do nothing */ \ - return NS_OK; \ - } \ - nsRefPtr handler; \ - JSObject *callable; \ - if (v.isObject() && \ - JS_ObjectIsCallable(cx, callable = &v.toObject())) { \ - bool ok; \ - handler = new EventHandlerNonNull(cx, obj, callable, &ok); \ - if (!ok) { \ - return NS_ERROR_OUT_OF_MEMORY; \ - } \ - } \ - ErrorResult rv; \ - nsGenericHTMLElement::SetOn##name_(handler, rv); \ - return rv.ErrorCode(); \ +#define FORWARDED_EVENT_HELPER(name_, getter_type_) \ + NS_IMETHODIMP \ + HTMLBodyElement::GetOn##name_(JSContext *cx, jsval *vp) \ + { \ + getter_type_ h = nsGenericHTMLElement::GetOn##name_(); \ + vp->setObjectOrNull(h ? h->Callable() : nullptr); \ + return NS_OK; \ + } \ + NS_IMETHODIMP \ + HTMLBodyElement::SetOn##name_(JSContext *cx, const jsval &v) \ + { \ + JSObject *obj = GetWrapper(); \ + if (!obj) { \ + /* Just silently do nothing */ \ + return NS_OK; \ + } \ + nsRefPtr handler; \ + JSObject *callable; \ + if (v.isObject() && \ + JS_ObjectIsCallable(cx, callable = &v.toObject())) { \ + bool ok; \ + handler = new EventHandlerNonNull(cx, obj, callable, &ok); \ + if (!ok) { \ + return NS_ERROR_OUT_OF_MEMORY; \ + } \ + } \ + ErrorResult rv; \ + nsGenericHTMLElement::SetOn##name_(handler, rv); \ + return rv.ErrorCode(); \ } -#define FORWARDED_EVENT(name_, id_, type_, struct_) \ +#define FORWARDED_EVENT(name_, id_, type_, struct_) \ FORWARDED_EVENT_HELPER(name_, EventHandlerNonNull*) -#define ERROR_EVENT(name_, id_, type_, struct_) \ +#define ERROR_EVENT(name_, id_, type_, struct_) \ FORWARDED_EVENT_HELPER(name_, nsCOMPtr) -#define WINDOW_EVENT(name_, id_, type_, struct_) \ - NS_IMETHODIMP nsHTMLBodyElement::GetOn##name_(JSContext *cx, \ - jsval *vp) { \ - nsPIDOMWindow* win = OwnerDoc()->GetInnerWindow(); \ - if (win && win->IsInnerWindow()) { \ - return win->GetOn##name_(cx, vp); \ - } \ - *vp = JSVAL_NULL; \ - return NS_OK; \ - } \ - NS_IMETHODIMP nsHTMLBodyElement::SetOn##name_(JSContext *cx, \ - const jsval &v) { \ - nsPIDOMWindow* win = OwnerDoc()->GetInnerWindow(); \ - if (win && win->IsInnerWindow()) { \ - return win->SetOn##name_(cx, v); \ - } \ - return NS_OK; \ +#define WINDOW_EVENT(name_, id_, type_, struct_) \ + NS_IMETHODIMP \ + HTMLBodyElement::GetOn##name_(JSContext *cx, jsval *vp) \ + { \ + nsPIDOMWindow* win = OwnerDoc()->GetInnerWindow(); \ + if (win && win->IsInnerWindow()) { \ + return win->GetOn##name_(cx, vp); \ + } \ + *vp = JSVAL_NULL; \ + return NS_OK; \ + } \ + NS_IMETHODIMP \ + HTMLBodyElement::SetOn##name_(JSContext *cx, const jsval &v) \ + { \ + nsPIDOMWindow* win = OwnerDoc()->GetInnerWindow(); \ + if (win && win->IsInnerWindow()) { \ + return win->SetOn##name_(cx, v); \ + } \ + return NS_OK; \ } #include "nsEventNameList.h" #undef WINDOW_EVENT @@ -535,3 +449,6 @@ nsHTMLBodyElement::GetAssociatedEditor() #undef FORWARDED_EVENT #undef FORWARDED_EVENT_HELPER #undef EVENT + +} // namespace dom +} // namespace mozilla diff --git a/content/html/content/src/HTMLBodyElement.h b/content/html/content/src/HTMLBodyElement.h new file mode 100644 index 000000000000..2131804f3645 --- /dev/null +++ b/content/html/content/src/HTMLBodyElement.h @@ -0,0 +1,97 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef HTMLBodyElement_h___ +#define HTMLBodyElement_h___ + +#include "nsGenericHTMLElement.h" +#include "nsIDOMHTMLBodyElement.h" +#include "nsIStyleRule.h" + +namespace mozilla { +namespace dom { + +class BeforeUnloadEventHandlerNonNull; +class HTMLBodyElement; + +class BodyRule: public nsIStyleRule +{ +public: + BodyRule(HTMLBodyElement* aPart); + virtual ~BodyRule(); + + NS_DECL_ISUPPORTS + + // nsIStyleRule interface + virtual void MapRuleInfoInto(nsRuleData* aRuleData); +#ifdef DEBUG + virtual void List(FILE* out = stdout, int32_t aIndent = 0) const; +#endif + + HTMLBodyElement* mPart; // not ref-counted, cleared by content +}; + +class HTMLBodyElement : public nsGenericHTMLElement, + public nsIDOMHTMLBodyElement +{ +public: + using Element::GetText; + using Element::SetText; + + HTMLBodyElement(already_AddRefed aNodeInfo) + : nsGenericHTMLElement(aNodeInfo), + mContentStyleRule(nullptr) + { + } + virtual ~HTMLBodyElement(); + + // nsISupports + NS_DECL_ISUPPORTS_INHERITED + + // nsIDOMNode + NS_FORWARD_NSIDOMNODE_TO_NSINODE + + // nsIDOMElement + NS_FORWARD_NSIDOMELEMENT_TO_GENERIC + + // nsIDOMHTMLElement + NS_FORWARD_NSIDOMHTMLELEMENT_TO_GENERIC + + // nsIDOMHTMLBodyElement + NS_DECL_NSIDOMHTMLBODYELEMENT + + // Event listener stuff; we need to declare only the ones we need to + // forward to window that don't come from nsIDOMHTMLBodyElement. +#define EVENT(name_, id_, type_, struct_) /* nothing; handled by the shim */ +#define FORWARDED_EVENT(name_, id_, type_, struct_) \ + NS_IMETHOD GetOn##name_(JSContext *cx, jsval *vp); \ + NS_IMETHOD SetOn##name_(JSContext *cx, const jsval &v); +#include "nsEventNameList.h" +#undef FORWARDED_EVENT +#undef EVENT + + virtual bool ParseAttribute(int32_t aNamespaceID, + nsIAtom* aAttribute, + const nsAString& aValue, + nsAttrValue& aResult); + virtual void UnbindFromTree(bool aDeep = true, + bool aNullParent = true); + virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const; + NS_IMETHOD WalkContentStyleRules(nsRuleWalker* aRuleWalker); + NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const; + virtual already_AddRefed GetAssociatedEditor(); + virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const; + virtual nsXPCClassInfo* GetClassInfo(); + virtual nsIDOMNode* AsDOMNode() { return this; } +private: + nsresult GetColorHelper(nsIAtom* aAtom, nsAString& aColor); + +protected: + BodyRule* mContentStyleRule; +}; + +} // namespace dom +} // namespace mozilla + +#endif /* HTMLBodyElement_h___ */ diff --git a/content/html/content/src/HTMLDataListElement.cpp b/content/html/content/src/HTMLDataListElement.cpp new file mode 100644 index 000000000000..0c2e32956d76 --- /dev/null +++ b/content/html/content/src/HTMLDataListElement.cpp @@ -0,0 +1,64 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "HTMLDataListElement.h" + +NS_IMPL_NS_NEW_HTML_ELEMENT(DataList) +DOMCI_NODE_DATA(HTMLDataListElement, mozilla::dom::HTMLDataListElement) + +namespace mozilla { +namespace dom { + +HTMLDataListElement::~HTMLDataListElement() +{ +} + + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLDataListElement, + nsGenericHTMLElement) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mOptions) +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLDataListElement) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLDataListElement, + nsGenericHTMLElement) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOptions) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_IMPL_ADDREF_INHERITED(HTMLDataListElement, Element) +NS_IMPL_RELEASE_INHERITED(HTMLDataListElement, Element) + +NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(HTMLDataListElement) + NS_HTML_CONTENT_INTERFACE_TABLE1(HTMLDataListElement, + nsIDOMHTMLDataListElement) + NS_HTML_CONTENT_INTERFACE_TABLE_TO_MAP_SEGUE(HTMLDataListElement, + nsGenericHTMLElement) +NS_HTML_CONTENT_INTERFACE_TABLE_TAIL_CLASSINFO(HTMLDataListElement) + + +NS_IMPL_ELEMENT_CLONE(HTMLDataListElement) + +bool +HTMLDataListElement::MatchOptions(nsIContent* aContent, int32_t aNamespaceID, + nsIAtom* aAtom, void* aData) +{ + return aContent->NodeInfo()->Equals(nsGkAtoms::option, kNameSpaceID_XHTML) && + !aContent->HasAttr(kNameSpaceID_None, nsGkAtoms::disabled); +} + +NS_IMETHODIMP +HTMLDataListElement::GetOptions(nsIDOMHTMLCollection** aOptions) +{ + if (!mOptions) { + mOptions = new nsContentList(this, MatchOptions, nullptr, nullptr, true); + } + + NS_ADDREF(*aOptions = mOptions); + + return NS_OK; +} + +} // namespace dom +} // namespace mozilla diff --git a/content/html/content/src/HTMLDataListElement.h b/content/html/content/src/HTMLDataListElement.h new file mode 100644 index 000000000000..a17fd1134eb0 --- /dev/null +++ b/content/html/content/src/HTMLDataListElement.h @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef HTMLDataListElement_h___ +#define HTMLDataListElement_h___ + +#include "nsGenericHTMLElement.h" +#include "nsIDOMHTMLDataListElement.h" +#include "nsContentList.h" + +namespace mozilla { +namespace dom { + +class HTMLDataListElement : public nsGenericHTMLElement, + public nsIDOMHTMLDataListElement +{ +public: + HTMLDataListElement(already_AddRefed aNodeInfo) + : nsGenericHTMLElement(aNodeInfo) + { + } + virtual ~HTMLDataListElement(); + + // nsISupports + NS_DECL_ISUPPORTS_INHERITED + + // nsIDOMNode + NS_FORWARD_NSIDOMNODE_TO_NSINODE + + // nsIDOMElement + NS_FORWARD_NSIDOMELEMENT_TO_GENERIC + + // nsIDOMHTMLElement + NS_FORWARD_NSIDOMHTMLELEMENT_TO_GENERIC + + // nsIDOMHTMLDataListElement + NS_DECL_NSIDOMHTMLDATALISTELEMENT + + virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const; + + // This function is used to generate the nsContentList (option elements). + static bool MatchOptions(nsIContent* aContent, int32_t aNamespaceID, + nsIAtom* aAtom, void* aData); + + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLDataListElement, + nsGenericHTMLElement) + + virtual nsXPCClassInfo* GetClassInfo(); + virtual nsIDOMNode* AsDOMNode() { return this; } +protected: + + //