mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge mozilla-central into mozilla-inbound
This commit is contained in:
commit
eb35c5e956
@ -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);
|
@ -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();
|
@ -53,7 +53,7 @@ CPPSRCS = \
|
||||
nsAccessibleWrap.cpp \
|
||||
nsDocAccessibleWrap.cpp \
|
||||
nsRootAccessibleWrap.cpp \
|
||||
nsApplicationAccessibleWrap.cpp \
|
||||
ApplicationAccessibleWrap.cpp \
|
||||
nsMaiInterfaceComponent.cpp \
|
||||
nsMaiInterfaceAction.cpp \
|
||||
nsMaiInterfaceText.cpp \
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
|
@ -69,7 +69,6 @@ CPPSRCS = \
|
||||
nsBaseWidgetAccessible.cpp \
|
||||
nsEventShell.cpp \
|
||||
nsRootAccessible.cpp \
|
||||
nsApplicationAccessible.cpp \
|
||||
nsCaretAccessible.cpp \
|
||||
nsTextAccessible.cpp \
|
||||
nsTextEquivUtils.cpp \
|
||||
|
@ -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"
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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();
|
||||
|
||||
|
@ -42,7 +42,6 @@
|
||||
|
||||
#include "Accessible-inl.h"
|
||||
#include "nsAccessibilityService.h"
|
||||
#include "nsApplicationAccessibleWrap.h"
|
||||
#include "nsAccUtils.h"
|
||||
#include "nsCoreUtils.h"
|
||||
#include "Relation.h"
|
||||
|
@ -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;
|
@ -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
|
@ -15,6 +15,7 @@ LIBXUL_LIBRARY = 1
|
||||
|
||||
|
||||
CPPSRCS = \
|
||||
ApplicationAccessible.cpp \
|
||||
ARIAGridAccessible.cpp \
|
||||
FormControlAccessible.cpp \
|
||||
OuterDocAccessible.cpp \
|
||||
|
@ -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() {}
|
@ -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 \
|
||||
|
@ -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()
|
||||
{
|
||||
}
|
||||
|
@ -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
|
@ -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 \
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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() {}
|
@ -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.
|
||||
|
@ -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>
|
||||
|
||||
|
209
build/mozinfo.py
209
build/mozinfo.py
@ -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()
|
53
configure.in
53
configure.in
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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 &&
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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 \
|
||||
|
32
dom/tests/mochitest/localstorage/test_bug746272-1.html
Normal file
32
dom/tests/mochitest/localstorage/test_bug746272-1.html
Normal 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>
|
31
dom/tests/mochitest/localstorage/test_bug746272-2.html
Normal file
31
dom/tests/mochitest/localstorage/test_bug746272-2.html
Normal 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>
|
@ -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;
|
||||
|
@ -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) \
|
||||
|
@ -86,6 +86,7 @@ CPPSRCS = \
|
||||
LayerManagerOGL.cpp \
|
||||
ThebesLayerOGL.cpp \
|
||||
TiledThebesLayerOGL.cpp \
|
||||
ReusableTileStoreOGL.cpp \
|
||||
LayerSorter.cpp \
|
||||
ImageLayers.cpp \
|
||||
$(NULL)
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
}
|
||||
};
|
||||
|
||||
|
188
gfx/layers/opengl/ReusableTileStoreOGL.cpp
Normal file
188
gfx/layers/opengl/ReusableTileStoreOGL.cpp
Normal 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
|
96
gfx/layers/opengl/ReusableTileStoreOGL.h
Normal file
96
gfx/layers/opengl/ReusableTileStoreOGL.h
Normal 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
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
{
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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 |
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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 \
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
95
mobile/android/base/gfx/DrawTimingQueue.java
Normal file
95
mobile/android/base/gfx/DrawTimingQueue.java
Normal 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;
|
||||
}
|
||||
}
|
@ -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();
|
||||
|
@ -103,6 +103,7 @@ XPIDLSRCS = \
|
||||
nsITransport.idl \
|
||||
nsISocketTransport.idl \
|
||||
nsISocketTransportService.idl \
|
||||
nsISpeculativeConnect.idl \
|
||||
nsIServerSocket.idl \
|
||||
nsIResumableChannel.idl \
|
||||
nsIRequestObserverProxy.idl \
|
||||
|
69
netwerk/base/public/nsISpeculativeConnect.idl
Normal file
69
netwerk/base/public/nsISpeculativeConnect.idl
Normal 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);
|
||||
|
||||
};
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -112,6 +112,7 @@ CPPSRCS = \
|
||||
HttpChannelParentListener.cpp \
|
||||
SpdySession.cpp \
|
||||
SpdyStream.cpp \
|
||||
NullHttpTransaction.cpp \
|
||||
$(NULL)
|
||||
|
||||
LOCAL_INCLUDES = \
|
||||
|
223
netwerk/protocol/http/NullHttpTransaction.cpp
Normal file
223
netwerk/protocol/http/NullHttpTransaction.cpp
Normal 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
|
||||
|
84
netwerk/protocol/http/NullHttpTransaction.h
Normal file
84
netwerk/protocol/http/NullHttpTransaction.h
Normal 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
|
@ -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;
|
||||
|
@ -166,6 +166,7 @@ private:
|
||||
|
||||
bool RequestIsConditional();
|
||||
nsresult Connect(bool firstTime = true);
|
||||
void SpeculativeConnect();
|
||||
nsresult SetupTransaction();
|
||||
nsresult CallOnStartRequest();
|
||||
nsresult ProcessResponse();
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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');
|
||||
|
@ -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; }
|
||||
|
@ -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;
|
||||
|
@ -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 *);
|
||||
|
@ -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()
|
||||
|
@ -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() { }
|
||||
|
42
netwerk/test/unit/test_speculative_connect.js
Normal file
42
netwerk/test/unit/test_speculative_connect.js
Normal 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();
|
||||
}
|
||||
|
@ -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]
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user