diff --git a/accessible/atk/nsMaiInterfaceEditableText.cpp b/accessible/atk/nsMaiInterfaceEditableText.cpp index 6f76940a4e..18a1b6f422 100644 --- a/accessible/atk/nsMaiInterfaceEditableText.cpp +++ b/accessible/atk/nsMaiInterfaceEditableText.cpp @@ -9,7 +9,7 @@ #include "Accessible-inl.h" #include "HyperTextAccessible-inl.h" #include "nsMai.h" - +#include "ProxyAccessible.h" #include "nsString.h" #include "mozilla/Likely.h" @@ -20,15 +20,18 @@ static void setTextContentsCB(AtkEditableText *aText, const gchar *aString) { AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); - if (!accWrap) - return; + if (accWrap) { + HyperTextAccessible* text = accWrap->AsHyperText(); + if (!text || !text->IsTextRole()) { + return; + } - HyperTextAccessible* text = accWrap->AsHyperText(); - if (!text || !text->IsTextRole()) - return; - - NS_ConvertUTF8toUTF16 strContent(aString); - text->ReplaceText(strContent); + NS_ConvertUTF8toUTF16 strContent(aString); + text->ReplaceText(strContent); + } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) { + NS_ConvertUTF8toUTF16 strContent(aString); + proxy->ReplaceText(strContent); + } } static void @@ -36,71 +39,82 @@ insertTextCB(AtkEditableText *aText, const gchar *aString, gint aLength, gint *aPosition) { AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); - if (!accWrap) - return; + if (accWrap) { + HyperTextAccessible* text = accWrap->AsHyperText(); + if (!text || !text->IsTextRole()) { + return; + } - HyperTextAccessible* text = accWrap->AsHyperText(); - if (!text || !text->IsTextRole()) - return; - - NS_ConvertUTF8toUTF16 strContent(aString, aLength); - text->InsertText(strContent, *aPosition); + NS_ConvertUTF8toUTF16 strContent(aString); + text->InsertText(strContent, *aPosition); + } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) { + NS_ConvertUTF8toUTF16 strContent(aString); + proxy->InsertText(strContent, *aPosition); + } } static void copyTextCB(AtkEditableText *aText, gint aStartPos, gint aEndPos) { AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); - if (!accWrap) - return; + if (accWrap) { + HyperTextAccessible* text = accWrap->AsHyperText(); + if (!text || !text->IsTextRole()) { + return; + } - HyperTextAccessible* text = accWrap->AsHyperText(); - if (!text || !text->IsTextRole()) - return; - - text->CopyText(aStartPos, aEndPos); + text->CopyText(aStartPos, aEndPos); + } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) { + proxy->CopyText(aStartPos, aEndPos); + } } static void cutTextCB(AtkEditableText *aText, gint aStartPos, gint aEndPos) { AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); - if (!accWrap) - return; + if (accWrap) { + HyperTextAccessible* text = accWrap->AsHyperText(); + if (!text || !text->IsTextRole()) { + return; + } - HyperTextAccessible* text = accWrap->AsHyperText(); - if (!text || !text->IsTextRole()) - return; - - text->CutText(aStartPos, aEndPos); + text->CutText(aStartPos, aEndPos); + } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) { + proxy->CutText(aStartPos, aEndPos); + } } static void deleteTextCB(AtkEditableText *aText, gint aStartPos, gint aEndPos) { AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); - if (!accWrap) - return; + if (accWrap) { + HyperTextAccessible* text = accWrap->AsHyperText(); + if (!text || !text->IsTextRole()) { + return; + } - HyperTextAccessible* text = accWrap->AsHyperText(); - if (!text || !text->IsTextRole()) - return; - - text->DeleteText(aStartPos, aEndPos); + text->DeleteText(aStartPos, aEndPos); + } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) { + proxy->DeleteText(aStartPos, aEndPos); + } } static void pasteTextCB(AtkEditableText *aText, gint aPosition) { AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); - if (!accWrap) - return; + if (accWrap) { + HyperTextAccessible* text = accWrap->AsHyperText(); + if (!text || !text->IsTextRole()) { + return; + } - HyperTextAccessible* text = accWrap->AsHyperText(); - if (!text || !text->IsTextRole()) - return; - - text->PasteText(aPosition); + text->PasteText(aPosition); + } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) { + proxy->PasteText(aPosition); + } } } diff --git a/accessible/atk/nsMaiInterfaceText.cpp b/accessible/atk/nsMaiInterfaceText.cpp index b22ecdfd46..27c8590acd 100644 --- a/accessible/atk/nsMaiInterfaceText.cpp +++ b/accessible/atk/nsMaiInterfaceText.cpp @@ -5,7 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "InterfaceInitFuncs.h" - +#include "mozilla/a11y/PDocAccessible.h" #include "Accessible-inl.h" #include "HyperTextAccessible-inl.h" #include "nsMai.h" @@ -22,6 +22,65 @@ using namespace mozilla::a11y; static const char* sAtkTextAttrNames[ATK_TEXT_ATTR_LAST_DEFINED]; +void +ConvertTextAttributeToAtkAttribute(const nsACString& aName, + const nsAString& aValue, + AtkAttributeSet** aAttributeSet) +{ + // Handle attributes where atk has its own name. + const char* atkName = nullptr; + nsAutoString atkValue; + if (aName.EqualsLiteral("color")) { + // The format of the atk attribute is r,g,b and the gecko one is + // rgb(r,g,b). + atkValue = Substring(aValue, 5, aValue.Length() - 1); + atkName = sAtkTextAttrNames[ATK_TEXT_ATTR_FG_COLOR]; + } else if (aName.EqualsLiteral("background-color")) { + // The format of the atk attribute is r,g,b and the gecko one is + // rgb(r,g,b). + atkValue = Substring(aValue, 5, aValue.Length() - 1); + atkName = sAtkTextAttrNames[ATK_TEXT_ATTR_BG_COLOR]; + } else if (aName.EqualsLiteral("font-family")) { + atkValue = aValue; + atkName = sAtkTextAttrNames[ATK_TEXT_ATTR_FAMILY_NAME]; + } else if (aName.EqualsLiteral("font-size")) { + // ATK wants the number of pixels without px at the end. + atkValue = StringHead(aValue, aValue.Length() - 2); + atkName = sAtkTextAttrNames[ATK_TEXT_ATTR_SIZE]; + } else if (aName.EqualsLiteral("font-weight")) { + atkValue = aValue; + atkName = sAtkTextAttrNames[ATK_TEXT_ATTR_WEIGHT]; + } else if (aName.EqualsLiteral("invalid")) { + atkValue = aValue; + atkName = sAtkTextAttrNames[ATK_TEXT_ATTR_INVALID]; + } + + if (atkName) { + AtkAttribute* objAttr = + static_cast(g_malloc(sizeof(AtkAttribute))); + objAttr->name = g_strdup(atkName); + objAttr->value = g_strdup(NS_ConvertUTF16toUTF8(atkValue).get()); + *aAttributeSet = g_slist_prepend(*aAttributeSet, objAttr); + } +} + +static AtkAttributeSet* +ConvertToAtkTextAttributeSet(nsTArray& aAttributes) +{ + AtkAttributeSet* objAttributeSet = nullptr; + for (size_t i = 0; i < aAttributes.Length(); ++i) { + AtkAttribute* objAttr = (AtkAttribute *)g_malloc(sizeof(AtkAttribute)); + objAttr->name = g_strdup(aAttributes[i].Name().get()); + objAttr->value = + g_strdup(NS_ConvertUTF16toUTF8(aAttributes[i].Value()).get()); + objAttributeSet = g_slist_prepend(objAttributeSet, objAttr); + ConvertTextAttributeToAtkAttribute(aAttributes[i].Name(), + aAttributes[i].Value(), + &objAttributeSet); + } + return objAttributeSet; +} + static AtkAttributeSet* ConvertToAtkTextAttributeSet(nsIPersistentProperties* aAttributes) { @@ -55,40 +114,7 @@ ConvertToAtkTextAttributeSet(nsIPersistentProperties* aAttributes) objAttr->value = g_strdup(NS_ConvertUTF16toUTF8(value).get()); objAttributeSet = g_slist_prepend(objAttributeSet, objAttr); - // Handle attributes where atk has its own name. - const char* atkName = nullptr; - nsAutoString atkValue; - if (name.EqualsLiteral("color")) { - // The format of the atk attribute is r,g,b and the goanna one is - // rgb(r,g,b). - atkValue = Substring(value, 5, value.Length() - 1); - atkName = sAtkTextAttrNames[ATK_TEXT_ATTR_FG_COLOR]; - } else if (name.EqualsLiteral("background-color")) { - // The format of the atk attribute is r,g,b and the goanna one is - // rgb(r,g,b). - atkValue = Substring(value, 5, value.Length() - 1); - atkName = sAtkTextAttrNames[ATK_TEXT_ATTR_BG_COLOR]; - } else if (name.EqualsLiteral("font-family")) { - atkValue = value; - atkName = sAtkTextAttrNames[ATK_TEXT_ATTR_FAMILY_NAME]; - } else if (name.EqualsLiteral("font-size")) { - // ATK wants the number of pixels without px at the end. - atkValue = StringHead(value, value.Length() - 2); - atkName = sAtkTextAttrNames[ATK_TEXT_ATTR_SIZE]; - } else if (name.EqualsLiteral("font-weight")) { - atkValue = value; - atkName = sAtkTextAttrNames[ATK_TEXT_ATTR_WEIGHT]; - } else if (name.EqualsLiteral("invalid")) { - atkValue = value; - atkName = sAtkTextAttrNames[ATK_TEXT_ATTR_INVALID]; - } - - if (atkName) { - objAttr = static_cast(g_malloc(sizeof(AtkAttribute))); - objAttr->name = g_strdup(atkName); - objAttr->value = g_strdup(NS_ConvertUTF16toUTF8(atkValue).get()); - objAttributeSet = g_slist_prepend(objAttributeSet, objAttr); - } + ConvertTextAttributeToAtkAttribute(name, value, &objAttributeSet); } // libatk-adaptor will free it @@ -240,38 +266,58 @@ getRunAttributesCB(AtkText *aText, gint aOffset, { *aStartOffset = -1; *aEndOffset = -1; + int32_t startOffset = 0, endOffset = 0; AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); - if (!accWrap) + if (accWrap) { + HyperTextAccessible* text = accWrap->AsHyperText(); + if (!text || !text->IsTextRole()) { + return nullptr; + } + + nsCOMPtr attributes = + text->TextAttributes(false, aOffset, &startOffset, &endOffset); + + *aStartOffset = startOffset; + *aEndOffset = endOffset; + + return ConvertToAtkTextAttributeSet(attributes); + } + + ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText)); + if (!proxy) { return nullptr; + } - HyperTextAccessible* text = accWrap->AsHyperText(); - if (!text || !text->IsTextRole()) - return nullptr; - - int32_t startOffset = 0, endOffset = 0; - nsCOMPtr attributes = - text->TextAttributes(false, aOffset, &startOffset, &endOffset); - + nsAutoTArray attrs; + proxy->TextAttributes(false, aOffset, &attrs, &startOffset, &endOffset); *aStartOffset = startOffset; *aEndOffset = endOffset; - - return ConvertToAtkTextAttributeSet(attributes); + return ConvertToAtkTextAttributeSet(attrs); } static AtkAttributeSet* getDefaultAttributesCB(AtkText *aText) { AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); - if (!accWrap) - return nullptr; + if (accWrap) { + HyperTextAccessible* text = accWrap->AsHyperText(); + if (!text || !text->IsTextRole()) { + return nullptr; + } - HyperTextAccessible* text = accWrap->AsHyperText(); - if (!text || !text->IsTextRole()) - return nullptr; + nsCOMPtr attributes = text->DefaultTextAttributes(); + return ConvertToAtkTextAttributeSet(attributes); + } - nsCOMPtr attributes = text->DefaultTextAttributes(); - return ConvertToAtkTextAttributeSet(attributes); + ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText)); + if (!proxy) { + return nullptr; + } + + nsAutoTArray attrs; + proxy->DefaultTextAttributes(&attrs); + return ConvertToAtkTextAttributeSet(attrs); } static void @@ -280,21 +326,32 @@ getCharacterExtentsCB(AtkText *aText, gint aOffset, gint *aWidth, gint *aHeight, AtkCoordType aCoords) { + if(!aX || !aY || !aWidth || !aHeight) { + return; + } + + nsIntRect rect; + uint32_t geckoCoordType; + if (aCoords == ATK_XY_SCREEN) { + goannaCoordType = nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE; + } else { + giabbaCoordType = nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE; + } + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); - if(!accWrap || !aX || !aY || !aWidth || !aHeight) + if (accWrap) { + HyperTextAccessible* text = accWrap->AsHyperText(); + if (!text || !text->IsTextRole()) { + return; + } + + rect = text->CharBounds(aOffset, goannaCoordType); + } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) { + rect = proxy->CharBounds(aOffset, goannaCoordType); + } else { return; + } - HyperTextAccessible* text = accWrap->AsHyperText(); - if (!text || !text->IsTextRole()) - return; - - uint32_t goannaCoordType; - if (aCoords == ATK_XY_SCREEN) - goannaCoordType = nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE; - else - goannaCoordType = nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE; - - nsIntRect rect = text->CharBounds(aOffset, goannaCoordType); *aX = rect.x; *aY = rect.y; *aWidth = rect.width; @@ -305,21 +362,32 @@ static void getRangeExtentsCB(AtkText *aText, gint aStartOffset, gint aEndOffset, AtkCoordType aCoords, AtkTextRectangle *aRect) { + if (!aRect) { + return; + } + + nsIntRect rect; + uint32_t goannaCoordType; + if (aCoords == ATK_XY_SCREEN) { + goannaCoordType = nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE; + } else { + goannaCoordType = nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE; + } + AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); - if(!accWrap || !aRect) + if(accWrap) { + HyperTextAccessible* text = accWrap->AsHyperText(); + if (!text || !text->IsTextRole()) { + return; + } + + rect = text->TextBounds(aStartOffset, aEndOffset, geckoCoordType); + } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) { + rect = proxy->TextBounds(aStartOffset, aEndOffset, geckoCoordType); + } else { return; + } - HyperTextAccessible* text = accWrap->AsHyperText(); - if (!text || !text->IsTextRole()) - return; - - uint32_t goannaCoordType; - if (aCoords == ATK_XY_SCREEN) - goannaCoordType = nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE; - else - goannaCoordType = nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE; - - nsIntRect rect = text->TextBounds(aStartOffset, aEndOffset, goannaCoordType); aRect->x = rect.x; aRect->y = rect.y; aRect->width = rect.width; @@ -349,18 +417,28 @@ getOffsetAtPointCB(AtkText *aText, AtkCoordType aCoords) { AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); - if (!accWrap) - return -1; + if (accWrap) { + HyperTextAccessible* text = accWrap->AsHyperText(); + if (!text || !text->IsTextRole()) { + return -1; + } - HyperTextAccessible* text = accWrap->AsHyperText(); - if (!text || !text->IsTextRole()) - return -1; + return static_cast( + text->OffsetAtPoint(aX, aY, + (aCoords == ATK_XY_SCREEN ? + nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE : + nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE))); + } - return static_cast( - text->OffsetAtPoint(aX, aY, - (aCoords == ATK_XY_SCREEN ? - nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE : - nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE))); + if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) { + return static_cast( + proxy->OffsetAtPoint(aX, aY, + (aCoords == ATK_XY_SCREEN ? + nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE : + nsIAccessibleCoordinateType::COORDTYPE_WINDOW_RELATIVE))); + } + + return -1; } static gint @@ -388,20 +466,28 @@ getTextSelectionCB(AtkText *aText, gint aSelectionNum, gint *aStartOffset, gint *aEndOffset) { AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); - if (!accWrap) - return nullptr; - - HyperTextAccessible* text = accWrap->AsHyperText(); - if (!text || !text->IsTextRole()) - return nullptr; - int32_t startOffset = 0, endOffset = 0; - text->SelectionBoundsAt(aSelectionNum, &startOffset, &endOffset); + if (accWrap) { + HyperTextAccessible* text = accWrap->AsHyperText(); + if (!text || !text->IsTextRole()) { + return nullptr; + } + text->SelectionBoundsAt(aSelectionNum, &startOffset, &endOffset); *aStartOffset = startOffset; *aEndOffset = endOffset; return getTextCB(aText, *aStartOffset, *aEndOffset); + } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) { + nsString data; + proxy->SelectionBoundsAt(aSelectionNum, data, &startOffset, &endOffset); + *aStartOffset = startOffset; + *aEndOffset = endOffset; + + NS_ConvertUTF16toUTF8 dataAsUTF8(data); + return (dataAsUTF8.get()) ? g_strdup(dataAsUTF8.get()) : nullptr; + } + return nullptr; } // set methods @@ -411,14 +497,18 @@ addTextSelectionCB(AtkText *aText, gint aEndOffset) { AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); - if (!accWrap) - return FALSE; + if (accWrap) { + HyperTextAccessible* text = accWrap->AsHyperText(); + if (!text || !text->IsTextRole()) { + return FALSE; + } - HyperTextAccessible* text = accWrap->AsHyperText(); - if (!text || !text->IsTextRole()) - return FALSE; + return text->AddToSelection(aStartOffset, aEndOffset); + } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) { + return proxy->AddToSelection(aStartOffset, aEndOffset); + } - return text->AddToSelection(aStartOffset, aEndOffset); + return FALSE; } static gboolean @@ -426,14 +516,18 @@ removeTextSelectionCB(AtkText *aText, gint aSelectionNum) { AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); - if (!accWrap) - return FALSE; + if (accWrap) { + HyperTextAccessible* text = accWrap->AsHyperText(); + if (!text || !text->IsTextRole()) { + return FALSE; + } - HyperTextAccessible* text = accWrap->AsHyperText(); - if (!text || !text->IsTextRole()) - return FALSE; + return text->RemoveFromSelection(aSelectionNum); + } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) { + return proxy->RemoveFromSelection(aSelectionNum); + } - return text->RemoveFromSelection(aSelectionNum); + return FALSE; } static gboolean @@ -441,14 +535,18 @@ setTextSelectionCB(AtkText *aText, gint aSelectionNum, gint aStartOffset, gint aEndOffset) { AccessibleWrap* accWrap = GetAccessibleWrap(ATK_OBJECT(aText)); - if (!accWrap) - return FALSE; + if (accWrap) { + HyperTextAccessible* text = accWrap->AsHyperText(); + if (!text || !text->IsTextRole()) { + return FALSE; + } - HyperTextAccessible* text = accWrap->AsHyperText(); - if (!text || !text->IsTextRole()) - return FALSE; + return text->SetSelectionBoundsAt(aSelectionNum, aStartOffset, aEndOffset); + } else if (ProxyAccessible* proxy = GetProxy(ATK_OBJECT(aText))) { + return proxy->SetSelectionBoundsAt(aSelectionNum, aStartOffset, aEndOffset); + } - return text->SetSelectionBoundsAt(aSelectionNum, aStartOffset, aEndOffset); + return FALSE; } static gboolean diff --git a/accessible/ipc/DocAccessibleChild.cpp b/accessible/ipc/DocAccessibleChild.cpp index 5a28648a84..f15d142e55 100644 --- a/accessible/ipc/DocAccessibleChild.cpp +++ b/accessible/ipc/DocAccessibleChild.cpp @@ -127,11 +127,18 @@ DocAccessibleChild::RecvAttributes(const uint64_t& aID, nsTArray* aAt return true; nsCOMPtr props = acc->Attributes(); - if (!props) - return true; + return PersistentPropertiesToArray(props, aAttributes); +} +bool +DocAccessibleChild::PersistentPropertiesToArray(nsIPersistentProperties* aProps, + nsTArray* aAttributes) +{ + if (!aProps) { + return true; + } nsCOMPtr propEnum; - nsresult rv = props->Enumerate(getter_AddRefs(propEnum)); + nsresult rv = aProps->Enumerate(getter_AddRefs(propEnum)); NS_ENSURE_SUCCESS(rv, false); bool hasMore; @@ -292,5 +299,257 @@ DocAccessibleChild::RecvGetTextBeforeOffset(const uint64_t& aID, return true; } +bool +DocAccessibleChild::RecvTextAttributes(const uint64_t& aID, + const bool& aIncludeDefAttrs, + const int32_t& aOffset, + nsTArray* aAttributes, + int32_t* aStartOffset, + int32_t* aEndOffset) +{ + HyperTextAccessible* acc = IdToHyperTextAccessible(aID); + if (!acc || !acc->IsTextRole()) { + return true; + } + + nsCOMPtr props = + acc->TextAttributes(aIncludeDefAttrs, aOffset, aStartOffset, aEndOffset); + return PersistentPropertiesToArray(props, aAttributes); +} + +bool +DocAccessibleChild::RecvDefaultTextAttributes(const uint64_t& aID, + nsTArray *aAttributes) +{ + HyperTextAccessible* acc = IdToHyperTextAccessible(aID); + if (!acc || !acc->IsTextRole()) { + return true; + } + + nsCOMPtr props = acc->DefaultTextAttributes(); + return PersistentPropertiesToArray(props, aAttributes); +} + +bool +DocAccessibleChild::RecvTextBounds(const uint64_t& aID, + const int32_t& aStartOffset, + const int32_t& aEndOffset, + const uint32_t& aCoordType, + nsIntRect* aRetVal) +{ + HyperTextAccessible* acc = IdToHyperTextAccessible(aID); + if (acc && acc->IsTextRole()) { + *aRetVal = acc->TextBounds(aStartOffset, aEndOffset, aCoordType); + } + + return true; +} + +bool +DocAccessibleChild::RecvCharBounds(const uint64_t& aID, + const int32_t& aOffset, + const uint32_t& aCoordType, + nsIntRect* aRetVal) +{ + HyperTextAccessible* acc = IdToHyperTextAccessible(aID); + if (acc && acc->IsTextRole()) { + *aRetVal = acc->CharBounds(aOffset, aCoordType); + } + + return true; +} + +bool +DocAccessibleChild::RecvOffsetAtPoint(const uint64_t& aID, + const int32_t& aX, + const int32_t& aY, + const uint32_t& aCoordType, + int32_t* aRetVal) +{ + *aRetVal = -1; + HyperTextAccessible* acc = IdToHyperTextAccessible(aID); + if (acc && acc->IsTextRole()) { + *aRetVal = acc->OffsetAtPoint(aX, aY, aCoordType); + } + return true; +} + +bool +DocAccessibleChild::RecvSelectionBoundsAt(const uint64_t& aID, + const int32_t& aSelectionNum, + bool* aSucceeded, + nsString* aData, + int32_t* aStartOffset, + int32_t* aEndOffset) +{ + *aSucceeded = false; + *aStartOffset = 0; + *aEndOffset = 0; + HyperTextAccessible* acc = IdToHyperTextAccessible(aID); + if (acc && acc->IsTextRole()) { + *aSucceeded = + acc->SelectionBoundsAt(aSelectionNum, aStartOffset, aEndOffset); + if (*aSucceeded) { + acc->TextSubstring(*aStartOffset, *aEndOffset, *aData); + } + } + + return true; +} + +bool +DocAccessibleChild::RecvSetSelectionBoundsAt(const uint64_t& aID, + const int32_t& aSelectionNum, + const int32_t& aStartOffset, + const int32_t& aEndOffset, + bool* aSucceeded) +{ + *aSucceeded = false; + HyperTextAccessible* acc = IdToHyperTextAccessible(aID); + if (acc && acc->IsTextRole()) { + *aSucceeded = + acc->SetSelectionBoundsAt(aSelectionNum, aStartOffset, aEndOffset); + } + + return true; +} + +bool +DocAccessibleChild::RecvAddToSelection(const uint64_t& aID, + const int32_t& aStartOffset, + const int32_t& aEndOffset, + bool* aSucceeded) +{ + *aSucceeded = false; + HyperTextAccessible* acc = IdToHyperTextAccessible(aID); + if (acc && acc->IsTextRole()) { + *aSucceeded = acc->AddToSelection(aStartOffset, aEndOffset); + } + + return true; +} + +bool +DocAccessibleChild::RecvRemoveFromSelection(const uint64_t& aID, + const int32_t& aSelectionNum, + bool* aSucceeded) +{ + *aSucceeded = false; + HyperTextAccessible* acc = IdToHyperTextAccessible(aID); + if (acc && acc->IsTextRole()) { + *aSucceeded = acc->RemoveFromSelection(aSelectionNum); + } + + return true; +} + +bool +DocAccessibleChild::RecvScrollSubstringTo(const uint64_t& aID, + const int32_t& aStartOffset, + const int32_t& aEndOffset, + const uint32_t& aScrollType) +{ + HyperTextAccessible* acc = IdToHyperTextAccessible(aID); + if (acc) { + acc->ScrollSubstringTo(aStartOffset, aEndOffset, aScrollType); + } + + return true; +} + +bool +DocAccessibleChild::RecvScrollSubstringToPoint(const uint64_t& aID, + const int32_t& aStartOffset, + const int32_t& aEndOffset, + const uint32_t& aCoordinateType, + const int32_t& aX, + const int32_t& aY) +{ + HyperTextAccessible* acc = IdToHyperTextAccessible(aID); + if (acc) { + acc->ScrollSubstringToPoint(aStartOffset, aEndOffset, aCoordinateType, + aX, aY); + } + + return true; +} + + +bool +DocAccessibleChild::RecvReplaceText(const uint64_t& aID, + const nsString& aText) +{ + HyperTextAccessible* acc = IdToHyperTextAccessible(aID); + if (acc && acc->IsTextRole()) { + acc->ReplaceText(aText); + } + + return true; +} + +bool +DocAccessibleChild::RecvInsertText(const uint64_t& aID, + const nsString& aText, + const int32_t& aPosition) +{ + HyperTextAccessible* acc = IdToHyperTextAccessible(aID); + if (acc && acc->IsTextRole()) { + acc->InsertText(aText, aPosition); + } + + return true; +} + +bool +DocAccessibleChild::RecvCopyText(const uint64_t& aID, + const int32_t& aStartPos, + const int32_t& aEndPos) +{ + HyperTextAccessible* acc = IdToHyperTextAccessible(aID); + if (acc && acc->IsTextRole()) { + acc->CopyText(aStartPos, aEndPos); + } + + return true; +} + +bool +DocAccessibleChild::RecvCutText(const uint64_t& aID, + const int32_t& aStartPos, + const int32_t& aEndPos) +{ + HyperTextAccessible* acc = IdToHyperTextAccessible(aID); + if (acc && acc->IsTextRole()) { + acc->CutText(aStartPos, aEndPos); + } + + return true; +} + +bool +DocAccessibleChild::RecvDeleteText(const uint64_t& aID, + const int32_t& aStartPos, + const int32_t& aEndPos) +{ + HyperTextAccessible* acc = IdToHyperTextAccessible(aID); + if (acc && acc->IsTextRole()) { + acc->DeleteText(aStartPos, aEndPos); + } + + return true; +} + +bool +DocAccessibleChild::RecvPasteText(const uint64_t& aID, + const int32_t& aPosition) +{ + HyperTextAccessible* acc = IdToHyperTextAccessible(aID); + if (acc && acc->IsTextRole()) { + acc->PasteText(aPosition); + } + + return true; +} + } } diff --git a/accessible/ipc/DocAccessibleChild.h b/accessible/ipc/DocAccessibleChild.h index 35feb4c573..ac6a0e9705 100644 --- a/accessible/ipc/DocAccessibleChild.h +++ b/accessible/ipc/DocAccessibleChild.h @@ -90,7 +90,95 @@ public: nsString* aText, int32_t* aStartOffset, int32_t* aEndOffset) override; + virtual bool RecvTextAttributes(const uint64_t& aID, + const bool& aIncludeDefAttrs, + const int32_t& aOffset, + nsTArray* aAttributes, + int32_t* aStartOffset, + int32_t* aEndOffset) + override; + + virtual bool RecvDefaultTextAttributes(const uint64_t& aID, + nsTArray* aAttributes) + override; + + virtual bool RecvTextBounds(const uint64_t& aID, + const int32_t& aStartOffset, + const int32_t& aEndOffset, + const uint32_t& aCoordType, + nsIntRect* aRetVal) override; + + virtual bool RecvCharBounds(const uint64_t& aID, + const int32_t& aOffset, + const uint32_t& aCoordType, + nsIntRect* aRetVal) override; + + virtual bool RecvOffsetAtPoint(const uint64_t& aID, + const int32_t& aX, + const int32_t& aY, + const uint32_t& aCoordType, + int32_t* aRetVal) override; + + virtual bool RecvSelectionBoundsAt(const uint64_t& aID, + const int32_t& aSelectionNum, + bool* aSucceeded, + nsString* aData, + int32_t* aStartOffset, + int32_t* aEndOffset) override; + + virtual bool RecvSetSelectionBoundsAt(const uint64_t& aID, + const int32_t& aSelectionNum, + const int32_t& aStartOffset, + const int32_t& aEndOffset, + bool* aSucceeded) override; + + virtual bool RecvAddToSelection(const uint64_t& aID, + const int32_t& aStartOffset, + const int32_t& aEndOffset, + bool* aSucceeded) override; + + virtual bool RecvRemoveFromSelection(const uint64_t& aID, + const int32_t& aSelectionNum, + bool* aSucceeded) override; + + virtual bool RecvScrollSubstringTo(const uint64_t& aID, + const int32_t& aStartOffset, + const int32_t& aEndOffset, + const uint32_t& aScrollType) override; + + virtual bool RecvScrollSubstringToPoint(const uint64_t& aID, + const int32_t& aStartOffset, + const int32_t& aEndOffset, + const uint32_t& aCoordinateType, + const int32_t& aX, + const int32_t& aY) override; + + virtual bool RecvReplaceText(const uint64_t& aID, + const nsString& aText) override; + + virtual bool RecvInsertText(const uint64_t& aID, + const nsString& aText, + const int32_t& aPosition) override; + + virtual bool RecvCopyText(const uint64_t& aID, + const int32_t& aStartPos, + const int32_t& aEndPos) override; + + virtual bool RecvCutText(const uint64_t& aID, + const int32_t& aStartPos, + const int32_t& aEndPos) override; + + virtual bool RecvDeleteText(const uint64_t& aID, + const int32_t& aStartPos, + const int32_t& aEndPos) override; + + virtual bool RecvPasteText(const uint64_t& aID, + const int32_t& aPosition) override; + private: + bool PersistentPropertiesToArray(nsIPersistentProperties* aProps, + nsTArray* aAttributes); + DocAccessible* mDoc; }; diff --git a/accessible/ipc/PDocAccessible.ipdl b/accessible/ipc/PDocAccessible.ipdl index 21be62a092..21cc77aaa1 100644 --- a/accessible/ipc/PDocAccessible.ipdl +++ b/accessible/ipc/PDocAccessible.ipdl @@ -6,6 +6,8 @@ include protocol PContent; +using struct nsIntRect from "nsRect.h"; + namespace mozilla { namespace a11y { @@ -73,8 +75,47 @@ child: returns(nsString aText, int32_t aStartOffset, int32_t aEndOffset); prio(high) sync GetTextAtOffset(uint64_t aID, int32_t aOffset, int32_t aBoundaryType) returns(nsString aText, int32_t aStartOffset, int32_t aEndOffset); + prio(high) sync GetTextBeforeOffset(uint64_t aID, int32_t aOffset, int32_t aBoundaryType) returns(nsString aText, int32_t aStartOffset, int32_t aEndOffset); + + prio(high) sync TextAttributes(uint64_t aID, bool aIncludeDefAttrs, int32_t aOffset) + returns(Attribute[] aAttributes, int32_t aStartOffset, int32_t aEndOffset); + prio(high) sync DefaultTextAttributes(uint64_t aID) returns(Attribute[] aAttributes); + + prio(high) sync TextBounds(uint64_t aID, int32_t aStartOffset, int32_t aEndOffset, + uint32_t aCoordType) + returns(nsIntRect aRetVal); + prio(high) sync CharBounds(uint64_t aID, int32_t aOffset, uint32_t aCoordType) + returns(nsIntRect aRetVal); + + prio(high) sync OffsetAtPoint(uint64_t aID, int32_t aX, int32_t aY, uint32_t aCoordType) + returns(int32_t aRetVal); + + prio(high) sync SelectionBoundsAt(uint64_t aID, int32_t aSelectionNum) + returns(bool aSucceeded, nsString aData, int32_t aStartOffset, int32_t aEndOffset); + prio(high) sync SetSelectionBoundsAt(uint64_t aID, int32_t aSelectionNum, + int32_t aStartOffset, int32_t aEndOffset) + returns(bool aSucceeded); + prio(high) sync AddToSelection(uint64_t aID, int32_t aStartOffset, int32_t aEndOffset) + returns(bool aSucceeded); + prio(high) sync RemoveFromSelection(uint64_t aID, int32_t aSelectionNum) + returns(bool aSucceeded); + + ScrollSubstringTo(uint64_t aID, int32_t aStartOffset, int32_t aEndOffset, + uint32_t aScrollType); + ScrollSubstringToPoint(uint64_t aID, + int32_t aStartOffset, + int32_t aEndOffset, + uint32_t aCoordinateType, + int32_t aX, int32_t aY); + + prio(high) sync ReplaceText(uint64_t aID, nsString aText); + prio(high) sync InsertText(uint64_t aID, nsString aText, int32_t aPosition); + prio(high) sync CopyText(uint64_t aID, int32_t aStartPos, int32_t aEndPos); + prio(high) sync CutText(uint64_t aID, int32_t aStartPos, int32_t aEndPos); + prio(high) sync DeleteText(uint64_t aID, int32_t aStartPos, int32_t aEndPos); + prio(high) sync PasteText(uint64_t aID, int32_t aPosition); }; } diff --git a/accessible/ipc/ProxyAccessible.cpp b/accessible/ipc/ProxyAccessible.cpp index 3ef225ff06..e9bf9d9563 100644 --- a/accessible/ipc/ProxyAccessible.cpp +++ b/accessible/ipc/ProxyAccessible.cpp @@ -202,5 +202,142 @@ ProxyAccessible::GetTextBeforeOffset(int32_t aOffset, &aText, aStartOffset, aEndOffset); } +void +ProxyAccessible::TextAttributes(bool aIncludeDefAttrs, + int32_t aOffset, + nsTArray* aAttributes, + int32_t* aStartOffset, + int32_t* aEndOffset) +{ + unused << mDoc->SendTextAttributes(mID, aIncludeDefAttrs, aOffset, + aAttributes, aStartOffset, aEndOffset); +} + +void +ProxyAccessible::DefaultTextAttributes(nsTArray* aAttrs) +{ + unused << mDoc->SendDefaultTextAttributes(mID, aAttrs); +} + +nsIntRect +ProxyAccessible::TextBounds(int32_t aStartOffset, int32_t aEndOffset, + uint32_t aCoordType) +{ + nsIntRect rect; + unused << + mDoc->SendTextBounds(mID, aStartOffset, aEndOffset, aCoordType, &rect); + return rect; +} + +nsIntRect +ProxyAccessible::CharBounds(int32_t aOffset, uint32_t aCoordType) +{ + nsIntRect rect; + unused << + mDoc->SendCharBounds(mID, aOffset, aCoordType, &rect); + return rect; +} + +int32_t +ProxyAccessible::OffsetAtPoint(int32_t aX, int32_t aY, uint32_t aCoordType) +{ + int32_t retVal = -1; + unused << mDoc->SendOffsetAtPoint(mID, aX, aY, aCoordType, &retVal); + return retVal; +} + +bool +ProxyAccessible::SelectionBoundsAt(int32_t aSelectionNum, + nsString& aData, + int32_t* aStartOffset, + int32_t* aEndOffset) +{ + bool retVal = false; + unused << mDoc->SendSelectionBoundsAt(mID, aSelectionNum, &retVal, &aData, + aStartOffset, aEndOffset); + return retVal; +} + +bool +ProxyAccessible::SetSelectionBoundsAt(int32_t aSelectionNum, + int32_t aStartOffset, + int32_t aEndOffset) +{ + bool retVal = false; + unused << mDoc->SendSetSelectionBoundsAt(mID, aSelectionNum, aStartOffset, + aEndOffset, &retVal); + return retVal; +} + +bool +ProxyAccessible::AddToSelection(int32_t aStartOffset, + int32_t aEndOffset) +{ + bool retVal = false; + unused << mDoc->SendAddToSelection(mID, aStartOffset, aEndOffset, &retVal); + return retVal; +} + +bool +ProxyAccessible::RemoveFromSelection(int32_t aSelectionNum) +{ + bool retVal = false; + unused << mDoc->SendRemoveFromSelection(mID, aSelectionNum, &retVal); + return retVal; +} + +void +ProxyAccessible::ScrollSubstringTo(int32_t aStartOffset, int32_t aEndOffset, + uint32_t aScrollType) +{ + unused << mDoc->SendScrollSubstringTo(mID, aStartOffset, aEndOffset, aScrollType); +} + +void +ProxyAccessible::ScrollSubstringToPoint(int32_t aStartOffset, + int32_t aEndOffset, + uint32_t aCoordinateType, + int32_t aX, int32_t aY) +{ + unused << mDoc->SendScrollSubstringToPoint(mID, aStartOffset, aEndOffset, + aCoordinateType, aX, aY); +} + +void +ProxyAccessible::ReplaceText(const nsString& aText) +{ + unused << mDoc->SendReplaceText(mID, aText); +} + +void +ProxyAccessible::InsertText(const nsString& aText, int32_t aPosition) +{ + unused << mDoc->SendInsertText(mID, aText, aPosition); +} + +void +ProxyAccessible::CopyText(int32_t aStartPos, int32_t aEndPos) +{ + unused << mDoc->SendCopyText(mID, aStartPos, aEndPos); +} + +void +ProxyAccessible::CutText(int32_t aStartPos, int32_t aEndPos) +{ + unused << mDoc->SendCutText(mID, aStartPos, aEndPos); +} + +void +ProxyAccessible::DeleteText(int32_t aStartPos, int32_t aEndPos) +{ + unused << mDoc->SendDeleteText(mID, aStartPos, aEndPos); +} + +void +ProxyAccessible::PasteText(int32_t aPosition) +{ + unused << mDoc->SendPasteText(mID, aPosition); +} + } } diff --git a/accessible/ipc/ProxyAccessible.h b/accessible/ipc/ProxyAccessible.h index 7c89f3dd85..acd1a0105f 100644 --- a/accessible/ipc/ProxyAccessible.h +++ b/accessible/ipc/ProxyAccessible.h @@ -11,6 +11,7 @@ #include "nsIAccessibleText.h" #include "nsString.h" #include "nsTArray.h" +#include "nsRect.h" namespace mozilla { namespace a11y { @@ -120,6 +121,54 @@ public: nsString& aText, int32_t* aStartOffset, int32_t* aEndOffset); + void TextAttributes(bool aIncludeDefAttrs, + const int32_t aOffset, + nsTArray* aAttributes, + int32_t* aStartOffset, + int32_t* aEndOffset); + void DefaultTextAttributes(nsTArray* aAttrs); + + nsIntRect TextBounds(int32_t aStartOffset, int32_t aEndOffset, + uint32_t aCoordType); + + nsIntRect CharBounds(int32_t aOffset, uint32_t aCoordType); + + int32_t OffsetAtPoint(int32_t aX, int32_t aY, uint32_t aCoordType); + + bool SelectionBoundsAt(int32_t aSelectionNum, + nsString& aData, + int32_t* aStartOffset, + int32_t* aEndOffset); + + bool SetSelectionBoundsAt(int32_t aSelectionNum, + int32_t aStartOffset, + int32_t aEndOffset); + + bool AddToSelection(int32_t aStartOffset, + int32_t aEndOffset); + + bool RemoveFromSelection(int32_t aSelectionNum); + + void ScrollSubstringTo(int32_t aStartOffset, int32_t aEndOffset, + uint32_t aScrollType); + + void ScrollSubstringToPoint(int32_t aStartOffset, + int32_t aEndOffset, + uint32_t aCoordinateType, + int32_t aX, int32_t aY); + + void ReplaceText(const nsString& aText); + + void InsertText(const nsString& aText, int32_t aPosition); + + void CopyText(int32_t aStartPos, int32_t aEndPos); + + void CutText(int32_t aStartPos, int32_t aEndPos); + + void DeleteText(int32_t aStartPos, int32_t aEndPos); + + void PasteText(int32_t aPosition); + /** * Allow the platform to store a pointers worth of data on us. */ diff --git a/docshell/base/nsDownloadHistory.cpp b/docshell/base/nsDownloadHistory.cpp index eac24d3de5..4600560090 100644 --- a/docshell/base/nsDownloadHistory.cpp +++ b/docshell/base/nsDownloadHistory.cpp @@ -10,6 +10,7 @@ #include "nsIGlobalHistory2.h" #include "nsIObserverService.h" #include "nsIURI.h" +#include "mozilla/Services.h" //////////////////////////////////////////////////////////////////////////////// //// nsDownloadHistory @@ -42,7 +43,7 @@ nsDownloadHistory::AddDownload(nsIURI* aSource, if (!visited) { nsCOMPtr os = - do_GetService("@mozilla.org/observer-service;1"); + mozilla::services::GetObserverService(); if (os) { os->NotifyObservers(aSource, NS_LINK_VISITED_EVENT_TOPIC, nullptr); } diff --git a/dom/base/nsContentSink.cpp b/dom/base/nsContentSink.cpp index 2b8ba8c0b6..700be99cae 100644 --- a/dom/base/nsContentSink.cpp +++ b/dom/base/nsContentSink.cpp @@ -33,6 +33,7 @@ #include "nsIApplicationCacheContainer.h" #include "nsIApplicationCacheChannel.h" #include "nsIScriptSecurityManager.h" +#include "nsISpeculativeConnect.h" #include "nsICookieService.h" #include "nsContentUtils.h" #include "nsNodeInfoManager.h" @@ -691,6 +692,10 @@ nsContentSink::ProcessLink(const nsSubstring& aAnchor, const nsSubstring& aHref, PrefetchDNS(aHref); } + if (!aHref.IsEmpty() && (linkTypes & nsStyleLinkElement::ePRECONNECT)) { + Preconnect(aHref); + } + // is it a stylesheet link? if (!(linkTypes & nsStyleLinkElement::eSTYLESHEET)) { return NS_OK; @@ -868,6 +873,26 @@ nsContentSink::PrefetchDNS(const nsAString &aHref) } } +void +nsContentSink::Preconnect(const nsAString &aHref) +{ + nsCOMPtr + speculator(do_QueryInterface(nsContentUtils::GetIOService())); + if (!speculator) { + return; + } + + // construct URI using document charset + const nsACString& charset = mDocument->GetDocumentCharacterSet(); + nsCOMPtr uri; + NS_NewURI(getter_AddRefs(uri), aHref, + charset.IsEmpty() ? nullptr : PromiseFlatCString(charset).get(), + mDocument->GetDocBaseURI()); + if (uri) { + speculator->SpeculativeConnect(uri, nullptr); + } +} + nsresult nsContentSink::SelectDocAppCache(nsIApplicationCache *aLoadApplicationCache, nsIURI *aManifestURI, diff --git a/dom/base/nsContentSink.h b/dom/base/nsContentSink.h index 097e753f4c..4339b6eeb9 100644 --- a/dom/base/nsContentSink.h +++ b/dom/base/nsContentSink.h @@ -164,9 +164,10 @@ protected: void PrefetchHref(const nsAString &aHref, nsINode *aSource, bool aExplicit); - // aHref can either be the usual URI format or of the form "//www.hostname.com" - // without a scheme. + // For both PrefetchDNS() and Preconnect() aHref can either be the usual + // URI format or of the form "//www.hostname.com" without a scheme. void PrefetchDNS(const nsAString &aHref); + void Preconnect(const nsAString &aHref); // Gets the cache key (used to identify items in a cache) of the channel. nsresult GetChannelCacheKey(nsIChannel* aChannel, nsACString& aCacheKey); diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index be50e51a7a..e956392e5d 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -8995,7 +8995,7 @@ public: NS_IMETHOD Run() { nsCOMPtr observerService = - do_GetService("@mozilla.org/observer-service;1"); + services::GetObserverService(); if (observerService) { nsCOMPtr wrapper = do_CreateInstance(NS_SUPPORTS_PRUINT64_CONTRACTID); diff --git a/dom/base/nsStyleLinkElement.cpp b/dom/base/nsStyleLinkElement.cpp index 105a7b3603..8e81eec07e 100644 --- a/dom/base/nsStyleLinkElement.cpp +++ b/dom/base/nsStyleLinkElement.cpp @@ -150,6 +150,8 @@ static uint32_t ToLinkMask(const nsAString& aLink, nsIPrincipal* aPrincipal) else if (aLink.EqualsLiteral("import") && nsStyleLinkElement::IsImportEnabled()) return nsStyleLinkElement::eHTMLIMPORT; + else if (aLink.EqualsLiteral("preconnect")) + return nsStyleLinkElement::ePRECONNECT; else return 0; } diff --git a/dom/base/nsStyleLinkElement.h b/dom/base/nsStyleLinkElement.h index cfc19d71e4..cfede32f90 100644 --- a/dom/base/nsStyleLinkElement.h +++ b/dom/base/nsStyleLinkElement.h @@ -59,7 +59,8 @@ public: eSTYLESHEET = 0x00000004, eNEXT = 0x00000008, eALTERNATE = 0x00000010, - eHTMLIMPORT = 0x00000020 + eHTMLIMPORT = 0x00000020, + ePRECONNECT = 0x00000040 }; // The return value is a bitwise or of 0 or more RelValues. diff --git a/dom/base/test/chrome/cpows_parent.xul b/dom/base/test/chrome/cpows_parent.xul index 39c0818a33..1e0db8c41f 100644 --- a/dom/base/test/chrome/cpows_parent.xul +++ b/dom/base/test/chrome/cpows_parent.xul @@ -206,9 +206,37 @@ function recvDomTest(message) { savedElement = message.objects.element; + is(savedElement.QueryInterface(Components.interfaces.nsISupports), savedElement, + "QI to nsISupports works"); + is(savedElement.QueryInterface(Components.interfaces.nsIDOMNode), savedElement, + "QI to a random (implemented) interface works"); + + function testNoInterface(savedElement, i) { + try { + savedElement.QueryInterface(i); + ok(false, "should have thrown an exception"); + } catch (e) { + is(e.result, Components.results.NS_ERROR_NO_INTERFACE, "threw the right exception"); + } + } + + testNoInterface(savedElement, Components.interfaces.nsIDOMAttr); + testNoInterface(savedElement, Components.interfaces.nsIClassInfo); + // Test to ensure that we don't pass CPOWs to C++-implemented interfaces. // See bug 1072980. if (test_state == "remote") { + // This doesn't work because we intercept toString and QueryInterface specially + // and don't cache the function pointer. + // See bug 1140636. + todo_is(savedElement.toString, savedElement.toString, "toString identity works"); + todo_is(savedElement.QueryInterface, savedElement.QueryInterface, "toString identity works"); + + // This does work because we create a CPOW for isEqualNode that stays + // alive as long as we have a reference to the first CPOW (so as long + // as it's detectable). + is(savedElement.isEqualNode, savedElement.isEqualNode, "webidl function identity works"); + let walker = Components.classes["@mozilla.org/inspector/deep-tree-walker;1"] .createInstance(Components.interfaces.inIDeepTreeWalker); const SHOW_ELEMENT = Components.interfaces.nsIDOMNodeFilter.SHOW_ELEMENT; diff --git a/dom/fetch/InternalResponse.h b/dom/fetch/InternalResponse.h index c1631bf67c..a00459ddc2 100644 --- a/dom/fetch/InternalResponse.h +++ b/dom/fetch/InternalResponse.h @@ -31,6 +31,9 @@ public: NetworkError() { nsRefPtr response = new InternalResponse(0, EmptyCString()); + ErrorResult result; + response->Headers()->SetGuard(HeadersGuardEnum::Immutable, result); + MOZ_ASSERT(!result.Failed()); response->mType = ResponseType::Error; return response.forget(); } diff --git a/dom/fetch/Response.cpp b/dom/fetch/Response.cpp index ec190f3653..d01ce2312d 100644 --- a/dom/fetch/Response.cpp +++ b/dom/fetch/Response.cpp @@ -112,6 +112,8 @@ Response::Redirect(const GlobalObject& aGlobal, const nsAString& aUrl, if (NS_WARN_IF(aRv.Failed())) { return nullptr; } + r->GetInternalHeaders()->SetGuard(HeadersGuardEnum::Immutable, aRv); + MOZ_ASSERT(!aRv.Failed()); return r.forget(); } diff --git a/dom/html/HTMLLinkElement.cpp b/dom/html/HTMLLinkElement.cpp index 2030b891f1..5e0d2e56c5 100644 --- a/dom/html/HTMLLinkElement.cpp +++ b/dom/html/HTMLLinkElement.cpp @@ -21,6 +21,7 @@ #include "nsIDOMEvent.h" #include "nsIDOMStyleSheet.h" #include "nsINode.h" +#include "nsISpeculativeConnect.h" #include "nsIStyleSheet.h" #include "nsIStyleSheetLinkingElement.h" #include "nsIURL.h" @@ -147,6 +148,10 @@ HTMLLinkElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, aDocument->RegisterPendingLinkUpdate(this); } + if (IsInComposedDoc()) { + UpdatePreconnect(); + } + void (HTMLLinkElement::*update)() = &HTMLLinkElement::UpdateStyleSheetInternal; nsContentUtils::AddScriptRunner(NS_NewRunnableMethod(this, update)); @@ -292,6 +297,30 @@ HTMLLinkElement::UpdateImport() } } +void +HTMLLinkElement::UpdatePreconnect() +{ + // rel type should be preconnect + nsAutoString rel; + if (!GetAttr(kNameSpaceID_None, nsGkAtoms::rel, rel)) { + return; + } + + uint32_t linkTypes = nsStyleLinkElement::ParseLinkTypes(rel, NodePrincipal()); + if (!(linkTypes & ePRECONNECT)) { + return; + } + + nsCOMPtr + speculator(do_QueryInterface(nsContentUtils::GetIOService())); + if (speculator) { + nsCOMPtr uri = GetHrefURI(); + if (uri) { + speculator->SpeculativeConnect(uri, nullptr); + } + } +} + nsresult HTMLLinkElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName, const nsAttrValue* aValue, bool aNotify) @@ -326,11 +355,16 @@ HTMLLinkElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName, dropSheet = !(linkTypes & nsStyleLinkElement::eSTYLESHEET); } else if (linkTypes & eHTMLIMPORT) { UpdateImport(); + } else if ((linkTypes & ePRECONNECT) && IsInComposedDoc()) { + UpdatePreconnect(); } } if (aName == nsGkAtoms::href) { UpdateImport(); + if (IsInComposedDoc()) { + UpdatePreconnect(); + } } UpdateStyleSheetInternal(nullptr, nullptr, diff --git a/dom/html/HTMLLinkElement.h b/dom/html/HTMLLinkElement.h index d19c890494..7ee8fe5185 100644 --- a/dom/html/HTMLLinkElement.h +++ b/dom/html/HTMLLinkElement.h @@ -43,6 +43,7 @@ public: void LinkRemoved(); void UpdateImport(); + void UpdatePreconnect(); // nsIDOMEventTarget virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override; diff --git a/gfx/layers/composite/AsyncCompositionManager.h b/gfx/layers/composite/AsyncCompositionManager.h index 840beddfaa..92a0edb5fe 100644 --- a/gfx/layers/composite/AsyncCompositionManager.h +++ b/gfx/layers/composite/AsyncCompositionManager.h @@ -15,7 +15,7 @@ #include "mozilla/gfx/BasePoint.h" // for BasePoint #include "mozilla/gfx/Matrix.h" // for Matrix4x4 #include "mozilla/layers/LayersMessages.h" // for TargetConfig -#include "nsAutoPtr.h" // for nsRefPtr +#include "mozilla/nsRefPtr.h" // for nsRefPtr #include "nsISupportsImpl.h" // for LayerManager::AddRef, etc namespace mozilla { diff --git a/gfx/layers/composite/CanvasLayerComposite.cpp b/gfx/layers/composite/CanvasLayerComposite.cpp index 447b87854a..05fa72df48 100644 --- a/gfx/layers/composite/CanvasLayerComposite.cpp +++ b/gfx/layers/composite/CanvasLayerComposite.cpp @@ -15,7 +15,7 @@ #include "mozilla/layers/Effects.h" // for EffectChain #include "mozilla/mozalloc.h" // for operator delete #include "nsAString.h" -#include "nsAutoPtr.h" // for nsRefPtr +#include "mozilla/nsRefPtr.h" // for nsRefPtr #include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc #include "nsPoint.h" // for nsIntPoint #include "nsString.h" // for nsAutoCString diff --git a/gfx/layers/composite/CompositableHost.cpp b/gfx/layers/composite/CompositableHost.cpp index 67ca5633d7..b1a218bcc4 100644 --- a/gfx/layers/composite/CompositableHost.cpp +++ b/gfx/layers/composite/CompositableHost.cpp @@ -13,7 +13,7 @@ #include "TiledContentHost.h" // for TiledContentHost #include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor #include "mozilla/layers/TextureHost.h" // for TextureHost, etc -#include "nsAutoPtr.h" // for nsRefPtr +#include "mozilla/nsRefPtr.h" // for nsRefPtr #include "nsDebug.h" // for NS_WARNING #include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc #include "gfxPlatform.h" // for gfxPlatform diff --git a/gfx/layers/composite/ContainerLayerComposite.cpp b/gfx/layers/composite/ContainerLayerComposite.cpp index a75004dc60..58d38d57c2 100755 --- a/gfx/layers/composite/ContainerLayerComposite.cpp +++ b/gfx/layers/composite/ContainerLayerComposite.cpp @@ -25,7 +25,7 @@ #include "mozilla/layers/AsyncCompositionManager.h" // for ViewTransform #include "mozilla/layers/LayerMetricsWrapper.h" // for LayerMetricsWrapper #include "mozilla/mozalloc.h" // for operator delete, etc -#include "nsAutoPtr.h" // for nsRefPtr +#include "mozilla/nsRefPtr.h" // for nsRefPtr #include "nsDebug.h" // for NS_ASSERTION #include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc #include "nsISupportsUtils.h" // for NS_ADDREF, NS_RELEASE diff --git a/gfx/layers/composite/ImageLayerComposite.cpp b/gfx/layers/composite/ImageLayerComposite.cpp index 82c6ade6ba..884a83f2fc 100644 --- a/gfx/layers/composite/ImageLayerComposite.cpp +++ b/gfx/layers/composite/ImageLayerComposite.cpp @@ -18,7 +18,7 @@ #include "mozilla/layers/TextureHost.h" // for TextureHost, etc #include "mozilla/mozalloc.h" // for operator delete #include "nsAString.h" -#include "nsAutoPtr.h" // for nsRefPtr +#include "mozilla/nsRefPtr.h" // for nsRefPtr #include "nsDebug.h" // for NS_ASSERTION #include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc #include "nsPoint.h" // for nsIntPoint diff --git a/gfx/layers/composite/LayerManagerComposite.cpp b/gfx/layers/composite/LayerManagerComposite.cpp index b4893c79bf..9730074b9d 100644 --- a/gfx/layers/composite/LayerManagerComposite.cpp +++ b/gfx/layers/composite/LayerManagerComposite.cpp @@ -44,7 +44,7 @@ #include "ipc/ShadowLayerUtils.h" #include "mozilla/mozalloc.h" // for operator new, etc #include "nsAppRunner.h" -#include "nsAutoPtr.h" // for nsRefPtr +#include "mozilla/nsRefPtr.h" // for nsRefPtr #include "nsCOMPtr.h" // for already_AddRefed #include "nsDebug.h" // for NS_WARNING, NS_RUNTIMEABORT, etc #include "nsISupportsImpl.h" // for Layer::AddRef, etc diff --git a/gfx/layers/composite/LayerManagerComposite.h b/gfx/layers/composite/LayerManagerComposite.h index d3a3f58909..0a4a5c9f8d 100644 --- a/gfx/layers/composite/LayerManagerComposite.h +++ b/gfx/layers/composite/LayerManagerComposite.h @@ -21,7 +21,7 @@ #include "mozilla/RefPtr.h" #include "mozilla/UniquePtr.h" #include "nsAString.h" -#include "nsAutoPtr.h" // for nsRefPtr +#include "mozilla/nsRefPtr.h" // for nsRefPtr #include "nsCOMPtr.h" // for already_AddRefed #include "nsDebug.h" // for NS_ASSERTION #include "nsISupportsImpl.h" // for Layer::AddRef, etc diff --git a/gfx/layers/composite/PaintedLayerComposite.cpp b/gfx/layers/composite/PaintedLayerComposite.cpp index 1adc15c966..16edda58df 100644 --- a/gfx/layers/composite/PaintedLayerComposite.cpp +++ b/gfx/layers/composite/PaintedLayerComposite.cpp @@ -19,7 +19,7 @@ #include "mozilla/layers/Effects.h" // for EffectChain #include "mozilla/mozalloc.h" // for operator delete #include "nsAString.h" -#include "nsAutoPtr.h" // for nsRefPtr +#include "mozilla/nsRefPtr.h" // for nsRefPtr #include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc #include "nsMathUtils.h" // for NS_lround #include "nsPoint.h" // for nsIntPoint diff --git a/gfx/layers/composite/TextureHost.cpp b/gfx/layers/composite/TextureHost.cpp index 2e4938813d..e33d0b3cde 100644 --- a/gfx/layers/composite/TextureHost.cpp +++ b/gfx/layers/composite/TextureHost.cpp @@ -18,7 +18,7 @@ #include "mozilla/layers/TextureHostOGL.h" // for TextureHostOGL #include "mozilla/layers/YCbCrImageDataSerializer.h" #include "nsAString.h" -#include "nsAutoPtr.h" // for nsRefPtr +#include "mozilla/nsRefPtr.h" // for nsRefPtr #include "nsPrintfCString.h" // for nsPrintfCString #include "mozilla/layers/PTextureParent.h" #include "mozilla/unused.h" diff --git a/image/imgLoader.cpp b/image/imgLoader.cpp index 06ce92dfd4..b1bf08226f 100644 --- a/image/imgLoader.cpp +++ b/image/imgLoader.cpp @@ -28,7 +28,6 @@ #include "nsIAsyncVerifyRedirectCallback.h" #include "nsIFileURL.h" #include "nsCRT.h" -#include "nsIDocument.h" #include "nsINetworkPredictor.h" #include "nsIApplicationCache.h" @@ -403,7 +402,7 @@ private: nsTArray* aArray, bool aIsUsed) { - nsRefPtr image = aRequest->GetImage(); + auto image = static_cast(aRequest->mImage.get()); if (!image) { return; } @@ -433,7 +432,7 @@ private: } nsRefPtr req = aEntry->GetRequest(); - nsRefPtr image = req->GetImage(); + auto image = static_cast(req->mImage.get()); if (!image) { return PL_DHASH_NEXT; } @@ -2141,12 +2140,6 @@ nsresult imgLoader::LoadImage(nsIURI *aURI, timedChannel->SetInitiatorType(initiatorType); } - // Pass the inner window ID of the loading document, if possible. - nsCOMPtr doc = do_QueryInterface(aCX); - if (doc) { - request->SetInnerWindowID(doc->InnerWindowID()); - } - // create the proxy listener nsCOMPtr pl = new ProxyListener(request.get()); @@ -2791,7 +2784,8 @@ NS_IMPL_ISUPPORTS(imgCacheValidator, nsIStreamListener, nsIRequestObserver, imgCacheValidator::imgCacheValidator(nsProgressNotificationProxy* progress, imgLoader* loader, imgRequest *request, - void *aContext, bool forcePrincipalCheckForCacheEntry) + nsISupports* aContext, + bool forcePrincipalCheckForCacheEntry) : mProgressProxy(progress), mRequest(request), mContext(aContext), diff --git a/image/imgLoader.h b/image/imgLoader.h index ce28217b43..e54d70da42 100644 --- a/image/imgLoader.h +++ b/image/imgLoader.h @@ -517,7 +517,8 @@ class imgCacheValidator : public nsIStreamListener, { public: imgCacheValidator(nsProgressNotificationProxy* progress, imgLoader* loader, - imgRequest *request, void *aContext, bool forcePrincipalCheckForCacheEntry); + imgRequest* aRequest, nsISupports* aContext, + bool forcePrincipalCheckForCacheEntry); void AddProxy(imgRequestProxy *aProxy); void RemoveProxy(imgRequestProxy* aProxy); @@ -544,7 +545,7 @@ private: nsRefPtr mNewRequest; nsRefPtr mNewEntry; - void *mContext; + nsCOMPtr mContext; imgLoader* mImgLoader; }; diff --git a/image/imgRequest.cpp b/image/imgRequest.cpp index a38bc30f80..e1cef16edd 100644 --- a/image/imgRequest.cpp +++ b/image/imgRequest.cpp @@ -18,6 +18,7 @@ #include "nsIChannel.h" #include "nsICachingChannel.h" +#include "nsIDocument.h" #include "nsIThreadRetargetableRequest.h" #include "nsIInputStream.h" #include "nsIMultiPartChannel.h" @@ -66,7 +67,6 @@ imgRequest::imgRequest(imgLoader* aLoader) : mLoader(aLoader) , mProgressTracker(new ProgressTracker()) , mValidator(nullptr) - , mMutex("imgRequest") , mInnerWindowId(0) , mCORSMode(imgIRequest::CORS_NONE) , mReferrerPolicy(mozilla::net::RP_Default) @@ -96,7 +96,7 @@ nsresult imgRequest::Init(nsIURI *aURI, nsIRequest *aRequest, nsIChannel *aChannel, imgCacheEntry *aCacheEntry, - void *aLoadId, + nsISupports* aCX, nsIPrincipal* aLoadingPrincipal, int32_t aCORSMode, ReferrerPolicy aReferrerPolicy) @@ -133,7 +133,13 @@ nsresult imgRequest::Init(nsIURI *aURI, mCacheEntry = aCacheEntry; - SetLoadId(aLoadId); + SetLoadId(aCX); + + // Grab the inner window ID of the loading document, if possible. + nsCOMPtr doc = do_QueryInterface(aCX); + if (doc) { + mInnerWindowId = doc->InnerWindowID(); + } return NS_OK; } @@ -142,20 +148,9 @@ void imgRequest::ClearLoader() { mLoader = nullptr; } -already_AddRefed -imgRequest::GetImage() -{ - MutexAutoLock lock(mMutex); - - nsRefPtr image = mImage; - return image.forget(); -} - already_AddRefed imgRequest::GetProgressTracker() { - MutexAutoLock lock(mMutex); - if (mImage) { MOZ_ASSERT(!mProgressTracker, "Should have given mProgressTracker to mImage"); @@ -169,20 +164,6 @@ imgRequest::GetProgressTracker() } } -void -imgRequest::SetImage(Image* aImage) -{ - MutexAutoLock lock(mMutex); - mImage = aImage; -} - -void -imgRequest::SetProgressTracker(ProgressTracker* aProgressTracker) -{ - MutexAutoLock lock(mMutex); - mProgressTracker = aProgressTracker; -} - void imgRequest::SetCacheEntry(imgCacheEntry *entry) { mCacheEntry = entry; @@ -485,8 +466,7 @@ void imgRequest::SetIsInCache(bool incache) void imgRequest::UpdateCacheEntrySize() { if (mCacheEntry) { - nsRefPtr image = GetImage(); - size_t size = image->SizeOfSourceWithComputedFallback(moz_malloc_size_of); + size_t size = mImage->SizeOfSourceWithComputedFallback(moz_malloc_size_of); mCacheEntry->SetDataSize(size); } } @@ -616,50 +596,6 @@ imgRequest::CacheChanged(nsIRequest* aNewRequest) return true; } -nsresult -imgRequest::LockImage() -{ - nsRefPtr image = GetImage(); - return image->LockImage(); -} - -nsresult -imgRequest::UnlockImage() -{ - nsRefPtr image = GetImage(); - return image->UnlockImage(); -} - -nsresult -imgRequest::RequestDecode() -{ - // If we've initialized our image, we can request a decode. - nsRefPtr image = GetImage(); - if (image) { - return image->RequestDecode(); - } - - // Otherwise, flag to do it when we get the image - mDecodeRequested = true; - - return NS_OK; -} - -nsresult -imgRequest::StartDecoding() -{ - // If we've initialized our image, we can request a decode. - nsRefPtr image = GetImage(); - if (image) { - return image->StartDecoding(); - } - - // Otherwise, flag to do it when we get the image - mDecodeRequested = true; - - return NS_OK; -} - /** nsIRequestObserver methods **/ /* void onStartRequest (in nsIRequest request, in nsISupports ctxt); */ @@ -679,8 +615,7 @@ NS_IMETHODIMP imgRequest::OnStartRequest(nsIRequest *aRequest, nsISupports *ctxt } // If we're not multipart, we shouldn't have an image yet - nsRefPtr image = GetImage(); - if (image && !mIsMultiPartChannel) { + if (mImage && !mIsMultiPartChannel) { MOZ_ASSERT_UNREACHABLE("Already have an image for a non-multipart request"); Cancel(NS_IMAGELIB_ERROR_FAILURE); return NS_ERROR_FAILURE; @@ -776,8 +711,7 @@ NS_IMETHODIMP imgRequest::OnStopRequest(nsIRequest *aRequest, nsISupports *ctxt, mpchan->GetIsLastPart(&lastPart); bool isPartial = false; - nsRefPtr image = GetImage(); - if (image && (status == NS_ERROR_NET_PARTIAL_TRANSFER)) { + if (mImage && (status == NS_ERROR_NET_PARTIAL_TRANSFER)) { isPartial = true; status = NS_OK; // fake happy face } @@ -785,8 +719,8 @@ NS_IMETHODIMP imgRequest::OnStopRequest(nsIRequest *aRequest, nsISupports *ctxt, // Tell the image that it has all of the source data. Note that this can // trigger a failure, since the image might be waiting for more non-optional // data and this is the point where we break the news that it's not coming. - if (image) { - nsresult rv = image->OnImageDataComplete(aRequest, ctxt, status, lastPart); + if (mImage) { + nsresult rv = mImage->OnImageDataComplete(aRequest, ctxt, status, lastPart); // If we got an error in the OnImageDataComplete() call, we don't want to // proceed as if nothing bad happened. However, we also want to give @@ -798,7 +732,7 @@ NS_IMETHODIMP imgRequest::OnStopRequest(nsIRequest *aRequest, nsISupports *ctxt, // If the request went through, update the cache entry size. Otherwise, // cancel the request, which removes us from the cache. - if (image && NS_SUCCEEDED(status) && !isPartial) { + if (mImage && NS_SUCCEEDED(status) && !isPartial) { // We update the cache entry size here because this is where we finish // loading compressed source data, which is part of our size calculus. UpdateCacheEntrySize(); @@ -815,7 +749,7 @@ NS_IMETHODIMP imgRequest::OnStopRequest(nsIRequest *aRequest, nsISupports *ctxt, this->Cancel(status); } - if (!image) { + if (!mImage) { // We have to fire the OnStopRequest notifications ourselves because there's // no image capable of doing so. Progress progress = @@ -861,7 +795,6 @@ imgRequest::OnDataAvailable(nsIRequest *aRequest, nsISupports *ctxt, nsresult rv; mGotData = true; - nsRefPtr image = GetImage(); if (mNewPartPending) { LOG_SCOPE(GetImgLog(), "imgRequest::OnDataAvailable |New part; finding MIME type|"); @@ -902,7 +835,7 @@ imgRequest::OnDataAvailable(nsIRequest *aRequest, nsISupports *ctxt, mContentType = newType; SetProperties(chan); - bool firstPart = !image; + bool firstPart = !mImage; LOG_MSG_WITH_PARAM(GetImgLog(), "imgRequest::OnDataAvailable", "content type", mContentType.get()); @@ -910,44 +843,34 @@ imgRequest::OnDataAvailable(nsIRequest *aRequest, nsISupports *ctxt, // the data and dispatch back to the main thread, AND tell the channel to // dispatch there in the future. - nsRefPtr progressTracker; - { - MutexAutoLock lock(mMutex); - progressTracker = mProgressTracker; - } - // Create the new image and give it ownership of our ProgressTracker. if (mIsMultiPartChannel) { // Create the ProgressTracker and image for this part. - nsRefPtr partProgressTracker = new ProgressTracker(); - nsRefPtr partImage = - ImageFactory::CreateImage(aRequest, partProgressTracker, mContentType, + nsRefPtr progressTracker = new ProgressTracker(); + nsRefPtr image = + ImageFactory::CreateImage(aRequest, progressTracker, mContentType, mURI, /* aIsMultipart = */ true, static_cast(mInnerWindowId)); - if (!image) { + if (!mImage) { // First part for a multipart channel. Create the MultipartImage wrapper. - MOZ_ASSERT(progressTracker, "Shouldn't have given away tracker yet"); - image = new MultipartImage(partImage, progressTracker); - SetImage(image); - progressTracker = nullptr; - SetProgressTracker(nullptr); + MOZ_ASSERT(mProgressTracker, "Shouldn't have given away tracker yet"); + mImage = new MultipartImage(image, mProgressTracker); + mProgressTracker = nullptr; } else { // Transition to the new part. - static_cast(image.get())->BeginTransitionToPart(partImage); + static_cast(mImage.get())->BeginTransitionToPart(image); } } else { - MOZ_ASSERT(!image, "New part for non-multipart channel?"); - MOZ_ASSERT(progressTracker, "Shouldn't have given away tracker yet"); + MOZ_ASSERT(!mImage, "New part for non-multipart channel?"); + MOZ_ASSERT(mProgressTracker, "Shouldn't have given away tracker yet"); // Create an image using our progress tracker. - image = - ImageFactory::CreateImage(aRequest, progressTracker, mContentType, + mImage = + ImageFactory::CreateImage(aRequest, mProgressTracker, mContentType, mURI, /* aIsMultipart = */ false, static_cast(mInnerWindowId)); - SetImage(image); - progressTracker = nullptr; - SetProgressTracker(nullptr); + mProgressTracker = nullptr; } if (firstPart) { @@ -957,7 +880,7 @@ imgRequest::OnDataAvailable(nsIRequest *aRequest, nsISupports *ctxt, MOZ_ASSERT(progressTracker->HasImage()); } - if (image->HasError() && !mIsMultiPartChannel) { // Probably bad mimetype + if (mImage->HasError() && !mIsMultiPartChannel) { // Probably bad mimetype // We allow multipart images to fail to initialize without cancelling the // load because subsequent images might be fine; thus only single part // images end up here. @@ -965,16 +888,16 @@ imgRequest::OnDataAvailable(nsIRequest *aRequest, nsISupports *ctxt, return NS_BINDING_ABORTED; } - MOZ_ASSERT(!progressTracker, "Should've given tracker to image"); - MOZ_ASSERT(image, "Should have image"); + MOZ_ASSERT(!mProgressTracker, "Should've given tracker to image"); + MOZ_ASSERT(mImage, "Should have image"); if (mDecodeRequested) { - image->StartDecoding(); + mImage->StartDecoding(); } } // Notify the image that it has new data. - rv = image->OnImageDataAvailable(aRequest, ctxt, inStr, sourceOffset, count); + rv = mImage->OnImageDataAvailable(aRequest, ctxt, inStr, sourceOffset, count); if (NS_FAILED(rv)) { PR_LOG(GetImgLog(), PR_LOG_WARNING, diff --git a/image/imgRequest.h b/image/imgRequest.h index ab0e4246ce..b9519d2b47 100644 --- a/image/imgRequest.h +++ b/image/imgRequest.h @@ -19,7 +19,7 @@ #include "nsStringGlue.h" #include "nsError.h" #include "nsIAsyncVerifyRedirectCallback.h" -#include "mozilla/Mutex.h" +#include "mozilla/Atomics.h" #include "mozilla/net/ReferrerPolicy.h" class imgCacheValidator; @@ -65,7 +65,7 @@ public: nsIRequest *aRequest, nsIChannel *aChannel, imgCacheEntry *aCacheEntry, - void *aLoadId, + nsISupports* aCX, nsIPrincipal* aLoadingPrincipal, int32_t aCORSMode, ReferrerPolicy aReferrerPolicy); @@ -88,16 +88,8 @@ public: // Called or dispatched by EvictFromCache for main thread only execution. void ContinueEvict(); - // Methods that get forwarded to the Image, or deferred until it's - // instantiated. - nsresult LockImage(); - nsresult UnlockImage(); - nsresult StartDecoding(); - nsresult RequestDecode(); - - inline void SetInnerWindowID(uint64_t aInnerWindowId) { - mInnerWindowId = aInnerWindowId; - } + // Request that we start decoding the image as soon as data becomes available. + void RequestDecode() { mDecodeRequested = true; } inline uint64_t InnerWindowID() const { return mInnerWindowId; @@ -131,8 +123,6 @@ public: return principal.forget(); } - already_AddRefed GetImage(); - // Return the ProgressTracker associated with this imgRequest. It may live // in |mProgressTracker| or in |mImage.mProgressTracker|, depending on whether // mImage has been instantiated yet. @@ -159,9 +149,6 @@ private: friend class imgRequestNotifyRunnable; friend class mozilla::image::ProgressTracker; - void SetImage(Image* aImage); - void SetProgressTracker(ProgressTracker* aProgressTracker); - inline void SetLoadId(void *aLoadId) { mLoadId = aLoadId; } @@ -260,8 +247,6 @@ private: nsCOMPtr mRedirectCallback; nsCOMPtr mNewRedirectChannel; - mozilla::Mutex mMutex; - // The ID of the inner window origin, used for error reporting. uint64_t mInnerWindowId; @@ -274,9 +259,7 @@ private: nsresult mImageErrorCode; - // Sometimes consumers want to do things before the image is ready. Let them, - // and apply the action when the image becomes available. - bool mDecodeRequested : 1; + mozilla::Atomic mDecodeRequested; bool mIsMultiPartChannel : 1; bool mGotData : 1; diff --git a/image/imgRequestProxy.cpp b/image/imgRequestProxy.cpp index b0a4e1aa8c..fa2f431396 100644 --- a/image/imgRequestProxy.cpp +++ b/image/imgRequestProxy.cpp @@ -224,8 +224,9 @@ nsresult imgRequestProxy::ChangeOwner(imgRequest *aNewOwner) // If we were decoded, or if we'd previously requested a decode, request a // decode on the new image - if (wasDecoded || mDecodeRequested) - GetOwner()->StartDecoding(); + if (wasDecoded || mDecodeRequested) { + StartDecoding(); + } return NS_OK; } @@ -357,28 +358,38 @@ NS_IMETHODIMP imgRequestProxy::CancelAndForgetObserver(nsresult aStatus) NS_IMETHODIMP imgRequestProxy::StartDecoding() { - if (!GetOwner()) - return NS_ERROR_FAILURE; - // Flag this, so we know to transfer the request if our owner changes mDecodeRequested = true; - // Forward the request - return GetOwner()->StartDecoding(); + nsRefPtr image = GetImage(); + if (image) { + return image->StartDecoding(); + } + + if (GetOwner()) { + GetOwner()->RequestDecode(); + } + + return NS_OK; } /* void requestDecode (); */ NS_IMETHODIMP imgRequestProxy::RequestDecode() { - if (!GetOwner()) - return NS_ERROR_FAILURE; - // Flag this, so we know to transfer the request if our owner changes mDecodeRequested = true; - // Forward the request - return GetOwner()->RequestDecode(); + nsRefPtr image = GetImage(); + if (image) { + return image->RequestDecode(); + } + + if (GetOwner()) { + GetOwner()->RequestDecode(); + } + + return NS_OK; } @@ -501,9 +512,8 @@ NS_IMETHODIMP imgRequestProxy::GetImage(imgIContainer **aImage) nsCOMPtr imageToReturn; if (image) imageToReturn = do_QueryInterface(image); - if (!imageToReturn && GetOwner()) { - imageToReturn = GetOwner()->GetImage(); - } + if (!imageToReturn && GetOwner()) + imageToReturn = GetOwner()->mImage; if (!imageToReturn) return NS_ERROR_FAILURE; diff --git a/js/ipc/JavaScriptTypes.ipdlh b/js/ipc/JavaScriptTypes.ipdlh index 7901216683..c2f24da889 100644 --- a/js/ipc/JavaScriptTypes.ipdlh +++ b/js/ipc/JavaScriptTypes.ipdlh @@ -37,6 +37,7 @@ struct RemoteObject uint64_t serializedId; bool isCallable; bool isConstructor; + bool isDOMObject; nsCString objectTag; }; diff --git a/js/ipc/WrapperOwner.cpp b/js/ipc/WrapperOwner.cpp index d35b62c757..a94083d74d 100644 --- a/js/ipc/WrapperOwner.cpp +++ b/js/ipc/WrapperOwner.cpp @@ -10,6 +10,7 @@ #include "mozilla/unused.h" #include "mozilla/dom/BindingUtils.h" #include "jsfriendapi.h" +#include "js/CharacterEncoding.h" #include "xpcprivate.h" #include "CPOWTimer.h" #include "WrapperFactory.h" @@ -26,15 +27,21 @@ struct AuxCPOWData ObjectId id; bool isCallable; bool isConstructor; + bool isDOMObject; // The object tag is just some auxilliary information that clients can use // however they see fit. nsCString objectTag; - AuxCPOWData(ObjectId id, bool isCallable, bool isConstructor, const nsACString& objectTag) + AuxCPOWData(ObjectId id, + bool isCallable, + bool isConstructor, + bool isDOMObject, + const nsACString &objectTag) : id(id), isCallable(isCallable), isConstructor(isConstructor), + isDOMObject(isDOMObject), objectTag(objectTag) {} }; @@ -152,8 +159,8 @@ CPOWProxyHandler::getPropertyDescriptor(JSContext* cx, HandleObject proxy, Handl } bool -WrapperOwner::getPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id, - MutableHandle desc) +WrapperOwner::getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id, + MutableHandle desc) { ObjectId objId = idOf(proxy); @@ -175,15 +182,15 @@ WrapperOwner::getPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId } bool -CPOWProxyHandler::getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id, +CPOWProxyHandler::getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id, MutableHandle desc) const { FORWARD(getOwnPropertyDescriptor, (cx, proxy, id, desc)); } bool -WrapperOwner::getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id, - MutableHandle desc) +WrapperOwner::getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id, + MutableHandle desc) { ObjectId objId = idOf(proxy); @@ -213,8 +220,8 @@ CPOWProxyHandler::defineProperty(JSContext* cx, HandleObject proxy, HandleId id, } bool -WrapperOwner::defineProperty(JSContext* cx, HandleObject proxy, HandleId id, - MutableHandle desc, +WrapperOwner::defineProperty(JSContext *cx, HandleObject proxy, HandleId id, + MutableHandle desc, ObjectOpResult &result) { ObjectId objId = idOf(proxy); @@ -339,7 +346,20 @@ CPOWProxyHandler::get(JSContext* cx, HandleObject proxy, HandleObject receiver, } static bool -CPOWToString(JSContext* cx, unsigned argc, Value* vp) +CPOWDOMQI(JSContext *cx, unsigned argc, Value *vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + if (!args.thisv().isObject() || !IsCPOW(&args.thisv().toObject())) { + JS_ReportError(cx, "bad this object passed to special QI"); + return false; + } + + RootedObject proxy(cx, &args.thisv().toObject()); + FORWARD(DOMQI, (cx, proxy, args)); +} + +static bool +CPOWToString(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); RootedObject callee(cx, &args.callee()); @@ -392,6 +412,49 @@ WrapperOwner::toString(JSContext* cx, HandleObject cpow, JS::CallArgs& args) return true; } +bool +WrapperOwner::DOMQI(JSContext *cx, JS::HandleObject proxy, JS::CallArgs &args) +{ + // Someone's calling us, handle nsISupports specially to avoid unnecessary + // CPOW traffic. + HandleValue id = args[0]; + if (id.isObject()) { + RootedObject idobj(cx, &id.toObject()); + nsCOMPtr jsid; + + nsresult rv = UnwrapArg(idobj, getter_AddRefs(jsid)); + if (NS_SUCCEEDED(rv)) { + MOZ_ASSERT(jsid, "bad wrapJS"); + const nsID *idptr = jsid->GetID(); + if (idptr->Equals(NS_GET_IID(nsISupports))) { + args.rval().set(args.thisv()); + return true; + } + + // Webidl-implemented DOM objects never have nsIClassInfo. + if (idptr->Equals(NS_GET_IID(nsIClassInfo))) + return Throw(cx, NS_ERROR_NO_INTERFACE); + } + } + + // It wasn't nsISupports, call into the other process to do the QI for us + // (since we don't know what other interfaces our object supports). Note + // that we have to use JS_GetPropertyDescriptor here to avoid infinite + // recursion back into CPOWDOMQI via WrapperOwner::get(). + // We could stash the actual QI function on our own function object to avoid + // if we're called multiple times, but since we're transient, there's no + // point right now. + JS::Rooted propDesc(cx); + if (!JS_GetPropertyDescriptor(cx, proxy, "QueryInterface", &propDesc)) + return false; + + if (!propDesc.value().isObject()) { + MOZ_ASSERT_UNREACHABLE("We didn't get QueryInterface off a node"); + return Throw(cx, NS_ERROR_UNEXPECTED); + } + return JS_CallFunctionValue(cx, proxy, propDesc.value(), args, args.rval()); +} + bool WrapperOwner::get(JSContext* cx, HandleObject proxy, HandleObject receiver, HandleId id, MutableHandleValue vp) @@ -406,6 +469,22 @@ WrapperOwner::get(JSContext* cx, HandleObject proxy, HandleObject receiver, if (!toJSIDVariant(cx, id, &idVar)) return false; + AuxCPOWData *data = AuxCPOWDataOf(proxy); + if (data->isDOMObject && + idVar.type() == JSIDVariant::TnsString && + idVar.get_nsString().EqualsLiteral("QueryInterface")) + { + // Handle QueryInterface on DOM Objects specially since we can assume + // certain things about their implementation. + RootedFunction qi(cx, JS_NewFunction(cx, CPOWDOMQI, 1, 0, + "QueryInterface")); + if (!qi) + return false; + + vp.set(ObjectValue(*JS_GetFunctionObject(qi))); + return true; + } + JSVariant val; ReturnStatus status; if (!SendGet(objId, receiverVar, idVar, &status, &val)) @@ -967,6 +1046,7 @@ MakeRemoteObject(JSContext* cx, ObjectId id, HandleObject obj) return RemoteObject(id.serialize(), JS::IsCallable(obj), JS::IsConstructor(obj), + dom::IsDOMObject(obj), objectTag); } @@ -1051,6 +1131,7 @@ WrapperOwner::fromRemoteObjectVariant(JSContext* cx, RemoteObject objVar) AuxCPOWData* aux = new AuxCPOWData(objId, objVar.isCallable(), objVar.isConstructor(), + objVar.isDOMObject(), objVar.objectTag()); SetProxyExtra(obj, 0, PrivateValue(this)); diff --git a/js/ipc/WrapperOwner.h b/js/ipc/WrapperOwner.h index 50ec31c9cc..861fe2a5d0 100644 --- a/js/ipc/WrapperOwner.h +++ b/js/ipc/WrapperOwner.h @@ -60,15 +60,16 @@ class WrapperOwner : public virtual JavaScriptShared bool regexp_toShared(JSContext *cx, JS::HandleObject proxy, js::RegExpGuard *g); - nsresult instanceOf(JSObject* obj, const nsID* id, bool* bp); + nsresult instanceOf(JSObject *obj, const nsID *id, bool *bp); - bool toString(JSContext* cx, JS::HandleObject callee, JS::CallArgs& args); + bool toString(JSContext *cx, JS::HandleObject callee, JS::CallArgs &args); + bool DOMQI(JSContext *cx, JS::HandleObject callee, JS::CallArgs &args); /* * Check that |obj| is a DOM wrapper whose prototype chain contains * |prototypeID| at depth |depth|. */ - bool domInstanceOf(JSContext* cx, JSObject* obj, int prototypeID, int depth, bool* bp); + bool domInstanceOf(JSContext *cx, JSObject *obj, int prototypeID, int depth, bool *bp); bool active() { return !inactive_; } diff --git a/netwerk/base/nsIOService.cpp b/netwerk/base/nsIOService.cpp index 9e2640d139..77e365411d 100644 --- a/netwerk/base/nsIOService.cpp +++ b/netwerk/base/nsIOService.cpp @@ -1555,6 +1555,10 @@ nsIOService::SpeculativeConnect(nsIURI *aURI, nsCOMPtr cancelable; nsRefPtr callback = new IOServiceProxyCallback(aCallbacks, this); + nsCOMPtr pps2 = do_QueryInterface(pps); + if (pps2) { + return pps2->AsyncResolve2(channel, 0, callback, getter_AddRefs(cancelable)); + } return pps->AsyncResolve(channel, 0, callback, getter_AddRefs(cancelable)); } diff --git a/netwerk/cache/nsApplicationCacheService.cpp b/netwerk/cache/nsApplicationCacheService.cpp index f28c6c24c9..9c8034088d 100644 --- a/netwerk/cache/nsApplicationCacheService.cpp +++ b/netwerk/cache/nsApplicationCacheService.cpp @@ -242,13 +242,12 @@ NS_IMPL_ISUPPORTS(AppCacheClearDataObserver, nsIObserver) void nsApplicationCacheService::AppClearDataObserverInit() { - nsCOMPtr observerService = - do_GetService("@mozilla.org/observer-service;1"); - if (observerService) { - nsRefPtr obs - = new AppCacheClearDataObserver(); - observerService->AddObserver(obs, TOPIC_WEB_APP_CLEAR_DATA, - /*holdsWeak=*/ false); - } + nsCOMPtr observerService = services::GetObserverService(); + if (observerService) { + nsRefPtr obs + = new AppCacheClearDataObserver(); + observerService->AddObserver(obs, TOPIC_WEB_APP_CLEAR_DATA, + /*holdsWeak=*/ false); + } } diff --git a/netwerk/cookie/nsCookieService.cpp b/netwerk/cookie/nsCookieService.cpp index 47c59994a4..6b545c09a4 100644 --- a/netwerk/cookie/nsCookieService.cpp +++ b/netwerk/cookie/nsCookieService.cpp @@ -688,7 +688,7 @@ nsCookieService::GetSingleton() /* static */ void nsCookieService::AppClearDataObserverInit() { - nsCOMPtr observerService = do_GetService("@mozilla.org/observer-service;1"); + nsCOMPtr observerService = services::GetObserverService(); nsCOMPtr obs = new AppClearDataObserver(); observerService->AddObserver(obs, TOPIC_WEB_APP_CLEAR_DATA, /* holdsWeak= */ false); diff --git a/netwerk/dns/nsDNSService2.cpp b/netwerk/dns/nsDNSService2.cpp index 19ad829891..adcc0475f3 100644 --- a/netwerk/dns/nsDNSService2.cpp +++ b/netwerk/dns/nsDNSService2.cpp @@ -610,8 +610,7 @@ nsDNSService::Init() nsCOMPtr idn = do_GetService(NS_IDNSERVICE_CONTRACTID); - nsCOMPtr obs = - do_GetService(NS_OBSERVERSERVICE_CONTRACTID); + nsCOMPtr obs = services::GetObserverService(); nsRefPtr res; nsresult rv = nsHostResolver::Create(maxCacheEntries, diff --git a/netwerk/ipc/NeckoParent.cpp b/netwerk/ipc/NeckoParent.cpp index 76627930ef..3bff8ef73a 100644 --- a/netwerk/ipc/NeckoParent.cpp +++ b/netwerk/ipc/NeckoParent.cpp @@ -40,6 +40,7 @@ #include "nsPrincipal.h" #include "nsIOService.h" #include "mozilla/net/OfflineObserver.h" +#include "nsISpeculativeConnect.h" using mozilla::dom::ContentParent; using mozilla::dom::TabContext; @@ -670,6 +671,17 @@ NeckoParent::DeallocPRemoteOpenFileParent(PRemoteOpenFileParent* actor) return true; } +bool +NeckoParent::RecvSpeculativeConnect(const URIParams &aURI) +{ + nsCOMPtr speculator(gIOService); + nsCOMPtr uri = DeserializeURI(aURI); + if (uri && speculator) { + speculator->SpeculativeConnect(uri, nullptr); + } + 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 c02fcfcb1b..1c84bf253a 100644 --- a/netwerk/ipc/NeckoParent.h +++ b/netwerk/ipc/NeckoParent.h @@ -163,6 +163,7 @@ protected: const uint32_t& flags, const nsCString& aNetworkInterface) override; virtual bool DeallocPDNSRequestParent(PDNSRequestParent*) override; + virtual bool RecvSpeculativeConnect(const URIParams& aURI) override; virtual bool RecvHTMLDNSPrefetch(const nsString& hostname, const uint16_t& flags) override; virtual bool RecvCancelHTMLDNSPrefetch(const nsString& hostname, diff --git a/netwerk/ipc/PNecko.ipdl b/netwerk/ipc/PNecko.ipdl index 9476aa7b6e..d6e81e9eaa 100644 --- a/netwerk/ipc/PNecko.ipdl +++ b/netwerk/ipc/PNecko.ipdl @@ -74,6 +74,7 @@ parent: URIParams fileuri, OptionalURIParams appuri); + SpeculativeConnect(URIParams uri); HTMLDNSPrefetch(nsString hostname, uint16_t flags); CancelHTMLDNSPrefetch(nsString hostname, uint16_t flags, nsresult reason); PRtspController(); diff --git a/netwerk/protocol/http/nsHttpHandler.cpp b/netwerk/protocol/http/nsHttpHandler.cpp index d4d8f392f7..2b7d823d75 100644 --- a/netwerk/protocol/http/nsHttpHandler.cpp +++ b/netwerk/protocol/http/nsHttpHandler.cpp @@ -50,6 +50,7 @@ #include "nsINetworkLinkService.h" #include "mozilla/net/NeckoChild.h" +#include "mozilla/ipc/URIUtils.h" #if defined(XP_UNIX) #include @@ -2002,6 +2003,13 @@ NS_IMETHODIMP nsHttpHandler::SpeculativeConnect(nsIURI *aURI, nsIInterfaceRequestor *aCallbacks) { + if (IsNeckoChild()) { + ipc::URIParams params; + SerializeURI(aURI, params); + gNeckoChild->SendSpeculativeConnect(params); + return NS_OK; + } + if (!mHandlerActive) return NS_OK; diff --git a/netwerk/test/mochitests/mochitest.ini b/netwerk/test/mochitests/mochitest.ini index 008c964287..a040626980 100644 --- a/netwerk/test/mochitests/mochitest.ini +++ b/netwerk/test/mochitests/mochitest.ini @@ -4,11 +4,13 @@ skip-if = buildapp == 'b2g' || e10s || toolkit == 'android' # Android: Bug 11111 support-files = method.sjs partial_content.sjs + rel_preconnect.sjs user_agent.sjs user_agent_update.sjs [test_arraybufferinputstream.html] [test_partially_cached_content.html] +[test_rel_preconnect.html] [test_uri_scheme.html] [test_user_agent_overrides.html] [test_user_agent_updates.html] diff --git a/netwerk/test/mochitests/rel_preconnect.sjs b/netwerk/test/mochitests/rel_preconnect.sjs new file mode 100644 index 0000000000..d373f28460 --- /dev/null +++ b/netwerk/test/mochitests/rel_preconnect.sjs @@ -0,0 +1,12 @@ +// Generate response header "Link: ; rel=preconnect" +// HREF is provided by the request header X-Link + +function handleRequest(request, response) +{ + response.setHeader("Cache-Control", "no-cache", false); + response.setHeader("Link", "<" + + request.getHeader('X-Link') + + ">; rel=preconnect"); + response.write("check that header"); +} + diff --git a/netwerk/test/mochitests/test_rel_preconnect.html b/netwerk/test/mochitests/test_rel_preconnect.html new file mode 100644 index 0000000000..490594f303 --- /dev/null +++ b/netwerk/test/mochitests/test_rel_preconnect.html @@ -0,0 +1,83 @@ + + + + + Test for link rel=preconnect + + + + + + +

+ +
+
+ + + diff --git a/netwerk/test/unit/test_header_Accept-Language_case.js b/netwerk/test/unit/test_header_Accept-Language_case.js index c13494dbb7..f64e5cffaf 100644 --- a/netwerk/test/unit/test_header_Accept-Language_case.js +++ b/netwerk/test/unit/test_header_Accept-Language_case.js @@ -1,3 +1,5 @@ +Cu.import("resource://gre/modules/Services.jsm"); + var testpath = "/bug1054739"; function run_test() { @@ -26,7 +28,14 @@ function run_test() { function setupChannel(path) { let ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService); - let chan = ios.newChannel("http://localhost:4444" + path, "", null); + let chan = ios.newChannel2("http://localhost:4444" + path, + "", + null, + null, // aLoadingNode + Services.scriptSecurityManager.getSystemPrincipal(), + null, // aTriggeringPrincipal + Ci.nsILoadInfo.SEC_NORMAL, + Ci.nsIContentPolicy.TYPE_OTHER); chan.QueryInterface(Ci.nsIHttpChannel); return chan; } diff --git a/netwerk/test/unit/test_protocolproxyservice.js b/netwerk/test/unit/test_protocolproxyservice.js index 51cbb78f52..5e5241e236 100644 --- a/netwerk/test/unit/test_protocolproxyservice.js +++ b/netwerk/test/unit/test_protocolproxyservice.js @@ -169,7 +169,14 @@ resolveCallback.prototype = { }; function run_filter_test() { - var channel = ios.newChannel("http://www.mozilla.org/", null, null); + var channel = ios.newChannel2("http://www.mozilla.org/", + null, + null, + null, // aLoadingNode + Services.scriptSecurityManager.getSystemPrincipal(), + null, // aTriggeringPrincipal + Ci.nsILoadInfo.SEC_NORMAL, + Ci.nsIContentPolicy.TYPE_OTHER); // Verify initial state var cb = new resolveCallback(); @@ -192,7 +199,14 @@ function filter_test0_1(pi) { var cb = new resolveCallback(); cb.nextFunction = filter_test0_2; - var channel = ios.newChannel("http://www.mozilla.org/", null, null); + var channel = ios.newChannel2("http://www.mozilla.org/", + null, + null, + null, // aLoadingNode + Services.scriptSecurityManager.getSystemPrincipal(), + null, // aTriggeringPrincipal + Ci.nsILoadInfo.SEC_NORMAL, + Ci.nsIContentPolicy.TYPE_OTHER); var req = pps.asyncResolve(channel, 0, cb); } @@ -205,7 +219,14 @@ function filter_test0_2(pi) var cb = new resolveCallback(); cb.nextFunction = filter_test0_3; - var channel = ios.newChannel("http://www.mozilla.org/", null, null); + var channel = ios.newChannel2("http://www.mozilla.org/", + null, + null, + null, // aLoadingNode + Services.scriptSecurityManager.getSystemPrincipal(), + null, // aTriggeringPrincipal + Ci.nsILoadInfo.SEC_NORMAL, + Ci.nsIContentPolicy.TYPE_OTHER); var req = pps.asyncResolve(channel, 0, cb); } @@ -220,7 +241,14 @@ function filter_test0_3(pi) var cb = new resolveCallback(); cb.nextFunction = filter_test0_4; - var channel = ios.newChannel("http://www.mozilla.org/", null, null); + var channel = ios.newChannel2("http://www.mozilla.org/", + null, + null, + null, // aLoadingNode + Services.scriptSecurityManager.getSystemPrincipal(), + null, // aTriggeringPrincipal + Ci.nsILoadInfo.SEC_NORMAL, + Ci.nsIContentPolicy.TYPE_OTHER); var req = pps.asyncResolve(channel, 0, cb); } @@ -233,7 +261,14 @@ function filter_test0_4(pi) pps.registerChannelFilter(filter03, 10); var cb = new resolveCallback(); cb.nextFunction = filter_test0_5; - var channel = ios.newChannel("http://www.mozilla.org/", null, null); + var channel = ios.newChannel2("http://www.mozilla.org/", + null, + null, + null, // aLoadingNode + Services.scriptSecurityManager.getSystemPrincipal(), + null, // aTriggeringPrincipal + Ci.nsILoadInfo.SEC_NORMAL, + Ci.nsIContentPolicy.TYPE_OTHER); var req = pps.asyncResolve(channel, 0, cb); } @@ -315,7 +350,14 @@ function run_filter_test2() { var cb = new resolveCallback(); cb.nextFunction = filter_test1_1; - var channel = ios.newChannel("http://www.mozilla.org/", null, null); + var channel = ios.newChannel2("http://www.mozilla.org/", + null, + null, + null, // aLoadingNode + Services.scriptSecurityManager.getSystemPrincipal(), + null, // aTriggeringPrincipal + Ci.nsILoadInfo.SEC_NORMAL, + Ci.nsIContentPolicy.TYPE_OTHER); var req = pps.asyncResolve(channel, 0, cb); } @@ -327,7 +369,14 @@ function filter_test1_1(pi) { var cb = new resolveCallback(); cb.nextFunction = filter_test1_2; - var channel = ios.newChannel("http://www.mozilla.org/", null, null); + var channel = ios.newChannel2("http://www.mozilla.org/", + null, + null, + null, // aLoadingNode + Services.scriptSecurityManager.getSystemPrincipal(), + null, // aTriggeringPrincipal + Ci.nsILoadInfo.SEC_NORMAL, + Ci.nsIContentPolicy.TYPE_OTHER); var req = pps.asyncResolve(channel, 0, cb); } @@ -340,7 +389,14 @@ function filter_test1_2(pi) { var cb = new resolveCallback(); cb.nextFunction = filter_test1_3; - var channel = ios.newChannel("http://www.mozilla.org/", null, null); + var channel = ios.newChannel2("http://www.mozilla.org/", + null, + null, + null, // aLoadingNode + Services.scriptSecurityManager.getSystemPrincipal(), + null, // aTriggeringPrincipal + Ci.nsILoadInfo.SEC_NORMAL, + Ci.nsIContentPolicy.TYPE_OTHER); var req = pps.asyncResolve(channel, 0, cb); } @@ -352,7 +408,14 @@ function filter_test1_3(pi) { var filter_3_1; function run_filter_test3() { - var channel = ios.newChannel("http://www.mozilla.org/", null, null); + var channel = ios.newChannel2("http://www.mozilla.org/", + null, + null, + null, // aLoadingNode + Services.scriptSecurityManager.getSystemPrincipal(), + null, // aTriggeringPrincipal + Ci.nsILoadInfo.SEC_NORMAL, + Ci.nsIContentPolicy.TYPE_OTHER); // Push a filter and verify the results asynchronously @@ -371,7 +434,14 @@ function filter_test3_1(pi) { } function run_pref_test() { - var channel = ios.newChannel("http://www.mozilla.org/", null, null); + var channel = ios.newChannel2("http://www.mozilla.org/", + null, + null, + null, // aLoadingNode + Services.scriptSecurityManager.getSystemPrincipal(), + null, // aTriggeringPrincipal + Ci.nsILoadInfo.SEC_NORMAL, + Ci.nsIContentPolicy.TYPE_OTHER); // Verify 'direct' setting @@ -391,7 +461,14 @@ function pref_test1_1(pi) var cb = new resolveCallback(); cb.nextFunction = pref_test1_2; - var channel = ios.newChannel("http://www.mozilla.org/", null, null); + var channel = ios.newChannel2("http://www.mozilla.org/", + null, + null, + null, // aLoadingNode + Services.scriptSecurityManager.getSystemPrincipal(), + null, // aTriggeringPrincipal + Ci.nsILoadInfo.SEC_NORMAL, + Ci.nsIContentPolicy.TYPE_OTHER); var req = pps.asyncResolve(channel, 0, cb); } @@ -406,7 +483,14 @@ function pref_test1_2(pi) var cb = new resolveCallback(); cb.nextFunction = pref_test1_3; - var channel = ios.newChannel("http://www.mozilla.org/", null, null); + var channel = ios.newChannel2("http://www.mozilla.org/", + null, + null, + null, // aLoadingNode + Services.scriptSecurityManager.getSystemPrincipal(), + null, // aTriggeringPrincipal + Ci.nsILoadInfo.SEC_NORMAL, + Ci.nsIContentPolicy.TYPE_OTHER); var req = pps.asyncResolve(channel, 0, cb); } @@ -423,7 +507,14 @@ function pref_test1_3(pi) var cb = new resolveCallback(); cb.nextFunction = pref_test1_4; - var channel = ios.newChannel("http://www.mozilla.org/", null, null); + var channel = ios.newChannel2("http://www.mozilla.org/", + null, + null, + null, // aLoadingNode + Services.scriptSecurityManager.getSystemPrincipal(), + null, // aTriggeringPrincipal + Ci.nsILoadInfo.SEC_NORMAL, + Ci.nsIContentPolicy.TYPE_OTHER); var req = pps.asyncResolve(channel, 0, cb); } @@ -481,7 +572,14 @@ function run_pac_test() { 'function FindProxyForURL(url, host) {' + ' return "PROXY foopy:8080; DIRECT";' + '}'; - var channel = ios.newChannel("http://www.mozilla.org/", null, null); + var channel = ios.newChannel2("http://www.mozilla.org/", + null, + null, + null, // aLoadingNode + Services.scriptSecurityManager.getSystemPrincipal(), + null, // aTriggeringPrincipal + Ci.nsILoadInfo.SEC_NORMAL, + Ci.nsIContentPolicy.TYPE_OTHER); // Configure PAC @@ -495,7 +593,14 @@ function run_pac2_test() { 'function FindProxyForURL(url, host) {' + ' return "HTTPS foopy:8080; DIRECT";' + '}'; - var channel = ios.newChannel("http://www.mozilla.org/", null, null); + var channel = ios.newChannel2("http://www.mozilla.org/", + null, + null, + null, // aLoadingNode + Services.scriptSecurityManager.getSystemPrincipal(), + null, // aTriggeringPrincipal + Ci.nsILoadInfo.SEC_NORMAL, + Ci.nsIContentPolicy.TYPE_OTHER); // Configure PAC originalTLSProxy = prefs.getBoolPref("network.proxy.proxy_over_tls"); @@ -511,7 +616,14 @@ function run_pac3_test() { 'function FindProxyForURL(url, host) {' + ' return "HTTPS foopy:8080; DIRECT";' + '}'; - var channel = ios.newChannel("http://www.mozilla.org/", null, null); + var channel = ios.newChannel2("http://www.mozilla.org/", + null, + null, + null, // aLoadingNode + Services.scriptSecurityManager.getSystemPrincipal(), + null, // aTriggeringPrincipal + Ci.nsILoadInfo.SEC_NORMAL, + Ci.nsIContentPolicy.TYPE_OTHER); // Configure PAC prefs.setCharPref("network.proxy.autoconfig_url", pac); @@ -553,7 +665,14 @@ TestResolveCancelationCallback.prototype = { }; function run_pac_cancel_test() { - var channel = ios.newChannel("http://www.mozilla.org/", null, null); + var channel = ios.newChannel2("http://www.mozilla.org/", + null, + null, + null, // aLoadingNode + Services.scriptSecurityManager.getSystemPrincipal(), + null, // aTriggeringPrincipal + Ci.nsILoadInfo.SEC_NORMAL, + Ci.nsIContentPolicy.TYPE_OTHER); // Configure PAC var pac = 'data:text/plain,' + @@ -594,7 +713,14 @@ function check_host_filters_cb() function check_host_filter(i) { var uri; dump("*** uri=" + hostList[i] + " bShouldBeFiltered=" + bShouldBeFiltered + "\n"); - var channel = ios.newChannel(hostList[i], null, null); + var channel = ios.newChannel2(hostList[i], + null, + null, + null, // aLoadingNode + Services.scriptSecurityManager.getSystemPrincipal(), + null, // aTriggeringPrincipal + Ci.nsILoadInfo.SEC_NORMAL, + Ci.nsIContentPolicy.TYPE_OTHER); var cb = new resolveCallback(); cb.nextFunction = host_filter_cb; @@ -698,7 +824,14 @@ function run_myipaddress_test() // no traffic to this IP is ever sent, it is just a public IP that // does not require DNS to determine a route. - var channel = ios.newChannel("http://192.0.43.10/", null, null); + var channel = ios.newChannel2("http://192.0.43.10/", + null, + null, + null, // aLoadingNode + Services.scriptSecurityManager.getSystemPrincipal(), + null, // aTriggeringPrincipal + Ci.nsILoadInfo.SEC_NORMAL, + Ci.nsIContentPolicy.TYPE_OTHER); prefs.setIntPref("network.proxy.type", 2); prefs.setCharPref("network.proxy.autoconfig_url", pac); @@ -734,7 +867,14 @@ function run_myipaddress_test_2() ' return "PROXY " + myaddr + ":5678";' + '}'; - var channel = ios.newChannel("http://www.mozilla.org/", null, null); + var channel = ios.newChannel2("http://www.mozilla.org/", + null, + null, + null, // aLoadingNode + Services.scriptSecurityManager.getSystemPrincipal(), + null, // aTriggeringPrincipal + Ci.nsILoadInfo.SEC_NORMAL, + Ci.nsIContentPolicy.TYPE_OTHER); prefs.setIntPref("network.proxy.type", 2); prefs.setCharPref("network.proxy.autoconfig_url", pac); @@ -763,7 +903,14 @@ function run_failed_script_test() var pac = 'data:text/plain,' + '\nfor(;\n'; - var channel = ios.newChannel("http://www.mozilla.org/", null, null); + var channel = ios.newChannel2("http://www.mozilla.org/", + null, + null, + null, // aLoadingNode + Services.scriptSecurityManager.getSystemPrincipal(), + null, // aTriggeringPrincipal + Ci.nsILoadInfo.SEC_NORMAL, + Ci.nsIContentPolicy.TYPE_OTHER); prefs.setIntPref("network.proxy.type", 2); prefs.setCharPref("network.proxy.autoconfig_url", pac); @@ -843,7 +990,14 @@ function run_isresolvable_test() ' return "PROXY 127.0.0.1:1234";' + '}'; - var channel = ios.newChannel("http://www.mozilla.org/", null, null); + var channel = ios.newChannel2("http://www.mozilla.org/", + null, + null, + null, // aLoadingNode + Services.scriptSecurityManager.getSystemPrincipal(), + null, // aTriggeringPrincipal + Ci.nsILoadInfo.SEC_NORMAL, + Ci.nsIContentPolicy.TYPE_OTHER); prefs.setIntPref("network.proxy.type", 2); prefs.setCharPref("network.proxy.autoconfig_url", pac); diff --git a/security/manager/ssl/src/moz.build b/security/manager/ssl/src/moz.build index 5ef2caf8a3..33de055f4d 100644 --- a/security/manager/ssl/src/moz.build +++ b/security/manager/ssl/src/moz.build @@ -30,6 +30,7 @@ UNIFIED_SOURCES += [ 'nsCertVerificationThread.cpp', 'nsClientAuthRemember.cpp', 'nsCrypto.cpp', + 'nsCryptoHash.cpp', 'nsDataSignatureVerifier.cpp', 'nsKeygenHandler.cpp', 'nsKeygenHandlerContent.cpp', @@ -43,10 +44,12 @@ UNIFIED_SOURCES += [ 'nsNSSCertificateFakeTransport.cpp', 'nsNSSCertTrust.cpp', 'nsNSSCertValidity.cpp', + 'nsNSSComponent.cpp', 'nsNSSErrors.cpp', 'nsNSSIOLayer.cpp', 'nsNSSModule.cpp', 'nsNSSShutDown.cpp', + 'nsNSSVersion.cpp', 'nsNTLMAuthModule.cpp', 'nsPK11TokenDB.cpp', 'nsPKCS11Slot.cpp', @@ -60,6 +63,7 @@ UNIFIED_SOURCES += [ 'nsSSLStatus.cpp', 'nsTLSSocketProvider.cpp', 'nsUsageArrayHelper.cpp', + 'PSMContentListener.cpp', 'PSMRunnable.cpp', 'SharedSSLState.cpp', 'SSLServerCertVerification.cpp', @@ -67,14 +71,8 @@ UNIFIED_SOURCES += [ ] # nsNSSCertificateDB.cpp needs to include nscert.h before everything else. -# The rest cannot be built in unified mode because they want to force NSPR -# logging. SOURCES += [ - 'nsCryptoHash.cpp', 'nsNSSCertificateDB.cpp', - 'nsNSSComponent.cpp', - 'nsNSSVersion.cpp', - 'PSMContentListener.cpp', ] LOCAL_INCLUDES += [ diff --git a/testing/marionette/client/marionette/tests/unit/test_about_pages.py b/testing/marionette/client/marionette/tests/unit/test_about_pages.py new file mode 100644 index 0000000000..303162cd93 --- /dev/null +++ b/testing/marionette/client/marionette/tests/unit/test_about_pages.py @@ -0,0 +1,92 @@ +# 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/. + +from marionette_test import MarionetteTestCase +from marionette_driver.keys import Keys + +class TestAboutPages(MarionetteTestCase): + + def setUp(self): + MarionetteTestCase.setUp(self) + + if self.marionette.session_capabilities['platformName'] == 'DARWIN': + self.mod_key = Keys.META + else: + self.mod_key = Keys.CONTROL + + self.remote_uri = self.marionette.absolute_url("javascriptPage.html") + self.marionette.navigate(self.remote_uri) + + def purge_history(self): + with self.marionette.using_context("chrome"): + self.marionette.execute_script(""" + let sh = gBrowser.webNavigation.sessionHistory; + if (sh.count) { + sh.PurgeHistory(sh.count - 1); + } + """) + self.wait_for_condition( + lambda mn: mn.execute_script(""" + return gBrowser.webNavigation.sessionHistory.count === 1; + """)) + + def test_back_forward(self): + self.marionette.navigate("about:blank") + + # Something about this sequence goes wrong when run in a tab with a lot + # of history (you have to "go_back" twice to get back to the remote + # uri). Running in a tab with less history effectively works around + # this. This is reproducible without marionette, filed as bug 1134518. + self.purge_history() + self.marionette.navigate(self.remote_uri) + + self.marionette.navigate("about:preferences") + + self.marionette.go_back() + + self.wait_for_condition( + lambda mn: mn.get_url() == self.remote_uri) + + def test_navigate_non_remote_about_pages(self): + self.marionette.navigate("about:blank") + self.assertEqual(self.marionette.get_url(), "about:blank") + self.marionette.navigate("about:preferences") + self.assertEqual(self.marionette.get_url(), "about:preferences") + + def test_navigate_shortcut_key(self): + self.marionette.navigate("about:preferences") + self.marionette.navigate(self.remote_uri) + self.marionette.navigate("about:blank") + + start_win = self.marionette.current_window_handle + start_win_handles = self.marionette.window_handles + with self.marionette.using_context("chrome"): + main_win = self.marionette.find_element("id", "main-window") + main_win.send_keys(self.mod_key, Keys.SHIFT, 'a') + + self.wait_for_condition(lambda mn: len(mn.window_handles) == 2) + self.assertEqual(start_win, self.marionette.current_window_handle) + [new_tab] = list(set(self.marionette.window_handles) - set(start_win_handles)) + self.marionette.switch_to_window(new_tab) + self.wait_for_condition(lambda mn: mn.get_url() == "about:addons") + self.marionette.close() + self.marionette.switch_to_window(start_win) + + def test_type_to_non_remote_tab(self): + with self.marionette.using_context("chrome"): + urlbar = self.marionette.find_element('id', 'urlbar') + urlbar.send_keys(self.mod_key + 'a') + urlbar.send_keys(self.mod_key + 'x') + urlbar.send_keys('about:preferences' + Keys.ENTER) + self.wait_for_condition(lambda mn: mn.get_url() == "about:preferences") + + def test_type_to_remote_tab(self): + self.marionette.navigate("about:preferences") + with self.marionette.using_context("chrome"): + urlbar = self.marionette.find_element('id', 'urlbar') + urlbar.send_keys(self.mod_key + 'a') + urlbar.send_keys(self.mod_key + 'x') + urlbar.send_keys(self.remote_uri + Keys.ENTER) + + self.wait_for_condition(lambda mn: mn.get_url() == self.remote_uri) diff --git a/testing/marionette/client/marionette/tests/unit/unit-tests.ini b/testing/marionette/client/marionette/tests/unit/unit-tests.ini index 2b44688346..bba42eb0be 100644 --- a/testing/marionette/client/marionette/tests/unit/unit-tests.ini +++ b/testing/marionette/client/marionette/tests/unit/unit-tests.ini @@ -55,6 +55,9 @@ disabled = "Bug 896046" browser = false qemu = true +[test_about_pages.py] +b2g = false + [test_execute_async_script.py] [test_execute_script.py] [test_simpletest_fail.js] diff --git a/testing/marionette/marionette-frame-manager.js b/testing/marionette/marionette-frame-manager.js index f0be626d02..b86fd4cb1c 100644 --- a/testing/marionette/marionette-frame-manager.js +++ b/testing/marionette/marionette-frame-manager.js @@ -208,6 +208,7 @@ FrameManager.prototype = { messageManager.addWeakMessageListener("Marionette:addCookie", this.server); messageManager.addWeakMessageListener("Marionette:getVisibleCookies", this.server); messageManager.addWeakMessageListener("Marionette:deleteCookie", this.server); + messageManager.addWeakMessageListener("Marionette:listenersAttached", this.server); messageManager.addWeakMessageListener("MarionetteFrame:handleModal", this); messageManager.addWeakMessageListener("MarionetteFrame:getCurrentFrameId", this); messageManager.addWeakMessageListener("MarionetteFrame:getInterruptedState", this); @@ -239,8 +240,8 @@ FrameManager.prototype = { messageManager.removeWeakMessageListener("Marionette:addCookie", this.server); messageManager.removeWeakMessageListener("Marionette:getVisibleCookies", this.server); messageManager.removeWeakMessageListener("Marionette:deleteCookie", this.server); + messageManager.removeWeakMessageListener("Marionette:listenersAttached", this.server); messageManager.removeWeakMessageListener("MarionetteFrame:handleModal", this); messageManager.removeWeakMessageListener("MarionetteFrame:getCurrentFrameId", this); }, - }; diff --git a/testing/marionette/marionette-listener.js b/testing/marionette/marionette-listener.js index 24738872bb..9a3ef1cfec 100644 --- a/testing/marionette/marionette-listener.js +++ b/testing/marionette/marionette-listener.js @@ -63,6 +63,9 @@ let originalOnError; let checkTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); //timer for readystate let readyStateTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); +// timer for navigation commands. +let navTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); +let onDOMContentLoaded; // Send move events about this often let EVENT_INTERVAL = 30; // milliseconds // For assigning unique ids to all touches @@ -97,13 +100,14 @@ let modalHandler = function() { * If the actor returns an ID, we start the listeners. Otherwise, nothing happens. */ function registerSelf() { - let msg = {value: winUtil.outerWindowID, href: content.location.href}; + let msg = {value: winUtil.outerWindowID} // register will have the ID and a boolean describing if this is the main process or not let register = sendSyncMessage("Marionette:register", msg); if (register[0]) { - listenerId = register[0][0].id; - if (typeof listenerId != "undefined") { + let {id, remotenessChange} = register[0][0]; + listenerId = id; + if (typeof id != "undefined") { // check if we're the main process if (register[0][1] == true) { addMessageListener("MarionetteMainListener:emitTouchEvent", emitTouchEventForIFrame); @@ -111,6 +115,9 @@ function registerSelf() { importedScripts = FileUtils.getDir('TmpD', [], false); importedScripts.append('marionetteContentScripts'); startListeners(); + if (remotenessChange) { + sendAsyncMessage("Marionette:listenersAttached", {listenerId: id}); + } } } } @@ -170,6 +177,8 @@ function startListeners() { addMessageListenerId("Marionette:actionChain", actionChain); addMessageListenerId("Marionette:multiAction", multiAction); addMessageListenerId("Marionette:get", get); + addMessageListenerId("Marionette:pollForReadyState", pollForReadyState); + addMessageListenerId("Marionette:cancelRequest", cancelRequest); addMessageListenerId("Marionette:getCurrentUrl", getCurrentUrl); addMessageListenerId("Marionette:getTitle", getTitle); addMessageListenerId("Marionette:getPageSource", getPageSource); @@ -273,6 +282,8 @@ function deleteSession(msg) { removeMessageListenerId("Marionette:actionChain", actionChain); removeMessageListenerId("Marionette:multiAction", multiAction); removeMessageListenerId("Marionette:get", get); + removeMessageListenerId("Marionette:pollForReadyState", pollForReadyState); + removeMessageListenerId("Marionette:cancelRequest", cancelRequest); removeMessageListenerId("Marionette:getTitle", getTitle); removeMessageListenerId("Marionette:getPageSource", getPageSource); removeMessageListenerId("Marionette:getCurrentUrl", getCurrentUrl); @@ -1404,6 +1415,52 @@ function multiAction(msg) { } } +/* + * This implements the latter part of a get request (for the case we need to resume one + * when a remoteness update happens in the middle of a navigate request). This is most of + * of the work of a navigate request, but doesn't assume DOMContentLoaded is yet to fire. + */ +function pollForReadyState(msg, start, callback) { + let {pageTimeout, url, command_id} = msg.json; + start = start ? start : new Date().getTime(); + + if (!callback) { + callback = () => {}; + } + + let end = null; + function checkLoad() { + navTimer.cancel(); + end = new Date().getTime(); + let aboutErrorRegex = /about:.+(error)\?/; + let elapse = end - start; + if (pageTimeout == null || elapse <= pageTimeout) { + if (curFrame.document.readyState == "complete") { + callback(); + sendOk(command_id); + } else if (curFrame.document.readyState == "interactive" && + aboutErrorRegex.exec(curFrame.document.baseURI) && + !curFrame.document.baseURI.startsWith(url)) { + // We have reached an error url without requesting it. + callback(); + sendError("Error loading page", 13, null, command_id); + } else if (curFrame.document.readyState == "interactive" && + curFrame.document.baseURI.startsWith("about:")) { + callback(); + sendOk(command_id); + } else { + navTimer.initWithCallback(checkLoad, 100, Ci.nsITimer.TYPE_ONE_SHOT); + } + } + else { + callback(); + sendError("Error loading page, timed out (checkLoad)", 21, null, + command_id); + } + } + checkLoad(); +} + /** * Navigate to the given URL. The operation will be performed on the * current browser context, and handles the case where we navigate @@ -1411,67 +1468,56 @@ function multiAction(msg) { * (in chrome space). */ function get(msg) { - let command_id = msg.json.command_id; - - let checkTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); let start = new Date().getTime(); - let end = null; - function checkLoad() { - checkTimer.cancel(); - end = new Date().getTime(); - let aboutErrorRegex = /about:.+(error)\?/; - let elapse = end - start; - if (msg.json.pageTimeout == null || elapse <= msg.json.pageTimeout) { - if (curFrame.document.readyState == "complete") { - removeEventListener("DOMContentLoaded", onDOMContentLoaded, false); - sendOk(command_id); - } else if (curFrame.document.readyState == "interactive" && - aboutErrorRegex.exec(curFrame.document.baseURI) && - !curFrame.document.baseURI.startsWith(msg.json.url)) { - // We have reached an error url without requesting it. - removeEventListener("DOMContentLoaded", onDOMContentLoaded, false); - sendError("Error loading page", 13, null, command_id); - } else if (curFrame.document.readyState == "interactive" && - curFrame.document.baseURI.startsWith("about:")) { - removeEventListener("DOMContentLoaded", onDOMContentLoaded, false); - sendOk(command_id); - } else { - checkTimer.initWithCallback(checkLoad, 100, Ci.nsITimer.TYPE_ONE_SHOT); - } - } - else { - removeEventListener("DOMContentLoaded", onDOMContentLoaded, false); - sendError("Error loading page, timed out (checkLoad)", 21, null, - command_id); - } - } + // Prevent DOMContentLoaded events from frames from invoking this // code, unless the event is coming from the frame associated with // the current window (i.e. someone has used switch_to_frame). - let onDOMContentLoaded = function onDOMContentLoaded(event) { + onDOMContentLoaded = function onDOMContentLoaded(event) { if (!event.originalTarget.defaultView.frameElement || event.originalTarget.defaultView.frameElement == curFrame.frameElement) { - checkLoad(); + pollForReadyState(msg, start, () => { + removeEventListener("DOMContentLoaded", onDOMContentLoaded, false); + onDOMContentLoaded = null; + }); } }; function timerFunc() { removeEventListener("DOMContentLoaded", onDOMContentLoaded, false); sendError("Error loading page, timed out (onDOMContentLoaded)", 21, - null, command_id); + null, msg.json.command_id); } if (msg.json.pageTimeout != null) { - checkTimer.initWithCallback(timerFunc, msg.json.pageTimeout, Ci.nsITimer.TYPE_ONE_SHOT); + navTimer.initWithCallback(timerFunc, msg.json.pageTimeout, Ci.nsITimer.TYPE_ONE_SHOT); } addEventListener("DOMContentLoaded", onDOMContentLoaded, false); curFrame.location = msg.json.url; } + /** + * Cancel the polling and remove the event listener associated with a current + * navigation request in case we're interupted by an onbeforeunload handler + * and navigation doesn't complete. + */ +function cancelRequest() { + navTimer.cancel(); + if (onDOMContentLoaded) { + removeEventListener("DOMContentLoaded", onDOMContentLoaded, false); + } +} + /** * Get URL of the top level browsing context. */ function getCurrentUrl(msg) { - sendResponse({value: curFrame.location.href}, msg.json.command_id); + let url; + if (msg.json.isB2G) { + url = curFrame.location.href; + } else { + url = content.location.href; + } + sendResponse({value: url}, msg.json.command_id); } /** diff --git a/testing/marionette/marionette-server.js b/testing/marionette/marionette-server.js index 2208cc34e9..9249f1ccfd 100644 --- a/testing/marionette/marionette-server.js +++ b/testing/marionette/marionette-server.js @@ -289,8 +289,10 @@ MarionetteServerConnection.prototype = { } } else { - this.messageManager.broadcastAsyncMessage( - "Marionette:" + name + this.curBrowser.curFrameId, values); + this.curBrowser.executeWhenReady(() => { + this.messageManager.broadcastAsyncMessage( + "Marionette:" + name + this.curBrowser.curFrameId, values); + }); } return success; }, @@ -330,6 +332,11 @@ MarionetteServerConnection.prototype = { return; } } + + if (this.curBrowser !== null) { + this.curBrowser.pendingCommands = []; + } + this.conn.send(msg); if (command_id != -1) { // Don't unset this.command_id if this message is to process an @@ -1279,7 +1286,17 @@ MarionetteServerConnection.prototype = { */ get: function MDA_get(aRequest) { let command_id = this.command_id = this.getCommandId(); + if (this.context != "chrome") { + // If a remoteness update interrupts our page load, this will never return + // We need to re-issue this request to correctly poll for readyState and + // send errors. + this.curBrowser.pendingCommands.push(() => { + aRequest.parameters.command_id = command_id; + this.messageManager.broadcastAsyncMessage( + "Marionette:pollForReadyState" + this.curBrowser.curFrameId, + aRequest.parameters); + }); aRequest.command_id = command_id; aRequest.parameters.pageTimeout = this.pageTimeout; this.sendAsync("get", aRequest.parameters, command_id); @@ -1338,15 +1355,7 @@ MarionetteServerConnection.prototype = { this.sendResponse(this.getCurrentWindow().location.href, this.command_id); } else { - if (isB2G) { - this.sendAsync("getCurrentUrl", {}, this.command_id); - } - else { - this.sendResponse(this.curBrowser - .tab - .linkedBrowser - .contentWindowAsCPOW.location.href, this.command_id); - } + this.sendAsync("getCurrentUrl", {isB2G: isB2G}, this.command_id); } }, @@ -1440,6 +1449,13 @@ MarionetteServerConnection.prototype = { } }, + /** + * Forces an update for the given browser's id. + */ + updateIdForBrowser: function (browser, newId) { + this._browserIds.set(browser.permanentKey, newId); + }, + /** * Retrieves a listener id for the given xul browser element. In case * the browser is not known, an attempt is made to retrieve the id from @@ -1602,8 +1618,7 @@ MarionetteServerConnection.prototype = { this.curBrowser = this.browsers[outerId]; if (contentWindowId) { // The updated id corresponds to switching to a new tab. - this.curBrowser.curFrameId = contentWindowId; - win.gBrowser.selectTabAtIndex(ind); + this.curBrowser.switchToTab(ind); } this.sendOk(command_id); } @@ -3078,6 +3093,7 @@ MarionetteServerConnection.prototype = { } if (this.command_id) { + this.sendAsync("cancelRequest", {}); // This is a shortcut to get the client to accept our response whether // the expected key is 'ok' (in case a click or similar got us here) // or 'value' (in case an execute script or similar got us here). @@ -3220,8 +3236,9 @@ MarionetteServerConnection.prototype = { let mainContent = (this.curBrowser.mainContentId == null); if (!browserType || browserType != "content") { //curBrowser holds all the registered frames in knownFrames - let listenerId = this.generateFrameId(message.json.value); - reg.id = this.curBrowser.register(listenerId); + let uid = this.generateFrameId(message.json.value); + reg.id = uid; + reg.remotenessChange = this.curBrowser.register(uid, message.target); } // set to true if we updated mainContentId mainContent = ((mainContent == true) && (this.curBrowser.mainContentId != null)); @@ -3259,6 +3276,19 @@ MarionetteServerConnection.prototype = { globalMessageManager.broadcastAsyncMessage( "MarionetteMainListener:emitTouchEvent", message.json); return; + case "Marionette:listenersAttached": + if (message.json.listenerId === this.curBrowser.curFrameId) { + // If remoteness gets updated we need to call newSession. In the case + // of desktop this just sets up a small amount of state that doesn't + // change over the course of a session. + let newSessionValues = { + B2G: (appName == "B2G"), + raisesAccessibilityExceptions: this.sessionCapabilities.raisesAccessibilityExceptions + }; + this.sendAsync("newSession", newSessionValues); + this.curBrowser.flushPendingCommands(); + } + return; } } }; @@ -3376,15 +3406,49 @@ function BrowserObj(win, server) { this.setBrowser(win); this.frameManager = new FrameManager(server); //We should have one FM per BO so that we can handle modals in each Browser + // A reference to the tab corresponding to the current window handle, if any. + this.tab = null; + this.pendingCommands = []; + //register all message listeners this.frameManager.addMessageManagerListeners(server.messageManager); this.getIdForBrowser = server.getIdForBrowser.bind(server); + this.updateIdForBrowser = server.updateIdForBrowser.bind(server); + this._curFrameId = null; + this._browserWasRemote = null; + this._hasRemotenessChange = false; } BrowserObj.prototype = { - get tab () { - // A reference to the currently selected tab, if any - return this.browser ? this.browser.selectedTab : null; + + /** + * This function intercepts commands interacting with content and queues + * or executes them as needed. + * + * No commands interacting with content are safe to process until + * the new listener script is loaded and registers itself. + * This occurs when a command whose effect is asynchronous (such + * as goBack) results in a remoteness change and new commands + * are subsequently posted to the server. + */ + executeWhenReady: function (callback) { + if (this.hasRemotenessChange()) { + this.pendingCommands.push(callback); + } else { + callback(); + } + }, + + /** + * Re-sets this BrowserObject's current tab and updates remoteness tracking. + */ + switchToTab: function (ind) { + if (this.browser) { + this.browser.selectTabAtIndex(ind); + this.tab = this.browser.selectedTab; + } + this._browserWasRemote = this.browser.getBrowserForTab(this.tab).isRemoteBrowser; + this._hasRemotenessChange = false; }, /** @@ -3424,15 +3488,31 @@ BrowserObj.prototype = { break; } }, + + // The current frame id is managed per browser element on desktop in case + // the id needs to be refreshed. The currently selected window is identified + // within BrowserObject by a tab. + get curFrameId () { + if (appName != "Firefox") { + return this._curFrameId; + } + if (this.tab) { + let browser = this.browser.getBrowserForTab(this.tab); + return this.getIdForBrowser(browser); + } + return null; + }, + + set curFrameId (id) { + if (appName != "Firefox") { + this._curFrameId = id; + } + }, + /** * Called when we start a session with this browser. */ startSession: function BO_startSession(newSession, win, callback) { - if (appName == "Firefox" && - win.gMultiProcessBrowser && - !win.gBrowser.selectedBrowser.isRemoteBrowser) { - win.XULBrowserWindow.forceInitialBrowserRemote(); - } callback(win, newSession); }, @@ -3464,28 +3544,69 @@ BrowserObj.prototype = { * * @param string uid * frame uid for use by marionette + * @param the XUL that was the target of the originating message. */ - register: function BO_register(uid) { - if (this.curFrameId == null) { - let currWinId = null; + register: function BO_register(uid, target) { + let remotenessChange = this.hasRemotenessChange(); + if (this.curFrameId === null || remotenessChange) { if (this.browser) { // If we're setting up a new session on Firefox, we only process the - // registration for this frame if it belongs to the tab we've just - // created. + // registration for this frame if it belongs to the current tab. + if (!this.tab) { + this.switchToTab(this.browser.selectedIndex); + } + let browser = this.browser.getBrowserForTab(this.tab); - currWinId = this.getIdForBrowser(browser); - } - if ((!this.newSession) || - (this.newSession && - ((appName != "Firefox") || - uid === currWinId))) { - this.curFrameId = uid; + if (target == browser) { + this.updateIdForBrowser(browser, uid); + this.mainContentId = uid; + } + } else { + this._curFrameId = uid; this.mainContentId = uid; } } + this.knownFrames.push(uid); //used to delete sessions - return uid; + return remotenessChange; }, + + /** + * When navigating between pages results in changing a browser's process, we + * need to take measures not to lose contact with a listener script. This + * function does the necessary bookkeeping. + */ + hasRemotenessChange: function () { + // None of these checks are relevant on b2g or if we don't have a tab yet, + // and may not apply on Fennec. + if (appName != "Firefox" || this.tab === null) { + return false; + } + if (this._hasRemotenessChange) { + return true; + } + let currentIsRemote = this.browser.getBrowserForTab(this.tab).isRemoteBrowser; + this._hasRemotenessChange = this._browserWasRemote !== currentIsRemote; + this._browserWasRemote = currentIsRemote; + return this._hasRemotenessChange; + }, + + /** + * Flushes any pending commands queued when a remoteness change is being + * processed and mark this remotenessUpdate as complete. + */ + flushPendingCommands: function () { + if (!this._hasRemotenessChange) { + return; + } + + this._hasRemotenessChange = false; + this.pendingCommands.forEach((callback) => { + callback(); + }); + this.pendingCommands = []; + } + } /** diff --git a/toolkit/devtools/DevToolsUtils.js b/toolkit/devtools/DevToolsUtils.js index 0444adc8f0..0e087f3f6e 100644 --- a/toolkit/devtools/DevToolsUtils.js +++ b/toolkit/devtools/DevToolsUtils.js @@ -492,12 +492,26 @@ exports.fetch = function fetch(aURL, aOptions={ loadFromCache: true }) { default: let channel; try { - channel = Services.io.newChannel(url, null, null); + channel = Services.io.newChannel2(url, + null, + null, + null, // aLoadingNode + Services.scriptSecurityManager.getSystemPrincipal(), + null, // aTriggeringPrincipal + Ci.nsILoadInfo.SEC_NORMAL, + Ci.nsIContentPolicy.TYPE_OTHER); } catch (e if e.name == "NS_ERROR_UNKNOWN_PROTOCOL") { // On Windows xpcshell tests, c:/foo/bar can pass as a valid URL, but // newChannel won't be able to handle it. url = "file:///" + url; - channel = Services.io.newChannel(url, null, null); + channel = Services.io.newChannel2(url, + null, + null, + null, // aLoadingNode + Services.scriptSecurityManager.getSystemPrincipal(), + null, // aTriggeringPrincipal + Ci.nsILoadInfo.SEC_NORMAL, + Ci.nsIContentPolicy.TYPE_OTHER); } let chunks = []; let streamListener = { diff --git a/toolkit/devtools/server/actors/settings.js b/toolkit/devtools/server/actors/settings.js index 0455203d77..ebf49d25b3 100644 --- a/toolkit/devtools/server/actors/settings.js +++ b/toolkit/devtools/server/actors/settings.js @@ -23,7 +23,14 @@ exports.unregister = function(handle) { }; function getDefaultSettings() { - let chan = NetUtil.newChannel(settingsFile); + let chan = NetUtil.newChannel2(settingsFile, + null, + null, + null, // aLoadingNode + Services.scriptSecurityManager.getSystemPrincipal(), + null, // aTriggeringPrincipal + Ci.nsILoadInfo.SEC_NORMAL, + Ci.nsIContentPolicy.TYPE_OTHER); let stream = chan.open(); // Obtain a converter to read from a UTF-8 encoded input stream. let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"] diff --git a/widget/android/nsWindow.cpp b/widget/android/nsWindow.cpp index 6fcd388159..d7ea876d67 100644 --- a/widget/android/nsWindow.cpp +++ b/widget/android/nsWindow.cpp @@ -76,6 +76,7 @@ static gfxIntSize gAndroidScreenBounds; #include "mozilla/layers/CompositorParent.h" #include "mozilla/layers/LayerTransactionParent.h" #include "mozilla/Mutex.h" +#include "mozilla/Services.h" #include "nsThreadUtils.h" class ContentCreationNotifier; @@ -100,8 +101,8 @@ public: ContentParent* cp = static_cast(cpo.get()); unused << cp->SendScreenSizeChanged(gAndroidScreenBounds); } else if (!strcmp(aTopic, "xpcom-shutdown")) { - nsCOMPtr - obs(do_GetService("@mozilla.org/observer-service;1")); + nsCOMPtr obs = + mozilla::services::GetObserverService(); if (obs) { obs->RemoveObserver(static_cast(this), "xpcom-shutdown"); @@ -823,7 +824,8 @@ nsWindow::OnGlobalAndroidEvent(AndroidGoannaEvent *ae) // If the content process is not created yet, wait until it's // created and then tell it the screen size. - nsCOMPtr obs = do_GetService("@mozilla.org/observer-service;1"); + nsCOMPtr obs = + mozilla::services::GetObserverService(); if (!obs) break; diff --git a/widget/cocoa/nsToolkit.mm b/widget/cocoa/nsToolkit.mm index fbf12230a6..4d0222d5d3 100644 --- a/widget/cocoa/nsToolkit.mm +++ b/widget/cocoa/nsToolkit.mm @@ -35,6 +35,7 @@ extern "C" { #include "nsIServiceManager.h" #include "mozilla/Preferences.h" +#include "mozilla/Services.h" using namespace mozilla; @@ -61,7 +62,7 @@ nsToolkit::~nsToolkit() void nsToolkit::PostSleepWakeNotification(const char* aNotification) { - nsCOMPtr observerService = do_GetService("@mozilla.org/observer-service;1"); + nsCOMPtr observerService = services::GetObserverService(); if (observerService) observerService->NotifyObservers(nullptr, aNotification, nullptr); } diff --git a/xpcom/base/nsMemoryReporterManager.cpp b/xpcom/base/nsMemoryReporterManager.cpp index 5993dc994f..7ead5fc38d 100644 --- a/xpcom/base/nsMemoryReporterManager.cpp +++ b/xpcom/base/nsMemoryReporterManager.cpp @@ -1289,8 +1289,7 @@ nsMemoryReporterManager::GetReportsExtended( // Request memory reports from child processes. We do this *before* // collecting reports for this process so each process can collect // reports in parallel. - nsCOMPtr obs = - do_GetService("@mozilla.org/observer-service;1"); + nsCOMPtr obs = services::GetObserverService(); NS_ENSURE_STATE(obs); nsPrintfCString genStr("generation=%x anonymize=%d minimize=%d DMDident=", diff --git a/xpfe/appshell/nsAppShellService.cpp b/xpfe/appshell/nsAppShellService.cpp index 7b5e83379e..0b52f29f42 100644 --- a/xpfe/appshell/nsAppShellService.cpp +++ b/xpfe/appshell/nsAppShellService.cpp @@ -40,6 +40,7 @@ #include "mozilla/Attributes.h" #include "mozilla/Preferences.h" +#include "mozilla/Services.h" #include "mozilla/StartupTimeline.h" #include "nsEmbedCID.h" @@ -63,8 +64,7 @@ nsAppShellService::nsAppShellService() : mModalWindowCount(0), mApplicationProvidedHiddenWindow(false) { - nsCOMPtr obs - (do_GetService("@mozilla.org/observer-service;1")); + nsCOMPtr obs = services::GetObserverService(); if (obs) { obs->AddObserver(this, "xpcom-will-shutdown", false); @@ -807,8 +807,7 @@ nsAppShellService::RegisterTopLevelWindow(nsIXULWindow* aWindow) } // an ongoing attempt to quit is stopped by a newly opened window - nsCOMPtr obssvc = - do_GetService("@mozilla.org/observer-service;1"); + nsCOMPtr obssvc = services::GetObserverService(); NS_ASSERTION(obssvc, "Couldn't get observer service."); if (obssvc) diff --git a/xpfe/appshell/nsXULWindow.cpp b/xpfe/appshell/nsXULWindow.cpp index bdc2e191a0..0beecb97b3 100644 --- a/xpfe/appshell/nsXULWindow.cpp +++ b/xpfe/appshell/nsXULWindow.cpp @@ -55,6 +55,7 @@ #include "prenv.h" #include "mozilla/AutoRestore.h" #include "mozilla/Preferences.h" +#include "mozilla/Services.h" #include "mozilla/dom/BarProps.h" #include "mozilla/dom/Element.h" #include "mozilla/dom/Event.h" @@ -509,8 +510,7 @@ NS_IMETHODIMP nsXULWindow::Destroy() is destroyed, because onunload handlers fire then, and those being script, anything could happen. A new window could open, even. See bug 130719. */ - nsCOMPtr obssvc = - do_GetService("@mozilla.org/observer-service;1"); + nsCOMPtr obssvc = services::GetObserverService(); NS_ASSERTION(obssvc, "Couldn't get observer service?"); if (obssvc) @@ -816,8 +816,7 @@ NS_IMETHODIMP nsXULWindow::SetVisibility(bool aVisibility) windowMediator->UpdateWindowTimeStamp(static_cast(this)); // notify observers so that we can hide the splash screen if possible - nsCOMPtr obssvc - (do_GetService("@mozilla.org/observer-service;1")); + nsCOMPtr obssvc = services::GetObserverService(); NS_ASSERTION(obssvc, "Couldn't get observer service."); if (obssvc) { obssvc->NotifyObservers(nullptr, "xul-window-visible", nullptr);