Merge last PGO-green changeset of mozilla-inbound to mozilla-central

This commit is contained in:
Ed Morley 2012-05-28 14:13:56 +01:00
commit 13dfef4805
39 changed files with 636 additions and 571 deletions

View File

@ -302,32 +302,21 @@ IDRefsIterator::GetElem(const nsDependentSubstring& aID)
// If content is in anonymous subtree or an element having anonymous subtree
// then use "anonid" attribute to get elements in anonymous subtree.
nsCOMPtr<nsIDOMElement> refDOMElm;
nsCOMPtr<nsIDOMDocumentXBL> xblDocument =
do_QueryInterface(mContent->OwnerDoc());
// Check inside the binding the element is contained in.
nsIContent* bindingParent = mContent->GetBindingParent();
if (bindingParent) {
nsCOMPtr<nsIDOMElement> bindingParentElm = do_QueryInterface(bindingParent);
xblDocument->GetAnonymousElementByAttribute(bindingParentElm,
NS_LITERAL_STRING("anonid"),
aID,
getter_AddRefs(refDOMElm));
nsCOMPtr<dom::Element> refElm = do_QueryInterface(refDOMElm);
nsIContent* refElm = bindingParent->OwnerDoc()->
GetAnonymousElementByAttribute(bindingParent, nsGkAtoms::anonid, aID);
if (refElm)
return refElm;
}
// Check inside the binding of the element.
if (mContent->OwnerDoc()->BindingManager()->GetBinding(mContent)) {
nsCOMPtr<nsIDOMElement> elm = do_QueryInterface(mContent);
xblDocument->GetAnonymousElementByAttribute(elm,
NS_LITERAL_STRING("anonid"),
aID,
getter_AddRefs(refDOMElm));
nsCOMPtr<dom::Element> refElm = do_QueryInterface(refDOMElm);
return refElm;
return mContent->OwnerDoc()->
GetAnonymousElementByAttribute(mContent, nsGkAtoms::anonid, aID);
}
return nsnull;

View File

@ -12,8 +12,6 @@
#include "nscore.h"
#include "DocAccessible.h"
#include "nsIDOMDocumentXBL.h"
/**
* AccIterable is a basic interface for iterators over accessibles.
*/

View File

@ -24,13 +24,8 @@
#include "StyleInfo.h"
#include "nsContentUtils.h"
#include "nsIDOMCSSValue.h"
#include "nsIDOMCSSPrimitiveValue.h"
#include "nsIDOMElement.h"
#include "nsIDOMDocument.h"
#include "nsIDOMDocumentXBL.h"
#include "nsIDOMHTMLDocument.h"
#include "nsIDOMHTMLFormElement.h"
#include "nsIDOMNodeFilter.h"
#include "nsIDOMHTMLElement.h"
#include "nsIDOMTreeWalker.h"
@ -2096,20 +2091,12 @@ nsAccessible::RelationByType(PRUint32 aType)
}
}
if (!buttonEl) { // Check for anonymous accept button in <dialog>
nsCOMPtr<nsIDOMDocumentXBL> xblDoc(do_QueryInterface(xulDoc));
if (xblDoc) {
nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(xulDoc);
NS_ASSERTION(domDoc, "No DOM document");
nsCOMPtr<nsIDOMElement> rootEl;
domDoc->GetDocumentElement(getter_AddRefs(rootEl));
if (rootEl) {
nsCOMPtr<nsIDOMElement> possibleButtonEl;
xblDoc->GetAnonymousElementByAttribute(rootEl,
NS_LITERAL_STRING("default"),
NS_LITERAL_STRING("true"),
getter_AddRefs(possibleButtonEl));
buttonEl = do_QueryInterface(possibleButtonEl);
}
dom::Element* rootElm = mContent->OwnerDoc()->GetRootElement();
if (rootElm) {
nsIContent* possibleButtonEl = rootElm->OwnerDoc()->
GetAnonymousElementByAttribute(rootElm, nsGkAtoms::_default,
NS_LITERAL_STRING("true"));
buttonEl = do_QueryInterface(possibleButtonEl);
}
}
nsCOMPtr<nsIContent> relatedContent(do_QueryInterface(buttonEl));

View File

@ -9,8 +9,6 @@
#include "Role.h"
#include "States.h"
#include "nsIDOMDocument.h"
#include "nsIDOMDocumentXBL.h"
#include "nsIFrame.h"
using namespace mozilla::a11y;
@ -42,19 +40,20 @@ nsXULSliderAccessible::NativeRole()
PRUint64
nsXULSliderAccessible::NativeState()
{
PRUint64 states = nsAccessibleWrap::NativeState();
PRUint64 state = nsAccessibleWrap::NativeState();
nsCOMPtr<nsIContent> sliderContent(GetSliderNode());
NS_ENSURE_STATE(sliderContent);
nsIContent* sliderElm = GetSliderElement();
if (!sliderElm)
return state;
nsIFrame *frame = sliderContent->GetPrimaryFrame();
nsIFrame *frame = sliderElm->GetPrimaryFrame();
if (frame && frame->IsFocusable())
states |= states::FOCUSABLE;
state |= states::FOCUSABLE;
if (FocusMgr()->IsFocused(this))
states |= states::FOCUSED;
state |= states::FOCUSED;
return states;
return state;
}
// nsIAccessible
@ -87,10 +86,10 @@ nsXULSliderAccessible::DoAction(PRUint8 aIndex)
{
NS_ENSURE_ARG(aIndex == 0);
nsCOMPtr<nsIContent> sliderContent(GetSliderNode());
NS_ENSURE_STATE(sliderContent);
nsIContent* sliderElm = GetSliderElement();
if (sliderElm)
DoCommand(sliderElm);
DoCommand(sliderContent);
return NS_OK;
}
@ -165,30 +164,17 @@ nsXULSliderAccessible::CanHaveAnonChildren()
// Utils
already_AddRefed<nsIContent>
nsXULSliderAccessible::GetSliderNode()
nsIContent*
nsXULSliderAccessible::GetSliderElement()
{
if (IsDefunct())
return nsnull;
if (!mSliderNode) {
nsCOMPtr<nsIDOMDocumentXBL> xblDoc(do_QueryInterface(mContent->OwnerDoc()));
if (!xblDoc)
return nsnull;
// XXX: we depend on anonymous content.
nsCOMPtr<nsIDOMElement> domElm(do_QueryInterface(mContent));
if (!domElm)
return nsnull;
xblDoc->GetAnonymousElementByAttribute(domElm, NS_LITERAL_STRING("anonid"),
NS_LITERAL_STRING("slider"),
getter_AddRefs(mSliderNode));
mSliderNode = mContent->OwnerDoc()->
GetAnonymousElementByAttribute(mContent, nsGkAtoms::anonid,
NS_LITERAL_STRING("slider"));
}
nsIContent *sliderNode = nsnull;
nsresult rv = CallQueryInterface(mSliderNode, &sliderNode);
return NS_FAILED(rv) ? nsnull : sliderNode;
return mSliderNode;
}
nsresult
@ -199,10 +185,10 @@ nsXULSliderAccessible::GetSliderAttr(nsIAtom *aName, nsAString& aValue)
if (IsDefunct())
return NS_ERROR_FAILURE;
nsCOMPtr<nsIContent> sliderNode(GetSliderNode());
NS_ENSURE_STATE(sliderNode);
nsIContent* sliderElm = GetSliderElement();
if (sliderElm)
sliderElm->GetAttr(kNameSpaceID_None, aName, aValue);
sliderNode->GetAttr(kNameSpaceID_None, aName, aValue);
return NS_OK;
}
@ -212,10 +198,10 @@ nsXULSliderAccessible::SetSliderAttr(nsIAtom *aName, const nsAString& aValue)
if (IsDefunct())
return NS_ERROR_FAILURE;
nsCOMPtr<nsIContent> sliderNode(GetSliderNode());
NS_ENSURE_STATE(sliderNode);
nsIContent* sliderElm = GetSliderElement();
if (sliderElm)
sliderElm->SetAttr(kNameSpaceID_None, aName, aValue, true);
sliderNode->SetAttr(kNameSpaceID_None, aName, aValue, true);
return NS_OK;
}

View File

@ -38,7 +38,10 @@ public:
virtual PRUint8 ActionCount();
protected:
already_AddRefed<nsIContent> GetSliderNode();
/**
* Return anonymous slider element.
*/
nsIContent* GetSliderElement();
nsresult GetSliderAttr(nsIAtom *aName, nsAString& aValue);
nsresult SetSliderAttr(nsIAtom *aName, const nsAString& aValue);
@ -47,7 +50,7 @@ protected:
nsresult SetSliderAttr(nsIAtom *aName, double aValue);
private:
nsCOMPtr<nsIDOMElement> mSliderNode;
nsCOMPtr<nsIContent> mSliderNode;
};

View File

@ -259,6 +259,14 @@ panel[noactions] > richlistbox > richlistitem[type~="action"] > .ac-url-box > .a
visibility: collapse;
}
#urlbar[pageproxystate="invalid"] > #identity-box > #identity-box-inner > #identity-icon-labels {
visibility: collapse;
}
#urlbar[pageproxystate="invalid"] > #identity-box {
pointer-events: none;
}
#identity-icon-labels {
max-width: 18em;
}

View File

@ -8398,10 +8398,10 @@ var gIdentityHandler = {
event.keyCode != KeyEvent.DOM_VK_RETURN))
return; // Left click, space or enter only
// Revert the contents of the location bar, see bug 406779
gURLBar.handleRevert();
if (this._mode == this.IDENTITY_MODE_CHROMEUI)
// Don't allow left click, space or enter if the location
// is chrome UI or the location has been modified.
if (this._mode == this.IDENTITY_MODE_CHROMEUI ||
gURLBar.getAttribute("pageproxystate") != "valid")
return;
// Make sure that the display:none style we set in xul is removed now that

View File

@ -1001,15 +1001,15 @@ toolbar[iconsize="small"] #feed-button {
-moz-image-region: rect(0, 16px, 16px, 0);
}
.verifiedDomain > #identity-box-inner > #page-proxy-stack > #page-proxy-favicon {
.verifiedDomain > #identity-box-inner > #page-proxy-stack > #page-proxy-favicon[pageproxystate="valid"] {
list-style-image: url(chrome://browser/skin/identity-icons-https.png);
}
.verifiedIdentity > #identity-box-inner > #page-proxy-stack > #page-proxy-favicon {
.verifiedIdentity > #identity-box-inner > #page-proxy-stack > #page-proxy-favicon[pageproxystate="valid"] {
list-style-image: url(chrome://browser/skin/identity-icons-https-ev.png);
}
.mixedContent > #identity-box-inner > #page-proxy-stack > #page-proxy-favicon {
.mixedContent > #identity-box-inner > #page-proxy-stack > #page-proxy-favicon[pageproxystate="valid"] {
list-style-image: url(chrome://browser/skin/identity-icons-https-mixed.png);
}
@ -1054,7 +1054,7 @@ toolbar[iconsize="small"] #feed-button {
-moz-padding-end: 5px;
}
#identity-box.verifiedIdentity {
#urlbar[pageproxystate="valid"] > #identity-box.verifiedIdentity {
background-color: #fff;
color: hsl(92,100%,30%);
-moz-margin-end: 4px;

View File

@ -983,7 +983,7 @@ toolbar[mode="icons"] #zoom-in-button {
padding-right: 10.01px;
}
#identity-box.verifiedIdentity {
#urlbar[pageproxystate="valid"] > #identity-box.verifiedIdentity {
color: hsl(92,100%,30%);
-moz-padding-end: 4px;
background-image: -moz-linear-gradient(hsla(92,81%,16%,0),
@ -1058,15 +1058,15 @@ toolbar[mode="icons"] #zoom-in-button {
-moz-image-region: rect(0, 16px, 16px, 0);
}
.verifiedDomain > #identity-box-inner > #page-proxy-stack > #page-proxy-favicon {
.verifiedDomain > #identity-box-inner > #page-proxy-stack > #page-proxy-favicon[pageproxystate="valid"] {
list-style-image: url(chrome://browser/skin/identity-icons-https.png);
}
.verifiedIdentity > #identity-box-inner > #page-proxy-stack > #page-proxy-favicon {
.verifiedIdentity > #identity-box-inner > #page-proxy-stack > #page-proxy-favicon[pageproxystate="valid"] {
list-style-image: url(chrome://browser/skin/identity-icons-https-ev.png);
}
.mixedContent > #identity-box-inner > #page-proxy-stack > #page-proxy-favicon {
.mixedContent > #identity-box-inner > #page-proxy-stack > #page-proxy-favicon[pageproxystate="valid"] {
list-style-image: url(chrome://browser/skin/identity-icons-https-mixed.png);
}
@ -1076,7 +1076,7 @@ toolbar[mode="icons"] #zoom-in-button {
}
#page-proxy-favicon[pageproxystate="invalid"] {
opacity: 0.5;
opacity: 0.3;
}
#wrapper-urlbar-container[place="palette"] {

View File

@ -1363,7 +1363,7 @@ html|*.urlbar-input:-moz-lwtheme:-moz-placeholder,
padding-right: 5.01px;
}
#identity-box.verifiedIdentity {
#urlbar[pageproxystate="valid"] > #identity-box.verifiedIdentity {
color: hsl(92,100%,30%);
-moz-margin-end: 4px;
background-image: -moz-linear-gradient(hsla(92,81%,16%,0),
@ -1430,15 +1430,15 @@ html|*.urlbar-input:-moz-lwtheme:-moz-placeholder,
-moz-image-region: rect(0, 16px, 16px, 0);
}
.verifiedDomain > #identity-box-inner > #page-proxy-stack > #page-proxy-favicon {
.verifiedDomain > #identity-box-inner > #page-proxy-stack > #page-proxy-favicon[pageproxystate="valid"] {
list-style-image: url(chrome://browser/skin/identity-icons-https.png);
}
.verifiedIdentity > #identity-box-inner > #page-proxy-stack > #page-proxy-favicon {
.verifiedIdentity > #identity-box-inner > #page-proxy-stack > #page-proxy-favicon[pageproxystate="valid"] {
list-style-image: url(chrome://browser/skin/identity-icons-https-ev.png);
}
.mixedContent > #identity-box-inner > #page-proxy-stack > #page-proxy-favicon {
.mixedContent > #identity-box-inner > #page-proxy-stack > #page-proxy-favicon[pageproxystate="valid"] {
list-style-image: url(chrome://browser/skin/identity-icons-https-mixed.png);
}
@ -1452,7 +1452,7 @@ html|*.urlbar-input:-moz-lwtheme:-moz-placeholder,
}
#page-proxy-favicon[pageproxystate="invalid"] {
opacity: 0.5;
opacity: 0.3;
}
/* autocomplete */

View File

@ -1,5 +1,5 @@
/* 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/. */
# 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/.
hwcap_1 = OVERRIDE;

View File

@ -92,8 +92,8 @@ class Element;
} // namespace mozilla
#define NS_IDOCUMENT_IID \
{ 0x88d887da, 0xd228, 0x41c2, \
{ 0xb8, 0x0a, 0x42, 0xec, 0xf0, 0xcb, 0xce, 0x37 } }
{ 0x7bac702d, 0xca67, 0x4ce1, \
{ 0x80, 0x3c, 0x35, 0xde, 0x81, 0x26, 0x04, 0x97 } }
// Flag for AddStyleSheet().
#define NS_STYLESHEET_FROM_CATALOG (1 << 0)
@ -1113,6 +1113,14 @@ public:
virtual nsresult GetContentListFor(nsIContent* aContent,
nsIDOMNodeList** aResult) = 0;
/**
* See GetAnonymousElementByAttribute on nsIDOMDocumentXBL.
*/
virtual nsIContent*
GetAnonymousElementByAttribute(nsIContent* aElement,
nsIAtom* aAttrName,
const nsAString& aAttrValue) const = 0;
/**
* Helper for nsIDOMDocument::elementFromPoint implementation that allows
* ignoring the scroll frame and/or avoiding layout flushes.

View File

@ -4931,29 +4931,52 @@ nsDocument::GetBindingParent(nsIDOMNode* aNode, nsIDOMElement** aResult)
return NS_OK;
}
static nsresult
static nsIContent*
GetElementByAttribute(nsIContent* aContent, nsIAtom* aAttrName,
const nsAString& aAttrValue, bool aUniversalMatch,
nsIDOMElement** aResult)
const nsAString& aAttrValue, bool aUniversalMatch)
{
if (aUniversalMatch ? aContent->HasAttr(kNameSpaceID_None, aAttrName) :
aContent->AttrValueIs(kNameSpaceID_None, aAttrName,
aAttrValue, eCaseMatters)) {
return CallQueryInterface(aContent, aResult);
return aContent;
}
for (nsIContent* child = aContent->GetFirstChild();
child;
child = child->GetNextSibling()) {
GetElementByAttribute(child, aAttrName, aAttrValue, aUniversalMatch,
aResult);
if (*aResult)
return NS_OK;
nsIContent* matchedContent =
GetElementByAttribute(child, aAttrName, aAttrValue, aUniversalMatch);
if (matchedContent)
return matchedContent;
}
return NS_OK;
return nsnull;
}
nsIContent*
nsDocument::GetAnonymousElementByAttribute(nsIContent* aElement,
nsIAtom* aAttrName,
const nsAString& aAttrValue) const
{
nsINodeList* nodeList = BindingManager()->GetAnonymousNodesFor(aElement);
if (!nodeList)
return nsnull;
PRUint32 length = 0;
nodeList->GetLength(&length);
bool universalMatch = aAttrValue.EqualsLiteral("*");
for (PRUint32 i = 0; i < length; ++i) {
nsIContent* current = nodeList->GetNodeAt(i);
nsIContent* matchedElm =
GetElementByAttribute(current, aAttrName, aAttrValue, universalMatch);
if (matchedElm)
return matchedElm;
}
return nsnull;
}
NS_IMETHODIMP
@ -4964,32 +4987,12 @@ nsDocument::GetAnonymousElementByAttribute(nsIDOMElement* aElement,
{
*aResult = nsnull;
nsCOMPtr<nsIDOMNodeList> nodeList;
GetAnonymousNodes(aElement, getter_AddRefs(nodeList));
if (!nodeList)
return NS_OK;
nsCOMPtr<nsIAtom> attribute = do_GetAtom(aAttrName);
nsCOMPtr<nsIContent> content(do_QueryInterface(aElement));
PRUint32 length;
nodeList->GetLength(&length);
bool universalMatch = aAttrValue.EqualsLiteral("*");
for (PRUint32 i = 0; i < length; ++i) {
nsCOMPtr<nsIDOMNode> current;
nodeList->Item(i, getter_AddRefs(current));
nsCOMPtr<nsIContent> content(do_QueryInterface(current));
GetElementByAttribute(content, attribute, aAttrValue, universalMatch,
aResult);
if (*aResult)
return NS_OK;
}
return NS_OK;
nsIContent* matchedContent =
GetAnonymousElementByAttribute(content, attribute, aAttrValue);
return matchedContent ? CallQueryInterface(matchedContent, aResult) : NS_OK;
}

View File

@ -796,6 +796,10 @@ public:
nsIDOMNodeList** aResult);
virtual NS_HIDDEN_(nsresult) GetContentListFor(nsIContent* aContent,
nsIDOMNodeList** aResult);
virtual NS_HIDDEN_(nsIContent*)
GetAnonymousElementByAttribute(nsIContent* aElement,
nsIAtom* aAttrName,
const nsAString& aAttrValue) const;
virtual NS_HIDDEN_(nsresult) ElementFromPointHelper(float aX, float aY,
bool aIgnoreRootScrollFrame,

View File

@ -159,6 +159,10 @@ public:
// (no data has arrived for a while).
void DownloadStalled();
// Called by the media decoder to indicate whether the media cache has
// suspended the channel.
void NotifySuspendedByCache(bool aIsSuspended);
// Called when a "MozAudioAvailable" event listener is added. The media
// element will then notify its decoder that it needs to make a copy of
// the audio data sent to hardware and dispatch it in "mozaudioavailable"
@ -833,7 +837,7 @@ protected:
// due to loading a preload:none media. When true, the resource we'll
// load when the user initiates either playback or an explicit load is
// stored in mPreloadURI.
bool mLoadIsSuspended;
bool mSuspendedForPreloadNone;
// True if a same-origin check has been done for the media element and resource.
bool mMediaSecurityVerified;
@ -843,6 +847,9 @@ protected:
// True if the media has an audio track
bool mHasAudio;
// True if the media's channel's download has been suspended.
bool mDownloadSuspendedByCache;
};
#endif

View File

@ -593,7 +593,8 @@ void nsHTMLMediaElement::AbortExistingLoads()
mSuspendedAfterFirstFrame = false;
mAllowSuspendAfterFirstFrame = true;
mHaveQueuedSelectResource = false;
mLoadIsSuspended = false;
mSuspendedForPreloadNone = false;
mDownloadSuspendedByCache = false;
mSourcePointer = nsnull;
// TODO: The playback rate must be set to the default playback rate.
@ -905,7 +906,7 @@ void nsHTMLMediaElement::LoadFromSourceChildren()
void nsHTMLMediaElement::SuspendLoad()
{
mLoadIsSuspended = true;
mSuspendedForPreloadNone = true;
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_IDLE;
DispatchAsyncEvent(NS_LITERAL_STRING("suspend"));
ChangeDelayLoadStatus(false);
@ -913,8 +914,9 @@ void nsHTMLMediaElement::SuspendLoad()
void nsHTMLMediaElement::ResumeLoad(PreloadAction aAction)
{
NS_ASSERTION(mLoadIsSuspended, "Can only resume preload if halted for one");
mLoadIsSuspended = false;
NS_ASSERTION(mSuspendedForPreloadNone,
"Must be halted for preload:none to resume from preload:none suspended load.");
mSuspendedForPreloadNone = false;
mPreloadAction = aAction;
ChangeDelayLoadStatus(true);
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_LOADING;
@ -987,7 +989,7 @@ void nsHTMLMediaElement::UpdatePreloadAction()
mPreloadAction = nextAction;
if (nextAction == nsHTMLMediaElement::PRELOAD_ENOUGH) {
if (mLoadIsSuspended) {
if (mSuspendedForPreloadNone) {
// Our load was previouly suspended due to the media having preload
// value "none". The preload value has changed to preload:auto, so
// resume the load.
@ -1001,7 +1003,7 @@ void nsHTMLMediaElement::UpdatePreloadAction()
} else if (nextAction == nsHTMLMediaElement::PRELOAD_METADATA) {
// Ensure that the video can be suspended after first frame.
mAllowSuspendAfterFirstFrame = true;
if (mLoadIsSuspended) {
if (mSuspendedForPreloadNone) {
// Our load was previouly suspended due to the media having preload
// value "none". The preload value has changed to preload:metadata, so
// resume the load. We'll pause the load again after we've read the
@ -1650,10 +1652,11 @@ nsHTMLMediaElement::nsHTMLMediaElement(already_AddRefed<nsINodeInfo> aNodeInfo)
mHasPlayedOrSeeked(false),
mHasSelfReference(false),
mShuttingDown(false),
mLoadIsSuspended(false),
mSuspendedForPreloadNone(false),
mMediaSecurityVerified(false),
mCORSMode(CORS_NONE),
mHasAudio(false)
mHasAudio(false),
mDownloadSuspendedByCache(false)
{
#ifdef PR_LOGGING
if (!gMediaElementLog) {
@ -1733,7 +1736,7 @@ NS_IMETHODIMP nsHTMLMediaElement::Play()
nsresult rv = Load();
NS_ENSURE_SUCCESS(rv, rv);
}
if (mLoadIsSuspended) {
if (mSuspendedForPreloadNone) {
ResumeLoad(PRELOAD_ENOUGH);
}
// Even if we just did Load() or ResumeLoad(), we could already have a decoder
@ -2636,6 +2639,20 @@ void nsHTMLMediaElement::FirstFrameLoaded(bool aResourceFullyLoaded)
mPreloadAction == nsHTMLMediaElement::PRELOAD_METADATA) {
mSuspendedAfterFirstFrame = true;
mDecoder->Suspend();
} else if (mLoadedFirstFrame &&
mDownloadSuspendedByCache &&
mDecoder &&
!mDecoder->IsEnded()) {
// We've already loaded the first frame, and the decoder has signalled
// that the download has been suspended by the media cache. So move
// readyState into HAVE_ENOUGH_DATA, in case there's script waiting
// for a "canplaythrough" event; without this forced transition, we will
// never fire the "canplaythrough" event if the media cache is so small
// that the download was suspended before the first frame was loaded.
// Don't force this transition if the decoder is in ended state; the
// readyState should remain at HAVE_CURRENT_DATA in this case.
ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA);
return;
}
}
@ -2734,6 +2751,7 @@ void nsHTMLMediaElement::PlaybackEnded()
void nsHTMLMediaElement::SeekStarted()
{
DispatchAsyncEvent(NS_LITERAL_STRING("seeking"));
ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_METADATA);
FireTimeUpdate(false);
}
@ -2746,6 +2764,11 @@ void nsHTMLMediaElement::SeekCompleted()
AddRemoveSelfReference();
}
void nsHTMLMediaElement::NotifySuspendedByCache(bool aIsSuspended)
{
mDownloadSuspendedByCache = aIsSuspended;
}
void nsHTMLMediaElement::DownloadSuspended()
{
DispatchAsyncEvent(NS_LITERAL_STRING("progress"));
@ -2786,6 +2809,21 @@ void nsHTMLMediaElement::UpdateReadyStateForData(NextFrameStatus aNextFrame)
return;
}
if (mReadyState > nsIDOMHTMLMediaElement::HAVE_METADATA &&
mDownloadSuspendedByCache &&
mDecoder &&
!mDecoder->IsEnded()) {
// The decoder has signalled that the download has been suspended by the
// media cache. So move readyState into HAVE_ENOUGH_DATA, in case there's
// script waiting for a "canplaythrough" event; without this forced
// transition, we will never fire the "canplaythrough" event if the
// media cache is too small, and scripts are bound to fail. Don't force
// this transition if the decoder is in ended state; the readyState
// should remain at HAVE_CURRENT_DATA in this case.
ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA);
return;
}
if (aNextFrame != NEXT_FRAME_AVAILABLE) {
ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA);
if (!mWaitingFired && aNextFrame == NEXT_FRAME_UNAVAILABLE_BUFFERING) {

View File

@ -647,10 +647,14 @@ void nsBuiltinDecoder::NotifySuspendedStatusChanged()
MediaResource* activeStream;
bool suspended = mResource->IsSuspendedByCache(&activeStream);
if (suspended && mElement) {
// if this is an autoplay element, we need to kick off its autoplaying
// now so we consume data and hopefully free up cache space
mElement->NotifyAutoplayDataReady();
if (mElement) {
if (suspended) {
// If this is an autoplay element, we need to kick off its autoplaying
// now so we consume data and hopefully free up cache space.
mElement->NotifyAutoplayDataReady();
}
mElement->NotifySuspendedByCache(suspended);
UpdateReadyStateForData();
}
}

View File

@ -28,7 +28,7 @@ class gfxImageSurface;
* the content it then releases the read lock.
*/
class gfxReusableSurfaceWrapper {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(gfxReusableSurfaceWrapper);
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(gfxReusableSurfaceWrapper)
public:
/**
* Pass the gfxASurface to the wrapper.

View File

@ -22,7 +22,7 @@ CPPSRCS = \
nsPosixLocale.cpp \
$(NULL)
ifeq (android,$(MOZ_WIDGET_TOOLKIT))
ifeq (Android,$(OS_TARGET))
CPPSRCS += nsAndroidCharset.cpp
else
CPPSRCS += nsUNIXCharset.cpp

View File

@ -1,5 +1,5 @@
/* 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/. */
# 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/.
hwcap_1 = OVERRIDE;

View File

@ -205,7 +205,13 @@ nsMathMLmpaddedFrame::ParseAttribute(nsString& aString,
aPseudoUnit = NS_MATHML_PSEUDO_UNIT_ITSELF;
return true;
} else {
// The REC does not allow the case ["+"|"-"] unsigned-number
// case ["+"|"-"] unsigned-number
// XXXfredw: should we allow non-zero unitless values? See bug 757703.
if (!floatValue) {
aCSSValue.SetFloatValue(floatValue, eCSSUnit_Number);
aPseudoUnit = NS_MATHML_PSEUDO_UNIT_ITSELF;
return true;
}
}
}
else if (unit.EqualsLiteral("width")) aPseudoUnit = NS_MATHML_PSEUDO_UNIT_WIDTH;
@ -225,7 +231,6 @@ nsMathMLmpaddedFrame::ParseAttribute(nsString& aString,
}
// see if the input was just a CSS value
// We use a specific flag to indicate that the call is made from mpadded.
// We are not supposed to have a unitless, percent, negative or namedspace
// value here.
number.Append(unit); // leave the sign out if it was there

View File

@ -14,6 +14,7 @@
#include "nsISVGChildFrame.h"
#include "nsQueryFrame.h"
#include "nsRect.h"
#include "nsSVGUtils.h"
class nsFrameList;
class nsIContent;

View File

@ -32,6 +32,9 @@ endif
ifeq ($(OS_ARCH),AIX)
DEFINES += -Dalloca=__alloca
endif
ifeq ($(OS_ARCH),SunOS)
DEFINES += -DHAVE_ALLOCA_H
endif
EXPORTS_NAMESPACES = opus

View File

@ -104,6 +104,14 @@ struct ParamTraits<nsHttpHeaderArray::nsEntry>
}
};
template<>
struct ParamTraits<mozilla::net::InfallableCopyCString>
: public ParamTraits<nsCString>
{
};
template<>
struct ParamTraits<nsHttpHeaderArray>
{

View File

@ -89,17 +89,17 @@ nsHttpHeaderArray::ClearHeader(nsHttpAtom header)
}
const char *
nsHttpHeaderArray::PeekHeader(nsHttpAtom header)
nsHttpHeaderArray::PeekHeader(nsHttpAtom header) const
{
nsEntry *entry = nsnull;
const nsEntry *entry = nsnull;
LookupEntry(header, &entry);
return entry ? entry->value.get() : nsnull;
}
nsresult
nsHttpHeaderArray::GetHeader(nsHttpAtom header, nsACString &result)
nsHttpHeaderArray::GetHeader(nsHttpAtom header, nsACString &result) const
{
nsEntry *entry = nsnull;
const nsEntry *entry = nsnull;
LookupEntry(header, &entry);
if (!entry)
return NS_ERROR_NOT_AVAILABLE;
@ -196,7 +196,7 @@ nsHttpHeaderArray::Flatten(nsACString &buf, bool pruneProxyHeaders)
}
const char *
nsHttpHeaderArray::PeekHeaderAt(PRUint32 index, nsHttpAtom &header)
nsHttpHeaderArray::PeekHeaderAt(PRUint32 index, nsHttpAtom &header) const
{
const nsEntry &entry = mHeaders[index];

View File

@ -14,13 +14,40 @@
#include "nsCOMPtr.h"
#include "nsString.h"
namespace mozilla { namespace net {
// A nsCString that aborts if it fails to successfully copy its input during
// copy construction and/or assignment. This is useful for building classes
// that are safely copy-constructable and safely assignable using the compiler-
// generated copy constructor and assignment operator.
class InfallableCopyCString : public nsCString
{
public:
InfallableCopyCString() { }
InfallableCopyCString(const nsACString & other)
: nsCString(other)
{
if (Length() != other.Length())
NS_RUNTIMEABORT("malloc");
}
InfallableCopyCString & operator=(const nsACString & other)
{
nsCString::operator=(other);
if (Length() != other.Length())
NS_RUNTIMEABORT("malloc");
return *this;
}
};
} } // namespace mozilla::net
class nsHttpHeaderArray
{
public:
nsHttpHeaderArray() {}
~nsHttpHeaderArray() { Clear(); }
const char *PeekHeader(nsHttpAtom header);
const char *PeekHeader(nsHttpAtom header) const;
// Used by internal setters: to set header from network use SetHeaderFromNet
nsresult SetHeader(nsHttpAtom header, const nsACString &value,
@ -30,17 +57,19 @@ public:
// needs to be thrown or 1st value kept.
nsresult SetHeaderFromNet(nsHttpAtom header, const nsACString &value);
nsresult GetHeader(nsHttpAtom header, nsACString &value);
nsresult GetHeader(nsHttpAtom header, nsACString &value) const;
void ClearHeader(nsHttpAtom h);
// Find the location of the given header value, or null if none exists.
const char *FindHeaderValue(nsHttpAtom header, const char *value) {
const char *FindHeaderValue(nsHttpAtom header, const char *value) const
{
return nsHttp::FindToken(PeekHeader(header), value,
HTTP_HEADER_VALUE_SEPS);
}
// Determine if the given header value exists.
bool HasHeaderValue(nsHttpAtom header, const char *value) {
bool HasHeaderValue(nsHttpAtom header, const char *value) const
{
return FindHeaderValue(header, value) != nsnull;
}
@ -54,18 +83,17 @@ public:
void Flatten(nsACString &, bool pruneProxyHeaders=false);
PRUint32 Count() { return mHeaders.Length(); }
PRUint32 Count() const { return mHeaders.Length(); }
const char *PeekHeaderAt(PRUint32 i, nsHttpAtom &header);
const char *PeekHeaderAt(PRUint32 i, nsHttpAtom &header) const;
void Clear();
// Must be copy-constructable and assignable
struct nsEntry
{
nsEntry() {}
nsHttpAtom header;
nsCString value;
mozilla::net::InfallableCopyCString value;
struct MatchHeader {
bool Equals(const nsEntry &entry, const nsHttpAtom &header) const {
@ -75,6 +103,7 @@ public:
};
private:
PRInt32 LookupEntry(nsHttpAtom header, const nsEntry **) const;
PRInt32 LookupEntry(nsHttpAtom header, nsEntry **);
void MergeHeader(nsHttpAtom header, nsEntry *entry, const nsACString &value);
@ -89,6 +118,7 @@ private:
// injection)
bool IsSuspectDuplicateHeader(nsHttpAtom header);
// All members must be copy-constructable and assignable
nsTArray<nsEntry> mHeaders;
friend struct IPC::ParamTraits<nsHttpHeaderArray>;
@ -99,6 +129,15 @@ private:
// nsHttpHeaderArray <private>: inline functions
//-----------------------------------------------------------------------------
inline PRInt32
nsHttpHeaderArray::LookupEntry(nsHttpAtom header, const nsEntry **entry) const
{
PRUint32 index = mHeaders.IndexOf(header, 0, nsEntry::MatchHeader());
if (index != PR_UINT32_MAX)
*entry = &mHeaders[index];
return index;
}
inline PRInt32
nsHttpHeaderArray::LookupEntry(nsHttpAtom header, nsEntry **entry)
{

View File

@ -20,33 +20,46 @@ class nsHttpRequestHead
{
public:
nsHttpRequestHead() : mMethod(nsHttp::Get), mVersion(NS_HTTP_VERSION_1_1) {}
~nsHttpRequestHead() {}
void SetMethod(nsHttpAtom method) { mMethod = method; }
void SetVersion(nsHttpVersion version) { mVersion = version; }
void SetRequestURI(const nsCSubstring &s) { mRequestURI = s; }
nsHttpHeaderArray &Headers() { return mHeaders; }
nsHttpAtom Method() { return mMethod; }
nsHttpVersion Version() { return mVersion; }
const nsCSubstring &RequestURI() { return mRequestURI; }
const nsHttpHeaderArray &Headers() const { return mHeaders; }
nsHttpHeaderArray & Headers() { return mHeaders; }
nsHttpAtom Method() const { return mMethod; }
nsHttpVersion Version() const { return mVersion; }
const nsCSubstring &RequestURI() const { return mRequestURI; }
const char *PeekHeader(nsHttpAtom h) { return mHeaders.PeekHeader(h); }
const char *PeekHeader(nsHttpAtom h) const
{
return mHeaders.PeekHeader(h);
}
nsresult SetHeader(nsHttpAtom h, const nsACString &v, bool m=false) { return mHeaders.SetHeader(h, v, m); }
nsresult GetHeader(nsHttpAtom h, nsACString &v) { return mHeaders.GetHeader(h, v); }
nsresult GetHeader(nsHttpAtom h, nsACString &v) const
{
return mHeaders.GetHeader(h, v);
}
void ClearHeader(nsHttpAtom h) { mHeaders.ClearHeader(h); }
void ClearHeaders() { mHeaders.Clear(); }
const char *FindHeaderValue(nsHttpAtom h, const char *v) { return mHeaders.FindHeaderValue(h, v); }
bool HasHeaderValue(nsHttpAtom h, const char *v) { return mHeaders.HasHeaderValue(h, v); }
const char *FindHeaderValue(nsHttpAtom h, const char *v) const
{
return mHeaders.FindHeaderValue(h, v);
}
bool HasHeaderValue(nsHttpAtom h, const char *v) const
{
return mHeaders.HasHeaderValue(h, v);
}
void Flatten(nsACString &, bool pruneProxyHeaders = false);
private:
// All members must be copy-constructable and assignable
nsHttpHeaderArray mHeaders;
nsHttpAtom mMethod;
nsHttpVersion mVersion;
nsCString mRequestURI;
mozilla::net::InfallableCopyCString mRequestURI;
};
#endif // nsHttpRequestHead_h__

View File

@ -155,7 +155,7 @@ nsHttpResponseHead::ParseStatusLine(const char *line)
mStatusText.AssignLiteral("OK");
}
else
mStatusText = ++line;
mStatusText = nsDependentCString(++line);
}
LOG(("Have status line [version=%u status=%u statusText=%s]\n",
@ -214,7 +214,7 @@ nsHttpResponseHead::ParseHeaderLine(const char *line)
nsresult
nsHttpResponseHead::ComputeCurrentAge(PRUint32 now,
PRUint32 requestTime,
PRUint32 *result)
PRUint32 *result) const
{
PRUint32 dateValue;
PRUint32 ageValue;
@ -256,7 +256,7 @@ nsHttpResponseHead::ComputeCurrentAge(PRUint32 now,
// freshnessLifetime = 0
//
nsresult
nsHttpResponseHead::ComputeFreshnessLifetime(PRUint32 *result)
nsHttpResponseHead::ComputeFreshnessLifetime(PRUint32 *result) const
{
*result = 0;
@ -303,7 +303,7 @@ nsHttpResponseHead::ComputeFreshnessLifetime(PRUint32 *result)
}
bool
nsHttpResponseHead::MustValidate()
nsHttpResponseHead::MustValidate() const
{
LOG(("nsHttpResponseHead::MustValidate ??\n"));
@ -364,7 +364,7 @@ nsHttpResponseHead::MustValidate()
}
bool
nsHttpResponseHead::MustValidateIfExpired()
nsHttpResponseHead::MustValidateIfExpired() const
{
// according to RFC2616, section 14.9.4:
//
@ -376,7 +376,7 @@ nsHttpResponseHead::MustValidateIfExpired()
}
bool
nsHttpResponseHead::IsResumable()
nsHttpResponseHead::IsResumable() const
{
// even though some HTTP/1.0 servers may support byte range requests, we're not
// going to bother with them, since those servers wouldn't understand If-Range.
@ -387,7 +387,7 @@ nsHttpResponseHead::IsResumable()
}
bool
nsHttpResponseHead::ExpiresInPast()
nsHttpResponseHead::ExpiresInPast() const
{
PRUint32 maxAgeVal, expiresVal, dateVal;
@ -402,7 +402,7 @@ nsHttpResponseHead::ExpiresInPast()
}
nsresult
nsHttpResponseHead::UpdateHeaders(nsHttpHeaderArray &headers)
nsHttpResponseHead::UpdateHeaders(const nsHttpHeaderArray &headers)
{
LOG(("nsHttpResponseHead::UpdateHeaders [this=%x]\n", this));
@ -469,7 +469,7 @@ nsHttpResponseHead::Reset()
}
nsresult
nsHttpResponseHead::ParseDateHeader(nsHttpAtom header, PRUint32 *result)
nsHttpResponseHead::ParseDateHeader(nsHttpAtom header, PRUint32 *result) const
{
const char *val = PeekHeader(header);
if (!val)
@ -485,7 +485,7 @@ nsHttpResponseHead::ParseDateHeader(nsHttpAtom header, PRUint32 *result)
}
nsresult
nsHttpResponseHead::GetAgeValue(PRUint32 *result)
nsHttpResponseHead::GetAgeValue(PRUint32 *result) const
{
const char *val = PeekHeader(nsHttp::Age);
if (!val)
@ -498,7 +498,7 @@ nsHttpResponseHead::GetAgeValue(PRUint32 *result)
// Return the value of the (HTTP 1.1) max-age directive, which itself is a
// component of the Cache-Control response header
nsresult
nsHttpResponseHead::GetMaxAgeValue(PRUint32 *result)
nsHttpResponseHead::GetMaxAgeValue(PRUint32 *result) const
{
const char *val = PeekHeader(nsHttp::Cache_Control);
if (!val)
@ -516,7 +516,7 @@ nsHttpResponseHead::GetMaxAgeValue(PRUint32 *result)
}
nsresult
nsHttpResponseHead::GetExpiresValue(PRUint32 *result)
nsHttpResponseHead::GetExpiresValue(PRUint32 *result) const
{
const char *val = PeekHeader(nsHttp::Expires);
if (!val)
@ -539,7 +539,7 @@ nsHttpResponseHead::GetExpiresValue(PRUint32 *result)
}
PRInt64
nsHttpResponseHead::TotalEntitySize()
nsHttpResponseHead::TotalEntitySize() const
{
const char* contentRange = PeekHeader(nsHttp::Content_Range);
if (!contentRange)

View File

@ -24,35 +24,38 @@ public:
, mCacheControlNoStore(false)
, mCacheControlNoCache(false)
, mPragmaNoCache(false) {}
~nsHttpResponseHead()
{
Reset();
}
nsHttpHeaderArray &Headers() { return mHeaders; }
nsHttpVersion Version() { return mVersion; }
PRUint16 Status() { return mStatus; }
const nsAFlatCString &StatusText() { return mStatusText; }
PRInt64 ContentLength() { return mContentLength; }
const nsAFlatCString &ContentType() { return mContentType; }
const nsAFlatCString &ContentCharset() { return mContentCharset; }
bool NoStore() { return mCacheControlNoStore; }
bool NoCache() { return (mCacheControlNoCache || mPragmaNoCache); }
const nsHttpHeaderArray & Headers() const { return mHeaders; }
nsHttpHeaderArray &Headers() { return mHeaders; }
nsHttpVersion Version() const { return mVersion; }
PRUint16 Status() const { return mStatus; }
const nsAFlatCString &StatusText() const { return mStatusText; }
PRInt64 ContentLength() const { return mContentLength; }
const nsAFlatCString &ContentType() const { return mContentType; }
const nsAFlatCString &ContentCharset() const { return mContentCharset; }
bool NoStore() const { return mCacheControlNoStore; }
bool NoCache() const { return (mCacheControlNoCache || mPragmaNoCache); }
/**
* Full length of the entity. For byte-range requests, this may be larger
* than ContentLength(), which will only represent the requested part of the
* entity.
*/
PRInt64 TotalEntitySize();
PRInt64 TotalEntitySize() const;
const char *PeekHeader(nsHttpAtom h) { return mHeaders.PeekHeader(h); }
const char *PeekHeader(nsHttpAtom h) const { return mHeaders.PeekHeader(h); }
nsresult SetHeader(nsHttpAtom h, const nsACString &v, bool m=false);
nsresult GetHeader(nsHttpAtom h, nsACString &v) { return mHeaders.GetHeader(h, v); }
nsresult GetHeader(nsHttpAtom h, nsACString &v) const { return mHeaders.GetHeader(h, v); }
void ClearHeader(nsHttpAtom h) { mHeaders.ClearHeader(h); }
void ClearHeaders() { mHeaders.Clear(); }
const char *FindHeaderValue(nsHttpAtom h, const char *v) { return mHeaders.FindHeaderValue(h, v); }
bool HasHeaderValue(nsHttpAtom h, const char *v) { return mHeaders.HasHeaderValue(h, v); }
const char *FindHeaderValue(nsHttpAtom h, const char *v) const
{
return mHeaders.FindHeaderValue(h, v);
}
bool HasHeaderValue(nsHttpAtom h, const char *v) const
{
return mHeaders.HasHeaderValue(h, v);
}
void SetContentType(const nsACString &s) { mContentType = s; }
void SetContentCharset(const nsACString &s) { mContentCharset = s; }
@ -74,31 +77,37 @@ public:
nsresult ParseHeaderLine(const char *line);
// cache validation support methods
nsresult ComputeFreshnessLifetime(PRUint32 *);
nsresult ComputeCurrentAge(PRUint32 now, PRUint32 requestTime, PRUint32 *result);
bool MustValidate();
bool MustValidateIfExpired();
nsresult ComputeFreshnessLifetime(PRUint32 *) const;
nsresult ComputeCurrentAge(PRUint32 now, PRUint32 requestTime, PRUint32 *result) const;
bool MustValidate() const;
bool MustValidateIfExpired() const;
// returns true if the server appears to support byte range requests.
bool IsResumable();
bool IsResumable() const;
// returns true if the Expires header has a value in the past relative to the
// value of the Date header.
bool ExpiresInPast();
bool ExpiresInPast() const;
// update headers...
nsresult UpdateHeaders(nsHttpHeaderArray &headers);
nsresult UpdateHeaders(const nsHttpHeaderArray &headers);
// reset the response head to it's initial state
void Reset();
// these return failure if the header does not exist.
nsresult ParseDateHeader(nsHttpAtom header, PRUint32 *result);
nsresult GetAgeValue(PRUint32 *result);
nsresult GetMaxAgeValue(PRUint32 *result);
nsresult GetDateValue(PRUint32 *result) { return ParseDateHeader(nsHttp::Date, result); }
nsresult GetExpiresValue(PRUint32 *result);
nsresult GetLastModifiedValue(PRUint32 *result) { return ParseDateHeader(nsHttp::Last_Modified, result); }
nsresult ParseDateHeader(nsHttpAtom header, PRUint32 *result) const;
nsresult GetAgeValue(PRUint32 *result) const;
nsresult GetMaxAgeValue(PRUint32 *result) const;
nsresult GetDateValue(PRUint32 *result) const
{
return ParseDateHeader(nsHttp::Date, result);
}
nsresult GetExpiresValue(PRUint32 *result) const ;
nsresult GetLastModifiedValue(PRUint32 *result) const
{
return ParseDateHeader(nsHttp::Last_Modified, result);
}
private:
void ParseVersion(const char *);
@ -106,13 +115,14 @@ private:
void ParsePragma(const char *);
private:
// All members must be copy-constructable and assignable
nsHttpHeaderArray mHeaders;
nsHttpVersion mVersion;
PRUint16 mStatus;
nsCString mStatusText;
mozilla::net::InfallableCopyCString mStatusText;
PRInt64 mContentLength;
nsCString mContentType;
nsCString mContentCharset;
mozilla::net::InfallableCopyCString mContentType;
mozilla::net::InfallableCopyCString mContentCharset;
bool mCacheControlNoStore;
bool mCacheControlNoCache;
bool mPragmaNoCache;

View File

@ -1113,6 +1113,12 @@ AuthCertificateHook(void *arg, PRFileDesc *fd, PRBool checkSig, PRBool isServer)
NS_ASSERTION(!isServer, "AuthCertificateHook: isServer unexpectedly true");
nsNSSSocketInfo *socketInfo = static_cast<nsNSSSocketInfo*>(arg);
if (socketInfo) {
// This is the first callback during full handshakes.
socketInfo->SetFirstServerHelloReceived();
}
CERTCertificate *serverCert = SSL_PeerCertificate(fd);
CERTCertificateCleaner serverCertCleaner(serverCert);

View File

@ -831,6 +831,11 @@ void PR_CALLBACK HandshakeCallback(PRFileDesc* fd, void* client_data) {
nsNSSSocketInfo* infoObject = (nsNSSSocketInfo*) fd->higher->secret;
if (infoObject) {
// This is the first callback on resumption handshakes
infoObject->SetFirstServerHelloReceived();
}
// If the handshake completed, then we know the site is TLS tolerant (if this
// was a TLS connection).
nsSSLIOLayerHelpers::rememberTolerantSite(infoObject);

View File

@ -98,8 +98,6 @@ extern PRLogModuleInfo* gPIPNSSLog;
nsNSSSocketInfo::nsNSSSocketInfo()
: mFd(nsnull),
mCertVerificationState(before_cert_verification),
mCertVerificationStarted(0),
mCertVerificationEnded(0),
mForSTARTTLS(false),
mSSL3Enabled(false),
mTLSEnabled(false),
@ -109,6 +107,7 @@ nsNSSSocketInfo::nsNSSSocketInfo()
mAllowTLSIntoleranceTimeout(true),
mRememberClientAuthCertificate(false),
mHandshakeStartTime(0),
mFirstServerHelloReceived(false),
mNPNCompleted(false),
mHandshakeCompleted(false),
mJoined(false),
@ -423,7 +422,6 @@ nsNSSSocketInfo::SetCertVerificationWaiting()
NS_ASSERTION(mCertVerificationState != waiting_for_cert_verification,
"Invalid state transition to waiting_for_cert_verification");
mCertVerificationState = waiting_for_cert_verification;
mCertVerificationStarted = PR_IntervalNow();
}
// Be careful that SetCertVerificationResult does NOT get called while we are
@ -437,8 +435,6 @@ nsNSSSocketInfo::SetCertVerificationResult(PRErrorCode errorCode,
NS_ASSERTION(mCertVerificationState == waiting_for_cert_verification,
"Invalid state transition to cert_verification_finished");
mCertVerificationEnded = PR_IntervalNow();
if (mFd) {
SECStatus rv = SSL_AuthCertificateComplete(mFd, errorCode);
// Only replace errorCode if there was originally no error
@ -474,40 +470,30 @@ void nsNSSSocketInfo::SetAllowTLSIntoleranceTimeout(bool aAllow)
mAllowTLSIntoleranceTimeout = aAllow;
}
#define HANDSHAKE_TIMEOUT_SECONDS 25
bool nsNSSSocketInfo::HandshakeTimeout()
{
if (mCertVerificationState == waiting_for_cert_verification) {
// Do not do a TLS interlerance timeout during cert verification because:
//
// * If we would have timed out, but cert verification is still ongoing,
// then the handshake probably already completed, and it is probably the
// certificate validation (OCSP responder or similar) that is timing
// out.
// * If certificate validation AND the handshake is slow, then that is a
// good indication that the network is bad, and so the problem probably
// isn't the server being TLS intolerant.
// * When we timeout, we return non-zero flags from PR_Poll, which will
// cause the application to try to read from and/or write to the socket,
// possibly in a loop. But, it is likely that the socket is blocked on
// cert authentication, so those read and/or write calls would result in
// PR_WOULD_BLOCK_ERROR, causing the application to spin.
if (!mAllowTLSIntoleranceTimeout)
return false;
}
if (!mHandshakeInProgress || !mAllowTLSIntoleranceTimeout)
if (!mHandshakeInProgress)
return false; // have not even sent client hello yet
if (mFirstServerHelloReceived)
return false;
// Now we know we are in the first handshake, and haven't received the
// ServerHello+Certificate sequence or the
// ServerHello+ChangeCipherSpec+Finished sequence.
//
// XXX: Bug 754356 - waiting to receive the Certificate or Finished messages
// may cause us to time out in cases where we shouldn't.
static const PRIntervalTime handshakeTimeoutInterval
= PR_SecondsToInterval(25);
PRIntervalTime now = PR_IntervalNow();
PRIntervalTime certVerificationTime =
mCertVerificationEnded - mCertVerificationStarted;
PRIntervalTime totalTime = now - mHandshakeStartTime;
PRIntervalTime totalTimeExceptCertVerificationTime =
totalTime - certVerificationTime;
return totalTimeExceptCertVerificationTime >
PR_SecondsToInterval(HANDSHAKE_TIMEOUT_SECONDS);
bool result = (now - mHandshakeStartTime) > handshakeTimeoutInterval;
return result;
}
void nsSSLIOLayerHelpers::Cleanup()

View File

@ -76,6 +76,7 @@ public:
void SetHandshakeInProgress(bool aIsIn);
bool GetHandshakeInProgress() { return mHandshakeInProgress; }
void SetFirstServerHelloReceived() { mFirstServerHelloReceived = true; }
bool HandshakeTimeout();
void SetAllowTLSIntoleranceTimeout(bool aAllow);
@ -115,8 +116,6 @@ private:
PRFileDesc* mFd;
CertVerificationState mCertVerificationState;
PRIntervalTime mCertVerificationStarted;
PRIntervalTime mCertVerificationEnded;
bool mForSTARTTLS;
bool mSSL3Enabled;
@ -127,6 +126,7 @@ private:
bool mAllowTLSIntoleranceTimeout;
bool mRememberClientAuthCertificate;
PRIntervalTime mHandshakeStartTime;
bool mFirstServerHelloReceived;
nsresult ActivateSSL();

View File

@ -23,7 +23,7 @@ h2 {
color: #f00;
}
.treeLine {
.treeline {
color: #888;
}

View File

@ -47,7 +47,10 @@ String.prototype.startsWith =
// undone are prefixed with "unsafe"; the rest are prefixed with "safe".
function flipBackslashes(aUnsafeStr)
{
return aUnsafeStr.replace(/\\/g, '/');
// Save memory by only doing the replacement if it's necessary.
return (aUnsafeStr.indexOf('\\') === -1)
? aUnsafeStr
: aUnsafeStr.replace(/\\/g, '/');
}
const gAssertionFailureMsgPrefix = "aboutMemory.js assertion failed: ";
@ -408,16 +411,23 @@ function updateAboutMemory()
let mgr = Cc["@mozilla.org/memory-reporter-manager;1"].
getService(Ci.nsIMemoryReporterManager);
let treesByProcess = {}, othersByProcess = {}, heapTotalByProcess = {};
getTreesAndOthersByProcess(mgr, treesByProcess, othersByProcess,
heapTotalByProcess);
// Generate output for one process at a time. Always start with the
// Main process.
let reportsByProcess = getReportsByProcess(mgr);
let hasMozMallocUsableSize = mgr.hasMozMallocUsableSize;
appendProcessReportsElements(body, "Main", reportsByProcess["Main"],
hasMozMallocUsableSize);
for (let process in reportsByProcess) {
if (process !== "Main") {
appendProcessReportsElements(body, process, reportsByProcess[process],
appendProcessAboutMemoryElements(body, "Main", treesByProcess["Main"],
othersByProcess["Main"],
heapTotalByProcess["Main"],
hasMozMallocUsableSize);
for (let process in treesByProcess) {
if (process !== "Main") {
appendProcessAboutMemoryElements(body, process, treesByProcess[process],
othersByProcess[process],
heapTotalByProcess[process],
hasMozMallocUsableSize);
}
}
@ -475,28 +485,23 @@ function updateAboutMemory()
//---------------------------------------------------------------------------
function Report(aUnsafePath, aKind, aUnits, aAmount, aDescription)
{
this._unsafePath = aUnsafePath;
this._kind = aKind;
this._units = aUnits;
this._amount = aAmount;
this._description = aDescription;
// this._nMerged is only defined if > 1
// this._done is defined and set to true when the Report's amount is read
}
Report.prototype = {
// Sum the values and mark |this| as a dup. We mark dups because it's useful
// to know when a report is duplicated; it might be worth investigating and
// splitting up to have non-duplicated names.
merge: function(r) {
this._amount += r._amount;
this._nMerged = this._nMerged ? this._nMerged + 1 : 2;
},
};
function getReportsByProcess(aMgr)
/**
* This function reads all the memory reports, and puts that data in structures
* that will be used to generate the page.
*
* @param aMgr
* The memory reporter manager.
* @param aTreesByProcess
* Table of trees, indexed by process, which this function appends to.
* @param aOthersByProcess
* Table of other lists, indexed by process, which this function appends
* to.
* @param aHeapTotalByProcess
* Table of heap total counts, indexed by process, which this function
* appends to.
*/
function getTreesAndOthersByProcess(aMgr, aTreesByProcess, aOthersByProcess,
aHeapTotalByProcess)
{
// Ignore the "smaps" multi-reporter in non-verbose mode, and the
// "compartments" and "ghost-windows" multi-reporters all the time. (Note
@ -517,50 +522,91 @@ function getReportsByProcess(aMgr)
aMRName === "ghost-windows";
}
let reportsByProcess = {};
function handleReport(aProcess, aUnsafePath, aKind, aUnits, aAmount,
aDescription)
{
let process = aProcess === "" ? "Main" : aProcess;
let r = new Report(aUnsafePath, aKind, aUnits, aAmount, aDescription);
if (!reportsByProcess[process]) {
reportsByProcess[process] = {};
}
let reports = reportsByProcess[process];
let rOld = reports[r._unsafePath];
if (rOld) {
// Already an entry; must be a duplicated report. This can happen
// legitimately. Merge them.
rOld.merge(r);
if (aUnsafePath.indexOf('/') !== -1) {
// Tree report. Get the tree for the process, creating it if necessary.
// All the trees for each process ("explicit", "vsize", etc) are stored
// in a "tree-of-trees". This makes things simple later.
if (!aTreesByProcess[process]) {
aTreesByProcess[process] = new TreeNode("tree-of-trees");
}
let t = aTreesByProcess[process];
// Add any missing nodes in the tree implied by aUnsafePath, and fill in
// the properties that we can with a top-down traversal.
let unsafeNames = aUnsafePath.split('/');
let u = t;
for (let i = 0; i < unsafeNames.length; i++) {
let unsafeName = unsafeNames[i];
let uMatch = u.findKid(unsafeName);
if (uMatch) {
u = uMatch;
} else {
let v = new TreeNode(unsafeName);
if (!u._kids) {
u._kids = [];
}
u._kids.push(v);
u = v;
}
}
if (u._amount) {
// Duplicate! Sum the values and mark it as a dup.
u._amount += aAmount;
u._nMerged = u._nMerged ? u._nMerged + 1 : 2;
} else {
// New leaf node. Fill in extra details node from the report.
u._amount = aAmount;
u._description = aDescription;
}
if (unsafeNames[0] === "explicit" && aKind == KIND_HEAP) {
if (!aHeapTotalByProcess[process]) {
aHeapTotalByProcess[process] = 0;
}
aHeapTotalByProcess[process] += aAmount;
}
} else {
reports[r._unsafePath] = r;
// "Other" (non-tree) report. Get the "others" for the process, creating
// it if necessary.
if (!aOthersByProcess[process]) {
aOthersByProcess[process] = {};
}
let others = aOthersByProcess[process];
// Record the report.
assert(!others[aUnsafePath], "dup'd OTHER report");
others[aUnsafePath] =
new OtherReport(aUnsafePath, aUnits, aAmount, aDescription);
}
}
processMemoryReporters(aMgr, ignoreSingle, ignoreMulti, handleReport);
return reportsByProcess;
}
//---------------------------------------------------------------------------
// There are two kinds of TreeNode.
// - Leaf TreeNodes correspond to Reports and have more properties.
// - Leaf TreeNodes correspond to reports.
// - Non-leaf TreeNodes are just scaffolding nodes for the tree; their values
// are derived from their children.
function TreeNode(aUnsafeName)
{
// Nb: _units is not needed, it's always UNITS_BYTES.
this._unsafeName = aUnsafeName;
this._kids = [];
// Leaf TreeNodes have these properties added immediately after construction:
// - _amount
// - _description
// - _kind
// - _nMerged (only defined if > 1)
//
// Non-leaf TreeNodes have these properties added later:
// - _kids
// - _amount
// - _description
// - _hideKids (only defined if true)
@ -568,9 +614,11 @@ function TreeNode(aUnsafeName)
TreeNode.prototype = {
findKid: function(aUnsafeName) {
for (let i = 0; i < this._kids.length; i++) {
if (this._kids[i]._unsafeName === aUnsafeName) {
return this._kids[i];
if (this._kids) {
for (let i = 0; i < this._kids.length; i++) {
if (this._kids[i]._unsafeName === aUnsafeName) {
return this._kids[i];
}
}
}
return undefined;
@ -586,100 +634,61 @@ TreeNode.compare = function(a, b) {
};
/**
* From a table of Reports, builds a tree that mirrors the tree structure that
* will be shown as output.
* Fill in the remaining properties for the specified tree in a bottom-up
* fashion.
*
* @param aReports
* The table of Reports, indexed by _unsafePath.
* @param aTreeOfTrees
* The tree-of-trees.
* @param aTreePrefix
* The prefix (name) of the tree being built. Must have '/' on the end.
* @return The built tree.
*/
function buildTree(aReports, aTreePrefix)
function fillInTree(aTreeOfTrees, aTreePrefix)
{
assert(aTreePrefix.indexOf('/') == aTreePrefix.length - 1,
"aTreePrefix doesn't end in '/'");
// We want to process all reports that begin with |aTreePrefix|. First we
// build the tree but only fill the properties that we can with a top-down
// traversal.
let foundReport = false;
let t = new TreeNode("falseRoot");
for (let unsafePath in aReports) {
// Add any missing nodes in the tree implied by the unsafePath.
if (unsafePath.startsWith(aTreePrefix)) {
foundReport = true;
let r = aReports[unsafePath];
let unsafeNames = r._unsafePath.split('/');
let u = t;
for (let i = 0; i < unsafeNames.length; i++) {
let unsafeName = unsafeNames[i];
let uMatch = u.findKid(unsafeName);
if (uMatch) {
u = uMatch;
} else {
let v = new TreeNode(unsafeName);
u._kids.push(v);
u = v;
}
}
// Fill in extra details in the leaf node from the Report object.
u._amount = r._amount;
u._description = r._description;
u._kind = r._kind;
if (r._nMerged) {
u._nMerged = r._nMerged;
}
r._done = true;
}
}
// There should always be at least one matching Report object when
// |aTreePrefix| is "explicit/". But there may be zero for smaps trees; if
// that happens, bail.
if (!foundReport) {
assert(aTreePrefix !== 'explicit/', "aTreePrefix !== 'explicit/'");
// There should always be an "explicit/" tree. But smaps trees might not be
// present; if that happens, return early.
let t = aTreeOfTrees.findKid(aTreePrefix.replace(/\//g, ''));
if (!t) {
assert(aTreePrefix !== 'explicit/', "missing explicit tree");
return null;
}
// Using falseRoot makes the above code simpler. Now discard it, leaving
// aTreePrefix at the root.
t = t._kids[0];
// Next, fill in the remaining properties bottom-up.
function fillInNonLeafNodes(aT, aCannotMerge)
{
if (aT._kids.length === 0) {
if (!aT._kids) {
// Leaf node. Has already been filled in.
assert(aT._kind !== undefined, "aT._kind is undefined for leaf node");
} else if (aT._kids.length === 1 && !aCannotMerge) {
// Non-leaf node with one child. Merge the child with the node to avoid
// redundant entries.
assert(aT._kind === undefined, "aT._kind is defined for non-leaf node");
let kid = aT._kids[0];
let kidBytes = fillInNonLeafNodes(kid);
aT._unsafeName += '/' + kid._unsafeName;
aT._kids = kid._kids;
if (kid._kids) {
aT._kids = kid._kids;
} else {
delete aT._kids;
}
aT._amount = kid._amount;
aT._description = kid._description;
aT._kind = kid._kind;
if (kid._nMerged) {
if (kid._nMerged !== undefined) {
aT._nMerged = kid._nMerged
}
assert(!aT._hideKids && !kid._hideKids, "_hideKids set when merging");
} else {
// Non-leaf node with multiple children. Derive its _amount and
// _description entirely from its children.
assert(aT._kind === undefined, "aT._kind is defined for non-leaf node");
let kidsBytes = 0;
for (let i = 0; i < aT._kids.length; i++) {
kidsBytes += fillInNonLeafNodes(aT._kids[i]);
}
aT._amount = kidsBytes;
aT._description = "The sum of all entries below '" +
flipBackslashes(aT._unsafeName) + "'.";
aT._description = "The sum of all entries below this one.";
}
return aT._amount;
}
@ -694,63 +703,27 @@ function buildTree(aReports, aTreePrefix)
}
/**
* Ignore all the memory reports that belong to a smaps tree; this involves
* explicitly marking them as done.
*
* @param aReports
* The table of Reports, indexed by _unsafePath.
*/
function ignoreSmapsTrees(aReports)
{
for (let unsafePath in aReports) {
let r = aReports[unsafePath];
if (isSmapsPath(r._unsafePath)) {
r._done = true;
}
}
}
/**
* Do some work which only makes sense for the 'explicit' tree.
* Compute the "heap-unclassified" value and insert it into the "explicit"
* tree.
*
* @param aT
* The tree.
* @param aReports
* Table of Reports for this process, indexed by _unsafePath.
* The "explicit" tree.
* @param aOthers
* "Other measurements" for this process, indexed by _unsafePath.
* @param aHeapTotal
* The sum of all explicit HEAP reporters for this process.
* @return A boolean indicating if "heap-allocated" is known for the process.
*/
function fixUpExplicitTree(aT, aReports)
function addHeapUnclassifiedNode(aT, aOthers, aHeapTotal)
{
// Determine how many bytes are in heap reports.
function getKnownHeapUsedBytes(aT)
{
let n = 0;
if (aT._kids.length === 0) {
// Leaf node.
assert(aT._kind !== undefined, "aT._kind is undefined for leaf node");
n = aT._kind === KIND_HEAP ? aT._amount : 0;
} else {
for (let i = 0; i < aT._kids.length; i++) {
n += getKnownHeapUsedBytes(aT._kids[i]);
}
}
return n;
}
// A special case: compute the derived "heap-unclassified" value. Don't
// mark "heap-allocated" when we get its size because we want it to appear
// in the "Other Measurements" list.
let heapAllocatedReport = aReports["heap-allocated"];
let heapAllocatedReport = aOthers["heap-allocated"];
if (heapAllocatedReport === undefined)
return false;
let heapAllocatedBytes = heapAllocatedReport._amount;
let heapUnclassifiedT = new TreeNode("heap-unclassified");
heapUnclassifiedT._amount = heapAllocatedBytes - getKnownHeapUsedBytes(aT);
// This kindToString() ensures the "(Heap)" prefix is set without having to
// set the _kind property, which would mean that there is a corresponding
// Report object for this TreeNode object (which isn't true)
heapUnclassifiedT._description = kindToString(KIND_HEAP) +
heapUnclassifiedT._amount = heapAllocatedBytes - aHeapTotal;
heapUnclassifiedT._description =
"Memory not classified by a more specific reporter. This includes " +
"slop bytes due to internal fragmentation in the heap allocator " +
"(caused when the allocator rounds up request sizes).";
@ -778,7 +751,7 @@ function sortTreeAndInsertAggregateNodes(aTotalBytes, aT)
(100 * aT._amount / aTotalBytes) < kSignificanceThresholdPerc;
}
if (aT._kids.length === 0) {
if (!aT._kids) {
return;
}
@ -805,6 +778,7 @@ function sortTreeAndInsertAggregateNodes(aTotalBytes, aT)
let nAgg = aT._kids.length - i0;
// Create an aggregate node.
let aggT = new TreeNode("(" + nAgg + " tiny)");
aggT._kids = [];
let aggBytes = 0;
for ( ; i < aT._kids.length; i++) {
aggBytes += aT._kids[i]._amount;
@ -886,37 +860,40 @@ function appendWarningElements(aP, aHasKnownHeapAllocated,
}
/**
* Appends the elements for a single process's Reports.
* Appends the about:memory elements for a single process.
*
* @param aP
* The parent DOM node.
* @param aProcess
* The name of the process.
* @param aReports
* Table of Reports for this process, indexed by _unsafePath.
* @param aTreeOfTrees
* The tree-of-trees for this process.
* @param aOthers
* The "other measurements" for this process.
* @param aHasMozMallocUsableSize
* Boolean indicating if moz_malloc_usable_size works.
* @return The generated text.
*/
function appendProcessReportsElements(aP, aProcess, aReports,
aHasMozMallocUsableSize)
function appendProcessAboutMemoryElements(aP, aProcess, aTreeOfTrees, aOthers,
aHeapTotal, aHasMozMallocUsableSize)
{
appendElementWithText(aP, "h1", "", aProcess + " Process\n\n");
// We'll fill this in later.
let warningsDiv = appendElement(aP, "div", "accuracyWarning");
let explicitTree = buildTree(aReports, 'explicit/');
let hasKnownHeapAllocated = fixUpExplicitTree(explicitTree, aReports);
let explicitTree = fillInTree(aTreeOfTrees, "explicit/");
let hasKnownHeapAllocated =
addHeapUnclassifiedNode(explicitTree, aOthers, aHeapTotal);
sortTreeAndInsertAggregateNodes(explicitTree._amount, explicitTree);
appendTreeElements(aP, explicitTree, aProcess);
// We only show these breakdown trees in verbose mode.
if (gVerbose) {
kSmapsTreePrefixes.forEach(function(aTreePrefix) {
let t = buildTree(aReports, aTreePrefix);
let t = fillInTree(aTreeOfTrees, aTreePrefix);
// |t| will be null if we don't have any reports for the given
// |t| will be undefined if we don't have any reports for the given
// unsafePath.
if (t) {
sortTreeAndInsertAggregateNodes(t._amount, t);
@ -924,16 +901,11 @@ function appendProcessReportsElements(aP, aProcess, aReports,
appendTreeElements(aP, t, aProcess);
}
});
} else {
// Although we skip the "smaps" multi-reporter in getReportsByProcess(),
// we might get some smaps reports from a child process, and they must be
// explicitly ignored.
ignoreSmapsTrees(aReports);
}
// We have to call appendOtherElements after we process all the trees,
// because it looks at all the reports which aren't part of a tree.
appendOtherElements(aP, aReports);
appendOtherElements(aP, aOthers);
// Add any warnings about inaccuracies due to platform limitations.
// These must be computed after generating all the text. The newlines give
@ -1060,18 +1032,21 @@ function pad(aS, aN, aC)
return padding + aS;
}
// There's a subset of the Unicode "light" box-drawing chars that are widely
// There's a subset of the Unicode "light" box-drawing chars that is widely
// implemented in terminals, and this code sticks to that subset to maximize
// the chance that cutting and pasting about:memory output to a terminal will
// work correctly:
const kHorizontal = "\u2500",
kVertical = "\u2502",
kUpAndRight = "\u2514",
kVerticalAndRight = "\u251c",
kNoKidsSep = " \u2500\u2500 ",
kHideKidsSep = " ++ ",
kShowKidsSep = " -- ";
// work correctly.
const kHorizontal = "\u2500",
kVertical = "\u2502",
kUpAndRight = "\u2514",
kUpAndRight_Right_Right = "\u2514\u2500\u2500",
kVerticalAndRight = "\u251c",
kVerticalAndRight_Right_Right = "\u251c\u2500\u2500",
kVertical_Space_Space = "\u2502 ";
const kNoKidsSep = " \u2500\u2500 ",
kHideKidsSep = " ++ ",
kShowKidsSep = " -- ";
function appendMrValueSpan(aP, aValue, aIsInvalid)
{
@ -1079,35 +1054,29 @@ function appendMrValueSpan(aP, aValue, aIsInvalid)
aValue);
}
function kindToString(aKind)
function appendMrNameSpan(aP, aDescription, aUnsafeName, aIsInvalid, aNMerged)
{
switch (aKind) {
case KIND_NONHEAP: return "(Non-heap) ";
case KIND_HEAP: return "(Heap) ";
case KIND_OTHER:
case undefined: return "";
default: assert(false, "bad kind in kindToString");
let safeName = flipBackslashes(aUnsafeName);
if (!aIsInvalid && !aNMerged) {
safeName += "\n";
}
}
function appendMrNameSpan(aP, aKind, aSep, aDescription, aUnsafeName,
aIsInvalid, aNMerged)
{
appendElementWithText(aP, "span", "mrSep", aSep);
let nameSpan = appendElementWithText(aP, "span", "mrName",
flipBackslashes(aUnsafeName));
nameSpan.title = kindToString(aKind) + aDescription;
let nameSpan = appendElementWithText(aP, "span", "mrName", safeName);
nameSpan.title = aDescription;
if (aIsInvalid) {
let noteSpan = appendElementWithText(aP, "span", "mrNote", " [?!]");
let noteText = " [?!]";
if (!aNMerged) {
noteText += "\n";
}
let noteSpan = appendElementWithText(aP, "span", "mrNote", noteText);
noteSpan.title =
"Warning: this value is invalid and indicates a bug in one or more " +
"memory reporters. ";
}
if (aNMerged) {
let noteSpan = appendElementWithText(aP, "span", "mrNote",
" [" + aNMerged + "]");
" [" + aNMerged + "]\n");
noteSpan.title =
"This value is the sum of " + aNMerged +
" memory reporters that all have the same path.";
@ -1136,7 +1105,7 @@ function toggle(aEvent)
// right nodes. And the span containing the children of this line must
// immediately follow. Assertions check this.
// |aEvent.target| will be one of the five spans. Get the outer span.
// |aEvent.target| will be one of the spans. Get the outer span.
let outerSpan = aEvent.target.parentNode;
assertClassListContains(outerSpan, "hasKids");
@ -1196,7 +1165,6 @@ function expandPathToThisElement(aElement)
* The tree.
* @param aProcess
* The process the tree corresponds to.
* @return The generated text.
*/
function appendTreeElements(aPOuter, aT, aProcess)
{
@ -1209,78 +1177,74 @@ function appendTreeElements(aPOuter, aT, aProcess)
*
* @param aP
* The parent DOM node.
* @param aUnsafePrePath
* The partial unsafePath leading up to this node.
* @param aUnsafeNames
* An array of the names forming the path to aT.
* @param aT
* The tree.
* @param aBaseIndentText
* The base text of the indent, which may be augmented within the
* function.
* @param aIndentGuide
* Records what indentation is required for this tree. It has one
* entry per level of indentation. For each entry, ._isLastKid
* records whether the node in question is the last child, and
* ._depth records how many chars of indentation are required.
* @param aTreelineText1
* The first part of the treeline for this entry and this entry's
* children.
* @param aTreelineText2a
* The second part of the treeline for this entry.
* @param aTreelineText2b
* The second part of the treeline for this entry's children.
* @param aParentStringLength
* The length of the formatted byte count of the top node in the tree.
* @return The generated text.
*/
function appendTreeElements2(aP, aUnsafePrePath, aT, aIndentGuide,
aBaseIndentText, aParentStringLength)
function appendTreeElements2(aP, aUnsafeNames, aT, aTreelineText1,
aTreelineText2a, aTreelineText2b,
aParentStringLength)
{
function repeatStr(aA, aC, aN)
function appendN(aS, aC, aN)
{
for (let i = 0; i < aN; i++) {
aA.push(aC);
aS += aC;
}
return aS;
}
let unsafePath = aUnsafePrePath + aT._unsafeName;
// Indent more if this entry is narrower than its parent, and update
// aIndentGuide accordingly.
let tString = aT.toString();
let extraIndentLength = Math.max(aParentStringLength - tString.length, 0);
let indentText;
if (extraIndentLength > 0) {
let extraIndentArray = [];
repeatStr(extraIndentArray, kHorizontal, extraIndentLength);
aIndentGuide[aIndentGuide.length - 1]._depth += extraIndentLength;
indentText = aBaseIndentText + extraIndentArray.join("");
// Indent more if this entry is narrower than its parent.
let valueText = aT.toString();
let extraTreelineLength =
Math.max(aParentStringLength - valueText.length, 0);
if (extraTreelineLength > 0) {
aTreelineText2a =
appendN(aTreelineText2a, kHorizontal, extraTreelineLength);
aTreelineText2b =
appendN(aTreelineText2b, " ", extraTreelineLength);
}
else {
indentText = aBaseIndentText;
}
appendElementWithText(aP, "span", "treeLine", indentText);
let treelineText = aTreelineText1 + aTreelineText2a;
appendElementWithText(aP, "span", "treeline", treelineText);
// Generate the percentage; detect and record invalid values at the same
// time.
let percText = "";
let percText;
let tIsInvalid = false;
if (aT._amount === treeBytes) {
percText = "100.0";
percText = " (100.0%)";
} else {
if (!(0 <= aT._amount && aT._amount <= treeBytes)) {
tIsInvalid = true;
let unsafePath = aUnsafeNames.join("/");
gUnsafePathsWithInvalidValuesForThisProcess.push(unsafePath);
reportAssertionFailure("Invalid value for " +
flipBackslashes(unsafePath));
}
percText = (100 * aT._amount / treeBytes).toFixed(2);
percText = pad(percText, 5, '0');
let num = 100 * aT._amount / treeBytes;
let numText = num.toFixed(2);
percText = (0 <= num && num < 10 ? " (0" : " (") + numText + "%)";
}
percText = " (" + percText + "%)";
// For non-leaf nodes, the entire sub-tree is put within a span so it can
// be collapsed if the node is clicked on.
let d;
let hasKids = aT._kids.length > 0;
let sep;
let showSubtrees;
if (hasKids) {
if (aT._kids) {
// Determine if we should show the sub-tree below this entry; this
// involves reinstating any previous toggling of the sub-tree.
let safeTreeId = flipBackslashes(aProcess + ":" + unsafePath);
let unsafePath = aUnsafeNames.join("/");
let safeTreeId = aProcess + ":" + flipBackslashes(unsafePath);
showSubtrees = !aT._hideKids;
if (gShowSubtreesBySafeTreeId[safeTreeId] !== undefined) {
showSubtrees = gShowSubtreesBySafeTreeId[safeTreeId];
@ -1295,15 +1259,12 @@ function appendTreeElements(aPOuter, aT, aProcess)
d = aP;
}
appendMrValueSpan(d, tString, tIsInvalid);
appendMrValueSpan(d, valueText, tIsInvalid);
appendElementWithText(d, "span", "mrPerc", percText);
appendElementWithText(d, "span", "mrSep", sep);
// We don't want to show '(nonheap)' on a tree like 'vsize/', since
// the whole tree is non-heap.
let kind = isExplicitTree ? aT._kind : undefined;
appendMrNameSpan(d, kind, sep, aT._description, aT._unsafeName,
appendMrNameSpan(d, aT._description, aT._unsafeName,
tIsInvalid, aT._nMerged);
appendTextNode(d, "\n");
// In non-verbose mode, invalid nodes can be hidden in collapsed sub-trees.
// But it's good to always see them, so force this.
@ -1311,31 +1272,25 @@ function appendTreeElements(aPOuter, aT, aProcess)
expandPathToThisElement(d);
}
if (hasKids) {
if (aT._kids) {
// The 'kids' class is just used for sanity checking in toggle().
d = appendElement(aP, "span", showSubtrees ? "kids" : "kids hidden");
let kidTreelineText1 = aTreelineText1 + aTreelineText2b;
for (let i = 0; i < aT._kids.length; i++) {
// 3 is the standard depth, the callee adjusts it if necessary.
aIndentGuide.push({ _isLastKid: (i === aT._kids.length - 1), _depth: 3 });
// Generate the base indent.
let baseIndentArray = [];
if (aIndentGuide.length > 0) {
let j;
for (j = 0; j < aIndentGuide.length - 1; j++) {
baseIndentArray.push(aIndentGuide[j]._isLastKid ? " " : kVertical);
repeatStr(baseIndentArray, " ", aIndentGuide[j]._depth - 1);
}
baseIndentArray.push(aIndentGuide[j]._isLastKid ?
kUpAndRight : kVerticalAndRight);
repeatStr(baseIndentArray, kHorizontal, aIndentGuide[j]._depth - 1);
let kidTreelineText2a, kidTreelineText2b;
if (i < aT._kids.length - 1) {
kidTreelineText2a = kVerticalAndRight_Right_Right;
kidTreelineText2b = kVertical_Space_Space;
} else {
kidTreelineText2a = kUpAndRight_Right_Right;
kidTreelineText2b = " ";
}
let baseIndentText = baseIndentArray.join("");
appendTreeElements2(d, unsafePath + "/", aT._kids[i], aIndentGuide,
baseIndentText, tString.length);
aIndentGuide.pop();
aUnsafeNames.push(aT._kids[i]._unsafeName);
appendTreeElements2(d, aUnsafeNames, aT._kids[i], kidTreelineText1,
kidTreelineText2a, kidTreelineText2b,
valueText.length);
aUnsafeNames.pop();
}
}
}
@ -1343,7 +1298,7 @@ function appendTreeElements(aPOuter, aT, aProcess)
appendSectionHeader(aPOuter, kSectionNames[aT._unsafeName]);
let pre = appendElement(aPOuter, "pre", "entries");
appendTreeElements2(pre, /* prePath = */"", aT, [], "", rootStringLength);
appendTreeElements2(pre, [aT._unsafeName], aT, "", "", "", rootStringLength);
appendTextNode(aPOuter, "\n"); // gives nice spacing when we cut and paste
}
@ -1351,7 +1306,6 @@ function appendTreeElements(aPOuter, aT, aProcess)
function OtherReport(aUnsafePath, aUnits, aAmount, aDescription, aNMerged)
{
// Nb: _kind is not needed, it's always KIND_OTHER.
this._unsafePath = aUnsafePath;
this._units = aUnits;
this._amount = aAmount;
@ -1395,33 +1349,24 @@ OtherReport.compare = function(a, b) {
*
* @param aP
* The parent DOM node.
* @param aReportsByProcess
* Table of Reports for this process, indexed by _unsafePath.
* @param aProcess
* The process these Reports correspond to.
* @return The generated text.
* @param aOthers
* The "other measurements" for this process.
*/
function appendOtherElements(aP, aReportsByProcess)
function appendOtherElements(aP, aOthers)
{
appendSectionHeader(aP, kSectionNames['other']);
let pre = appendElement(aP, "pre", "entries");
// Generate an array of Report-like elements, stripping out all the
// Reports that have already been handled. Also find the width of the
// Convert the table of OtherReports to an array. Also find the width of the
// widest element, so we can format things nicely.
let maxStringLength = 0;
let otherReports = [];
for (let unsafePath in aReportsByProcess) {
let r = aReportsByProcess[unsafePath];
if (!r._done) {
assert(r._nMerged === undefined, "dup'd OTHER report");
let o = new OtherReport(r._unsafePath, r._units, r._amount,
r._description);
otherReports.push(o);
if (o._asString.length > maxStringLength) {
maxStringLength = o._asString.length;
}
for (let unsafePath in aOthers) {
let o = aOthers[unsafePath];
otherReports.push(o);
if (o._asString.length > maxStringLength) {
maxStringLength = o._asString.length;
}
}
otherReports.sort(OtherReport.compare);
@ -1437,9 +1382,8 @@ function appendOtherElements(aP, aReportsByProcess)
flipBackslashes(o._unsafePath));
}
appendMrValueSpan(pre, pad(o._asString, maxStringLength, ' '), oIsInvalid);
appendMrNameSpan(pre, KIND_OTHER, kNoKidsSep, o._description, o._unsafePath,
oIsInvalid);
appendTextNode(pre, "\n");
appendElementWithText(pre, "span", "mrSep", kNoKidsSep);
appendMrNameSpan(pre, o._description, o._unsafePath, oIsInvalid);
}
appendTextNode(aP, "\n"); // gives nice spacing when we cut and paste
@ -1688,8 +1632,6 @@ function appendProcessAboutCompartmentsElementsHelper(aP, aEntries, aKindString)
* Table of Compartments for this process, indexed by _unsafeName.
* @param aGhostWindows
* Array of window URLs of ghost windows.
*
* @return The generated text.
*/
function appendProcessAboutCompartmentsElements(aP, aProcess, aCompartments, aGhostWindows)
{

View File

@ -188,6 +188,7 @@
// Check that we can handle "heap-allocated" not being present.
f("3rd", "explicit/a/b", HEAP, 333 * MB),
f("3rd", "explicit/a/c", HEAP, 444 * MB),
f2("3rd", "other1", OTHER, BYTES, 1 * MB),
// Invalid values (negative, too-big) should be identified.
f("4th", "heap-allocated", OTHER, 100 * MB),
@ -290,6 +291,7 @@ Explicit Allocations\n\
└──333.00 MB (42.86%) ── b\n\
\n\
Other Measurements\n\
1.00 MB ── other1\n\
\n\
4th Process\n\
\n\
@ -432,6 +434,7 @@ Explicit Allocations\n\
└──349,175,808 B (42.86%) ── b\n\
\n\
Other Measurements\n\
1,048,576 B ── other1\n\
\n\
4th Process\n\
\n\

View File

@ -678,9 +678,9 @@ ensure_tree_header_cell_widget()
gtk_tree_view_append_column(GTK_TREE_VIEW(gTreeViewWidget), lastTreeViewColumn);
/* Use the middle column's header for our button */
/* TODO */
gTreeHeaderCellWidget = NULL;
gTreeHeaderSortArrowWidget = NULL;
/* TODO, but they can't be NULL */
gTreeHeaderCellWidget = gtk_button_new_with_label("M");
gTreeHeaderSortArrowWidget = gtk_button_new();
}
return MOZ_GTK_SUCCESS;
}
@ -2259,9 +2259,9 @@ moz_gtk_tabpanels_paint(cairo_t *cr, GdkRectangle* rect,
*/
/* left side */
cairo_save(cr);
cairo_rectangle(rect->x, rect->y,
cairo_rectangle(cr, rect->x, rect->y,
rect->x + rect->width / 2,
rect->y + rect->height)
rect->y + rect->height);
cairo_clip(cr);
gtk_render_frame_gap(style, cr,
rect->x, rect->y,
@ -2271,9 +2271,9 @@ moz_gtk_tabpanels_paint(cairo_t *cr, GdkRectangle* rect,
/* right side */
cairo_save(cr);
cairo_rectangle(rect->x + rect->width / 2, rect->y,
cairo_rectangle(cr, rect->x + rect->width / 2, rect->y,
rect->x + rect->width,
rect->y + rect->height)
rect->y + rect->height);
cairo_clip(cr);
gtk_render_frame_gap(style, cr,
rect->x, rect->y,
@ -2429,17 +2429,19 @@ moz_gtk_menu_item_paint(cairo_t *cr, GdkRectangle* rect,
GtkWidget* item_widget;
if (state->inHover && !state->disabled) {
gtk_style_context_save(style);
style = gtk_widget_get_style_context(item_widget);
if (flags & MOZ_TOPLEVEL_MENU_ITEM) {
ensure_menu_bar_item_widget();
item_widget = gMenuBarItemWidget;
gtk_style_context_add_class(style, GTK_STYLE_CLASS_MENUBAR);
} else {
ensure_menu_item_widget();
item_widget = gMenuItemWidget;
}
style = gtk_widget_get_style_context(item_widget);
gtk_style_context_save(style);
if (flags & MOZ_TOPLEVEL_MENU_ITEM) {
gtk_style_context_add_class(style, GTK_STYLE_CLASS_MENUBAR);
}
gtk_widget_set_direction(item_widget, direction);
gtk_style_context_add_class(style, GTK_STYLE_CLASS_MENUITEM);
@ -3247,6 +3249,12 @@ moz_gtk_shutdown()
if (gProtoWindow)
gtk_widget_destroy(gProtoWindow);
/* TODO - replace it with appropriate widgets */
if (gTreeHeaderCellWidget)
gtk_widget_destroy(gTreeHeaderCellWidget);
if (gTreeHeaderSortArrowWidget)
gtk_widget_destroy(gTreeHeaderSortArrowWidget);
gProtoWindow = NULL;
gProtoLayout = NULL;
gButtonWidget = NULL;

View File

@ -1502,9 +1502,10 @@ nsWindow::GetClientOffset()
int format_returned;
int length_returned;
long *frame_extents;
GdkWindow* window;
if (!mShell || !mShell->window ||
!gdk_property_get(mShell->window,
if (!mShell || !(window = gtk_widget_get_window(mShell)) ||
!gdk_property_get(window,
gdk_atom_intern ("_NET_FRAME_EXTENTS", FALSE),
cardinal_atom,
0, // offset

View File

@ -131,7 +131,7 @@ GfxInfo::GetData()
// only useful for Linux kernel version check for FGLRX driver.
// assumes X client == X server, which is sad.
utsname unameobj;
struct utsname unameobj;
if (!uname(&unameobj))
{
mOS.Assign(unameobj.sysname);