Merge mozilla-central into mozilla-inbound

This commit is contained in:
Ehsan Akhgari 2012-04-25 10:07:17 -04:00
commit eb35c5e956
75 changed files with 1886 additions and 616 deletions

View File

@ -38,7 +38,7 @@
*
* ***** END LICENSE BLOCK ***** */
#include "nsApplicationAccessibleWrap.h"
#include "ApplicationAccessibleWrap.h"
#include "nsCOMPtr.h"
#include "nsMai.h"
@ -466,25 +466,19 @@ mai_util_remove_key_event_listener (guint remove_listener)
}
}
AtkObject *
AtkObject*
mai_util_get_root(void)
{
if (nsAccessibilityService::IsShutdown()) {
// We've shutdown, try to use gail instead
// (to avoid assert in spi_atk_tidy_windows())
if (gail_get_root)
return gail_get_root();
return nsnull;
}
nsApplicationAccessible *applicationAcc =
nsAccessNode::GetApplicationAccessible();
if (applicationAcc)
return applicationAcc->GetAtkObject();
if (nsAccessibilityService::IsShutdown()) {
// We've shutdown, try to use gail instead
// (to avoid assert in spi_atk_tidy_windows())
if (gail_get_root)
return gail_get_root();
return nsnull;
}
return nsAccessNode::GetApplicationAccessible()->GetAtkObject();
}
G_CONST_RETURN gchar *
@ -550,15 +544,15 @@ add_listener (GSignalEmissionHook listener,
static nsresult LoadGtkModule(GnomeAccessibilityModule& aModule);
// nsApplicationAccessibleWrap
// ApplicationAccessibleWrap
nsApplicationAccessibleWrap::nsApplicationAccessibleWrap():
nsApplicationAccessible()
ApplicationAccessibleWrap::ApplicationAccessibleWrap():
ApplicationAccessible()
{
MAI_LOG_DEBUG(("======Create AppRootAcc=%p\n", (void*)this));
MAI_LOG_DEBUG(("======Create AppRootAcc=%p\n", (void*)this));
}
nsApplicationAccessibleWrap::~nsApplicationAccessibleWrap()
ApplicationAccessibleWrap::~ApplicationAccessibleWrap()
{
MAI_LOG_DEBUG(("======Destory AppRootAcc=%p\n", (void*)this));
nsAccessibleWrap::ShutdownAtkObject();
@ -613,7 +607,7 @@ toplevel_event_watcher(GSignalInvocationHint* ihint,
}
bool
nsApplicationAccessibleWrap::Init()
ApplicationAccessibleWrap::Init()
{
if (ShouldA11yBeEnabled()) {
// load and initialize gail library
@ -655,11 +649,11 @@ nsApplicationAccessibleWrap::Init()
}
}
return nsApplicationAccessible::Init();
return ApplicationAccessible::Init();
}
void
nsApplicationAccessibleWrap::Unload()
ApplicationAccessibleWrap::Unload()
{
if (sToplevel_event_hook_added) {
sToplevel_event_hook_added = false;
@ -697,7 +691,7 @@ nsApplicationAccessibleWrap::Unload()
}
NS_IMETHODIMP
nsApplicationAccessibleWrap::GetName(nsAString& aName)
ApplicationAccessibleWrap::GetName(nsAString& aName)
{
// ATK doesn't provide a way to obtain an application name (for example,
// Firefox or Thunderbird) like IA2 does. Thus let's return an application
@ -707,7 +701,7 @@ nsApplicationAccessibleWrap::GetName(nsAString& aName)
}
NS_IMETHODIMP
nsApplicationAccessibleWrap::GetNativeInterface(void **aOutAccessible)
ApplicationAccessibleWrap::GetNativeInterface(void** aOutAccessible)
{
*aOutAccessible = nsnull;
@ -745,9 +739,9 @@ gboolean fireRootAccessibleAddedCB(gpointer data)
}
bool
nsApplicationAccessibleWrap::AppendChild(nsAccessible *aChild)
ApplicationAccessibleWrap::AppendChild(nsAccessible* aChild)
{
if (!nsApplicationAccessible::AppendChild(aChild))
if (!ApplicationAccessible::AppendChild(aChild))
return false;
AtkObject *atkAccessible = nsAccessibleWrap::GetAtkObject(aChild);
@ -772,7 +766,7 @@ nsApplicationAccessibleWrap::AppendChild(nsAccessible *aChild)
}
bool
nsApplicationAccessibleWrap::RemoveChild(nsAccessible* aChild)
ApplicationAccessibleWrap::RemoveChild(nsAccessible* aChild)
{
PRInt32 index = aChild->IndexInParent();
@ -781,11 +775,11 @@ nsApplicationAccessibleWrap::RemoveChild(nsAccessible* aChild)
g_signal_emit_by_name(mAtkObject, "children_changed::remove", index,
atkAccessible, NULL);
return nsApplicationAccessible::RemoveChild(aChild);
return ApplicationAccessible::RemoveChild(aChild);
}
void
nsApplicationAccessibleWrap::PreCreate()
ApplicationAccessibleWrap::PreCreate()
{
if (!sATKChecked) {
sATKLib = PR_LoadLibrary(sATKLibName);

View File

@ -38,20 +38,20 @@
*
* ***** END LICENSE BLOCK ***** */
#ifndef __NS_APP_ROOT_ACCESSIBLE_H__
#define __NS_APP_ROOT_ACCESSIBLE_H__
#ifndef MOZILLA_A11Y_APPLICATION_ACCESSIBLE_WRAP_H__
#define MOZILLA_A11Y_APPLICATION_ACCESSIBLE_WRAP_H__
#include "nsApplicationAccessible.h"
#include "ApplicationAccessible.h"
class nsApplicationAccessibleWrap: public nsApplicationAccessible
class ApplicationAccessibleWrap: public ApplicationAccessible
{
public:
static void Unload();
static void PreCreate();
public:
nsApplicationAccessibleWrap();
virtual ~nsApplicationAccessibleWrap();
ApplicationAccessibleWrap();
virtual ~ApplicationAccessibleWrap();
// nsAccessNode
virtual bool Init();

View File

@ -53,7 +53,7 @@ CPPSRCS = \
nsAccessibleWrap.cpp \
nsDocAccessibleWrap.cpp \
nsRootAccessibleWrap.cpp \
nsApplicationAccessibleWrap.cpp \
ApplicationAccessibleWrap.cpp \
nsMaiInterfaceComponent.cpp \
nsMaiInterfaceAction.cpp \
nsMaiInterfaceText.cpp \

View File

@ -38,7 +38,6 @@
* ***** END LICENSE BLOCK ***** */
#include "nsAccessNodeWrap.h"
#include "nsApplicationAccessibleWrap.h"
/* For documentation of the accessibility architecture,
* see http://lxr.mozilla.org/seamonkey/source/accessible/accessible-docs.html

View File

@ -41,9 +41,9 @@
#include "nsAccessibleWrap.h"
#include "Accessible-inl.h"
#include "ApplicationAccessibleWrap.h"
#include "InterfaceInitFuncs.h"
#include "nsAccUtils.h"
#include "nsApplicationAccessibleWrap.h"
#include "nsIAccessibleRelation.h"
#include "nsRootAccessible.h"
#include "nsDocAccessibleWrap.h"
@ -68,7 +68,7 @@ using namespace mozilla::a11y;
nsAccessibleWrap::EAvailableAtkSignals nsAccessibleWrap::gAvailableAtkSignals =
eUnknown;
//defined in nsApplicationAccessibleWrap.cpp
//defined in ApplicationAccessibleWrap.cpp
extern "C" GType g_atk_hyperlink_impl_type;
/* MaiAtkObject */
@ -976,25 +976,20 @@ refRelationSetCB(AtkObject *aAtkObj)
// for it.
nsAccessibleWrap *GetAccessibleWrap(AtkObject *aAtkObj)
{
NS_ENSURE_TRUE(IS_MAI_OBJECT(aAtkObj), nsnull);
nsAccessibleWrap *tmpAccWrap = MAI_ATK_OBJECT(aAtkObj)->accWrap;
NS_ENSURE_TRUE(IS_MAI_OBJECT(aAtkObj), nsnull);
nsAccessibleWrap* accWrap = MAI_ATK_OBJECT(aAtkObj)->accWrap;
// Check if AccessibleWrap was deconstructed
if (tmpAccWrap == nsnull) {
return nsnull;
}
// Check if the accessible was deconstructed.
if (!accWrap)
return nsnull;
NS_ENSURE_TRUE(tmpAccWrap->GetAtkObject() == aAtkObj, nsnull);
NS_ENSURE_TRUE(accWrap->GetAtkObject() == aAtkObj, nsnull);
nsApplicationAccessible *applicationAcc =
nsAccessNode::GetApplicationAccessible();
nsAccessibleWrap* tmpAppAccWrap =
static_cast<nsAccessibleWrap*>(applicationAcc);
nsAccessibleWrap* appAccWrap = nsAccessNode::GetApplicationAccessible();
if (appAccWrap != accWrap && !accWrap->IsValidObject())
return nsnull;
if (tmpAppAccWrap != tmpAccWrap && !tmpAccWrap->IsValidObject())
return nsnull;
return tmpAccWrap;
return accWrap;
}
nsresult

View File

@ -39,9 +39,9 @@
#include "AccEvent.h"
#include "ApplicationAccessibleWrap.h"
#include "nsAccessibilityService.h"
#include "nsAccUtils.h"
#include "nsApplicationAccessibleWrap.h"
#include "nsDocAccessible.h"
#include "nsIAccessibleText.h"
#include "nsAccEvent.h"
@ -155,7 +155,7 @@ AccEvent::CaptureIsFromUserInput(EIsFromUserInput aIsFromUserInput)
// XXX: remove this hack during reorganization of 506907. Meanwhile we
// want to get rid an assertion for application accessible events which
// don't have DOM node (see bug 506206).
nsApplicationAccessible *applicationAcc =
ApplicationAccessible* applicationAcc =
nsAccessNode::GetApplicationAccessible();
if (mAccessible != static_cast<nsIAccessible*>(applicationAcc))

View File

@ -69,7 +69,6 @@ CPPSRCS = \
nsBaseWidgetAccessible.cpp \
nsEventShell.cpp \
nsRootAccessible.cpp \
nsApplicationAccessible.cpp \
nsCaretAccessible.cpp \
nsTextAccessible.cpp \
nsTextEquivUtils.cpp \

View File

@ -38,9 +38,9 @@
#include "nsAccDocManager.h"
#include "ApplicationAccessible.h"
#include "nsAccessibilityService.h"
#include "nsAccUtils.h"
#include "nsApplicationAccessible.h"
#include "nsARIAMap.h"
#include "nsRootAccessibleWrap.h"
#include "States.h"

View File

@ -38,9 +38,9 @@
#include "nsAccessNode.h"
#include "ApplicationAccessibleWrap.h"
#include "nsAccessibilityService.h"
#include "nsAccUtils.h"
#include "nsApplicationAccessibleWrap.h"
#include "nsCoreUtils.h"
#include "nsRootAccessible.h"
@ -67,7 +67,7 @@ nsIStringBundle *nsAccessNode::gStringBundle = 0;
bool nsAccessNode::gIsFormFillEnabled = false;
nsApplicationAccessible *nsAccessNode::gApplicationAccessible = nsnull;
ApplicationAccessible* nsAccessNode::gApplicationAccessible = nsnull;
/*
* Class nsAccessNode
@ -130,18 +130,16 @@ nsAccessNode::Shutdown()
mDoc = nsnull;
}
nsApplicationAccessible*
ApplicationAccessible*
nsAccessNode::GetApplicationAccessible()
{
NS_ASSERTION(!nsAccessibilityService::IsShutdown(),
"Accessibility wasn't initialized!");
if (!gApplicationAccessible) {
nsApplicationAccessibleWrap::PreCreate();
ApplicationAccessibleWrap::PreCreate();
gApplicationAccessible = new nsApplicationAccessibleWrap();
if (!gApplicationAccessible)
return nsnull;
gApplicationAccessible = new ApplicationAccessibleWrap();
// Addref on create. Will Release in ShutdownXPAccessibility()
NS_ADDREF(gApplicationAccessible);
@ -200,7 +198,7 @@ void nsAccessNode::ShutdownXPAccessibility()
// Release gApplicationAccessible after everything else is shutdown
// so we don't accidently create it again while tearing down root accessibles
nsApplicationAccessibleWrap::Unload();
ApplicationAccessibleWrap::Unload();
if (gApplicationAccessible) {
gApplicationAccessible->Shutdown();
NS_RELEASE(gApplicationAccessible);

View File

@ -53,8 +53,8 @@
#include "nsIStringBundle.h"
#include "nsWeakReference.h"
class ApplicationAccessible;
class nsAccessNode;
class nsApplicationAccessible;
class nsDocAccessible;
class nsIAccessibleDocument;
class nsRootAccessible;
@ -83,7 +83,7 @@ public:
/**
* Return an application accessible.
*/
static nsApplicationAccessible* GetApplicationAccessible();
static ApplicationAccessible* GetApplicationAccessible();
/**
* Return the document accessible for this access node.
@ -174,7 +174,7 @@ private:
nsAccessNode(const nsAccessNode&) MOZ_DELETE;
nsAccessNode& operator =(const nsAccessNode&) MOZ_DELETE;
static nsApplicationAccessible *gApplicationAccessible;
static ApplicationAccessible* gApplicationAccessible;
};
#endif

View File

@ -40,6 +40,7 @@
// NOTE: alphabetically ordered
#include "Accessible-inl.h"
#include "ApplicationAccessibleWrap.h"
#include "ARIAGridAccessibleWrap.h"
#ifdef MOZ_ACCESSIBILITY_ATK
#include "AtkSocketAccessible.h"
@ -48,7 +49,6 @@
#include "nsAccessiblePivot.h"
#include "nsAccUtils.h"
#include "nsARIAMap.h"
#include "nsApplicationAccessibleWrap.h"
#include "nsIAccessibleProvider.h"
#include "nsHTMLCanvasAccessible.h"
#include "nsHTMLImageMapAccessible.h"
@ -678,7 +678,7 @@ nsAccessibilityService::RecreateAccessible(nsIPresShell* aPresShell,
// nsIAccessibleRetrieval
NS_IMETHODIMP
nsAccessibilityService::GetApplicationAccessible(nsIAccessible **aAccessibleApplication)
nsAccessibilityService::GetApplicationAccessible(nsIAccessible** aAccessibleApplication)
{
NS_ENSURE_ARG_POINTER(aAccessibleApplication);
@ -1724,7 +1724,7 @@ nsAccessible*
nsAccessibilityService::AddNativeRootAccessible(void* aAtkAccessible)
{
#ifdef MOZ_ACCESSIBILITY_ATK
nsApplicationAccessible* applicationAcc =
ApplicationAccessible* applicationAcc =
nsAccessNode::GetApplicationAccessible();
if (!applicationAcc)
return nsnull;
@ -1745,7 +1745,7 @@ void
nsAccessibilityService::RemoveNativeRootAccessible(nsAccessible* aAccessible)
{
#ifdef MOZ_ACCESSIBILITY_ATK
nsApplicationAccessible* applicationAcc =
ApplicationAccessible* applicationAcc =
nsAccessNode::GetApplicationAccessible();
if (applicationAcc)

View File

@ -63,7 +63,7 @@ FocusManager* FocusMgr();
/**
* Perform initialization that should be done as soon as possible, in order
* to minimize startup time.
* XXX: this function and the next defined in nsApplicationAccessibleWrap.cpp
* XXX: this function and the next defined in ApplicationAccessibleWrap.cpp
*/
void PreInit();

View File

@ -42,7 +42,6 @@
#include "Accessible-inl.h"
#include "nsAccessibilityService.h"
#include "nsApplicationAccessibleWrap.h"
#include "nsAccUtils.h"
#include "nsCoreUtils.h"
#include "Relation.h"

View File

@ -40,7 +40,7 @@
*
* ***** END LICENSE BLOCK ***** */
#include "nsApplicationAccessible.h"
#include "ApplicationAccessible.h"
#include "nsAccessibilityService.h"
#include "nsAccUtils.h"
@ -57,7 +57,7 @@
using namespace mozilla::a11y;
nsApplicationAccessible::nsApplicationAccessible() :
ApplicationAccessible::ApplicationAccessible() :
nsAccessibleWrap(nsnull, nsnull)
{
mFlags |= eApplicationAccessible;
@ -66,14 +66,14 @@ nsApplicationAccessible::nsApplicationAccessible() :
////////////////////////////////////////////////////////////////////////////////
// nsISupports
NS_IMPL_ISUPPORTS_INHERITED1(nsApplicationAccessible, nsAccessible,
NS_IMPL_ISUPPORTS_INHERITED1(ApplicationAccessible, nsAccessible,
nsIAccessibleApplication)
////////////////////////////////////////////////////////////////////////////////
// nsIAccessible
NS_IMETHODIMP
nsApplicationAccessible::GetParent(nsIAccessible **aAccessible)
ApplicationAccessible::GetParent(nsIAccessible** aAccessible)
{
NS_ENSURE_ARG_POINTER(aAccessible);
*aAccessible = nsnull;
@ -81,7 +81,7 @@ nsApplicationAccessible::GetParent(nsIAccessible **aAccessible)
}
NS_IMETHODIMP
nsApplicationAccessible::GetNextSibling(nsIAccessible **aNextSibling)
ApplicationAccessible::GetNextSibling(nsIAccessible** aNextSibling)
{
NS_ENSURE_ARG_POINTER(aNextSibling);
*aNextSibling = nsnull;
@ -89,7 +89,7 @@ nsApplicationAccessible::GetNextSibling(nsIAccessible **aNextSibling)
}
NS_IMETHODIMP
nsApplicationAccessible::GetPreviousSibling(nsIAccessible **aPreviousSibling)
ApplicationAccessible::GetPreviousSibling(nsIAccessible** aPreviousSibling)
{
NS_ENSURE_ARG_POINTER(aPreviousSibling);
*aPreviousSibling = nsnull;
@ -97,7 +97,7 @@ nsApplicationAccessible::GetPreviousSibling(nsIAccessible **aPreviousSibling)
}
NS_IMETHODIMP
nsApplicationAccessible::GetName(nsAString& aName)
ApplicationAccessible::GetName(nsAString& aName)
{
aName.Truncate();
@ -125,25 +125,25 @@ nsApplicationAccessible::GetName(nsAString& aName)
}
void
nsApplicationAccessible::Description(nsString &aDescription)
ApplicationAccessible::Description(nsString& aDescription)
{
aDescription.Truncate();
}
void
nsApplicationAccessible::Value(nsString& aValue)
ApplicationAccessible::Value(nsString& aValue)
{
aValue.Truncate();
}
PRUint64
nsApplicationAccessible::State()
ApplicationAccessible::State()
{
return IsDefunct() ? states::DEFUNCT : 0;
}
NS_IMETHODIMP
nsApplicationAccessible::GetAttributes(nsIPersistentProperties **aAttributes)
ApplicationAccessible::GetAttributes(nsIPersistentProperties** aAttributes)
{
NS_ENSURE_ARG_POINTER(aAttributes);
*aAttributes = nsnull;
@ -151,9 +151,9 @@ nsApplicationAccessible::GetAttributes(nsIPersistentProperties **aAttributes)
}
NS_IMETHODIMP
nsApplicationAccessible::GroupPosition(PRInt32 *aGroupLevel,
PRInt32 *aSimilarItemsInGroup,
PRInt32 *aPositionInGroup)
ApplicationAccessible::GroupPosition(PRInt32* aGroupLevel,
PRInt32* aSimilarItemsInGroup,
PRInt32* aPositionInGroup)
{
NS_ENSURE_ARG_POINTER(aGroupLevel);
*aGroupLevel = 0;
@ -165,14 +165,14 @@ nsApplicationAccessible::GroupPosition(PRInt32 *aGroupLevel,
}
nsAccessible*
nsApplicationAccessible::ChildAtPoint(PRInt32 aX, PRInt32 aY,
EWhichChildAtPoint aWhichChild)
ApplicationAccessible::ChildAtPoint(PRInt32 aX, PRInt32 aY,
EWhichChildAtPoint aWhichChild)
{
return nsnull;
}
nsAccessible*
nsApplicationAccessible::FocusedChild()
ApplicationAccessible::FocusedChild()
{
nsAccessible* focus = FocusMgr()->FocusedAccessible();
if (focus && focus->Parent() == this)
@ -182,14 +182,14 @@ nsApplicationAccessible::FocusedChild()
}
Relation
nsApplicationAccessible::RelationByType(PRUint32 aRelationType)
ApplicationAccessible::RelationByType(PRUint32 aRelationType)
{
return Relation();
}
NS_IMETHODIMP
nsApplicationAccessible::GetBounds(PRInt32 *aX, PRInt32 *aY,
PRInt32 *aWidth, PRInt32 *aHeight)
ApplicationAccessible::GetBounds(PRInt32* aX, PRInt32* aY,
PRInt32* aWidth, PRInt32* aHeight)
{
NS_ENSURE_ARG_POINTER(aX);
*aX = 0;
@ -203,46 +203,46 @@ nsApplicationAccessible::GetBounds(PRInt32 *aX, PRInt32 *aY,
}
NS_IMETHODIMP
nsApplicationAccessible::SetSelected(bool aIsSelected)
ApplicationAccessible::SetSelected(bool aIsSelected)
{
return NS_OK;
}
NS_IMETHODIMP
nsApplicationAccessible::TakeSelection()
ApplicationAccessible::TakeSelection()
{
return NS_OK;
}
NS_IMETHODIMP
nsApplicationAccessible::TakeFocus()
ApplicationAccessible::TakeFocus()
{
return NS_OK;
}
PRUint8
nsApplicationAccessible::ActionCount()
ApplicationAccessible::ActionCount()
{
return 0;
}
NS_IMETHODIMP
nsApplicationAccessible::GetActionName(PRUint8 aIndex, nsAString &aName)
ApplicationAccessible::GetActionName(PRUint8 aIndex, nsAString& aName)
{
aName.Truncate();
return NS_ERROR_INVALID_ARG;
}
NS_IMETHODIMP
nsApplicationAccessible::GetActionDescription(PRUint8 aIndex,
nsAString &aDescription)
ApplicationAccessible::GetActionDescription(PRUint8 aIndex,
nsAString& aDescription)
{
aDescription.Truncate();
return NS_ERROR_INVALID_ARG;
}
NS_IMETHODIMP
nsApplicationAccessible::DoAction(PRUint8 aIndex)
ApplicationAccessible::DoAction(PRUint8 aIndex)
{
return NS_OK;
}
@ -251,7 +251,7 @@ nsApplicationAccessible::DoAction(PRUint8 aIndex)
// nsIAccessibleApplication
NS_IMETHODIMP
nsApplicationAccessible::GetAppName(nsAString& aName)
ApplicationAccessible::GetAppName(nsAString& aName)
{
aName.Truncate();
@ -267,7 +267,7 @@ nsApplicationAccessible::GetAppName(nsAString& aName)
}
NS_IMETHODIMP
nsApplicationAccessible::GetAppVersion(nsAString& aVersion)
ApplicationAccessible::GetAppVersion(nsAString& aVersion)
{
aVersion.Truncate();
@ -283,14 +283,14 @@ nsApplicationAccessible::GetAppVersion(nsAString& aVersion)
}
NS_IMETHODIMP
nsApplicationAccessible::GetPlatformName(nsAString& aName)
ApplicationAccessible::GetPlatformName(nsAString& aName)
{
aName.AssignLiteral("Gecko");
return NS_OK;
}
NS_IMETHODIMP
nsApplicationAccessible::GetPlatformVersion(nsAString& aVersion)
ApplicationAccessible::GetPlatformVersion(nsAString& aVersion)
{
aVersion.Truncate();
@ -309,20 +309,20 @@ nsApplicationAccessible::GetPlatformVersion(nsAString& aVersion)
// nsAccessNode public methods
bool
nsApplicationAccessible::Init()
ApplicationAccessible::Init()
{
mAppInfo = do_GetService("@mozilla.org/xre/app-info;1");
return true;
}
void
nsApplicationAccessible::Shutdown()
ApplicationAccessible::Shutdown()
{
mAppInfo = nsnull;
}
bool
nsApplicationAccessible::IsPrimaryForNode() const
ApplicationAccessible::IsPrimaryForNode() const
{
return false;
}
@ -331,31 +331,31 @@ nsApplicationAccessible::IsPrimaryForNode() const
// nsAccessible public methods
void
nsApplicationAccessible::ApplyARIAState(PRUint64* aState)
ApplicationAccessible::ApplyARIAState(PRUint64* aState)
{
}
role
nsApplicationAccessible::NativeRole()
ApplicationAccessible::NativeRole()
{
return roles::APP_ROOT;
}
PRUint64
nsApplicationAccessible::NativeState()
ApplicationAccessible::NativeState()
{
return 0;
}
void
nsApplicationAccessible::InvalidateChildren()
ApplicationAccessible::InvalidateChildren()
{
// Do nothing because application children are kept updated by AppendChild()
// and RemoveChild() method calls.
}
KeyBinding
nsApplicationAccessible::AccessKey() const
ApplicationAccessible::AccessKey() const
{
return KeyBinding();
}
@ -364,7 +364,7 @@ nsApplicationAccessible::AccessKey() const
// nsAccessible protected methods
void
nsApplicationAccessible::CacheChildren()
ApplicationAccessible::CacheChildren()
{
// CacheChildren is called only once for application accessible when its
// children are requested because empty InvalidateChldren() prevents its
@ -404,8 +404,8 @@ nsApplicationAccessible::CacheChildren()
}
nsAccessible*
nsApplicationAccessible::GetSiblingAtOffset(PRInt32 aOffset,
nsresult* aError) const
ApplicationAccessible::GetSiblingAtOffset(PRInt32 aOffset,
nsresult* aError) const
{
if (aError)
*aError = NS_OK; // fail peacefully
@ -417,7 +417,7 @@ nsApplicationAccessible::GetSiblingAtOffset(PRInt32 aOffset,
// nsIAccessible
NS_IMETHODIMP
nsApplicationAccessible::GetDOMNode(nsIDOMNode **aDOMNode)
ApplicationAccessible::GetDOMNode(nsIDOMNode** aDOMNode)
{
NS_ENSURE_ARG_POINTER(aDOMNode);
*aDOMNode = nsnull;
@ -425,7 +425,7 @@ nsApplicationAccessible::GetDOMNode(nsIDOMNode **aDOMNode)
}
NS_IMETHODIMP
nsApplicationAccessible::GetDocument(nsIAccessibleDocument **aDocument)
ApplicationAccessible::GetDocument(nsIAccessibleDocument** aDocument)
{
NS_ENSURE_ARG_POINTER(aDocument);
*aDocument = nsnull;
@ -433,7 +433,7 @@ nsApplicationAccessible::GetDocument(nsIAccessibleDocument **aDocument)
}
NS_IMETHODIMP
nsApplicationAccessible::GetRootDocument(nsIAccessibleDocument **aRootDocument)
ApplicationAccessible::GetRootDocument(nsIAccessibleDocument** aRootDocument)
{
NS_ENSURE_ARG_POINTER(aRootDocument);
*aRootDocument = nsnull;
@ -441,20 +441,20 @@ nsApplicationAccessible::GetRootDocument(nsIAccessibleDocument **aRootDocument)
}
NS_IMETHODIMP
nsApplicationAccessible::ScrollTo(PRUint32 aScrollType)
ApplicationAccessible::ScrollTo(PRUint32 aScrollType)
{
return NS_OK;
}
NS_IMETHODIMP
nsApplicationAccessible::ScrollToPoint(PRUint32 aCoordinateType,
PRInt32 aX, PRInt32 aY)
ApplicationAccessible::ScrollToPoint(PRUint32 aCoordinateType,
PRInt32 aX, PRInt32 aY)
{
return NS_OK;
}
NS_IMETHODIMP
nsApplicationAccessible::GetLanguage(nsAString &aLanguage)
ApplicationAccessible::GetLanguage(nsAString& aLanguage)
{
aLanguage.Truncate();
return NS_OK;

View File

@ -40,8 +40,8 @@
*
* ***** END LICENSE BLOCK ***** */
#ifndef __NS_APPLICATION_ACCESSIBLE_H__
#define __NS_APPLICATION_ACCESSIBLE_H__
#ifndef MOZILLA_A11Y_APPLICATION_ACCESSIBLE_H__
#define MOZILLA_A11Y_APPLICATION_ACCESSIBLE_H__
#include "nsAccessibleWrap.h"
#include "nsIAccessibleApplication.h"
@ -50,21 +50,21 @@
#include "nsIXULAppInfo.h"
/**
* nsApplicationAccessible is for the whole application of Mozilla.
* Only one instance of nsApplicationAccessible exists for one Mozilla instance.
* ApplicationAccessible is for the whole application of Mozilla.
* Only one instance of ApplicationAccessible exists for one Mozilla instance.
* And this one should be created when Mozilla Startup (if accessibility
* feature has been enabled) and destroyed when Mozilla Shutdown.
*
* All the accessibility objects for toplevel windows are direct children of
* the nsApplicationAccessible instance.
* the ApplicationAccessible instance.
*/
class nsApplicationAccessible: public nsAccessibleWrap,
public nsIAccessibleApplication
class ApplicationAccessible: public nsAccessibleWrap,
public nsIAccessibleApplication
{
public:
nsApplicationAccessible();
ApplicationAccessible();
// nsISupports
NS_DECL_ISUPPORTS_INHERITED

View File

@ -15,6 +15,7 @@ LIBXUL_LIBRARY = 1
CPPSRCS = \
ApplicationAccessible.cpp \
ARIAGridAccessible.cpp \
FormControlAccessible.cpp \
OuterDocAccessible.cpp \

View File

@ -38,12 +38,12 @@
*
* ***** END LICENSE BLOCK ***** */
#ifndef __NS_APPLICATION_ACCESSIBLE_WRAP_H__
#define __NS_APPLICATION_ACCESSIBLE_WRAP_H__
#ifndef MOZILLA_A11Y_APPLICATION_ACCESSIBLE_WRAP_H__
#define MOZILLA_A11Y_APPLICATION_ACCESSIBLE_WRAP_H__
#include "nsApplicationAccessible.h"
#include "ApplicationAccessible.h"
class nsApplicationAccessibleWrap: public nsApplicationAccessible
class ApplicationAccessibleWrap: public ApplicationAccessible
{
public:
static void PreCreate() {}

View File

@ -62,6 +62,7 @@ CMMSRCS = nsAccessNodeWrap.mm \
EXPORTS = \
ApplicationAccessibleWrap.h \
ARIAGridAccessibleWrap.h \
nsAccessNodeWrap.h \
nsTextAccessibleWrap.h \
@ -74,7 +75,6 @@ EXPORTS = \
nsHyperTextAccessibleWrap.h \
nsHTMLImageAccessibleWrap.h \
nsHTMLTableAccessibleWrap.h \
nsApplicationAccessibleWrap.h \
mozDocAccessible.h \
mozAccessible.h \
mozAccessibleProtocol.h \

View File

@ -38,7 +38,7 @@
*
* ***** END LICENSE BLOCK ***** */
#include "nsApplicationAccessibleWrap.h"
#include "ApplicationAccessibleWrap.h"
#include "AccessibleApplication_i.c"
@ -48,11 +48,11 @@
////////////////////////////////////////////////////////////////////////////////
// nsISupports
NS_IMPL_ISUPPORTS_INHERITED0(nsApplicationAccessibleWrap,
nsApplicationAccessible)
NS_IMPL_ISUPPORTS_INHERITED0(ApplicationAccessibleWrap,
ApplicationAccessible)
NS_IMETHODIMP
nsApplicationAccessibleWrap::GetAttributes(nsIPersistentProperties** aAttributes)
ApplicationAccessibleWrap::GetAttributes(nsIPersistentProperties** aAttributes)
{
NS_ENSURE_ARG_POINTER(aAttributes);
*aAttributes = nsnull;
@ -80,7 +80,7 @@ nsApplicationAccessibleWrap::GetAttributes(nsIPersistentProperties** aAttributes
// IUnknown
STDMETHODIMP
nsApplicationAccessibleWrap::QueryInterface(REFIID iid, void** ppv)
ApplicationAccessibleWrap::QueryInterface(REFIID iid, void** ppv)
{
*ppv = NULL;
@ -97,7 +97,7 @@ nsApplicationAccessibleWrap::QueryInterface(REFIID iid, void** ppv)
// IAccessibleApplication
STDMETHODIMP
nsApplicationAccessibleWrap::get_appName(BSTR *aName)
ApplicationAccessibleWrap::get_appName(BSTR* aName)
{
__try {
*aName = NULL;
@ -121,7 +121,7 @@ __try {
}
STDMETHODIMP
nsApplicationAccessibleWrap::get_appVersion(BSTR *aVersion)
ApplicationAccessibleWrap::get_appVersion(BSTR* aVersion)
{
__try {
*aVersion = NULL;
@ -145,7 +145,7 @@ __try {
}
STDMETHODIMP
nsApplicationAccessibleWrap::get_toolkitName(BSTR *aName)
ApplicationAccessibleWrap::get_toolkitName(BSTR* aName)
{
__try {
if (IsDefunct())
@ -167,7 +167,7 @@ __try {
}
STDMETHODIMP
nsApplicationAccessibleWrap::get_toolkitVersion(BSTR *aVersion)
ApplicationAccessibleWrap::get_toolkitVersion(BSTR* aVersion)
{
__try {
*aVersion = NULL;
@ -191,15 +191,15 @@ __try {
}
////////////////////////////////////////////////////////////////////////////////
// nsApplicationAccessibleWrap public static
// ApplicationAccessibleWrap public static
void
nsApplicationAccessibleWrap::PreCreate()
ApplicationAccessibleWrap::PreCreate()
{
}
void
nsApplicationAccessibleWrap::Unload()
ApplicationAccessibleWrap::Unload()
{
}

View File

@ -38,15 +38,15 @@
*
* ***** END LICENSE BLOCK ***** */
#ifndef __NS_APPLICATION_ACCESSIBLE_WRAP_H__
#define __NS_APPLICATION_ACCESSIBLE_WRAP_H__
#ifndef MOZILLA_A11Y_APPLICATION_ACCESSIBLE_WRAP_H__
#define MOZILLA_A11Y_APPLICATION_ACCESSIBLE_WRAP_H__
#include "nsApplicationAccessible.h"
#include "ApplicationAccessible.h"
#include "AccessibleApplication.h"
class nsApplicationAccessibleWrap: public nsApplicationAccessible,
public IAccessibleApplication
class ApplicationAccessibleWrap: public ApplicationAccessible,
public IAccessibleApplication
{
public:
// nsISupporst

View File

@ -48,12 +48,13 @@ LIBXUL_LIBRARY = 1
CPPSRCS = \
ApplicationAccessibleWrap.cpp \
ARIAGridAccessibleWrap.cpp \
nsAccessNodeWrap.cpp \
nsAccessibleWrap.cpp \
nsTextAccessibleWrap.cpp \
nsDocAccessibleWrap.cpp \
nsHTMLWin32ObjectAccessible.cpp \
ARIAGridAccessibleWrap.cpp \
nsRootAccessibleWrap.cpp \
nsXULMenuAccessibleWrap.cpp \
nsXULListboxAccessibleWrap.cpp \
@ -61,7 +62,6 @@ CPPSRCS = \
nsHyperTextAccessibleWrap.cpp \
nsHTMLImageAccessibleWrap.cpp \
nsHTMLTableAccessibleWrap.cpp \
nsApplicationAccessibleWrap.cpp \
nsWinUtils.cpp \
ia2AccessibleAction.cpp \
ia2AccessibleComponent.cpp \
@ -78,6 +78,7 @@ CPPSRCS = \
$(NULL)
EXPORTS = \
ApplicationAccessibleWrap.h \
ARIAGridAccessibleWrap.h \
nsAccessNodeWrap.h \
nsAccessibleWrap.h \
@ -91,7 +92,6 @@ EXPORTS = \
nsHyperTextAccessibleWrap.h \
nsHTMLImageAccessibleWrap.h \
nsHTMLTableAccessibleWrap.h \
nsApplicationAccessibleWrap.h \
ia2AccessibleAction.h \
ia2AccessibleComponent.h \
CAccessibleImage.h \

View File

@ -39,11 +39,11 @@
#include "nsAccessNodeWrap.h"
#include "AccessibleApplication.h"
#include "ApplicationAccessibleWrap.h"
#include "ISimpleDOMNode_i.c"
#include "Compatibility.h"
#include "nsAccessibilityService.h"
#include "nsApplicationAccessibleWrap.h"
#include "nsCoreUtils.h"
#include "nsRootAccessible.h"
#include "nsWinUtils.h"
@ -174,7 +174,7 @@ nsAccessNodeWrap::QueryService(REFGUID guidService, REFIID iid, void** ppv)
// Can get to IAccessibleApplication from any node via QS
if (iid == IID_IAccessibleApplication) {
nsApplicationAccessible *applicationAcc = GetApplicationAccessible();
ApplicationAccessible* applicationAcc = GetApplicationAccessible();
if (!applicationAcc)
return E_NOINTERFACE;

View File

@ -38,12 +38,12 @@
*
* ***** END LICENSE BLOCK ***** */
#ifndef __NS_APPLICATION_ACCESSIBLE_WRAP_H__
#define __NS_APPLICATION_ACCESSIBLE_WRAP_H__
#ifndef MOZILLA_A11Y_APPLICATION_ACCESSIBLE_WRAP_H__
#define MOZILLA_A11Y_APPLICATION_ACCESSIBLE_WRAP_H__
#include "nsApplicationAccessible.h"
#include "ApplicationAccessible.h"
class nsApplicationAccessibleWrap: public nsApplicationAccessible
class ApplicationAccessibleWrap: public ApplicationAccessible
{
public:
static void PreCreate() {}

View File

@ -54,6 +54,7 @@ CPPSRCS = \
$(NULL)
EXPORTS = \
ApplicationAccessibleWrap.h \
ARIAGridAccessibleWrap.h \
nsAccessNodeWrap.h \
nsTextAccessibleWrap.h \
@ -66,7 +67,6 @@ EXPORTS = \
nsHyperTextAccessibleWrap.h \
nsHTMLImageAccessibleWrap.h \
nsHTMLTableAccessibleWrap.h \
nsApplicationAccessibleWrap.h \
$(NULL)
# we don't want the shared lib, but we want to force the creation of a static lib.

View File

@ -524,6 +524,25 @@
phase="capturing"
modifiers="accel"
action="this.selectEngine(event, (event.detail > 0));"/>
<handler event="focus">
<![CDATA[
// Speculatively connect to the current engine's search URI (and
// suggest URI, if different) to reduce request latency
const SUGGEST_TYPE = "application/x-suggestions+json";
var engine = this.currentEngine;
var connector =
Services.io.QueryInterface(Components.interfaces.nsISpeculativeConnect);
var searchURI = engine.getSubmission("dummy").uri;
connector.speculativeConnect(searchURI, null, null);
if (engine.supportsResponseType(SUGGEST_TYPE)) {
var suggestURI = engine.getSubmission("dummy", SUGGEST_TYPE).uri;
if (suggestURI.prePath != searchURI.prePath)
connector.speculativeConnect(suggestURI, null, null);
}
]]></handler>
</handlers>
</binding>

View File

@ -1,209 +0,0 @@
#!/usr/bin/env python
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is Mozilla Corporation Code.
#
# The Initial Developer of the Original Code is
# Mikeal Rogers.
# Portions created by the Initial Developer are Copyright (C) 2008
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Mikeal Rogers <mikeal.rogers@gmail.com>
# Henrik Skupin <hskupin@mozilla.com>
# Clint Talbert <ctalbert@mozilla.com>
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
"""
file for interface to transform introspected system information to a format
pallatable to Mozilla
Information:
- os : what operating system ['win', 'mac', 'linux', ...]
- bits : 32 or 64
- processor : processor architecture ['x86', 'x86_64', 'ppc', ...]
- version : operating system version string
For windows, the service pack information is also included
"""
# TODO: it might be a good idea of adding a system name (e.g. 'Ubuntu' for
# linux) to the information; I certainly wouldn't want anyone parsing this
# information and having behaviour depend on it
import os
import platform
import re
import sys
# keep a copy of the os module since updating globals overrides this
_os = os
class unknown(object):
"""marker class for unknown information"""
def __nonzero__(self):
return False
def __str__(self):
return 'UNKNOWN'
unknown = unknown() # singleton
# get system information
info = {'os': unknown,
'processor': unknown,
'version': unknown,
'bits': unknown }
(system, node, release, version, machine, processor) = platform.uname()
(bits, linkage) = platform.architecture()
# get os information and related data
if system in ["Microsoft", "Windows"]:
info['os'] = 'win'
# There is a Python bug on Windows to determine platform values
# http://bugs.python.org/issue7860
if "PROCESSOR_ARCHITEW6432" in os.environ:
processor = os.environ.get("PROCESSOR_ARCHITEW6432", processor)
else:
processor = os.environ.get('PROCESSOR_ARCHITECTURE', processor)
system = os.environ.get("OS", system).replace('_', ' ')
service_pack = os.sys.getwindowsversion()[4]
info['service_pack'] = service_pack
elif system == "Linux":
(distro, version, codename) = platform.dist()
version = distro + " " + version
if not processor:
processor = machine
info['os'] = 'linux'
elif system == "Darwin":
(release, versioninfo, machine) = platform.mac_ver()
version = "OS X " + release
info['os'] = 'mac'
elif sys.platform in ('solaris', 'sunos5'):
info['os'] = 'unix'
version = sys.platform
info['version'] = version # os version
# processor type and bits
if processor in ["i386", "i686"]:
if bits == "32bit":
processor = "x86"
elif bits == "64bit":
processor = "x86_64"
elif processor == "AMD64":
bits = "64bit"
processor = "x86_64"
elif processor == "Power Macintosh":
processor = "ppc"
bits = re.search('(\d+)bit', bits).group(1)
info.update({'processor': processor,
'bits': int(bits),
})
# standard value of choices, for easy inspection
choices = {'os': ['linux', 'win', 'mac', 'unix'],
'bits': [32, 64],
'processor': ['x86', 'x86_64', 'ppc']}
def sanitize(info):
"""Do some sanitization of input values, primarily
to handle universal Mac builds."""
if "processor" in info and info["processor"] == "universal-x86-x86_64":
# If we're running on OS X 10.6 or newer, assume 64-bit
if release[:4] >= "10.6":
info["processor"] = "x86_64"
info["bits"] = 64
else:
info["processor"] = "x86"
info["bits"] = 32
# method for updating information
def update(new_info):
"""update the info"""
info.update(new_info)
sanitize(info)
globals().update(info)
# convenience data for os access
for os_name in choices['os']:
globals()['is' + os_name.title()] = info['os'] == os_name
# unix is special
if isLinux:
globals()['isUnix'] = True
update({})
# exports
__all__ = info.keys()
__all__ += ['is' + os_name.title() for os_name in choices['os']]
__all__ += ['info', 'unknown', 'main', 'choices', 'update']
def main(args=None):
# parse the command line
from optparse import OptionParser
parser = OptionParser()
for key in choices:
parser.add_option('--%s' % key, dest=key,
action='store_true', default=False,
help="display choices for %s" % key)
options, args = parser.parse_args()
# args are JSON blobs to override info
if args:
try:
from json import loads
except ImportError:
try:
from simplejson import loads
except ImportError:
def loads(string):
"""*really* simple json; will not work with unicode"""
return eval(string, {'true': True, 'false': False, 'null': None})
for arg in args:
if _os.path.exists(arg):
string = file(arg).read()
else:
string = arg
update(loads(string))
# print out choices if requested
flag = False
for key, value in options.__dict__.items():
if value is True:
print '%s choices: %s' % (key, ' '.join([str(choice)
for choice in choices[key]]))
flag = True
if flag: return
# otherwise, print out all info
for key, value in info.items():
print '%s: %s' % (key, value)
if __name__ == '__main__':
main()

View File

@ -6327,44 +6327,6 @@ if test -n "$MOZ_TREE_FREETYPE"; then
AC_SUBST(CAIRO_FT_CFLAGS)
fi
dnl ========================================================
dnl Web App Runtime
dnl ========================================================
MOZ_ARG_DISABLE_BOOL(webapp-runtime,
[ --disable-webapp-runtime Disable Web App Runtime],
MOZ_WEBAPP_RUNTIME=,
MOZ_WEBAPP_RUNTIME=1)
if test -n "$MOZ_WEBAPP_RUNTIME" -a "$OS_ARCH" = "WINNT"; then
# Disable Web App Runtime for Windows builds that use the new toolkit if the
# required major version and minimum minor version of Unicode NSIS isn't in
# the path.
REQ_NSIS_MAJOR_VER=2
MIN_NSIS_MINOR_VER=33
MOZ_PATH_PROGS(MAKENSISU, $MAKENSISU makensisu-2.46 makensisu makensis)
if test -z "$MAKENSISU" -o "$MAKENSISU" = ":"; then
AC_MSG_ERROR([To build the Web App Runtime you must have the latest MozillaBuild or Unicode NSIS with a major version of $REQ_NSIS_MAJOR_VER and a minimum minor version of $MIN_NSIS_MINOR_VER in your path. To build without the Web App Runtime reconfigure using --disable-webapp-runtime.])
fi
changequote(,)
MAKENSISU_VER=`"$MAKENSISU" -version 2>/dev/null | sed -e '/-Unicode/!s/.*//g' -e 's/^v\([0-9]\+\.[0-9]\+\)\-Unicode$/\1/g'`
changequote([,])
if test ! "$MAKENSISU_VER" = ""; then
MAKENSISU_MAJOR_VER=`echo $MAKENSISU_VER | $AWK -F\. '{ print $1 }'`
MAKENSISU_MINOR_VER=`echo $MAKENSISU_VER | $AWK -F\. '{ print $2 }'`
fi
AC_MSG_CHECKING([for Unicode NSIS with major version == $REQ_NSIS_MAJOR_VER and minor version >= $MIN_NSIS_MINOR_VER])
if test "$MAKENSISU_VER" = "" ||
test ! "$MAKENSISU_MAJOR_VER" = "$REQ_NSIS_MAJOR_VER" -o \
! "$MAKENSISU_MINOR_VER" -ge $MIN_NSIS_MINOR_VER; then
AC_MSG_RESULT([no])
AC_MSG_ERROR([To build the Web App Runtime you must have the latest MozillaBuild or Unicode NSIS with a major version of $REQ_NSIS_MAJOR_VER and a minimum minor version of $MIN_NSIS_MINOR_VER in your path. To build without the Web App Runtime reconfigure using --disable-webapp-runtime.])
fi
AC_MSG_RESULT([yes])
fi
AC_SUBST(MOZ_WEBAPP_RUNTIME)
if test "$MOZ_WEBAPP_RUNTIME"; then
AC_DEFINE(MOZ_WEBAPP_RUNTIME)
fi
dnl ========================================================
dnl Installer
dnl ========================================================
@ -6403,6 +6365,21 @@ if test "$OS_ARCH" = "WINNT"; then
fi
fi
dnl ========================================================
dnl Web App Runtime
dnl ========================================================
MOZ_ARG_DISABLE_BOOL(webapp-runtime,
[ --disable-webapp-runtime Disable Web App Runtime],
MOZ_WEBAPP_RUNTIME=,
MOZ_WEBAPP_RUNTIME=1)
if test "$OS_ARCH" = "WINNT" -a -z "$MAKENSISU" -a -n "$CROSS_COMPILE"; then
MOZ_WEBAPP_RUNTIME=
fi
AC_SUBST(MOZ_WEBAPP_RUNTIME)
if test "$MOZ_WEBAPP_RUNTIME"; then
AC_DEFINE(MOZ_WEBAPP_RUNTIME)
fi
AC_MSG_CHECKING([for tar archiver])
AC_CHECK_PROGS(TAR, gnutar gtar tar, "")
if test -z "$TAR"; then

View File

@ -83,9 +83,6 @@ nsresult NS_NewContentSubtreeIterator(nsIContentIterator** aInstancePtrResult);
if (!nsContentUtils::CanCallerAccess(node_)) { \
return NS_ERROR_DOM_SECURITY_ERR; \
} \
if (mIsDetached) { \
return NS_ERROR_DOM_INVALID_STATE_ERR; \
} \
PR_END_MACRO
static void InvalidateAllFrames(nsINode* aNode)
@ -653,9 +650,6 @@ nsRange::IsPointInRange(nsIDOMNode* aParent, PRInt32 aOffset, bool* aResult)
NS_IMETHODIMP
nsRange::ComparePoint(nsIDOMNode* aParent, PRInt32 aOffset, PRInt16* aResult)
{
if (mIsDetached)
return NS_ERROR_DOM_INVALID_STATE_ERR;
// our range is in a good state?
if (!mIsPositioned)
return NS_ERROR_NOT_INITIALIZED;
@ -755,8 +749,7 @@ nsRange::DoSetRange(nsINode* aStartN, PRInt32 aStartOffset,
if (newCommonAncestor) {
RegisterCommonAncestor(newCommonAncestor);
} else {
NS_ASSERTION(mIsDetached || !mIsPositioned,
"unexpected disconnected nodes");
NS_ASSERTION(!mIsPositioned, "unexpected disconnected nodes");
mInSelection = false;
}
}
@ -844,8 +837,6 @@ nsRange::GetEndOffset(PRInt32* aEndOffset)
NS_IMETHODIMP
nsRange::GetCollapsed(bool* aIsCollapsed)
{
if(mIsDetached)
return NS_ERROR_DOM_INVALID_STATE_ERR;
if (!mIsPositioned)
return NS_ERROR_NOT_INITIALIZED;
@ -858,8 +849,6 @@ NS_IMETHODIMP
nsRange::GetCommonAncestorContainer(nsIDOMNode** aCommonParent)
{
*aCommonParent = nsnull;
if(mIsDetached)
return NS_ERROR_DOM_INVALID_STATE_ERR;
if (!mIsPositioned)
return NS_ERROR_NOT_INITIALIZED;
@ -1049,8 +1038,6 @@ nsRange::SetEndAfter(nsIDOMNode* aSibling)
NS_IMETHODIMP
nsRange::Collapse(bool aToStart)
{
if(mIsDetached)
return NS_ERROR_DOM_INVALID_STATE_ERR;
if (!mIsPositioned)
return NS_ERROR_NOT_INITIALIZED;
@ -1502,9 +1489,6 @@ nsresult nsRange::CutContents(nsIDOMDocumentFragment** aFragment)
*aFragment = nsnull;
}
if (IsDetached())
return NS_ERROR_DOM_INVALID_STATE_ERR;
nsresult rv;
nsCOMPtr<nsIDocument> doc = mStartParent->OwnerDoc();
@ -1782,8 +1766,6 @@ nsRange::CompareBoundaryPoints(PRUint16 aHow, nsIDOMRange* aOtherRange,
nsRange* otherRange = static_cast<nsRange*>(aOtherRange);
NS_ENSURE_TRUE(otherRange, NS_ERROR_NULL_POINTER);
if(mIsDetached || otherRange->IsDetached())
return NS_ERROR_DOM_INVALID_STATE_ERR;
if (!mIsPositioned || !otherRange->IsPositioned())
return NS_ERROR_NOT_INITIALIZED;
@ -1883,9 +1865,6 @@ nsRange::CloneParentsBetween(nsIDOMNode *aAncestor,
NS_IMETHODIMP
nsRange::CloneContents(nsIDOMDocumentFragment** aReturn)
{
if (IsDetached())
return NS_ERROR_DOM_INVALID_STATE_ERR;
nsresult res;
nsCOMPtr<nsIDOMNode> commonAncestor;
res = GetCommonAncestorContainer(getter_AddRefs(commonAncestor));
@ -2078,9 +2057,6 @@ nsRange::CloneContents(nsIDOMDocumentFragment** aReturn)
nsresult
nsRange::CloneRange(nsRange** aReturn) const
{
if(mIsDetached)
return NS_ERROR_DOM_INVALID_STATE_ERR;
if (aReturn == 0)
return NS_ERROR_NULL_POINTER;
@ -2264,9 +2240,6 @@ nsRange::SurroundContents(nsIDOMNode* aNewParent)
NS_IMETHODIMP
nsRange::ToString(nsAString& aReturn)
{
if(mIsDetached)
return NS_ERROR_DOM_INVALID_STATE_ERR;
// clear the string
aReturn.Truncate();
@ -2358,17 +2331,8 @@ nsRange::ToString(nsAString& aReturn)
NS_IMETHODIMP
nsRange::Detach()
{
if(mIsDetached)
return NS_ERROR_DOM_INVALID_STATE_ERR;
if (IsInSelection()) {
::InvalidateAllFrames(GetRegisteredCommonAncestor());
}
// No-op, but still set mIsDetached for telemetry (bug 702948)
mIsDetached = true;
DoSetRange(nsnull, 0, nsnull, 0, nsnull);
return NS_OK;
}

View File

@ -108,11 +108,6 @@ public:
return mIsPositioned;
}
bool IsDetached() const
{
return mIsDetached;
}
bool Collapsed() const
{
return mIsPositioned && mStartParent == mEndParent &&
@ -138,7 +133,7 @@ public:
*/
void SetInSelection(bool aInSelection)
{
if (mInSelection == aInSelection || mIsDetached) {
if (mInSelection == aInSelection) {
return;
}
mInSelection = aInSelection;
@ -245,7 +240,6 @@ protected:
return;
}
mIsNested = true;
NS_ASSERTION(!mRange->IsDetached(), "detached range in selection");
mCommonAncestor = mRange->GetRegisteredCommonAncestor();
}
~AutoInvalidateSelection();

View File

@ -5184,6 +5184,20 @@ WebGLContext::TexImage2D_base(WebGLenum target, WebGLint level, WebGLenum intern
int actualSrcFormat = srcFormat == WebGLTexelFormat::Auto ? dstFormat : srcFormat;
size_t srcStride = srcStrideOrZero ? srcStrideOrZero : checked_alignedRowSize.value();
if (gl->CanUploadBGRA() &&
actualSrcFormat == WebGLTexelFormat::BGRA8 &&
dstFormat == WebGLTexelFormat::RGBA8)
{
dstFormat = WebGLTexelFormat::BGRA8;
format = LOCAL_GL_BGRA;
if (gl->IsGLES2()) {
internalformat = LOCAL_GL_BGRA;
} else {
internalformat = LOCAL_GL_RGBA;
type = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV;
}
}
size_t dstPlainRowSize = texelSize * width;
size_t unpackAlignment = mPixelStoreUnpackAlignment;
size_t dstStride = ((dstPlainRowSize + unpackAlignment-1) / unpackAlignment) * unpackAlignment;
@ -5394,6 +5408,17 @@ WebGLContext::TexSubImage2D_base(WebGLenum target, WebGLint level,
// There are checks above to ensure that this won't overflow.
size_t dstStride = RoundedToNextMultipleOf(dstPlainRowSize, mPixelStoreUnpackAlignment).value();
if (gl->CanUploadBGRA() &&
actualSrcFormat == WebGLTexelFormat::BGRA8 &&
dstFormat == WebGLTexelFormat::RGBA8)
{
dstFormat = WebGLTexelFormat::BGRA8;
format = LOCAL_GL_BGRA;
if (!gl->IsGLES2()) {
type = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV;
}
}
if (actualSrcFormat == dstFormat &&
srcPremultiplied == mPixelStorePremultiplyAlpha &&
srcStride == dstStride &&

View File

@ -369,33 +369,6 @@ function run_extract_test() {
// Clean up after ourselves.
walker = null;
/* Whenever a DOM range is detached, we cannot use any methods on
it - including extracting its contents or deleting its contents. It
should throw a NS_ERROR_DOM_INVALID_STATE_ERR exception.
*/
dump("Detached range test\n");
var compareFrag = getFragment(baseSource);
baseFrag = getFragment(baseSource);
baseRange = getRange(baseSource, baseFrag);
baseRange.detach();
try {
var cutFragment = baseRange.extractContents();
do_throw("Should have thrown INVALID_STATE_ERR!");
} catch (e if (e instanceof C_i.nsIException &&
e.result == INVALID_STATE_ERR)) {
// do nothing
}
do_check_true(compareFrag.isEqualNode(baseFrag));
try {
baseRange.deleteContents();
do_throw("Should have thrown INVALID_STATE_ERR!");
} catch (e if (e instanceof C_i.nsIException &&
e.result == INVALID_STATE_ERR)) {
// do nothing
}
do_check_true(compareFrag.isEqualNode(baseFrag));
}
}

View File

@ -2762,6 +2762,11 @@ nsXULDocument::LoadOverlayInternal(nsIURI* aURI, bool aIsDynamic,
// Not there. Initiate a load.
PR_LOG(gXULLog, PR_LOG_DEBUG, ("xul: overlay was not cached"));
if (mIsGoingAway) {
PR_LOG(gXULLog, PR_LOG_DEBUG, ("xul: ...and document already destroyed"));
return NS_ERROR_NOT_AVAILABLE;
}
// We'll set the right principal on the proto doc when we get
// OnStartRequest from the parser, so just pass in a null principal for
// now.

View File

@ -1244,6 +1244,8 @@ DOMStorageImpl::RemoveValue(bool aCallerSecure, const nsAString& aKey,
nsresult rv = InitDB();
NS_ENSURE_SUCCESS(rv, rv);
CacheKeysFromDB();
nsAutoString value;
bool secureItem;
rv = GetDBValue(aKey, value, &secureItem);

View File

@ -64,6 +64,8 @@ _TEST_FILES = \
pbSwitch.js \
test_brokenUTF-16.html \
test_bug624047.html \
test_bug746272-1.html \
test_bug746272-2.html \
test_cookieBlock.html \
test_cookieSession-phase1.html \
test_cookieSession-phase2.html \

View File

@ -0,0 +1,32 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>incomplete UTF-16 test</title>
<meta http-equiv="Content-type" content="text/html; charset=UTF-8" />
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script type="text/javascript">
function startTest()
{
localStorage.clear();
localStorage.setItem("test1", "value1");
localStorage.setItem("test2", "value2");
localStorage.setItem("test3", "value3");
is(localStorage.length, 3, "expected number of items");
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
</script>
</head>
<body onload="startTest();">
</body>
</html>

View File

@ -0,0 +1,31 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>incomplete UTF-16 test</title>
<meta http-equiv="Content-type" content="text/html; charset=UTF-8" />
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script type="text/javascript">
function startTest()
{
var test2 = localStorage.getItem("test2");
is(test2, "value2", "expected item");
localStorage.removeItem("test2");
is(localStorage.length, 2, "expected number of items");
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
</script>
</head>
<body onload="startTest();">
</body>
</html>

View File

@ -1517,7 +1517,7 @@ public:
Extensions_Max
};
bool IsExtensionSupported(GLExtensions aKnownExtension) {
bool IsExtensionSupported(GLExtensions aKnownExtension) const {
return mAvailableExtensions[aKnownExtension];
}
@ -1545,7 +1545,12 @@ public:
}
bool& operator[](size_t index) {
NS_ASSERTION(index < setlen, "out of range");
NS_ABORT_IF_FALSE(index < setlen, "out of range");
return values[index];
}
const bool& operator[](size_t index) const {
NS_ABORT_IF_FALSE(index < setlen, "out of range");
return values[index];
}
@ -1672,6 +1677,16 @@ public:
bool WorkAroundDriverBugs() const { return mWorkAroundDriverBugs; }
bool CanUploadBGRA() const {
if (!IsGLES2())
return true;
if (IsExtensionSupported(EXT_texture_format_BGRA8888))
return true;
return false;
}
protected:
nsDataHashtable<nsPtrHashKey<void>, void*> mUserData;

View File

@ -110,6 +110,7 @@ public:
, mViewportScrollOffset(0, 0)
, mScrollId(NULL_SCROLL_ID)
, mCSSContentSize(0, 0)
, mResolution(1, 1)
{}
// Default copy ctor and operator= are fine
@ -151,6 +152,10 @@ public:
// Consumers often want to know the size before scaling to pixels
// so we record this size as well.
gfx::Size mCSSContentSize;
// This represents the resolution at which the associated layer
// will been rendered.
gfxSize mResolution;
};
#define MOZ_LAYER_DECL_NAME(n, e) \

View File

@ -86,6 +86,7 @@ CPPSRCS = \
LayerManagerOGL.cpp \
ThebesLayerOGL.cpp \
TiledThebesLayerOGL.cpp \
ReusableTileStoreOGL.cpp \
LayerSorter.cpp \
ImageLayers.cpp \
$(NULL)

View File

@ -87,8 +87,20 @@ public:
// (x*GetTileLength(), y*GetTileLength(), GetTileLength(), GetTileLength())
Tile GetTile(int x, int y) const;
// This operates the same as GetTile(aTileOrigin), but will also replace the
// specified tile with the placeholder tile. This does not call ReleaseTile
// on the removed tile.
bool RemoveTile(const nsIntPoint& aTileOrigin, Tile& aRemovedTile);
// This operates the same as GetTile(x, y), but will also replace the
// specified tile with the placeholder tile. This does not call ReleaseTile
// on the removed tile.
bool RemoveTile(int x, int y, Tile& aRemovedTile);
uint16_t GetTileLength() const { return TILEDLAYERBUFFER_TILE_SIZE; }
unsigned int GetTileCount() const { return mRetainedTiles.Length(); }
const nsIntRegion& GetValidRegion() const { return mValidRegion; }
const nsIntRegion& GetLastPaintRegion() const { return mLastPaintRegion; }
void SetLastPaintRegion(const nsIntRegion& aLastPaintRegion) {
@ -161,6 +173,30 @@ TiledLayerBuffer<Derived, Tile>::GetTile(int x, int y) const
return mRetainedTiles.SafeElementAt(index, AsDerived().GetPlaceholderTile());
}
template<typename Derived, typename Tile> bool
TiledLayerBuffer<Derived, Tile>::RemoveTile(const nsIntPoint& aTileOrigin,
Tile& aRemovedTile)
{
int firstTileX = mValidRegion.GetBounds().x / GetTileLength();
int firstTileY = mValidRegion.GetBounds().y / GetTileLength();
return RemoveTile(aTileOrigin.x / GetTileLength() - firstTileX,
aTileOrigin.y / GetTileLength() - firstTileY,
aRemovedTile);
}
template<typename Derived, typename Tile> bool
TiledLayerBuffer<Derived, Tile>::RemoveTile(int x, int y, Tile& aRemovedTile)
{
int index = x * mRetainedHeight + y;
const Tile& tileToRemove = mRetainedTiles.SafeElementAt(index, AsDerived().GetPlaceholderTile());
if (!IsPlaceholder(tileToRemove)) {
aRemovedTile = tileToRemove;
mRetainedTiles[index] = AsDerived().GetPlaceholderTile();
return true;
}
return false;
}
template<typename Derived, typename Tile> void
TiledLayerBuffer<Derived, Tile>::Update(const nsIntRegion& aNewValidRegion,
const nsIntRegion& aPaintRegion)
@ -209,14 +245,16 @@ TiledLayerBuffer<Derived, Tile>::Update(const nsIntRegion& aNewValidRegion,
int tileY = (y - oldBufferOrigin.y) / GetTileLength();
int index = tileX * oldRetainedHeight + tileY;
NS_ABORT_IF_FALSE(!IsPlaceholder(oldRetainedTiles.
SafeElementAt(index, AsDerived().GetPlaceholderTile())),
"Expected tile");
// The tile may have been removed, skip over it in this case.
if (IsPlaceholder(oldRetainedTiles.
SafeElementAt(index, AsDerived().GetPlaceholderTile()))) {
newRetainedTiles.AppendElement(AsDerived().GetPlaceholderTile());
} else {
Tile tileWithPartialValidContent = oldRetainedTiles[index];
newRetainedTiles.AppendElement(tileWithPartialValidContent);
oldRetainedTiles[index] = AsDerived().GetPlaceholderTile();
}
Tile tileWithPartialValidContent = oldRetainedTiles[index];
newRetainedTiles.AppendElement(tileWithPartialValidContent);
oldRetainedTiles[index] = AsDerived().GetPlaceholderTile();
} else {
// This tile is either:
// 1) Outside the new valid region and will simply be an empty

View File

@ -73,6 +73,7 @@ struct ParamTraits<mozilla::layers::FrameMetrics>
WriteParam(aMsg, aParam.mViewportScrollOffset);
WriteParam(aMsg, aParam.mDisplayPort);
WriteParam(aMsg, aParam.mScrollId);
WriteParam(aMsg, aParam.mResolution);
}
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
@ -82,7 +83,8 @@ struct ParamTraits<mozilla::layers::FrameMetrics>
ReadParam(aMsg, aIter, &aResult->mContentSize) &&
ReadParam(aMsg, aIter, &aResult->mViewportScrollOffset) &&
ReadParam(aMsg, aIter, &aResult->mDisplayPort) &&
ReadParam(aMsg, aIter, &aResult->mScrollId));
ReadParam(aMsg, aIter, &aResult->mScrollId) &&
ReadParam(aMsg, aIter, &aResult->mResolution));
}
};

View File

@ -0,0 +1,188 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ReusableTileStoreOGL.h"
namespace mozilla {
namespace layers {
ReusableTileStoreOGL::~ReusableTileStoreOGL()
{
if (mTiles.Length() == 0)
return;
mContext->MakeCurrent();
for (int i = 0; i < mTiles.Length(); i++)
mContext->fDeleteTextures(1, &mTiles[i]->mTexture.mTextureHandle);
mTiles.Clear();
}
void
ReusableTileStoreOGL::HarvestTiles(TiledLayerBufferOGL* aVideoMemoryTiledBuffer,
const nsIntRegion& aOldValidRegion,
const nsIntRegion& aNewValidRegion,
const gfxSize& aOldResolution,
const gfxSize& aNewResolution)
{
gfxSize scaleFactor = gfxSize(aNewResolution.width / aOldResolution.width,
aNewResolution.height / aOldResolution.height);
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
printf_stderr("Seeing if there are any tiles we can reuse\n");
#endif
// Iterate over existing harvested tiles and release any that are contained
// within the new valid region.
mContext->MakeCurrent();
for (int i = 0; i < mTiles.Length();) {
ReusableTiledTextureOGL* tile = mTiles[i];
bool release = false;
if (tile->mResolution == aNewResolution) {
if (aNewValidRegion.Contains(tile->mTileRegion))
release = true;
} else {
nsIntRegion transformedTileRegion(tile->mTileRegion);
transformedTileRegion.ScaleRoundOut(tile->mResolution.width / aNewResolution.width,
tile->mResolution.height / aNewResolution.height);
if (aNewValidRegion.Contains(transformedTileRegion))
release = true;
}
if (release) {
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
nsIntRect tileBounds = tile->mTileRegion.GetBounds();
printf_stderr("Releasing obsolete reused tile at %d,%d, x%f\n",
tileBounds.x, tileBounds.y, tile->mResolution.width);
#endif
mContext->fDeleteTextures(1, &tile->mTexture.mTextureHandle);
mTiles.RemoveElementAt(i);
continue;
}
i++;
}
// Iterate over the tiles and decide which ones we're going to harvest.
// We harvest any tile that is entirely outside of the new valid region, or
// any tile that is partially outside of the valid region and whose
// resolution has changed.
// XXX Tile iteration needs to be abstracted, or have some utility functions
// to make it simpler.
uint16_t tileSize = aVideoMemoryTiledBuffer->GetTileLength();
nsIntRect validBounds = aOldValidRegion.GetBounds();
for (int x = validBounds.x; x < validBounds.XMost();) {
int w = tileSize - x % tileSize;
if (x + w > validBounds.x + validBounds.width)
w = validBounds.x + validBounds.width - x;
for (int y = validBounds.y; y < validBounds.YMost();) {
int h = tileSize - y % tileSize;
if (y + h > validBounds.y + validBounds.height)
h = validBounds.y + validBounds.height - y;
// If the new valid region doesn't contain this tile region,
// harvest the tile.
nsIntRegion tileRegion;
tileRegion.And(aOldValidRegion, nsIntRect(x, y, w, h));
nsIntRegion intersectingRegion;
bool retainTile = false;
if (aNewResolution != aOldResolution) {
// Reconcile resolution changes.
// If the resolution changes, we know the backing layer will have been
// invalidated, so retain tiles that are partially encompassed by the
// new valid area, instead of just tiles that don't intersect at all.
nsIntRegion transformedTileRegion(tileRegion);
transformedTileRegion.ScaleRoundOut(scaleFactor.width, scaleFactor.height);
if (!aNewValidRegion.Contains(transformedTileRegion))
retainTile = true;
} else if (intersectingRegion.And(tileRegion, aNewValidRegion).IsEmpty()) {
retainTile = true;
}
if (retainTile) {
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
printf_stderr("Retaining tile at %d,%d, x%f for reuse\n", x, y, aOldResolution.width);
#endif
TiledTexture removedTile;
if (aVideoMemoryTiledBuffer->RemoveTile(nsIntPoint(x, y), removedTile)) {
ReusableTiledTextureOGL* reusedTile =
new ReusableTiledTextureOGL(removedTile, tileRegion, tileSize,
aOldResolution);
mTiles.AppendElement(reusedTile);
}
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
else
printf_stderr("Failed to retain tile for reuse\n");
#endif
}
y += h;
}
x += w;
}
// Now prune our reused tile store of its oldest tiles if it gets too large.
while (mTiles.Length() > aVideoMemoryTiledBuffer->GetTileCount() * mSizeLimit) {
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
nsIntRect tileBounds = mTiles[0]->mTileRegion.GetBounds();
printf_stderr("Releasing old reused tile at %d,%d, x%f\n",
tileBounds.x, tileBounds.y, mTiles[0]->mResolution.width);
#endif
mContext->fDeleteTextures(1, &mTiles[0]->mTexture.mTextureHandle);
mTiles.RemoveElementAt(0);
}
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
printf_stderr("Retained %d tiles\n", mTiles.Length());
#endif
}
void
ReusableTileStoreOGL::DrawTiles(TiledThebesLayerOGL* aLayer,
const nsIntRegion& aValidRegion,
const gfxSize& aResolution,
const gfx3DMatrix& aTransform,
const nsIntPoint& aRenderOffset)
{
// Render old tiles to fill in gaps we haven't had the time to render yet.
for (size_t i = 0; i < mTiles.Length(); i++) {
ReusableTiledTextureOGL* tile = mTiles[i];
// Work out the scaling factor in case of resolution differences.
gfxSize scaleFactor = gfxSize(aResolution.width / tile->mResolution.width,
aResolution.height / tile->mResolution.height);
// Get the valid tile region, in the given coordinate space.
nsIntRegion transformedTileRegion(tile->mTileRegion);
if (aResolution != tile->mResolution)
transformedTileRegion.ScaleRoundOut(scaleFactor.width, scaleFactor.height);
// Skip drawing tiles that will be completely drawn over.
if (aValidRegion.Contains(transformedTileRegion))
continue;
// Reconcile the resolution difference by adjusting the transform.
gfx3DMatrix transform = aTransform;
if (aResolution != tile->mResolution)
transform.Scale(scaleFactor.width, scaleFactor.height, 1);
// XXX We should clip here to make sure we don't overlap with the valid
// region, otherwise we may end up with rendering artifacts on
// semi-transparent layers.
// Similarly, if we have multiple tiles covering the same area, we will
// end up with rendering artifacts if the aLayer isn't opaque.
nsIntRect tileRect = tile->mTileRegion.GetBounds();
uint16_t tileStartX = tileRect.x % tile->mTileSize;
uint16_t tileStartY = tileRect.y % tile->mTileSize;
nsIntRect textureRect(tileStartX, tileStartY, tileRect.width, tileRect.height);
nsIntSize textureSize(tile->mTileSize, tile->mTileSize);
aLayer->RenderTile(tile->mTexture, transform, aRenderOffset, tileRect, textureRect, textureSize);
}
}
} // mozilla
} // layers

View File

@ -0,0 +1,96 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef GFX_REUSABLETILESTOREOGL_H
#define GFX_REUSABLETILESTOREOGL_H
#include "TiledThebesLayerOGL.h"
#include "nsTArray.h"
#include "nsAutoPtr.h"
namespace mozilla {
namespace gl {
class GLContext;
}
namespace layers {
// A storage class for the information required to render a single tile from
// a TiledLayerBufferOGL.
class ReusableTiledTextureOGL
{
public:
ReusableTiledTextureOGL(TiledTexture aTexture,
const nsIntRegion& aTileRegion,
uint16_t aTileSize,
gfxSize aResolution)
: mTexture(aTexture)
, mTileRegion(aTileRegion)
, mTileSize(aTileSize)
, mResolution(aResolution)
{}
~ReusableTiledTextureOGL() {}
TiledTexture mTexture;
const nsIntRegion mTileRegion;
uint16_t mTileSize;
gfxSize mResolution;
};
// This class will operate on a TiledLayerBufferOGL to harvest tiles that have
// rendered content that is about to become invalid. We do this so that in the
// situation that we need to render an area of a TiledThebesLayerOGL that hasn't
// been updated quickly enough, we can still display something (and hopefully
// it'll be the same as the valid rendered content). While this may end up
// showing invalid data, it should only be momentarily.
class ReusableTileStoreOGL
{
public:
ReusableTileStoreOGL(gl::GLContext* aContext, float aSizeLimit)
: mContext(aContext)
, mSizeLimit(aSizeLimit)
{}
~ReusableTileStoreOGL();
// Harvests tiles from a TiledLayerBufferOGL that are about to become
// invalid. aOldValidRegion and aOldResolution should be the valid region
// and resolution of the data currently in aVideoMemoryTiledBuffer, and
// aNewValidRegion and aNewResolution should be the valid region and
// resolution of the data that is about to update aVideoMemoryTiledBuffer.
void HarvestTiles(TiledLayerBufferOGL* aVideoMemoryTiledBuffer,
const nsIntRegion& aOldValidRegion,
const nsIntRegion& aNewValidRegion,
const gfxSize& aOldResolution,
const gfxSize& aNewResolution);
// Draws all harvested tiles that don't intersect with the given valid region.
// Differences in resolution will be reconciled via altering the given
// transformation.
void DrawTiles(TiledThebesLayerOGL* aLayer,
const nsIntRegion& aValidRegion,
const gfxSize& aResolution,
const gfx3DMatrix& aTransform,
const nsIntPoint& aRenderOffset);
private:
// This GLContext should correspond to the one used in any TiledLayerBufferOGL
// that is passed into HarvestTiles and DrawTiles.
nsRefPtr<gl::GLContext> mContext;
// This determines the maximum number of tiles stored in this tile store,
// as a fraction of the amount of tiles stored in the TiledLayerBufferOGL
// given to HarvestTiles.
float mSizeLimit;
// This stores harvested tiles, in the order in which they were harvested.
nsTArray< nsAutoPtr<ReusableTiledTextureOGL> > mTiles;
};
} // layers
} // mozilla
#endif // GFX_REUSABLETILESTOREOGL_H

View File

@ -4,6 +4,7 @@
#include "mozilla/layers/PLayersChild.h"
#include "TiledThebesLayerOGL.h"
#include "ReusableTileStoreOGL.h"
#include "BasicTiledThebesLayer.h"
#include "gfxImageSurface.h"
@ -37,12 +38,15 @@ TiledLayerBufferOGL::ReleaseTile(TiledTexture aTile)
void
TiledLayerBufferOGL::Upload(const BasicTiledLayerBuffer* aMainMemoryTiledBuffer,
const nsIntRegion& aNewValidRegion,
const nsIntRegion& aInvalidateRegion)
const nsIntRegion& aInvalidateRegion,
const gfxSize& aResolution)
{
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
printf_stderr("Upload %i, %i, %i, %i\n", aInvalidateRegion.GetBounds().x, aInvalidateRegion.GetBounds().y, aInvalidateRegion.GetBounds().width, aInvalidateRegion.GetBounds().height);
long start = PR_IntervalNow();
#endif
mResolution = aResolution;
mMainMemoryTiledBuffer = aMainMemoryTiledBuffer;
mContext->MakeCurrent();
Update(aNewValidRegion, aInvalidateRegion);
@ -113,6 +117,15 @@ TiledThebesLayerOGL::TiledThebesLayerOGL(LayerManagerOGL *aManager)
, mVideoMemoryTiledBuffer(aManager->gl())
{
mImplData = static_cast<LayerOGL*>(this);
// XXX Add a pref for reusable tile store size
mReusableTileStore = new ReusableTileStoreOGL(aManager->gl(), 1);
}
TiledThebesLayerOGL::~TiledThebesLayerOGL()
{
mMainMemoryTiledBuffer.ReadUnlock();
if (mReusableTileStore)
delete mReusableTileStore;
}
void
@ -132,7 +145,29 @@ TiledThebesLayerOGL::ProcessUploadQueue()
if (mRegionToUpload.IsEmpty())
return;
mVideoMemoryTiledBuffer.Upload(&mMainMemoryTiledBuffer, mMainMemoryTiledBuffer.GetValidRegion(), mRegionToUpload);
gfxSize resolution(1, 1);
if (mReusableTileStore) {
// Work out render resolution by multiplying the resolution of our ancestors.
// Only container layers can have frame metrics, so we start off with a
// resolution of 1, 1.
// XXX For large layer trees, it would be faster to do this once from the
// root node upwards and store the value on each layer.
for (ContainerLayer* parent = GetParent(); parent; parent = parent->GetParent()) {
const FrameMetrics& metrics = parent->GetFrameMetrics();
resolution.width *= metrics.mResolution.width;
resolution.height *= metrics.mResolution.height;
}
mReusableTileStore->HarvestTiles(&mVideoMemoryTiledBuffer,
mVideoMemoryTiledBuffer.GetValidRegion(),
mMainMemoryTiledBuffer.GetValidRegion(),
mVideoMemoryTiledBuffer.GetResolution(),
resolution);
}
mVideoMemoryTiledBuffer.Upload(&mMainMemoryTiledBuffer,
mMainMemoryTiledBuffer.GetValidRegion(),
mRegionToUpload, resolution);
mValidRegion = mVideoMemoryTiledBuffer.GetValidRegion();
mMainMemoryTiledBuffer.ReadUnlock();
@ -146,12 +181,46 @@ TiledThebesLayerOGL::ProcessUploadQueue()
}
void
TiledThebesLayerOGL::RenderTile(TiledTexture aTile,
const gfx3DMatrix& aTransform,
const nsIntPoint& aOffset,
nsIntRect aScreenRect,
nsIntRect aTextureRect,
nsIntSize aTextureBounds)
{
gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, aTile.mTextureHandle);
ColorTextureLayerProgram *program;
if (aTile.mFormat == LOCAL_GL_RGB) {
program = mOGLManager->GetRGBXLayerProgram();
} else {
program = mOGLManager->GetBGRALayerProgram();
}
program->Activate();
program->SetTextureUnit(0);
program->SetLayerOpacity(GetEffectiveOpacity());
program->SetLayerTransform(aTransform);
program->SetRenderOffset(aOffset);
program->SetLayerQuadRect(aScreenRect);
mOGLManager->BindAndDrawQuadWithTextureRect(program,
aTextureRect,
aTextureBounds);
}
void
TiledThebesLayerOGL::RenderLayer(int aPreviousFrameBuffer, const nsIntPoint& aOffset)
{
gl()->MakeCurrent();
ProcessUploadQueue();
// Render old tiles to fill in gaps we haven't had the time to render yet.
if (mReusableTileStore)
mReusableTileStore->DrawTiles(this, mVideoMemoryTiledBuffer.GetValidRegion(),
mVideoMemoryTiledBuffer.GetResolution(),
GetEffectiveTransform(), aOffset);
// Render valid tiles.
const nsIntRegion& visibleRegion = GetEffectiveVisibleRegion();
const nsIntRect visibleRect = visibleRegion.GetBounds();
unsigned int rowCount = 0;
@ -173,22 +242,9 @@ TiledThebesLayerOGL::RenderLayer(int aPreviousFrameBuffer, const nsIntPoint& aOf
GetTile(nsIntPoint(mVideoMemoryTiledBuffer.RoundDownToTileEdge(x),
mVideoMemoryTiledBuffer.RoundDownToTileEdge(y)));
if (tileTexture != mVideoMemoryTiledBuffer.GetPlaceholderTile()) {
gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, tileTexture.mTextureHandle);
ColorTextureLayerProgram *program;
if (tileTexture.mFormat == LOCAL_GL_RGB) {
program = mOGLManager->GetRGBXLayerProgram();
} else {
program = mOGLManager->GetBGRALayerProgram();
}
program->Activate();
program->SetTextureUnit(0);
program->SetLayerOpacity(GetEffectiveOpacity());
program->SetLayerTransform(GetEffectiveTransform());
program->SetRenderOffset(aOffset);
program->SetLayerQuadRect(nsIntRect(x,y,w,h)); // screen
mOGLManager->BindAndDrawQuadWithTextureRect(program, nsIntRect(tileStartX, tileStartY, w, h), nsIntSize(mVideoMemoryTiledBuffer.GetTileLength(), mVideoMemoryTiledBuffer.GetTileLength())); // texture bounds
uint16_t tileSize = mVideoMemoryTiledBuffer.GetTileLength();
RenderTile(tileTexture, GetEffectiveTransform(), aOffset, nsIntRect(x,y,w,h),
nsIntRect(tileStartX, tileStartY, w, h), nsIntSize(tileSize, tileSize));
}
tileY++;
y += h;

View File

@ -20,6 +20,8 @@ class GLContext;
namespace layers {
class ReusableTileStoreOGL;
class TiledTexture {
public:
// Constructs a placeholder TiledTexture. See the comments above
@ -73,10 +75,13 @@ public:
void Upload(const BasicTiledLayerBuffer* aMainMemoryTiledBuffer,
const nsIntRegion& aNewValidRegion,
const nsIntRegion& aInvalidateRegion);
const nsIntRegion& aInvalidateRegion,
const gfxSize& aResolution);
TiledTexture GetPlaceholderTile() const { return TiledTexture(); }
const gfxSize& GetResolution() { return mResolution; }
protected:
TiledTexture ValidateTile(TiledTexture aTile,
const nsIntPoint& aTileRect,
@ -91,6 +96,7 @@ protected:
private:
nsRefPtr<gl::GLContext> mContext;
const BasicTiledLayerBuffer* mMainMemoryTiledBuffer;
gfxSize mResolution;
void GetFormatAndTileForImageFormat(gfxASurface::gfxImageFormat aFormat,
GLenum& aOutFormat,
@ -103,10 +109,7 @@ class TiledThebesLayerOGL : public ShadowThebesLayer,
{
public:
TiledThebesLayerOGL(LayerManagerOGL *aManager);
virtual ~TiledThebesLayerOGL()
{
mMainMemoryTiledBuffer.ReadUnlock();
}
virtual ~TiledThebesLayerOGL();
// LayerOGL impl
void Destroy() {}
@ -126,10 +129,22 @@ public:
}
void PaintedTiledLayerBuffer(const BasicTiledLayerBuffer* mTiledBuffer);
void ProcessUploadQueue();
// Renders a single given tile.
// XXX This currently takes an nsIntRect, but should actually take an
// nsIntRegion and iterate over each rectangle in the region.
void RenderTile(TiledTexture aTile,
const gfx3DMatrix& aTransform,
const nsIntPoint& aOffset,
nsIntRect aScreenRect,
nsIntRect aTextureRect,
nsIntSize aTextureBounds);
private:
nsIntRegion mRegionToUpload;
BasicTiledLayerBuffer mMainMemoryTiledBuffer;
TiledLayerBufferOGL mVideoMemoryTiledBuffer;
ReusableTileStoreOGL* mReusableTileStore;
};
} // layers

View File

@ -53,6 +53,7 @@
#include "gfxColor.h"
#include "gfxMatrix.h"
#include "gfxPattern.h"
#include "gfxPoint.h"
#include "nsRect.h"
#include "nsRegion.h"
#include "gfxASurface.h"
@ -458,6 +459,27 @@ struct ParamTraits<gfxMatrix>
}
};
template<>
struct ParamTraits<gfxSize>
{
typedef gfxSize paramType;
static void Write(Message* aMsg, const paramType& aParam)
{
WriteParam(aMsg, aParam.width);
WriteParam(aMsg, aParam.height);
}
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
{
if (ReadParam(aMsg, aIter, &aResult->width) &&
ReadParam(aMsg, aIter, &aResult->height))
return true;
return false;
}
};
template<>
struct ParamTraits<gfx3DMatrix>
{

View File

@ -250,6 +250,10 @@ static void RecordFrameMetrics(nsIFrame* aForFrame,
}
metrics.mScrollId = aScrollId;
nsIPresShell* presShell = presContext->GetPresShell();
metrics.mResolution = gfxSize(presShell->GetXResolution(), presShell->GetYResolution());
aRoot->SetFrameMetrics(metrics);
}

View File

@ -78,12 +78,6 @@ function run() {
sel.removeAllRanges();
sel.modify("move", "forward", "character");
// Similarly, we should silently fail if the selection has been detached.
$("c").focus();
sel.collapse($("p1"), 0);
sel.getRangeAt(0).detach();
sel.modify("move", "forward", "character");
// Now focus our first div and put the cursor at the beginning of p1.
$("c").focus();
sel.collapse($("p1"), 0);

View File

@ -8,5 +8,5 @@
<!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=368840 -->
<rect x="0%" y="0%" width="100%" height="100%" fill="black"/>
<rect x="0%" y="0%" width="100%" height="100%" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 345 B

After

Width:  |  Height:  |  Size: 345 B

View File

@ -9266,7 +9266,7 @@ CSSParserImpl::ParsePaint(nsCSSProperty aPropID)
return false;
if (x.GetUnit() == eCSSUnit_URL) {
if (!ParseVariant(y, VARIANT_COLOR | VARIANT_NONE, nsnull))
y.SetColorValue(NS_RGB(0, 0, 0));
y.SetNoneValue();
}
if (!ExpectEndProperty())
return false;

View File

@ -365,7 +365,7 @@ pref("places.frecency.unvisitedTypedBonus", 200);
pref("gfx.color_management.mode", 0);
#ifdef ANDROID
// 0=fixed margin, 1=velocity bias, 2=dynamic resolution, 3=no margins
// 0=fixed margin, 1=velocity bias, 2=dynamic resolution, 3=no margins, 4=prediction bias
pref("gfx.displayport.strategy", 1);
// all of the following displayport strategy prefs will be divided by 1000
// to obtain some multiplier which is then used in the strategy.
@ -375,12 +375,14 @@ pref("gfx.displayport.strategy_fm.danger_x", -1); // danger zone on x-axis when
pref("gfx.displayport.strategy_fm.danger_y", -1); // danger zone on y-axis when multiplied by viewport height
// velocity bias strategy options
pref("gfx.displayport.strategy_vb.multiplier", -1); // displayport dimension multiplier
pref("gfx.displayport.strategy_vb.threshold", -1); // velocity threshold in pixels/frame when multiplied by screen DPI
pref("gfx.displayport.strategy_vb.threshold", -1); // velocity threshold in inches/frame
pref("gfx.displayport.strategy_vb.reverse_buffer", -1); // fraction of buffer to keep in reverse direction from scroll
pref("gfx.displayport.strategy_vb.danger_x_base", -1); // danger zone on x-axis when multiplied by viewport width
pref("gfx.displayport.strategy_vb.danger_y_base", -1); // danger zone on y-axis when multiplied by viewport height
pref("gfx.displayport.strategy_vb.danger_x_incr", -1); // additional danger zone on x-axis when multiplied by viewport width and velocity
pref("gfx.displayport.strategy_vb.danger_y_incr", -1); // additional danger zone on y-axis when multiplied by viewport height and velocity
// prediction bias strategy options
pref("gfx.displayport.strategy_pb.threshold", -1); // velocity threshold in inches/frame
#endif
// don't allow JS to move and resize existing windows

View File

@ -124,6 +124,7 @@ FENNEC_JAVA_FILES = \
gfx/CheckerboardImage.java \
gfx/DisplayPortCalculator.java \
gfx/DisplayPortMetrics.java \
gfx/DrawTimingQueue.java \
gfx/FloatSize.java \
gfx/GeckoLayerClient.java \
gfx/GLController.java \

View File

@ -32,6 +32,7 @@ final class DisplayPortCalculator {
private static final String PREF_DISPLAYPORT_VB_DANGER_Y_BASE = "gfx.displayport.strategy_vb.danger_y_base";
private static final String PREF_DISPLAYPORT_VB_DANGER_X_INCR = "gfx.displayport.strategy_vb.danger_x_incr";
private static final String PREF_DISPLAYPORT_VB_DANGER_Y_INCR = "gfx.displayport.strategy_vb.danger_y_incr";
private static final String PREF_DISPLAYPORT_PB_VELOCITY_THRESHOLD = "gfx.displayport.strategy_pb.threshold";
private static DisplayPortStrategy sStrategy = new VelocityBiasStrategy(null);
@ -46,6 +47,14 @@ final class DisplayPortCalculator {
return sStrategy.aboutToCheckerboard(metrics, (velocity == null ? ZERO_VELOCITY : velocity), displayPort);
}
static boolean drawTimeUpdate(long millis, int pixels) {
return sStrategy.drawTimeUpdate(millis, pixels);
}
static void resetPageState() {
sStrategy.resetPageState();
}
static void addPrefNames(JSONArray prefs) {
prefs.put(PREF_DISPLAYPORT_STRATEGY);
prefs.put(PREF_DISPLAYPORT_FM_MULTIPLIER);
@ -58,6 +67,7 @@ final class DisplayPortCalculator {
prefs.put(PREF_DISPLAYPORT_VB_DANGER_Y_BASE);
prefs.put(PREF_DISPLAYPORT_VB_DANGER_X_INCR);
prefs.put(PREF_DISPLAYPORT_VB_DANGER_Y_INCR);
prefs.put(PREF_DISPLAYPORT_PB_VELOCITY_THRESHOLD);
}
/**
@ -84,6 +94,9 @@ final class DisplayPortCalculator {
case 3:
sStrategy = new NoMarginStrategy(prefs);
break;
case 4:
sStrategy = new PredictionBiasStrategy(prefs);
break;
default:
Log.e(LOGTAG, "Invalid strategy index specified");
return false;
@ -97,11 +110,15 @@ final class DisplayPortCalculator {
return (float)(value == null || value < 0 ? defaultValue : value) / 1000f;
}
private interface DisplayPortStrategy {
private static abstract class DisplayPortStrategy {
/** Calculates a displayport given a viewport and panning velocity. */
public DisplayPortMetrics calculate(ImmutableViewportMetrics metrics, PointF velocity);
public abstract DisplayPortMetrics calculate(ImmutableViewportMetrics metrics, PointF velocity);
/** Returns true if a checkerboard is about to be visible and we should not throttle drawing. */
public boolean aboutToCheckerboard(ImmutableViewportMetrics metrics, PointF velocity, DisplayPortMetrics displayPort);
public abstract boolean aboutToCheckerboard(ImmutableViewportMetrics metrics, PointF velocity, DisplayPortMetrics displayPort);
/** Notify the strategy of a new recorded draw time. Return false to turn off draw time recording. */
public boolean drawTimeUpdate(long millis, int pixels) { return false; }
/** Reset any page-specific state stored, as the page being displayed has changed. */
public void resetPageState() {}
}
/**
@ -194,10 +211,21 @@ final class DisplayPortCalculator {
return margins;
}
/**
* Clamp the given rect to the page bounds and return it.
*/
private static RectF clampToPageBounds(RectF rect, ImmutableViewportMetrics metrics) {
rect.left = Math.max(rect.left, 0);
rect.top = Math.max(rect.top, 0);
rect.right = Math.min(rect.right, metrics.pageSizeWidth);
rect.bottom = Math.min(rect.bottom, metrics.pageSizeHeight);
return rect;
}
/**
* This class implements the variation where we basically don't bother with a a display port.
*/
private static class NoMarginStrategy implements DisplayPortStrategy {
private static class NoMarginStrategy extends DisplayPortStrategy {
NoMarginStrategy(Map<String, Integer> prefs) {
// no prefs in this strategy
}
@ -228,7 +256,7 @@ final class DisplayPortCalculator {
* and/or (b) increasing the buffer on the other axis to compensate for the reduced buffer on
* one axis.
*/
private static class FixedMarginStrategy implements DisplayPortStrategy {
private static class FixedMarginStrategy extends DisplayPortStrategy {
// The length of each axis of the display port will be the corresponding view length
// multiplied by this factor.
private final float SIZE_MULTIPLIER;
@ -294,7 +322,7 @@ final class DisplayPortCalculator {
* so that it is almost entirely in the direction of the pan, with a little bit in the
* reverse direction.
*/
private static class VelocityBiasStrategy implements DisplayPortStrategy {
private static class VelocityBiasStrategy extends DisplayPortStrategy {
// The length of each axis of the display port will be the corresponding view length
// multiplied by this factor.
private final float SIZE_MULTIPLIER;
@ -420,7 +448,7 @@ final class DisplayPortCalculator {
* looks blurry. The assumption is that drawing extra that we never display is better than checkerboarding,
* where we draw less but never even show it on the screen.
*/
private static class DynamicResolutionStrategy implements DisplayPortStrategy {
private static class DynamicResolutionStrategy extends DisplayPortStrategy {
// The length of each axis of the display port will be the corresponding view length
// multiplied by this factor.
private static final float SIZE_MULTIPLIER = 1.5f;
@ -609,4 +637,117 @@ final class DisplayPortCalculator {
return "DynamicResolutionStrategy";
}
}
/**
* This class implements the variation where we use the draw time to predict where we will be when
* a draw completes, and draw that instead of where we are now. In this variation, when our panning
* speed drops below a certain threshold, we draw 9 viewports' worth of content so that the user can
* pan in any direction without encountering checkerboarding.
* Once the user is panning, we modify the displayport to encompass an area range of where we think
* the user will be when the draw completes. This heuristic relies on both the estimated draw time
* the panning velocity; unexpected changes in either of these values will cause the heuristic to
* fail and show checkerboard.
*/
private static class PredictionBiasStrategy extends DisplayPortStrategy {
private static float VELOCITY_THRESHOLD;
private int mPixelArea; // area of the viewport, used in draw time calculations
private int mMinFramesToDraw; // minimum number of frames we take to draw
private int mMaxFramesToDraw; // maximum number of frames we take to draw
PredictionBiasStrategy(Map<String, Integer> prefs) {
VELOCITY_THRESHOLD = GeckoAppShell.getDpi() * getFloatPref(prefs, PREF_DISPLAYPORT_PB_VELOCITY_THRESHOLD, 16);
resetPageState();
}
public DisplayPortMetrics calculate(ImmutableViewportMetrics metrics, PointF velocity) {
float width = metrics.getWidth();
float height = metrics.getHeight();
mPixelArea = (int)(width * height);
if (velocity.length() < VELOCITY_THRESHOLD) {
// if we're going slow, expand the displayport to 9x viewport size
RectF margins = new RectF(width, height, width, height);
return getTileAlignedDisplayPortMetrics(margins, metrics.zoomFactor, metrics);
}
// figure out how far we expect to be
float minDx = velocity.x * mMinFramesToDraw;
float minDy = velocity.y * mMinFramesToDraw;
float maxDx = velocity.x * mMaxFramesToDraw;
float maxDy = velocity.y * mMaxFramesToDraw;
// figure out how many pixels we will be drawing when we draw the above-calculated range.
// this will be larger than the viewport area.
float pixelsToDraw = (width + Math.abs(maxDx - minDx)) * (height + Math.abs(maxDy - minDy));
// adjust how far we will get because of the time spent drawing all these extra pixels. this
// will again increase the number of pixels drawn so really we could keep iterating this over
// and over, but once seems enough for now.
maxDx = maxDx * pixelsToDraw / mPixelArea;
maxDy = maxDy * pixelsToDraw / mPixelArea;
// and finally generate the displayport. the min/max stuff takes care of
// negative velocities as well as positive.
RectF margins = new RectF(
-Math.min(minDx, maxDx),
-Math.min(minDy, maxDy),
Math.max(minDx, maxDx),
Math.max(minDy, maxDy));
return getTileAlignedDisplayPortMetrics(margins, metrics.zoomFactor, metrics);
}
public boolean aboutToCheckerboard(ImmutableViewportMetrics metrics, PointF velocity, DisplayPortMetrics displayPort) {
// the code below is the same as in calculate() but is awkward to refactor since it has multiple outputs.
// refer to the comments in calculate() to understand what this is doing.
float minDx = velocity.x * mMinFramesToDraw;
float minDy = velocity.y * mMinFramesToDraw;
float maxDx = velocity.x * mMaxFramesToDraw;
float maxDy = velocity.y * mMaxFramesToDraw;
float pixelsToDraw = (metrics.getWidth() + Math.abs(maxDx - minDx)) * (metrics.getHeight() + Math.abs(maxDy - minDy));
maxDx = maxDx * pixelsToDraw / mPixelArea;
maxDy = maxDy * pixelsToDraw / mPixelArea;
// now that we have an idea of how far we will be when the draw completes, take the farthest
// end of that range and see if it falls outside the displayport bounds. if it does, allow
// the draw to go through
RectF predictedViewport = metrics.getViewport();
predictedViewport.left += maxDx;
predictedViewport.top += maxDy;
predictedViewport.right += maxDx;
predictedViewport.bottom += maxDy;
predictedViewport = clampToPageBounds(predictedViewport, metrics);
return !displayPort.contains(predictedViewport);
}
@Override
public boolean drawTimeUpdate(long millis, int pixels) {
// calculate the number of frames it took to draw a viewport-sized area
float normalizedTime = (float)mPixelArea * (float)millis / (float)pixels;
int normalizedFrames = (int)FloatMath.ceil(normalizedTime * 60f / 1000f);
// broaden our range on how long it takes to draw if the draw falls outside
// the range. this allows it to grow gradually. this heuristic may need to
// be tweaked into more of a floating window average or something.
if (normalizedFrames <= mMinFramesToDraw) {
mMinFramesToDraw--;
} else if (normalizedFrames > mMaxFramesToDraw) {
mMaxFramesToDraw++;
} else {
return true;
}
Log.d(LOGTAG, "Widened draw range to [" + mMinFramesToDraw + ", " + mMaxFramesToDraw + "]");
return true;
}
@Override
public void resetPageState() {
mMinFramesToDraw = 0;
mMaxFramesToDraw = 2;
}
@Override
public String toString() {
return "PredictionBiasStrategy threshold=" + VELOCITY_THRESHOLD;
}
}
}

View File

@ -6,6 +6,7 @@
package org.mozilla.gecko.gfx;
import android.graphics.RectF;
import org.mozilla.gecko.FloatUtils;
/*
* This class keeps track of the area we request Gecko to paint, as well
@ -32,6 +33,11 @@ public final class DisplayPortMetrics {
return mPosition.contains(rect);
}
public boolean fuzzyEquals(DisplayPortMetrics metrics) {
return RectUtils.fuzzyEquals(mPosition, metrics.mPosition)
&& FloatUtils.fuzzyEquals(mResolution, metrics.mResolution);
}
public String toJSON() {
StringBuffer sb = new StringBuffer(256);
sb.append("{ \"left\": ").append(mPosition.left)

View File

@ -0,0 +1,95 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* 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/. */
package org.mozilla.gecko.gfx;
import android.os.SystemClock;
/**
* A custom-built data structure to assist with measuring draw times.
*
* This class maintains a fixed-size circular buffer of DisplayPortMetrics
* objects and associated timestamps. It provides only three operations, which
* is all we require for our purposes of measuring draw times. Note
* in particular that the class is designed so that even though it is
* accessed from multiple threads, it does not require synchronization;
* any concurrency errors that result from this are handled gracefully.
*
* Assuming an unrolled buffer so that mTail is greater than mHead, the data
* stored in the buffer at entries [mHead, mTail) will never be modified, and
* so are "safe" to read. If this reading is done on the same thread that
* owns mHead, then reading the range [mHead, mTail) is guaranteed to be safe
* since the range itself will not shrink.
*/
final class DrawTimingQueue {
private static final String LOGTAG = "GeckoDrawTimingQueue";
private static final int BUFFER_SIZE = 16;
private final DisplayPortMetrics[] mMetrics;
private final long[] mTimestamps;
private int mHead;
private int mTail;
DrawTimingQueue() {
mMetrics = new DisplayPortMetrics[BUFFER_SIZE];
mTimestamps = new long[BUFFER_SIZE];
mHead = BUFFER_SIZE - 1;
mTail = 0;
}
/**
* Add a new entry to the tail of the queue. If the buffer is full,
* do nothing. This must only be called from the Java UI thread.
*/
boolean add(DisplayPortMetrics metrics) {
if (mHead == mTail) {
return false;
}
mMetrics[mTail] = metrics;
mTimestamps[mTail] = SystemClock.uptimeMillis();
mTail = (mTail + 1) % BUFFER_SIZE;
return true;
}
/**
* Find the timestamp associated with the given metrics, AND remove
* all metrics objects from the start of the queue up to and including
* the one provided. Note that because of draw coalescing, the metrics
* object passed in here may not be the one at the head of the queue,
* and so we must iterate our way through the list to find it.
* This must only be called from the compositor thread.
*/
long findTimeFor(DisplayPortMetrics metrics) {
// keep a copy of the tail pointer so that we ignore new items
// added to the queue while we are searching. this is fine because
// the one we are looking for will either have been added already
// or will not be in the queue at all.
int tail = mTail;
// walk through the "safe" range from mHead to tail; these entries
// will not be modified unless we change mHead.
int i = (mHead + 1) % BUFFER_SIZE;
while (i != tail) {
if (mMetrics[i].fuzzyEquals(metrics)) {
// found it, copy out the timestamp to a local var BEFORE
// changing mHead or add could clobber the timestamp.
long timestamp = mTimestamps[i];
mHead = i;
return timestamp;
}
i = (i + 1) % BUFFER_SIZE;
}
return -1;
}
/**
* Reset the buffer to empty.
* This must only be called from the compositor thread.
*/
void reset() {
// we can only modify mHead on this thread.
mHead = (mTail + BUFFER_SIZE - 1) % BUFFER_SIZE;
}
}

View File

@ -74,6 +74,9 @@ public class GeckoLayerClient implements GeckoEventResponder,
private DisplayPortMetrics mDisplayPort;
private DisplayPortMetrics mReturnDisplayPort;
private boolean mRecordDrawTimes;
private DrawTimingQueue mDrawTimingQueue;
private VirtualLayer mRootLayer;
/* The Gecko viewport as per the UI thread. Must be touched only on the UI thread. */
@ -99,6 +102,8 @@ public class GeckoLayerClient implements GeckoEventResponder,
mScreenSize = new IntSize(0, 0);
mWindowSize = new IntSize(0, 0);
mDisplayPort = new DisplayPortMetrics();
mRecordDrawTimes = true;
mDrawTimingQueue = new DrawTimingQueue();
mCurrentViewTransform = new ViewTransform(0, 0, 1);
}
@ -193,6 +198,10 @@ public class GeckoLayerClient implements GeckoEventResponder,
mDisplayPort = displayPort;
mGeckoViewport = clampedMetrics;
if (mRecordDrawTimes) {
mDrawTimingQueue.add(displayPort);
}
GeckoAppShell.sendEventToGecko(GeckoEvent.createViewportEvent(clampedMetrics, displayPort));
}
@ -342,6 +351,8 @@ public class GeckoLayerClient implements GeckoEventResponder,
mLayerController.abortPanZoomAnimation();
mLayerController.getView().setPaintState(LayerView.PAINT_BEFORE_FIRST);
}
DisplayPortCalculator.resetPageState();
mDrawTimingQueue.reset();
mLayerController.getView().getRenderer().resetCheckerboard();
GeckoAppShell.screenshotWholePage(Tabs.getInstance().getSelectedTab());
}
@ -393,6 +404,19 @@ public class GeckoLayerClient implements GeckoEventResponder,
mRootLayer.setPositionAndResolution(x, y, x + width, y + height, resolution);
if (layersUpdated && mRecordDrawTimes) {
// If we got a layers update, that means a draw finished. Check to see if the area drawn matches
// one of our requested displayports; if it does calculate the draw time and notify the
// DisplayPortCalculator
DisplayPortMetrics drawn = new DisplayPortMetrics(x, y, x + width, y + height, resolution);
long time = mDrawTimingQueue.findTimeFor(drawn);
if (time >= 0) {
long now = SystemClock.uptimeMillis();
time = now - time;
mRecordDrawTimes = DisplayPortCalculator.drawTimeUpdate(time, width * height);
}
}
if (layersUpdated && mDrawListener != null) {
/* Used by robocop for testing purposes */
mDrawListener.drawFinished();

View File

@ -103,6 +103,7 @@ XPIDLSRCS = \
nsITransport.idl \
nsISocketTransport.idl \
nsISocketTransportService.idl \
nsISpeculativeConnect.idl \
nsIServerSocket.idl \
nsIResumableChannel.idl \
nsIRequestObserverProxy.idl \

View File

@ -0,0 +1,69 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla.
*
* The Initial Developer of the Original Code is
* Netscape Communications.
* Portions created by the Initial Developer are Copyright (C) 2012
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Patrick McManus <mcmanus@ducksong.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsISupports.idl"
interface nsIURI;
interface nsIInterfaceRequestor;
interface nsIEventTarget;
[scriptable, uuid(b3c53863-1313-480a-90a2-5b0da651ee5e)]
interface nsISpeculativeConnect : nsISupports
{
/**
* Called as a hint to indicate a new transaction for the URI is likely coming
* soon. The implementer may use this information to start a TCP
* and/or SSL level handshake for that resource immediately so that it is
* ready and/or progressed when the transaction is actually submitted.
*
* No obligation is taken on by the implementer, nor is the submitter obligated
* to actually open the new channel.
*
* @param aURI the URI of the hinted transaction
* @param aCallbacks any security callbacks for use with SSL for interfaces
* such as nsIBadCertListener. May be null.
* @param aTarget the thread on which the release of the callbacks will
* occur. May be null for "any thread".
*
*/
void speculativeConnect(in nsIURI aURI,
in nsIInterfaceRequestor aCallbacks,
in nsIEventTarget aTarget);
};

View File

@ -341,10 +341,11 @@ nsIOService::GetInstance() {
return gIOService;
}
NS_IMPL_THREADSAFE_ISUPPORTS5(nsIOService,
NS_IMPL_THREADSAFE_ISUPPORTS6(nsIOService,
nsIIOService,
nsIIOService2,
nsINetUtil,
nsISpeculativeConnect,
nsIObserver,
nsISupportsWeakReference)
@ -608,10 +609,47 @@ nsIOService::NewChannelFromURI(nsIURI *aURI, nsIChannel **result)
return NewChannelFromURIWithProxyFlags(aURI, nsnull, 0, result);
}
void
nsIOService::LookupProxyInfo(nsIURI *aURI,
nsIURI *aProxyURI,
PRUint32 aProxyFlags,
nsCString *aScheme,
nsIProxyInfo **outPI)
{
nsresult rv;
nsCOMPtr<nsIProxyInfo> pi;
if (!mProxyService) {
mProxyService = do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID);
if (!mProxyService)
NS_WARNING("failed to get protocol proxy service");
}
if (mProxyService) {
PRUint32 flags = 0;
if (aScheme->EqualsLiteral("http") || aScheme->EqualsLiteral("https"))
flags = nsIProtocolProxyService::RESOLVE_NON_BLOCKING;
rv = mProxyService->Resolve(aProxyURI ? aProxyURI : aURI, aProxyFlags,
getter_AddRefs(pi));
if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
// Use an UNKNOWN proxy to defer resolution and avoid blocking.
rv = mProxyService->NewProxyInfo(NS_LITERAL_CSTRING("unknown"),
NS_LITERAL_CSTRING(""),
-1, 0, 0, nsnull,
getter_AddRefs(pi));
}
if (NS_FAILED(rv))
pi = nsnull;
}
*outPI = pi;
if (pi)
pi.forget();
}
NS_IMETHODIMP
nsIOService::NewChannelFromURIWithProxyFlags(nsIURI *aURI,
nsIURI *aProxyURI,
PRUint32 proxyFlags,
PRUint32 aProxyFlags,
nsIChannel **result)
{
nsresult rv;
@ -636,27 +674,7 @@ nsIOService::NewChannelFromURIWithProxyFlags(nsIURI *aURI,
// skip this step. This allows us to lazily load the PPS at startup.
if (protoFlags & nsIProtocolHandler::ALLOWS_PROXY) {
nsCOMPtr<nsIProxyInfo> pi;
if (!mProxyService) {
mProxyService = do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID);
if (!mProxyService)
NS_WARNING("failed to get protocol proxy service");
}
if (mProxyService) {
PRUint32 flags = 0;
if (scheme.EqualsLiteral("http") || scheme.EqualsLiteral("https"))
flags = nsIProtocolProxyService::RESOLVE_NON_BLOCKING;
rv = mProxyService->Resolve(aProxyURI ? aProxyURI : aURI, proxyFlags,
getter_AddRefs(pi));
if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
// Use an UNKNOWN proxy to defer resolution and avoid blocking.
rv = mProxyService->NewProxyInfo(NS_LITERAL_CSTRING("unknown"),
NS_LITERAL_CSTRING(""),
-1, 0, 0, nsnull,
getter_AddRefs(pi));
}
if (NS_FAILED(rv))
pi = nsnull;
}
LookupProxyInfo(aURI, aProxyURI, aProxyFlags, &scheme, getter_AddRefs(pi));
if (pi) {
nsCAutoString type;
if (NS_SUCCEEDED(pi->GetType(type)) && type.EqualsLiteral("http")) {
@ -1236,3 +1254,37 @@ nsIOService::ExtractCharsetFromContentType(const nsACString &aTypeHeader,
}
return NS_OK;
}
// nsISpeculativeConnect
NS_IMETHODIMP
nsIOService::SpeculativeConnect(nsIURI *aURI,
nsIInterfaceRequestor *aCallbacks,
nsIEventTarget *aTarget)
{
nsCAutoString scheme;
nsresult rv = aURI->GetScheme(scheme);
if (NS_FAILED(rv))
return rv;
// Check for proxy information. If there is a proxy configured then a
// speculative connect should not be performed because the potential
// reward is slim with tcp peers closely located to the browser.
nsCOMPtr<nsIProxyInfo> pi;
LookupProxyInfo(aURI, nsnull, 0, &scheme, getter_AddRefs(pi));
if (pi)
return NS_OK;
nsCOMPtr<nsIProtocolHandler> handler;
rv = GetProtocolHandler(scheme.get(), getter_AddRefs(handler));
if (NS_FAILED(rv))
return rv;
nsCOMPtr<nsISpeculativeConnect> speculativeHandler =
do_QueryInterface(handler);
if (!handler)
return NS_OK;
return speculativeHandler->SpeculativeConnect(aURI,
aCallbacks,
aTarget);
}

View File

@ -58,6 +58,7 @@
#include "nsCategoryCache.h"
#include "nsINetworkLinkService.h"
#include "nsAsyncRedirectVerifyHelper.h"
#include "nsISpeculativeConnect.h"
#define NS_N(x) (sizeof(x)/sizeof(*x))
@ -74,6 +75,7 @@ class nsIPrefBranch;
class nsIOService : public nsIIOService2
, public nsIObserver
, public nsINetUtil
, public nsISpeculativeConnect
, public nsSupportsWeakReference
{
public:
@ -82,6 +84,7 @@ public:
NS_DECL_NSIIOSERVICE2
NS_DECL_NSIOBSERVER
NS_DECL_NSINETUTIL
NS_DECL_NSISPECULATIVECONNECT
// Gets the singleton instance of the IO Service, creating it as needed
// Returns nsnull on out of memory or failure to initialize.
@ -135,6 +138,10 @@ private:
nsresult InitializeSocketTransportService();
nsresult InitializeNetworkLinkService();
// consolidated helper function
void LookupProxyInfo(nsIURI *aURI, nsIURI *aProxyURI, PRUint32 aProxyFlags,
nsCString *aScheme, nsIProxyInfo **outPI);
private:
bool mOffline;
bool mOfflineForProfileChange;

View File

@ -112,6 +112,7 @@ CPPSRCS = \
HttpChannelParentListener.cpp \
SpdySession.cpp \
SpdyStream.cpp \
NullHttpTransaction.cpp \
$(NULL)
LOCAL_INCLUDES = \

View File

@ -0,0 +1,223 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et tw=80 : */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2012
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Patrick McManus <mcmanus@ducksong.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsHttp.h"
#include "NullHttpTransaction.h"
#include "nsProxyRelease.h"
#include "nsHttpHandler.h"
namespace mozilla {
namespace net {
NS_IMPL_THREADSAFE_ISUPPORTS0(NullHttpTransaction);
NullHttpTransaction::NullHttpTransaction(nsHttpConnectionInfo *ci,
nsIInterfaceRequestor *callbacks,
nsIEventTarget *target,
PRUint8 caps)
: mStatus(NS_OK)
, mCaps(caps)
, mCallbacks(callbacks)
, mEventTarget(target)
, mConnectionInfo(ci)
, mRequestHead(nsnull)
{
}
NullHttpTransaction::~NullHttpTransaction()
{
if (mCallbacks) {
nsIInterfaceRequestor *cbs = nsnull;
mCallbacks.swap(cbs);
NS_ProxyRelease(mEventTarget, cbs);
}
delete mRequestHead;
}
void
NullHttpTransaction::SetConnection(nsAHttpConnection *conn)
{
mConnection = conn;
}
nsAHttpConnection *
NullHttpTransaction::Connection()
{
return mConnection.get();
}
void
NullHttpTransaction::GetSecurityCallbacks(nsIInterfaceRequestor **outCB,
nsIEventTarget **outTarget)
{
nsCOMPtr<nsIInterfaceRequestor> copyCB(mCallbacks);
*outCB = copyCB;
copyCB.forget();
if (outTarget) {
nsCOMPtr<nsIEventTarget> copyET(mEventTarget);
*outTarget = copyET;
copyET.forget();
}
}
void
NullHttpTransaction::OnTransportStatus(nsITransport* transport,
nsresult status, PRUint64 progress)
{
}
bool
NullHttpTransaction::IsDone()
{
return true;
}
nsresult
NullHttpTransaction::Status()
{
return mStatus;
}
PRUint8
NullHttpTransaction::Caps()
{
return mCaps;
}
PRUint32
NullHttpTransaction::Available()
{
return 0;
}
nsresult
NullHttpTransaction::ReadSegments(nsAHttpSegmentReader *reader,
PRUint32 count, PRUint32 *countRead)
{
*countRead = 0;
return NS_BASE_STREAM_CLOSED;
}
nsresult
NullHttpTransaction::WriteSegments(nsAHttpSegmentWriter *writer,
PRUint32 count, PRUint32 *countWritten)
{
*countWritten = 0;
return NS_BASE_STREAM_CLOSED;
}
PRUint32
NullHttpTransaction::Http1xTransactionCount()
{
return 0;
}
nsHttpRequestHead *
NullHttpTransaction::RequestHead()
{
// We suport a requesthead at all so that a CONNECT tunnel transaction
// can obtain a Host header from it, but we lazy-popualate that header.
if (!mRequestHead) {
mRequestHead = new nsHttpRequestHead();
nsCAutoString hostHeader;
nsCString host(mConnectionInfo->GetHost());
nsresult rv = nsHttpHandler::GenerateHostPort(host,
mConnectionInfo->Port(),
hostHeader);
if (NS_SUCCEEDED(rv))
mRequestHead->SetHeader(nsHttp::Host, hostHeader);
// CONNECT tunnels may also want Proxy-Authorization but that is a lot
// harder to determine, so for now we will let those connections fail in
// the NullHttpTransaction and let them be retried from the pending queue
// with a bound transcation
}
return mRequestHead;
}
nsresult
NullHttpTransaction::TakeSubTransactions(
nsTArray<nsRefPtr<nsAHttpTransaction> > &outTransactions)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
void
NullHttpTransaction::SetSSLConnectFailed()
{
}
void
NullHttpTransaction::Close(nsresult reason)
{
mStatus = reason;
mConnection = nsnull;
}
nsresult
NullHttpTransaction::AddTransaction(nsAHttpTransaction *trans)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
PRUint32
NullHttpTransaction::PipelineDepth()
{
return 0;
}
nsresult
NullHttpTransaction::SetPipelinePosition(PRInt32 position)
{
return NS_OK;
}
PRInt32
NullHttpTransaction::PipelinePosition()
{
return 1;
}
} // namespace mozilla::net
} // namespace mozilla

View File

@ -0,0 +1,84 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2012
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Patrick McManus <mcmanus@ducksong.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef mozilla_net_NullHttpTransaction_h
#define mozilla_net_NullHttpTransaction_h
#include "nsAHttpTransaction.h"
#include "nsAHttpConnection.h"
#include "nsIInterfaceRequestor.h"
#include "nsIEventTarget.h"
#include "nsHttpConnectionInfo.h"
#include "nsHttpRequestHead.h"
// This is the minimal nsAHttpTransaction implementation. A NullHttpTransaction
// can be used to drive connection level semantics (such as SSL handshakes
// tunnels) so that a nsHttpConnection becomes fully established in
// anticiation of a real transaction needing to use it soon.
namespace mozilla { namespace net {
class NullHttpTransaction : public nsAHttpTransaction
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSAHTTPTRANSACTION
NullHttpTransaction(nsHttpConnectionInfo *ci,
nsIInterfaceRequestor *callbacks,
nsIEventTarget *target,
PRUint8 caps);
~NullHttpTransaction();
nsHttpConnectionInfo *ConnectionInfo() { return mConnectionInfo; }
private:
nsresult mStatus;
PRUint8 mCaps;
nsRefPtr<nsAHttpConnection> mConnection;
nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
nsCOMPtr<nsIEventTarget> mEventTarget;
nsRefPtr<nsHttpConnectionInfo> mConnectionInfo;
nsHttpRequestHead *mRequestHead;
};
}} // namespace mozilla::net
#endif // mozilla_net_NullHttpTransaction_h

View File

@ -73,6 +73,7 @@
#include "sampler.h"
#include "nsIConsoleService.h"
#include "base/compiler_specific.h"
#include "NullHttpTransaction.h"
using namespace mozilla;
@ -231,6 +232,10 @@ nsHttpChannel::Connect(bool firstTime)
// true when called from AsyncOpen
if (firstTime) {
// Consider opening a TCP connection right away
SpeculativeConnect();
// are we offline?
bool offline = gIOService->IsOffline();
if (offline)
@ -357,6 +362,33 @@ nsHttpChannel::Connect(bool firstTime)
return NS_OK;
}
void
nsHttpChannel::SpeculativeConnect()
{
// Before we take the latency hit of dealing with the cache, try and
// get the TCP (and SSL) handshakes going so they can overlap.
// don't speculate on uses of the offline application cache or if
// we are actually offline
if (mApplicationCache || gIOService->IsOffline())
return;
// Channel loads with this flags are meant to be local only
if (mLoadFlags & (LOAD_ONLY_FROM_CACHE | LOAD_FROM_CACHE |
LOAD_NO_NETWORK_IO | LOAD_CHECK_OFFLINE_CACHE))
return;
nsCOMPtr<nsIInterfaceRequestor> callbacks;
NS_NewNotificationCallbacksAggregation(mCallbacks, mLoadGroup,
getter_AddRefs(callbacks));
if (!callbacks)
return;
mConnectionInfo->SetAnonymous((mLoadFlags & LOAD_ANONYMOUS) != 0);
gHttpHandler->SpeculativeConnect(mConnectionInfo,
callbacks, NS_GetCurrentThread());
}
void
nsHttpChannel::DoNotifyListenerCleanup()
{
@ -3163,7 +3195,7 @@ nsHttpChannel::InitOfflineCacheEntry()
return NS_OK;
}
if (mResponseHead && mResponseHead->NoStore()) {
if (!mResponseHead || mResponseHead->NoStore()) {
CloseOfflineCacheEntry();
return NS_OK;

View File

@ -166,6 +166,7 @@ private:
bool RequestIsConditional();
nsresult Connect(bool firstTime = true);
void SpeculativeConnect();
nsresult SetupTransaction();
nsresult CallOnStartRequest();
nsresult ProcessResponse();

View File

@ -415,10 +415,9 @@ nsHttpConnection::SetupNPN(PRUint8 caps)
mNPNComplete = true;
if (mConnInfo->UsingSSL() &&
!(caps & NS_HTTP_DISALLOW_SPDY) &&
!mConnInfo->UsingHttpProxy() &&
gHttpHandler->IsSpdyEnabled()) {
LOG(("nsHttpConnection::Init Setting up SPDY Negotiation"));
!mConnInfo->UsingHttpProxy()) {
LOG(("nsHttpConnection::SetupNPN Setting up "
"Next Protocol Negotiation"));
nsCOMPtr<nsISupports> securityInfo;
nsresult rv =
mSocketTransport->GetSecurityInfo(getter_AddRefs(securityInfo));
@ -431,7 +430,12 @@ nsHttpConnection::SetupNPN(PRUint8 caps)
return;
nsTArray<nsCString> protocolArray;
protocolArray.AppendElement(NS_LITERAL_CSTRING("spdy/2"));
if (gHttpHandler->IsSpdyEnabled() &&
!(caps & NS_HTTP_DISALLOW_SPDY)) {
LOG(("nsHttpConnection::SetupNPN Allow SPDY NPN selection"));
protocolArray.AppendElement(NS_LITERAL_CSTRING("spdy/2"));
}
protocolArray.AppendElement(NS_LITERAL_CSTRING("http/1.1"));
if (NS_SUCCEEDED(ssl->SetNPNList(protocolArray))) {
LOG(("nsHttpConnection::Init Setting up SPDY Negotiation OK"));
@ -1251,7 +1255,7 @@ nsHttpConnection::OnSocketWritable()
rv, n, mSocketOutCondition));
// XXX some streams return NS_BASE_STREAM_CLOSED to indicate EOF.
if (rv == NS_BASE_STREAM_CLOSED) {
if (rv == NS_BASE_STREAM_CLOSED && !mTransaction->IsDone()) {
rv = NS_OK;
n = 0;
}

View File

@ -91,8 +91,6 @@ nsHttpConnectionInfo*
nsHttpConnectionInfo::Clone() const
{
nsHttpConnectionInfo* clone = new nsHttpConnectionInfo(mHost, mPort, mProxyInfo, mUsingSSL);
if (!clone)
return nsnull;
// Make sure the anonymous flag is transferred!
clone->SetAnonymous(mHashKey.CharAt(2) == 'A');

View File

@ -98,6 +98,7 @@ public:
SetOriginServer(nsDependentCString(host), port);
}
// OK to treat this as an infalible allocation
nsHttpConnectionInfo* Clone() const;
const char *ProxyHost() const { return mProxyInfo ? mProxyInfo->Host().get() : nsnull; }

View File

@ -53,6 +53,7 @@
#include "mozilla/Telemetry.h"
using namespace mozilla;
using namespace mozilla::net;
// defined by the socket transport service while active
extern PRThread *gSocketThread;
@ -352,6 +353,25 @@ nsHttpConnectionMgr::ClosePersistentConnections()
return PostEvent(&nsHttpConnectionMgr::OnMsgClosePersistentConnections);
}
nsresult
nsHttpConnectionMgr::SpeculativeConnect(nsHttpConnectionInfo *ci,
nsIInterfaceRequestor *callbacks,
nsIEventTarget *target)
{
LOG(("nsHttpConnectionMgr::SpeculativeConnect [ci=%s]\n",
ci->HashKey().get()));
PRUint8 caps = ci->GetAnonymous() ? NS_HTTP_LOAD_ANONYMOUS : 0;
nsRefPtr<NullHttpTransaction> trans =
new NullHttpTransaction(ci, callbacks, target, caps);
nsresult rv =
PostEvent(&nsHttpConnectionMgr::OnMsgSpeculativeConnect, 0, trans);
if (NS_SUCCEEDED(rv))
trans.forget();
return rv;
}
nsresult
nsHttpConnectionMgr::GetSocketThreadTarget(nsIEventTarget **target)
{
@ -1135,6 +1155,22 @@ nsHttpConnectionMgr::ClosePersistentConnectionsCB(const nsACString &key,
return PL_DHASH_NEXT;
}
bool
nsHttpConnectionMgr::RestrictConnections(nsConnectionEntry *ent)
{
NS_ABORT_IF_FALSE(PR_GetCurrentThread() == gSocketThread, "wrong thread");
// If this host is trying to negotiate a SPDY session right now,
// don't create any new ssl connections until the result of the
// negotiation is known.
return ent->mConnInfo->UsingSSL() &&
gHttpHandler->IsSpdyEnabled() &&
!ent->mConnInfo->UsingHttpProxy() &&
(!ent->mTestedSpdy || ent->mUsingSpdy) &&
(ent->mHalfOpens.Length() || ent->mActiveConns.Length());
}
bool
nsHttpConnectionMgr::MakeNewConnection(nsConnectionEntry *ent,
nsHttpTransaction *trans)
@ -1143,18 +1179,30 @@ nsHttpConnectionMgr::MakeNewConnection(nsConnectionEntry *ent,
this, ent, trans));
NS_ABORT_IF_FALSE(PR_GetCurrentThread() == gSocketThread, "wrong thread");
PRUint32 halfOpenLength = ent->mHalfOpens.Length();
for (PRUint32 i = 0; i < halfOpenLength; i++) {
if (ent->mHalfOpens[i]->IsSpeculative()) {
// We've found a speculative connection in the half
// open list. Remove the speculative bit from it and that
// connection can later be used for this transaction
// (or another one in the pending queue) - we don't
// need to open a new connection here.
LOG(("nsHttpConnectionMgr::MakeNewConnection [ci = %s]\n"
"Found a speculative half open connection\n",
ent->mConnInfo->HashKey().get()));
ent->mHalfOpens[i]->SetSpeculative(false);
// return true because we have essentially opened a new connection
// by converting a speculative half-open to general use
return true;
}
}
// If this host is trying to negotiate a SPDY session right now,
// don't create any new connections until the result of the
// negotiation is known.
if (gHttpHandler->IsSpdyEnabled() &&
ent->mConnInfo->UsingSSL() &&
!ent->mConnInfo->UsingHttpProxy() &&
!(trans->Caps() & NS_HTTP_DISALLOW_SPDY) &&
(!ent->mTestedSpdy || ent->mUsingSpdy) &&
(ent->mHalfOpens.Length() || ent->mActiveConns.Length())) {
if (!(trans->Caps() & NS_HTTP_DISALLOW_SPDY) && RestrictConnections(ent))
return false;
}
// We need to make a new connection. If that is going to exceed the
// global connection limit then try and free up some room by closing
@ -1168,7 +1216,7 @@ nsHttpConnectionMgr::MakeNewConnection(nsConnectionEntry *ent,
if (AtActiveConnectionLimit(ent, trans->Caps()))
return false;
nsresult rv = CreateTransport(ent, trans);
nsresult rv = CreateTransport(ent, trans, trans->Caps(), false);
if (NS_FAILED(rv)) /* hard failure */
trans->Close(rv);
@ -1450,12 +1498,38 @@ nsHttpConnectionMgr::DispatchTransaction(nsConnectionEntry *ent,
NS_ABORT_IF_FALSE(conn && !conn->Transaction(),
"DispatchTranaction() on non spdy active connection");
if (!(caps & NS_HTTP_ALLOW_PIPELINING))
conn->Classify(nsAHttpTransaction::CLASS_SOLO);
else
conn->Classify(trans->Classification());
return DispatchAbstractTransaction(ent, trans, caps, conn, priority);
}
// Use this method for dispatching nsAHttpTransction's. It can only safely be
// used upon first use of a connection when NPN has not negotiated SPDY vs
// HTTP/1 yet as multiplexing onto an existing SPDY session requires a
// concrete nsHttpTransaction
nsresult
nsHttpConnectionMgr::DispatchAbstractTransaction(nsConnectionEntry *ent,
nsAHttpTransaction *aTrans,
PRUint8 caps,
nsHttpConnection *conn,
PRInt32 priority)
{
NS_ABORT_IF_FALSE(!conn->UsingSpdy(),
"Spdy Must Not Use DispatchAbstractTransaction");
LOG(("nsHttpConnectionMgr::DispatchAbstractTransaction "
"[ci=%s trans=%x caps=%x conn=%x]\n",
ent->mConnInfo->HashKey().get(), aTrans, caps, conn));
/* Use pipeline datastructure even if connection does not currently qualify
to pipeline this transaction because a different pipeline-eligible
transaction might be placed on the active connection */
transaction might be placed on the active connection */
nsRefPtr<nsHttpPipeline> pipeline;
nsresult rv = BuildPipeline(ent, trans, getter_AddRefs(pipeline));
nsresult rv = BuildPipeline(ent, aTrans, getter_AddRefs(pipeline));
if (!NS_SUCCEEDED(rv))
return rv;
@ -1464,11 +1538,6 @@ nsHttpConnectionMgr::DispatchTransaction(nsConnectionEntry *ent,
// give the transaction the indirect reference to the connection.
pipeline->SetConnection(handle);
if (!(caps & NS_HTTP_ALLOW_PIPELINING))
conn->Classify(nsAHttpTransaction::CLASS_SOLO);
else
conn->Classify(trans->Classification());
rv = conn->Activate(pipeline, caps, priority);
if (NS_FAILED(rv)) {
LOG((" conn->Activate failed [rv=%x]\n", rv));
@ -1531,14 +1600,7 @@ nsHttpConnectionMgr::ProcessNewTransaction(nsHttpTransaction *trans)
nsHttpConnectionInfo *ci = trans->ConnectionInfo();
NS_ASSERTION(ci, "no connection info");
nsConnectionEntry *ent = mCT.Get(ci->HashKey());
if (!ent) {
nsHttpConnectionInfo *clone = ci->Clone();
if (!clone)
return NS_ERROR_OUT_OF_MEMORY;
ent = new nsConnectionEntry(clone);
mCT.Put(ci->HashKey(), ent);
}
nsConnectionEntry *ent = GetOrCreateConnectionEntry(ci);
// SPDY coalescing of hostnames means we might redirect from this
// connection entry onto the preferred one.
@ -1614,15 +1676,19 @@ nsHttpConnectionMgr::RecvdConnect()
nsresult
nsHttpConnectionMgr::CreateTransport(nsConnectionEntry *ent,
nsHttpTransaction *trans)
nsAHttpTransaction *trans,
PRUint8 caps,
bool speculative)
{
NS_ABORT_IF_FALSE(PR_GetCurrentThread() == gSocketThread, "wrong thread");
nsRefPtr<nsHalfOpenSocket> sock = new nsHalfOpenSocket(ent, trans);
nsRefPtr<nsHalfOpenSocket> sock = new nsHalfOpenSocket(ent, trans, caps);
nsresult rv = sock->SetupPrimaryStreams();
NS_ENSURE_SUCCESS(rv, rv);
ent->mHalfOpens.AppendElement(sock);
if (speculative)
sock->SetSpeculative(true);
return NS_OK;
}
@ -2057,6 +2123,19 @@ nsHttpConnectionMgr::nsConnectionHandle::~nsConnectionHandle()
NS_IMPL_THREADSAFE_ISUPPORTS0(nsHttpConnectionMgr::nsConnectionHandle)
nsHttpConnectionMgr::nsConnectionEntry *
nsHttpConnectionMgr::GetOrCreateConnectionEntry(nsHttpConnectionInfo *ci)
{
nsConnectionEntry *ent = mCT.Get(ci->HashKey());
if (ent)
return ent;
nsHttpConnectionInfo *clone = ci->Clone();
ent = new nsConnectionEntry(clone);
mCT.Put(ci->HashKey(), ent);
return ent;
}
nsresult
nsHttpConnectionMgr::nsConnectionHandle::OnHeadersAvailable(nsAHttpTransaction *trans,
nsHttpRequestHead *req,
@ -2099,6 +2178,26 @@ nsConnectionHandle::TakeTransport(nsISocketTransport **aTransport,
return mConn->TakeTransport(aTransport, aInputStream, aOutputStream);
}
void
nsHttpConnectionMgr::OnMsgSpeculativeConnect(PRInt32, void *param)
{
NS_ABORT_IF_FALSE(PR_GetCurrentThread() == gSocketThread, "wrong thread");
nsRefPtr<NullHttpTransaction> trans =
dont_AddRef(static_cast<NullHttpTransaction *>(param));
LOG(("nsHttpConnectionMgr::OnMsgSpeculativeConnect [ci=%s]\n",
trans->ConnectionInfo()->HashKey().get()));
nsConnectionEntry *ent =
GetOrCreateConnectionEntry(trans->ConnectionInfo());
if (!ent->mIdleConns.Length() && !RestrictConnections(ent) &&
!AtActiveConnectionLimit(ent, trans->Caps())) {
CreateTransport(ent, trans, trans->Caps(), true);
}
}
void
nsHttpConnectionMgr::nsConnectionHandle::GetSecurityInfo(nsISupports **result)
{
@ -2141,9 +2240,12 @@ NS_IMPL_THREADSAFE_ISUPPORTS4(nsHttpConnectionMgr::nsHalfOpenSocket,
nsHttpConnectionMgr::
nsHalfOpenSocket::nsHalfOpenSocket(nsConnectionEntry *ent,
nsHttpTransaction *trans)
nsAHttpTransaction *trans,
PRUint8 caps)
: mEnt(ent),
mTransaction(trans)
mTransaction(trans),
mCaps(caps),
mSpeculative(false)
{
NS_ABORT_IF_FALSE(ent && trans, "constructor with null arguments");
LOG(("Creating nsHalfOpenSocket [this=%p trans=%p ent=%s]\n",
@ -2158,10 +2260,22 @@ nsHttpConnectionMgr::nsHalfOpenSocket::~nsHalfOpenSocket()
LOG(("Destroying nsHalfOpenSocket [this=%p]\n", this));
if (mEnt) {
// If the removal of the HalfOpenSocket from the mHalfOpens list
// removes the RestrictConnections() throttle then we need to
// process the pending queue.
bool restrictedBeforeRelease =
gHttpHandler->ConnMgr()->RestrictConnections(mEnt);
// A failure to create the transport object at all
// will result in this not being present in the halfopen table
// so ignore failures of RemoveElement()
mEnt->mHalfOpens.RemoveElement(this);
if (restrictedBeforeRelease &&
!gHttpHandler->ConnMgr()->RestrictConnections(mEnt)) {
LOG(("nsHalfOpenSocket %p lifted RestrictConnections() limit.\n"));
gHttpHandler->ConnMgr()->ProcessPendingQForEntry(mEnt);
}
}
}
@ -2193,10 +2307,10 @@ nsHalfOpenSocket::SetupStreams(nsISocketTransport **transport,
NS_ENSURE_SUCCESS(rv, rv);
PRUint32 tmpFlags = 0;
if (mTransaction->Caps() & NS_HTTP_REFRESH_DNS)
if (mCaps & NS_HTTP_REFRESH_DNS)
tmpFlags = nsISocketTransport::BYPASS_CACHE;
if (mTransaction->Caps() & NS_HTTP_LOAD_ANONYMOUS)
if (mCaps & NS_HTTP_LOAD_ANONYMOUS)
tmpFlags |= nsISocketTransport::ANONYMOUS_CONNECT;
// For backup connections, we disable IPv6. That's because some users have
@ -2290,7 +2404,7 @@ nsHttpConnectionMgr::nsHalfOpenSocket::SetupBackupTimer()
PRUint16 timeout = gHttpHandler->GetIdleSynTimeout();
NS_ABORT_IF_FALSE(!mSynTimer, "timer already initd");
if (timeout) {
if (timeout && !mTransaction->IsDone()) {
// Setup the timer that will establish a backup socket
// if we do not get a writable event on the main one.
// We do this because a lost SYN takes a very long time
@ -2353,7 +2467,7 @@ nsHttpConnectionMgr::nsHalfOpenSocket::Notify(nsITimer *timer)
NS_ABORT_IF_FALSE(timer == mSynTimer, "wrong timer");
if (!gHttpHandler->ConnMgr()->
AtActiveConnectionLimit(mEnt, mTransaction->Caps())) {
AtActiveConnectionLimit(mEnt, mCaps)) {
SetupBackupStreams();
}
@ -2427,12 +2541,12 @@ nsHalfOpenSocket::OnOutputStreamReady(nsIAsyncOutputStream *out)
// if this is still in the pending list, remove it and dispatch it
index = mEnt->mPendingQ.IndexOf(mTransaction);
if (index != -1) {
NS_ABORT_IF_FALSE(!mSpeculative,
"Speculative Half Open found mTranscation");
nsRefPtr<nsHttpTransaction> temp = dont_AddRef(mEnt->mPendingQ[index]);
mEnt->mPendingQ.RemoveElementAt(index);
nsHttpTransaction *temp = mTransaction;
NS_RELEASE(temp);
gHttpHandler->ConnMgr()->AddActiveConn(conn, mEnt);
rv = gHttpHandler->ConnMgr()->DispatchTransaction(mEnt, mTransaction,
conn);
rv = gHttpHandler->ConnMgr()->DispatchTransaction(mEnt, temp, conn);
}
else {
// this transaction was dispatched off the pending q before all the
@ -2451,8 +2565,32 @@ nsHalfOpenSocket::OnOutputStreamReady(nsIAsyncOutputStream *out)
// minimum granularity we can expect a server to be timing out with.
conn->SetIsReusedAfter(950);
nsRefPtr<nsHttpConnection> copy(conn); // because onmsg*() expects to drop a reference
gHttpHandler->ConnMgr()->OnMsgReclaimConnection(NS_OK, conn.forget().get());
// if we are using ssl and no other transactions are waiting right now,
// then form a null transaction to drive the SSL handshake to
// completion. Afterwards the connection will be 100% ready for the next
// transaction to use it.
if (mEnt->mConnInfo->UsingSSL() && !mEnt->mPendingQ.Length()) {
LOG(("nsHalfOpenSocket::OnOutputStreamReady null transaction will "
"be used to finish SSL handshake on conn %p\n", conn.get()));
nsRefPtr<NullHttpTransaction> trans =
new NullHttpTransaction(mEnt->mConnInfo,
callbacks, callbackTarget,
mCaps & ~NS_HTTP_ALLOW_PIPELINING);
gHttpHandler->ConnMgr()->AddActiveConn(conn, mEnt);
conn->Classify(nsAHttpTransaction::CLASS_SOLO);
rv = gHttpHandler->ConnMgr()->
DispatchAbstractTransaction(mEnt, trans, mCaps, conn, 0);
}
else {
// otherwise just put this in the persistent connection pool
LOG(("nsHalfOpenSocket::OnOutputStreamReady no transaction match "
"returning conn %p to pool\n", conn.get()));
nsRefPtr<nsHttpConnection> copy(conn);
// forget() to effectively addref because onmsg*() will drop a ref
gHttpHandler->ConnMgr()->OnMsgReclaimConnection(
NS_OK, conn.forget().get());
}
}
return rv;

View File

@ -42,6 +42,7 @@
#include "nsHttpConnectionInfo.h"
#include "nsHttpConnection.h"
#include "nsHttpTransaction.h"
#include "NullHttpTransaction.h"
#include "nsTArray.h"
#include "nsThreadUtils.h"
#include "nsClassHashtable.h"
@ -131,6 +132,16 @@ public:
// transport service is not available when the connection manager is down.
nsresult GetSocketThreadTarget(nsIEventTarget **);
// called to indicate a transaction for the connectionInfo is likely coming
// soon. The connection manager may use this information to start a TCP
// and/or SSL level handshake for that resource immediately so that it is
// ready when the transaction is submitted. No obligation is taken on by the
// connection manager, nor is the submitter obligated to actually submit a
// real transaction for this connectionInfo.
nsresult SpeculativeConnect(nsHttpConnectionInfo *,
nsIInterfaceRequestor *,
nsIEventTarget *);
// called when a connection is done processing a transaction. if the
// connection can be reused then it will be added to the idle list, else
// it will be closed.
@ -383,7 +394,8 @@ private:
NS_DECL_NSITIMERCALLBACK
nsHalfOpenSocket(nsConnectionEntry *ent,
nsHttpTransaction *trans);
nsAHttpTransaction *trans,
PRUint8 caps);
~nsHalfOpenSocket();
nsresult SetupStreams(nsISocketTransport **,
@ -396,14 +408,27 @@ private:
void CancelBackupTimer();
void Abandon();
nsHttpTransaction *Transaction() { return mTransaction; }
nsAHttpTransaction *Transaction() { return mTransaction; }
bool IsSpeculative() { return mSpeculative; }
void SetSpeculative(bool val) { mSpeculative = val; }
private:
nsConnectionEntry *mEnt;
nsRefPtr<nsHttpTransaction> mTransaction;
nsRefPtr<nsAHttpTransaction> mTransaction;
nsCOMPtr<nsISocketTransport> mSocketTransport;
nsCOMPtr<nsIAsyncOutputStream> mStreamOut;
nsCOMPtr<nsIAsyncInputStream> mStreamIn;
PRUint8 mCaps;
// mSpeculative is set if the socket was created from
// SpeculativeConnect(). It is cleared when a transaction would normally
// start a new connection from scratch but instead finds this one in
// the half open list and claims it for its own use. (which due to
// the vagaries of scheduling from the pending queue might not actually
// match up - but it prevents a speculative connection from opening
// more connections that are needed.)
bool mSpeculative;
mozilla::TimeStamp mPrimarySynStarted;
mozilla::TimeStamp mBackupSynStarted;
@ -455,17 +480,26 @@ private:
nsresult DispatchTransaction(nsConnectionEntry *,
nsHttpTransaction *,
nsHttpConnection *);
nsresult DispatchAbstractTransaction(nsConnectionEntry *,
nsAHttpTransaction *,
PRUint8,
nsHttpConnection *,
PRInt32);
nsresult BuildPipeline(nsConnectionEntry *,
nsAHttpTransaction *,
nsHttpPipeline **);
bool RestrictConnections(nsConnectionEntry *);
nsresult ProcessNewTransaction(nsHttpTransaction *);
nsresult EnsureSocketThreadTargetIfOnline();
void ClosePersistentConnections(nsConnectionEntry *ent);
nsresult CreateTransport(nsConnectionEntry *, nsHttpTransaction *);
nsresult CreateTransport(nsConnectionEntry *, nsAHttpTransaction *,
PRUint8, bool);
void AddActiveConn(nsHttpConnection *, nsConnectionEntry *);
void StartedConnect();
void RecvdConnect();
nsConnectionEntry *GetOrCreateConnectionEntry(nsHttpConnectionInfo *);
bool MakeNewConnection(nsConnectionEntry *ent,
nsHttpTransaction *trans);
bool AddToShortestPipeline(nsConnectionEntry *ent,
@ -542,6 +576,7 @@ private:
void OnMsgCancelTransaction (PRInt32, void *);
void OnMsgProcessPendingQ (PRInt32, void *);
void OnMsgPruneDeadConnections (PRInt32, void *);
void OnMsgSpeculativeConnect (PRInt32, void *);
void OnMsgReclaimConnection (PRInt32, void *);
void OnMsgUpdateParam (PRInt32, void *);
void OnMsgClosePersistentConnections (PRInt32, void *);

View File

@ -1417,12 +1417,13 @@ nsHttpHandler::SetAcceptEncodings(const char *aAcceptEncodings)
// nsHttpHandler::nsISupports
//-----------------------------------------------------------------------------
NS_IMPL_THREADSAFE_ISUPPORTS5(nsHttpHandler,
NS_IMPL_THREADSAFE_ISUPPORTS6(nsHttpHandler,
nsIHttpProtocolHandler,
nsIProxiedProtocolHandler,
nsIProtocolHandler,
nsIObserver,
nsISupportsWeakReference)
nsISupportsWeakReference,
nsISpeculativeConnect)
//-----------------------------------------------------------------------------
// nsHttpHandler::nsIProtocolHandler
@ -1669,15 +1670,75 @@ nsHttpHandler::Observe(nsISupports *subject,
return NS_OK;
}
// nsISpeculativeConnect
NS_IMETHODIMP
nsHttpHandler::SpeculativeConnect(nsIURI *aURI,
nsIInterfaceRequestor *aCallbacks,
nsIEventTarget *aTarget)
{
nsIStrictTransportSecurityService* stss = gHttpHandler->GetSTSService();
bool isStsHost = false;
if (!stss)
return NS_OK;
nsCOMPtr<nsIURI> clone;
if (NS_SUCCEEDED(stss->IsStsURI(aURI, &isStsHost)) && isStsHost) {
if (NS_SUCCEEDED(aURI->Clone(getter_AddRefs(clone)))) {
clone->SetScheme(NS_LITERAL_CSTRING("https"));
aURI = clone.get();
}
}
nsCAutoString scheme;
nsresult rv = aURI->GetScheme(scheme);
if (NS_FAILED(rv))
return rv;
// If this is HTTPS, make sure PSM is initialized as the channel
// creation path may have been bypassed
if (scheme.EqualsLiteral("https")) {
if (!IsNeckoChild()) {
// make sure PSM gets initialized on the main thread.
net_EnsurePSMInit();
}
}
// Ensure that this is HTTP or HTTPS, otherwise we don't do preconnect here
else if (!scheme.EqualsLiteral("http"))
return NS_ERROR_UNEXPECTED;
// Construct connection info object
bool usingSSL = false;
rv = aURI->SchemeIs("https", &usingSSL);
if (NS_FAILED(rv))
return rv;
nsCAutoString host;
rv = aURI->GetAsciiHost(host);
if (NS_FAILED(rv))
return rv;
PRInt32 port = -1;
rv = aURI->GetPort(&port);
if (NS_FAILED(rv))
return rv;
nsHttpConnectionInfo *ci =
new nsHttpConnectionInfo(host, port, nsnull, usingSSL);
return SpeculativeConnect(ci, aCallbacks, aTarget);
}
//-----------------------------------------------------------------------------
// nsHttpsHandler implementation
//-----------------------------------------------------------------------------
NS_IMPL_THREADSAFE_ISUPPORTS4(nsHttpsHandler,
NS_IMPL_THREADSAFE_ISUPPORTS5(nsHttpsHandler,
nsIHttpProtocolHandler,
nsIProxiedProtocolHandler,
nsIProtocolHandler,
nsISupportsWeakReference)
nsISupportsWeakReference,
nsISpeculativeConnect)
nsresult
nsHttpsHandler::Init()

View File

@ -61,6 +61,7 @@
#include "nsIIDNService.h"
#include "nsITimer.h"
#include "nsIStrictTransportSecurityService.h"
#include "nsISpeculativeConnect.h"
class nsHttpConnectionInfo;
class nsHttpHeaderArray;
@ -76,6 +77,7 @@ class nsIPrefBranch;
class nsHttpHandler : public nsIHttpProtocolHandler
, public nsIObserver
, public nsSupportsWeakReference
, public nsISpeculativeConnect
{
public:
NS_DECL_ISUPPORTS
@ -83,6 +85,7 @@ public:
NS_DECL_NSIPROXIEDPROTOCOLHANDLER
NS_DECL_NSIHTTPPROTOCOLHANDLER
NS_DECL_NSIOBSERVER
NS_DECL_NSISPECULATIVECONNECT
nsHttpHandler();
virtual ~nsHttpHandler();
@ -182,6 +185,13 @@ public:
return mConnMgr->GetSocketThreadTarget(target);
}
nsresult SpeculativeConnect(nsHttpConnectionInfo *ci,
nsIInterfaceRequestor *callbacks,
nsIEventTarget *target)
{
return mConnMgr->SpeculativeConnect(ci, callbacks, target);
}
// for anything that wants to know if we're in private browsing mode.
bool InPrivateBrowsingMode();
@ -405,6 +415,7 @@ extern nsHttpHandler *gHttpHandler;
class nsHttpsHandler : public nsIHttpProtocolHandler
, public nsSupportsWeakReference
, public nsISpeculativeConnect
{
public:
// we basically just want to override GetScheme and GetDefaultPort...
@ -414,6 +425,7 @@ public:
NS_DECL_NSIPROTOCOLHANDLER
NS_FORWARD_NSIPROXIEDPROTOCOLHANDLER (gHttpHandler->)
NS_FORWARD_NSIHTTPPROTOCOLHANDLER (gHttpHandler->)
NS_FORWARD_NSISPECULATIVECONNECT (gHttpHandler->)
nsHttpsHandler() { }
virtual ~nsHttpsHandler() { }

View File

@ -0,0 +1,42 @@
const Cc = Components.classes;
const Ci = Components.interfaces;
const CC = Components.Constructor;
const ServerSocket = CC("@mozilla.org/network/server-socket;1",
"nsIServerSocket",
"init");
var serv;
function TestServer() {
this.listener = ServerSocket(4444, true, -1);
this.listener.asyncListen(this);
}
TestServer.prototype = {
QueryInterface: function(iid) {
if (iid.equals(Ci.nsIServerSocket) ||
iid.equals(Ci.nsISupports))
return this;
throw Components.results.NS_ERROR_NO_INTERFACE;
},
onSocketAccepted: function(socket, trans) {
try { this.listener.close(); } catch(e) {}
do_check_true(true);
do_test_finished();
},
onStopListening: function(socket) {}
}
function run_test() {
var ios = Cc["@mozilla.org/network/io-service;1"]
.getService(Ci.nsIIOService);
serv = new TestServer();
URI = ios.newURI("http://localhost:4444/just/a/test", null, null);
ios.QueryInterface(Components.interfaces.nsISpeculativeConnect)
.speculativeConnect(URI, null, null);
do_test_pending();
}

View File

@ -174,6 +174,7 @@ skip-if = os == "win"
[test_socks.js]
# Bug 675039: test hangs consistently on Android
skip-if = os == "android"
[test_speculative_connect.js]
[test_standardurl.js]
[test_standardurl_port.js]
[test_streamcopier.js]

View File

@ -62,7 +62,6 @@ TEST_HARNESS_FILES := \
EXTRA_BUILD_FILES := \
automationutils.py \
manifestparser.py \
mozinfo.py \
$(NULL)
# And files for running xpcshell remotely from $(topsrcdir)/build/mobile
@ -77,6 +76,9 @@ TEST_HARNESS_COMPONENTS := \
httpd.manifest \
$(NULL)
MOZINFO_FILES := \
mozinfo.py
# Rules for staging the necessary harness bits for a test package
PKG_STAGE = $(DIST)/test-package-stage
@ -87,10 +89,11 @@ libs::
# Run selftests
check::
OBJDIR=$(DEPTH) $(PYTHON) $(topsrcdir)/config/pythonpath.py \
-I$(topsrcdir)/build $(srcdir)/selftest.py
-I$(topsrcdir)/build -I$(topsrcdir)/testing/mozbase/mozinfo/mozinfo $(srcdir)/selftest.py
stage-package:
$(NSINSTALL) -D $(PKG_STAGE)/xpcshell/tests
@(cd $(topsrcdir)/testing/mozbase/mozinfo/mozinfo && tar $(TAR_CREATE_FLAGS) - $(MOZINFO_FILES)) | (cd $(PKG_STAGE)/xpcshell && tar -xf -)
@(cd $(srcdir) && tar $(TAR_CREATE_FLAGS) - $(TEST_HARNESS_FILES)) | (cd $(PKG_STAGE)/xpcshell && tar -xf -)
@(cd $(topsrcdir)/build && tar $(TAR_CREATE_FLAGS) - $(EXTRA_BUILD_FILES)) | (cd $(PKG_STAGE)/xpcshell && tar -xf -)
@cp $(DEPTH)/mozinfo.json $(PKG_STAGE)/xpcshell