This commit is contained in:
Rob Campbell 2011-04-21 13:18:12 -03:00
Родитель 19eba7bd60 5f410e5e8c
Коммит 9063436548
109 изменённых файлов: 2908 добавлений и 760 удалений

Просмотреть файл

@ -26,6 +26,28 @@
<key>CFBundleTypeRole</key>
<string>Viewer</string>
</dict>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>svg</string>
</array>
<key>CFBundleTypeIconFile</key>
<string>document.icns</string>
<key>CFBundleTypeMIMETypes</key>
<array>
<string>image/svg+xml</string>
</array>
<key>CFBundleTypeName</key>
<string>SVG document</string>
<key>CFBundleTypeOSTypes</key>
<array>
<string>TEXT</string>
</array>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>NSDocumentClass</key>
<string>BrowserDocument</string>
</dict>
<dict>
<key>CFBundleTypeExtensions</key>
<array>

Просмотреть файл

@ -946,6 +946,7 @@ pref("toolbar.customization.usesheet", false);
pref("dom.ipc.plugins.enabled.i386", false);
pref("dom.ipc.plugins.enabled.i386.flash player.plugin", true);
pref("dom.ipc.plugins.enabled.i386.javaplugin2_npapi.plugin", true);
pref("dom.ipc.plugins.enabled.i386.javaappletplugin.plugin", true);
// x86_64 ipc preferences
pref("dom.ipc.plugins.enabled.x86_64", true);
#else

Просмотреть файл

@ -134,13 +134,16 @@
margin-top: 10px;
}
#channelSelectorStart {
-moz-margin-start: 0;
}
#channelMenulist {
margin: 0;
}
.channel-description {
margin: 10px 0;
text-align: center;
}
#detailsBox,

Просмотреть файл

@ -127,8 +127,8 @@
</vbox>
<vbox id="channelSelector">
<hbox pack="center" align="center">
<label>&channel.selector.start;</label>
<hbox pack="start" align="center">
<label id="channelSelectorStart">&channel.selector.start;</label>
<menulist id="channelMenulist" onselect="gChannelSelector.selectChannel(this.selectedItem);">
<menupopup>
<menuitem id="releaseMenuitem" label="Release" value="release"/>
@ -146,9 +146,14 @@
<description id="auroraDescription" class="channel-description">&channel.aurora.description;</description>
</deck>
<hbox id="channelSelectorButtons" pack="center">
<hbox id="channelSelectorButtons" pack="end">
#ifdef XP_UNIX
<button oncommand="gChannelSelector.cancel();" label="&channel.selector.cancelButton;"/>
<button oncommand="gChannelSelector.apply();" label="&channel.selector.applyButton;"/>
#else
<button oncommand="gChannelSelector.apply();" label="&channel.selector.applyButton;"/>
<button oncommand="gChannelSelector.cancel();" label="&channel.selector.cancelButton;"/>
#endif
</hbox>
</vbox>
</deck>

Просмотреть файл

@ -2860,17 +2860,22 @@ SessionStoreService.prototype = {
// Attach data that will be restored on "load" event, after tab is restored.
if (activeIndex > -1) {
let curSHEntry = browser.webNavigation.sessionHistory.
getEntryAtIndex(activeIndex, false).
QueryInterface(Ci.nsISHEntry);
// restore those aspects of the currently active documents which are not
// preserved in the plain history entries (mainly scroll state and text data)
browser.__SS_restore_data = tabData.entries[activeIndex] || {};
browser.__SS_restore_pageStyle = tabData.pageStyle || "";
browser.__SS_restore_tab = aTab;
browser.__SS_restore_docIdentifier = curSHEntry.docIdentifier;
didStartLoad = true;
try {
// In order to work around certain issues in session history, we need to
// force session history to update its internal index and call reload
// instead of gotoIndex. c.f. bug 597315
// instead of gotoIndex. See bug 597315.
browser.webNavigation.sessionHistory.getEntryAtIndex(activeIndex, true);
browser.webNavigation.sessionHistory.
QueryInterface(Ci.nsISHistory_2_0_BRANCH).reloadCurrentEntry();
@ -3163,12 +3168,19 @@ SessionStoreService.prototype = {
aBrowser.markupDocumentViewer.authorStyleDisabled = selectedPageStyle == "_nostyle";
}
if (aBrowser.__SS_restore_docIdentifier) {
let sh = aBrowser.webNavigation.sessionHistory;
sh.getEntryAtIndex(sh.index, false).QueryInterface(Ci.nsISHEntry).
docIdentifier = aBrowser.__SS_restore_docIdentifier;
}
// notify the tabbrowser that this document has been completely restored
this._sendTabRestoredNotification(aBrowser.__SS_restore_tab);
delete aBrowser.__SS_restore_data;
delete aBrowser.__SS_restore_pageStyle;
delete aBrowser.__SS_restore_tab;
delete aBrowser.__SS_restore_docIdentifier;
},
/**

Просмотреть файл

@ -44,11 +44,15 @@ function checkState(tab) {
let popStateCount = 0;
let handler = function(aEvent) {
tab.linkedBrowser.addEventListener('popstate', function(aEvent) {
let contentWindow = tab.linkedBrowser.contentWindow;
if (popStateCount == 0) {
popStateCount++;
//ok(aEvent.state, "Event should have a state property.");
is(tab.linkedBrowser.contentWindow.testState, 'foo',
'testState after going back');
ok(aEvent.state, "Event should have a state property.");
is(JSON.stringify(tab.linkedBrowser.contentWindow.history.state), JSON.stringify({obj1:1}),
"first popstate object.");
@ -78,15 +82,16 @@ function checkState(tab) {
// Clean up after ourselves and finish the test.
tab.linkedBrowser.removeEventListener("popstate", arguments.callee, true);
tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
gBrowser.removeTab(tab);
finish();
}
};
}, true);
tab.linkedBrowser.addEventListener("load", handler, true);
tab.linkedBrowser.addEventListener("popstate", handler, true);
// Set some state in the page's window. When we go back(), the page should
// be retrieved from bfcache, and this state should still be there.
tab.linkedBrowser.contentWindow.testState = 'foo';
// Now go back. This should trigger the popstate event handler above.
tab.linkedBrowser.contentWindow.history.back();
}
@ -119,20 +124,24 @@ function test() {
let contentWindow = tab.linkedBrowser.contentWindow;
let history = contentWindow.history;
history.pushState({obj1:1}, "title-obj1");
history.pushState({obj2:2}, "title-obj2", "?foo");
history.pushState({obj2:2}, "title-obj2", "page2");
history.replaceState({obj3:3}, "title-obj3");
let state = ss.getTabState(tab);
gBrowser.removeTab(tab);
// In order to make sure that setWindowState actually modifies the
// window's state, we modify the state here. checkState will fail if
// this change isn't overwritten by setWindowState.
history.replaceState({should_be_overwritten:true}, "title-overwritten");
// Restore the state into a new tab. Things don't work well when we
// restore into the old tab, but that's not a real use case anyway.
let tab2 = gBrowser.addTab("about:blank");
ss.setTabState(tab2, state, true);
// Restore the state and make sure it looks right, after giving the event
// loop a chance to flush.
ss.setTabState(tab, state, true);
executeSoon(function() { checkState(tab); });
// Run checkState() once the tab finishes loading its restored state.
tab2.linkedBrowser.addEventListener("load", function() {
tab2.linkedBrowser.removeEventListener("load", arguments.callee, true);
SimpleTest.executeSoon(function() {
checkState(tab2);
});
}, true);
}, true);
}, true);

Просмотреть файл

@ -61,7 +61,6 @@ namespace std {
}
namespace std __attribute__((visibility("default"))) {
#if (__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)
/* Hack to avoid GLIBCXX_3.4.14 symbol versions */
struct _List_node_base
@ -73,35 +72,61 @@ namespace std __attribute__((visibility("default"))) {
void transfer(_List_node_base * const __first,
_List_node_base * const __last) throw();
/* Hack to avoid GLIBCXX_3.4.15 symbol versions */
#if (__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)
static void swap(_List_node_base& __x, _List_node_base& __y) throw ();
};
namespace __detail {
struct _List_node_base
{
#endif
void _M_hook(_List_node_base * const __position) throw ();
void _M_unhook() throw ();
void _M_transfer(_List_node_base * const __first,
_List_node_base * const __last) throw();
#if (__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)
static void swap(_List_node_base& __x, _List_node_base& __y) throw ();
#endif
};
/* The functions actually have the same implementation */
void
_List_node_base::_M_hook(_List_node_base * const __position) throw ()
{
hook(__position);
((std::_List_node_base *)this)->hook((std::_List_node_base * const) __position);
}
void
_List_node_base::_M_unhook() throw ()
{
unhook();
((std::_List_node_base *)this)->unhook();
}
void
_List_node_base::_M_transfer(_List_node_base * const __first,
_List_node_base * const __last) throw ()
{
transfer(__first, __last);
((std::_List_node_base *)this)->transfer((std::_List_node_base * const)__first,
(std::_List_node_base * const)__last);
}
#if (__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)
void
_List_node_base::swap(_List_node_base& __x, _List_node_base& __y) throw ()
{
std::_List_node_base::swap(*((std::_List_node_base *) &__x),
*((std::_List_node_base *) &__y));
}
}
#endif
#endif /* (__GNUC__ == 4) && (__GNUC_MINOR__ >= 5) */
#if (__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)
/* Hack to avoid GLIBCXX_3.4.11 symbol versions
An inline definition of ctype<char>::_M_widen_init() used to be in

Просмотреть файл

@ -707,6 +707,8 @@ ANDROID_PACKAGE_NAME = @ANDROID_PACKAGE_NAME@
JS_SHARED_LIBRARY = @JS_SHARED_LIBRARY@
MOZ_INSTRUMENT_EVENT_LOOP = @MOZ_INSTRUMENT_EVENT_LOOP@
# We only want to do the pymake sanity on Windows, other os's can cope
ifeq ($(HOST_OS_ARCH),WINNT)
# Ensure invariants between GNU Make and pymake

Просмотреть файл

@ -82,11 +82,7 @@ else
ELOG :=
endif
ifeq ($(OS_ARCH),WINNT)
_VPATH_SRCS = $(abspath $<)
else
_VPATH_SRCS = $<
endif
# Add $(DIST)/lib to VPATH so that -lfoo dependencies are followed
VPATH += $(DIST)/lib

Просмотреть файл

@ -2456,7 +2456,11 @@ ia64*-hpux*)
;;
*-openbsd*)
DLL_SUFFIX='.so.$(if $(SO_VERSION),$(SO_VERSION),1.0)'
if test "$SO_VERSION"; then
DLL_SUFFIX=".so.$SO_VERSION"
else
DLL_SUFFIX=".so.1.0"
fi
MOZ_FIX_LINK_PATHS='-Wl,-rpath-link,$(LIBXUL_DIST)/bin -Wl,-rpath-link,$(prefix)/lib -Wl,-rpath-link,$(if $(X11BASE),$(X11BASE),/usr/X11R6)/lib'
DSO_CFLAGS=''
DSO_PIC_CFLAGS='-fPIC'
@ -5019,6 +5023,7 @@ cairo-windows)
MOZ_WIDGET_TOOLKIT=windows
MOZ_WEBGL=1
MOZ_PDF_PRINTING=1
MOZ_INSTRUMENT_EVENT_LOOP=1
;;
cairo-gtk2|cairo-gtk2-x11)
@ -5036,6 +5041,7 @@ cairo-gtk2|cairo-gtk2-x11)
TK_LIBS='$(MOZ_GTK2_LIBS)'
AC_DEFINE(MOZ_WIDGET_GTK2)
MOZ_PDF_PRINTING=1
MOZ_INSTRUMENT_EVENT_LOOP=1
;;
cairo-gtk2-dfb)
@ -5095,6 +5101,7 @@ cairo-cocoa)
LIBXUL_LIBS='$(XPCOM_FROZEN_LDOPTS) $(LIBXUL_DIST)/bin/XUL'
MOZ_FS_LAYOUT=bundle
MOZ_WEBGL=1
MOZ_INSTRUMENT_EVENT_LOOP=1
;;
cairo-android)
@ -5118,6 +5125,10 @@ if test "$MOZ_ENABLE_XREMOTE"; then
AC_DEFINE(MOZ_ENABLE_XREMOTE)
fi
if test "$MOZ_INSTRUMENT_EVENT_LOOP"; then
AC_DEFINE(MOZ_INSTRUMENT_EVENT_LOOP)
fi
if test "$COMPILE_ENVIRONMENT"; then
if test "$MOZ_ENABLE_GTK2"; then
if test "$MOZ_X11"; then
@ -8988,6 +8999,7 @@ AC_SUBST(VPX_AS_CONVERSION)
AC_SUBST(VPX_ASM_SUFFIX)
AC_SUBST(VPX_X86_ASM)
AC_SUBST(VPX_ARM_ASM)
AC_SUBST(MOZ_INSTRUMENT_EVENT_LOOP)
AC_SUBST(LIBJPEG_TURBO_AS)
AC_SUBST(LIBJPEG_TURBO_ASFLAGS)
AC_SUBST(LIBJPEG_TURBO_X86_ASM)

Просмотреть файл

@ -1414,6 +1414,14 @@ public:
*/
static PRBool URIIsLocalFile(nsIURI *aURI);
/**
* Given a URI, return set beforeHash to the part before the '#', and
* afterHash to the remainder of the URI, including the '#'.
*/
static nsresult SplitURIAtHash(nsIURI *aURI,
nsACString &aBeforeHash,
nsACString &aAfterHash);
/**
* Get the application manifest URI for this document. The manifest URI
* is specified in the manifest= attribute of the root element of the

Просмотреть файл

@ -5012,6 +5012,32 @@ nsContentUtils::URIIsLocalFile(nsIURI *aURI)
isFile;
}
nsresult
nsContentUtils::SplitURIAtHash(nsIURI *aURI,
nsACString &aBeforeHash,
nsACString &aAfterHash)
{
// See bug 225910 for why we can't do this using nsIURL.
aBeforeHash.Truncate();
aAfterHash.Truncate();
NS_ENSURE_ARG_POINTER(aURI);
nsCAutoString spec;
nsresult rv = aURI->GetSpec(spec);
NS_ENSURE_SUCCESS(rv, rv);
PRInt32 index = spec.FindChar('#');
if (index == -1) {
index = spec.Length();
}
aBeforeHash.Assign(Substring(spec, 0, index));
aAfterHash.Assign(Substring(spec, index));
return NS_OK;
}
/* static */
nsIScriptContext*
nsContentUtils::GetContextForEventHandlers(nsINode* aNode,

Просмотреть файл

@ -42,7 +42,7 @@ function testCancelInPhase4() {
testCancelBeforePhase4();
}, false);
xhr2.open("GET", url, false); // note : synch-request
xhr2.open("GET", url);
xhr2.setRequestHeader("X-Request", "1", false);
try { xhr2.send(); }
@ -87,7 +87,7 @@ function testCancelBeforePhase4() {
SimpleTest.finish();
}, false);
xhr2.open("GET", url, false); // note : synch-request
xhr2.open("GET", url);
xhr2.setRequestHeader("X-Request", "1", false);
try { xhr2.send(); }

Просмотреть файл

@ -85,6 +85,7 @@ CPPSRCS = \
nsDOMScrollAreaEvent.cpp \
nsDOMTransitionEvent.cpp \
nsDOMPopStateEvent.cpp \
nsDOMHashChangeEvent.cpp \
nsDOMCloseEvent.cpp \
$(NULL)

Просмотреть файл

@ -0,0 +1,89 @@
/* -*- 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.org code.
*
* The Initial Developer of the Original Code is the Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* 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 "nsDOMHashChangeEvent.h"
#include "nsContentUtils.h"
NS_IMPL_ADDREF_INHERITED(nsDOMHashChangeEvent, nsDOMEvent)
NS_IMPL_RELEASE_INHERITED(nsDOMHashChangeEvent, nsDOMEvent)
DOMCI_DATA(HashChangeEvent, nsDOMHashChangeEvent)
NS_INTERFACE_MAP_BEGIN(nsDOMHashChangeEvent)
NS_INTERFACE_MAP_ENTRY(nsIDOMHashChangeEvent)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(HashChangeEvent)
NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent)
nsDOMHashChangeEvent::~nsDOMHashChangeEvent()
{
}
NS_IMETHODIMP
nsDOMHashChangeEvent::GetOldURL(nsAString &aURL)
{
aURL.Assign(mOldURL);
return NS_OK;
}
NS_IMETHODIMP
nsDOMHashChangeEvent::GetNewURL(nsAString &aURL)
{
aURL.Assign(mNewURL);
return NS_OK;
}
NS_IMETHODIMP
nsDOMHashChangeEvent::InitHashChangeEvent(const nsAString &aTypeArg,
PRBool aCanBubbleArg,
PRBool aCancelableArg,
const nsAString &aOldURL,
const nsAString &aNewURL)
{
nsresult rv = nsDOMEvent::InitEvent(aTypeArg, aCanBubbleArg, aCancelableArg);
NS_ENSURE_SUCCESS(rv, rv);
mOldURL.Assign(aOldURL);
mNewURL.Assign(aNewURL);
return NS_OK;
}
nsresult NS_NewDOMHashChangeEvent(nsIDOMEvent** aInstancePtrResult,
nsPresContext* aPresContext,
nsEvent* aEvent)
{
nsDOMHashChangeEvent* event =
new nsDOMHashChangeEvent(aPresContext, aEvent);
return CallQueryInterface(event, aInstancePtrResult);
}

Просмотреть файл

@ -0,0 +1,70 @@
/* -*- 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.org code.
*
* The Initial Developer of the Original Code is the Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* 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 nsDOMHashChangeEvent_h__
#define nsDOMHashChangeEvent_h__
class nsEvent;
#include "nsIDOMHashChangeEvent.h"
#include "nsDOMEvent.h"
#include "nsIVariant.h"
#include "nsCycleCollectionParticipant.h"
class nsDOMHashChangeEvent : public nsDOMEvent,
public nsIDOMHashChangeEvent
{
public:
nsDOMHashChangeEvent(nsPresContext* aPresContext, nsEvent* aEvent)
: nsDOMEvent(aPresContext, aEvent)
{
}
virtual ~nsDOMHashChangeEvent();
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIDOMHASHCHANGEEVENT
NS_FORWARD_TO_NSDOMEVENT
protected:
nsString mOldURL;
nsString mNewURL;
};
nsresult NS_NewDOMHashChangeEvent(nsIDOMEvent** aInstancePtrResult,
nsPresContext* aPresContext,
nsEvent* aEvent);
#endif // nsDOMHashChangeEvent_h__

Просмотреть файл

@ -50,6 +50,7 @@
#include "nsINode.h"
#include "nsPIDOMWindow.h"
#include "nsDOMPopStateEvent.h"
#include "nsDOMHashChangeEvent.h"
#include "nsFrameLoader.h"
#define NS_TARGET_CHAIN_FORCE_CONTENT_DISPATCH (1 << 0)
@ -871,6 +872,8 @@ nsEventDispatcher::CreateEvent(nsPresContext* aPresContext,
return NS_NewDOMAudioAvailableEvent(aDOMEvent, aPresContext, nsnull);
if (aEventType.LowerCaseEqualsLiteral("closeevent"))
return NS_NewDOMCloseEvent(aDOMEvent, aPresContext, nsnull);
if (aEventType.LowerCaseEqualsLiteral("hashchangeevent"))
return NS_NewDOMHashChangeEvent(aDOMEvent, aPresContext, nsnull);
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
}

Просмотреть файл

@ -237,6 +237,50 @@ SVGPathData::GetPathSegAtLength(float aDistance) const
return NS_MAX(0U, segIndex - 1); // -1 because while loop takes us 1 too far
}
/**
* The SVG spec says we have to paint stroke caps for zero length subpaths:
*
* http://www.w3.org/TR/SVG11/implnote.html#PathElementImplementationNotes
*
* Cairo only does this for |stroke-linecap: round| and not for
* |stroke-linecap: square| (since that's what Adobe Acrobat has always done).
*
* To help us conform to the SVG spec we have this helper function to draw an
* approximation of square caps for zero length subpaths. It does this by
* inserting a subpath containing a single axis aligned straight line that is
* as small as it can be without cairo throwing it away for being too small to
* affect rendering. Cairo will then draw stroke caps for this axis aligned
* line, creating an axis aligned rectangle (approximating the square that
* would ideally be drawn).
*
* Note that this function inserts a subpath into the current gfx path that
* will be present during both fill and stroke operations.
*/
static void
ApproximateZeroLengthSubpathSquareCaps(const gfxPoint &aPoint, gfxContext *aCtx)
{
// Cairo's fixed point fractional part is 8 bits wide, so its device space
// coordinate granularity is 1/256 pixels. However, to prevent user space
// |aPoint| and |aPoint + tinyAdvance| being rounded to the same device
// coordinates, we double this for |tinyAdvance|:
const gfxSize tinyAdvance = aCtx->DeviceToUser(gfxSize(2.0/256.0, 0.0));
aCtx->MoveTo(aPoint);
aCtx->LineTo(aPoint + gfxPoint(tinyAdvance.width, tinyAdvance.height));
aCtx->MoveTo(aPoint);
}
#define MAYBE_APPROXIMATE_ZERO_LENGTH_SUBPATH_SQUARE_CAPS \
do { \
if (capsAreSquare && !subpathHasLength && subpathContainsNonArc && \
SVGPathSegUtils::IsValidType(prevSegType) && \
(!IsMoveto(prevSegType) || \
segType == nsIDOMSVGPathSeg::PATHSEG_CLOSEPATH)) { \
ApproximateZeroLengthSubpathSquareCaps(segStart, aCtx); \
} \
} while(0)
void
SVGPathData::ConstructPath(gfxContext *aCtx) const
{
@ -244,9 +288,14 @@ SVGPathData::ConstructPath(gfxContext *aCtx) const
return; // paths without an initial moveto are invalid
}
PRBool capsAreSquare = aCtx->CurrentLineCap() == gfxContext::LINE_CAP_SQUARE;
PRBool subpathHasLength = PR_FALSE; // visual length
PRBool subpathContainsNonArc = PR_FALSE;
PRUint32 segType, prevSegType = nsIDOMSVGPathSeg::PATHSEG_UNKNOWN;
gfxPoint pathStart(0.0, 0.0); // start point of [sub]path
gfxPoint segEnd(0.0, 0.0); // end point of previous/current segment
gfxPoint segStart(0.0, 0.0);
gfxPoint segEnd;
gfxPoint cp1, cp2; // previous bezier's control points
gfxPoint tcp1, tcp2; // temporaries
@ -257,36 +306,50 @@ SVGPathData::ConstructPath(gfxContext *aCtx) const
PRUint32 i = 0;
while (i < mData.Length()) {
segType = SVGPathSegUtils::DecodeType(mData[i++]);
PRUint32 argCount = SVGPathSegUtils::ArgCountForType(segType);
switch (segType)
{
case nsIDOMSVGPathSeg::PATHSEG_CLOSEPATH:
// set this early to allow drawing of square caps for "M{x},{y} Z":
subpathContainsNonArc = PR_TRUE;
MAYBE_APPROXIMATE_ZERO_LENGTH_SUBPATH_SQUARE_CAPS;
segEnd = pathStart;
aCtx->ClosePath();
break;
case nsIDOMSVGPathSeg::PATHSEG_MOVETO_ABS:
MAYBE_APPROXIMATE_ZERO_LENGTH_SUBPATH_SQUARE_CAPS;
pathStart = segEnd = gfxPoint(mData[i], mData[i+1]);
aCtx->MoveTo(segEnd);
i += 2;
subpathHasLength = PR_FALSE;
subpathContainsNonArc = PR_FALSE;
break;
case nsIDOMSVGPathSeg::PATHSEG_MOVETO_REL:
pathStart = segEnd += gfxPoint(mData[i], mData[i+1]);
MAYBE_APPROXIMATE_ZERO_LENGTH_SUBPATH_SQUARE_CAPS;
pathStart = segEnd = segStart + gfxPoint(mData[i], mData[i+1]);
aCtx->MoveTo(segEnd);
i += 2;
subpathHasLength = PR_FALSE;
subpathContainsNonArc = PR_FALSE;
break;
case nsIDOMSVGPathSeg::PATHSEG_LINETO_ABS:
segEnd = gfxPoint(mData[i], mData[i+1]);
aCtx->LineTo(segEnd);
i += 2;
if (!subpathHasLength) {
subpathHasLength = (segEnd != segStart);
}
subpathContainsNonArc = PR_TRUE;
break;
case nsIDOMSVGPathSeg::PATHSEG_LINETO_REL:
segEnd += gfxPoint(mData[i], mData[i+1]);
segEnd = segStart + gfxPoint(mData[i], mData[i+1]);
aCtx->LineTo(segEnd);
i += 2;
if (!subpathHasLength) {
subpathHasLength = (segEnd != segStart);
}
subpathContainsNonArc = PR_TRUE;
break;
case nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_ABS:
@ -294,126 +357,170 @@ SVGPathData::ConstructPath(gfxContext *aCtx) const
cp2 = gfxPoint(mData[i+2], mData[i+3]);
segEnd = gfxPoint(mData[i+4], mData[i+5]);
aCtx->CurveTo(cp1, cp2, segEnd);
i += 6;
if (!subpathHasLength) {
subpathHasLength = (segEnd != segStart || segEnd != cp1 || segEnd != cp2);
}
subpathContainsNonArc = PR_TRUE;
break;
case nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_REL:
cp1 = segEnd + gfxPoint(mData[i], mData[i+1]);
cp2 = segEnd + gfxPoint(mData[i+2], mData[i+3]);
segEnd += gfxPoint(mData[i+4], mData[i+5]);
cp1 = segStart + gfxPoint(mData[i], mData[i+1]);
cp2 = segStart + gfxPoint(mData[i+2], mData[i+3]);
segEnd = segStart + gfxPoint(mData[i+4], mData[i+5]);
aCtx->CurveTo(cp1, cp2, segEnd);
i += 6;
if (!subpathHasLength) {
subpathHasLength = (segEnd != segStart || segEnd != cp1 || segEnd != cp2);
}
subpathContainsNonArc = PR_TRUE;
break;
case nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_ABS:
cp1 = gfxPoint(mData[i], mData[i+1]);
// Convert quadratic curve to cubic curve:
tcp1 = segEnd + (cp1 - segEnd) * 2 / 3;
segEnd = gfxPoint(mData[i+2], mData[i+3]); // changed before setting tcp2!
tcp1 = segStart + (cp1 - segStart) * 2 / 3;
segEnd = gfxPoint(mData[i+2], mData[i+3]); // set before setting tcp2!
tcp2 = cp1 + (segEnd - cp1) / 3;
aCtx->CurveTo(tcp1, tcp2, segEnd);
i += 4;
if (!subpathHasLength) {
subpathHasLength = (segEnd != segStart || segEnd != cp1);
}
subpathContainsNonArc = PR_TRUE;
break;
case nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_REL:
cp1 = segEnd + gfxPoint(mData[i], mData[i+1]);
cp1 = segStart + gfxPoint(mData[i], mData[i+1]);
// Convert quadratic curve to cubic curve:
tcp1 = segEnd + (cp1 - segEnd) * 2 / 3;
segEnd += gfxPoint(mData[i+2], mData[i+3]); // changed before setting tcp2!
tcp1 = segStart + (cp1 - segStart) * 2 / 3;
segEnd = segStart + gfxPoint(mData[i+2], mData[i+3]); // set before setting tcp2!
tcp2 = cp1 + (segEnd - cp1) / 3;
aCtx->CurveTo(tcp1, tcp2, segEnd);
i += 4;
if (!subpathHasLength) {
subpathHasLength = (segEnd != segStart || segEnd != cp1);
}
subpathContainsNonArc = PR_TRUE;
break;
case nsIDOMSVGPathSeg::PATHSEG_ARC_ABS:
case nsIDOMSVGPathSeg::PATHSEG_ARC_REL:
{
gfxPoint radii(mData[i], mData[i+1]);
gfxPoint start = segEnd;
gfxPoint end = gfxPoint(mData[i+5], mData[i+6]);
gfxPoint segEnd = gfxPoint(mData[i+5], mData[i+6]);
if (segType == nsIDOMSVGPathSeg::PATHSEG_ARC_REL) {
end += start;
segEnd += segStart;
}
segEnd = end;
if (start != end) {
if (segEnd != segStart) {
if (radii.x == 0.0f || radii.y == 0.0f) {
aCtx->LineTo(end);
i += 7;
break;
}
nsSVGArcConverter converter(start, end, radii, mData[i+2],
aCtx->LineTo(segEnd);
} else {
nsSVGArcConverter converter(segStart, segEnd, radii, mData[i+2],
mData[i+3] != 0, mData[i+4] != 0);
while (converter.GetNextSegment(&cp1, &cp2, &end)) {
aCtx->CurveTo(cp1, cp2, end);
while (converter.GetNextSegment(&cp1, &cp2, &segEnd)) {
aCtx->CurveTo(cp1, cp2, segEnd);
}
}
i += 7;
}
if (!subpathHasLength) {
subpathHasLength = (segEnd != segStart);
}
break;
}
case nsIDOMSVGPathSeg::PATHSEG_LINETO_HORIZONTAL_ABS:
segEnd = gfxPoint(mData[i++], segEnd.y);
segEnd = gfxPoint(mData[i], segStart.y);
aCtx->LineTo(segEnd);
if (!subpathHasLength) {
subpathHasLength = (segEnd != segStart);
}
subpathContainsNonArc = PR_TRUE;
break;
case nsIDOMSVGPathSeg::PATHSEG_LINETO_HORIZONTAL_REL:
segEnd += gfxPoint(mData[i++], 0.0f);
segEnd = segStart + gfxPoint(mData[i], 0.0f);
aCtx->LineTo(segEnd);
if (!subpathHasLength) {
subpathHasLength = (segEnd != segStart);
}
subpathContainsNonArc = PR_TRUE;
break;
case nsIDOMSVGPathSeg::PATHSEG_LINETO_VERTICAL_ABS:
segEnd = gfxPoint(segEnd.x, mData[i++]);
segEnd = gfxPoint(segStart.x, mData[i]);
aCtx->LineTo(segEnd);
if (!subpathHasLength) {
subpathHasLength = (segEnd != segStart);
}
subpathContainsNonArc = PR_TRUE;
break;
case nsIDOMSVGPathSeg::PATHSEG_LINETO_VERTICAL_REL:
segEnd += gfxPoint(0.0f, mData[i++]);
segEnd = segStart + gfxPoint(0.0f, mData[i]);
aCtx->LineTo(segEnd);
if (!subpathHasLength) {
subpathHasLength = (segEnd != segStart);
}
subpathContainsNonArc = PR_TRUE;
break;
case nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_ABS:
cp1 = SVGPathSegUtils::IsCubicType(prevSegType) ? segEnd * 2 - cp2 : segEnd;
cp1 = SVGPathSegUtils::IsCubicType(prevSegType) ? segStart * 2 - cp2 : segStart;
cp2 = gfxPoint(mData[i], mData[i+1]);
segEnd = gfxPoint(mData[i+2], mData[i+3]);
aCtx->CurveTo(cp1, cp2, segEnd);
i += 4;
if (!subpathHasLength) {
subpathHasLength = (segEnd != segStart || segEnd != cp1 || segEnd != cp2);
}
subpathContainsNonArc = PR_TRUE;
break;
case nsIDOMSVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_REL:
cp1 = SVGPathSegUtils::IsCubicType(prevSegType) ? segEnd * 2 - cp2 : segEnd;
cp2 = segEnd + gfxPoint(mData[i], mData[i+1]);
segEnd += gfxPoint(mData[i+2], mData[i+3]);
cp1 = SVGPathSegUtils::IsCubicType(prevSegType) ? segStart * 2 - cp2 : segStart;
cp2 = segStart + gfxPoint(mData[i], mData[i+1]);
segEnd = segStart + gfxPoint(mData[i+2], mData[i+3]);
aCtx->CurveTo(cp1, cp2, segEnd);
i += 4;
if (!subpathHasLength) {
subpathHasLength = (segEnd != segStart || segEnd != cp1 || segEnd != cp2);
}
subpathContainsNonArc = PR_TRUE;
break;
case nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS:
cp1 = SVGPathSegUtils::IsQuadraticType(prevSegType) ? segEnd * 2 - cp1 : segEnd;
cp1 = SVGPathSegUtils::IsQuadraticType(prevSegType) ? segStart * 2 - cp1 : segStart;
// Convert quadratic curve to cubic curve:
tcp1 = segEnd + (cp1 - segEnd) * 2 / 3;
segEnd = gfxPoint(mData[i], mData[i+1]); // changed before setting tcp2!
tcp1 = segStart + (cp1 - segStart) * 2 / 3;
segEnd = gfxPoint(mData[i], mData[i+1]); // set before setting tcp2!
tcp2 = cp1 + (segEnd - cp1) / 3;
aCtx->CurveTo(tcp1, tcp2, segEnd);
i += 2;
if (!subpathHasLength) {
subpathHasLength = (segEnd != segStart || segEnd != cp1);
}
subpathContainsNonArc = PR_TRUE;
break;
case nsIDOMSVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL:
cp1 = SVGPathSegUtils::IsQuadraticType(prevSegType) ? segEnd * 2 - cp1 : segEnd;
cp1 = SVGPathSegUtils::IsQuadraticType(prevSegType) ? segStart * 2 - cp1 : segStart;
// Convert quadratic curve to cubic curve:
tcp1 = segEnd + (cp1 - segEnd) * 2 / 3;
segEnd = segEnd + gfxPoint(mData[i], mData[i+1]); // changed before setting tcp2!
tcp1 = segStart + (cp1 - segStart) * 2 / 3;
segEnd = segStart + gfxPoint(mData[i], mData[i+1]); // changed before setting tcp2!
tcp2 = cp1 + (segEnd - cp1) / 3;
aCtx->CurveTo(tcp1, tcp2, segEnd);
i += 2;
if (!subpathHasLength) {
subpathHasLength = (segEnd != segStart || segEnd != cp1);
}
subpathContainsNonArc = PR_TRUE;
break;
default:
NS_NOTREACHED("Bad path segment type");
return; // according to spec we'd use everything up to the bad seg anyway
}
i += argCount;
prevSegType = segType;
segStart = segEnd;
}
NS_ABORT_IF_FALSE(i == mData.Length(), "Very, very bad - mData corrupt");
MAYBE_APPROXIMATE_ZERO_LENGTH_SUBPATH_SQUARE_CAPS;
}
already_AddRefed<gfxFlattenedPath>

Просмотреть файл

@ -79,6 +79,7 @@ _TEST_FILES = \
test_SVGAnimatedImageSMILDisabled.html \
animated-svg-image-helper.html \
animated-svg-image-helper.svg \
test_stroke-linecap-hit-testing.xhtml \
test_SVGLengthList.xhtml \
test_SVGLengthList-2.xhtml \
test_SVGPathSegList.xhtml \

Просмотреть файл

@ -0,0 +1,48 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=589648
-->
<head>
<title>Test hit-testing of line caps</title>
<script type="text/javascript" src="/MochiKit/packed.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body onload="run()">
<script class="testbody" type="text/javascript">
<![CDATA[
SimpleTest.waitForExplicitFinish();
function run()
{
var svg = document.getElementById('svg');
var div = document.getElementById("div");
var x = div.offsetLeft;
var y = div.offsetTop;
var got, expected;
got = document.elementFromPoint(5 + x, 5 + y);
expected = document.getElementById('zero-length-square-caps');
is(got, expected, 'Check hit on zero length subpath\'s square caps');
SimpleTest.finish();
}
]]>
</script>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=500174">Mozilla Bug 500174</a>
<p id="display"></p>
<div id="content">
<div width="100%" height="1" id="div"></div>
<svg xmlns="http://www.w3.org/2000/svg" id="svg" width="400" height="300">
<path id="zero-length-square-caps" stroke="blue" stroke-width="50"
stroke-linecap="square" d="M25,25 L25,25"/>
</svg>
</div>
<pre id="test">
</pre>
</body>
</html>

Просмотреть файл

@ -215,6 +215,7 @@
#endif
#include "nsPluginError.h"
#include "nsContentUtils.h"
static NS_DEFINE_CID(kDOMScriptObjectFactoryCID,
NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
@ -8216,25 +8217,36 @@ nsDocShell::InternalLoad(nsIURI * aURI,
(aFlags & INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) != 0;
mURIResultedInDocument = PR_FALSE; // reset the clock...
//
// First:
// Check to see if the new URI is an anchor in the existing document.
// Skip this check if we're doing some sort of abnormal load, if the
// new load is a non-history load and has postdata, or if we're doing
// a history load and the page identifiers of mOSHE and aSHEntry
// don't match.
//
PRBool allowScroll = PR_TRUE;
if (!aSHEntry) {
allowScroll = (aPostData == nsnull);
} else if (mOSHE) {
PRUint32 ourPageIdent;
mOSHE->GetPageIdentifier(&ourPageIdent);
PRUint32 otherPageIdent;
aSHEntry->GetPageIdentifier(&otherPageIdent);
allowScroll = (ourPageIdent == otherPageIdent);
if (aLoadType == LOAD_NORMAL ||
aLoadType == LOAD_STOP_CONTENT ||
LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_REPLACE_HISTORY) ||
aLoadType == LOAD_HISTORY ||
aLoadType == LOAD_LINK) {
// Split mCurrentURI and aURI on the '#' character. Make sure we read
// the return values of SplitURIAtHash; it might fail because
// mCurrentURI is null, for instance, and we don't want to allow a
// short-circuited navigation in that case.
nsCAutoString curBeforeHash, curHash, newBeforeHash, newHash;
nsresult splitRv1, splitRv2;
splitRv1 = nsContentUtils::SplitURIAtHash(mCurrentURI, curBeforeHash, curHash);
splitRv2 = nsContentUtils::SplitURIAtHash(aURI, newBeforeHash, newHash);
PRBool sameExceptHashes = NS_SUCCEEDED(splitRv1) &&
NS_SUCCEEDED(splitRv2) &&
curBeforeHash.Equals(newBeforeHash);
PRBool sameDocIdent = PR_FALSE;
if (mOSHE && aSHEntry) {
// We're doing a history load.
PRUint64 ourDocIdent, otherDocIdent;
mOSHE->GetDocIdentifier(&ourDocIdent);
aSHEntry->GetDocIdentifier(&otherDocIdent);
sameDocIdent = (ourDocIdent == otherDocIdent);
#ifdef DEBUG
if (allowScroll) {
if (sameDocIdent) {
nsCOMPtr<nsIInputStream> currentPostData;
mOSHE->GetPostData(getter_AddRefs(currentPostData));
NS_ASSERTION(currentPostData == aPostData,
@ -8243,46 +8255,49 @@ nsDocShell::InternalLoad(nsIURI * aURI,
#endif
}
if (aLoadType == LOAD_NORMAL ||
aLoadType == LOAD_STOP_CONTENT ||
LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_REPLACE_HISTORY) ||
aLoadType == LOAD_HISTORY ||
aLoadType == LOAD_LINK) {
// A short-circuited load happens when we navigate between two SHEntries
// for the same document. We do a short-circuited load under two
// circumstances. Either
//
// a) we're navigating between two different SHEntries which have the
// same document identifiers, or
//
// b) we're navigating to a new shentry whose URI differs from the
// current URI only in its hash, the new hash is non-empty, and
// we're not doing a POST.
//
// The restriction tha the SHEntries in (a) must be different ensures
// that history.go(0) and the like trigger full refreshes, rather than
// short-circuited loads.
PRBool doShortCircuitedLoad = (sameDocIdent && mOSHE != aSHEntry) ||
(!aSHEntry && aPostData == nsnull &&
sameExceptHashes && !newHash.IsEmpty());
PRBool wasAnchor = PR_FALSE;
PRBool doHashchange = PR_FALSE;
// Fire a hashchange event if we're doing a short-circuited load and the
// URIs differ only in their hashes.
PRBool doHashchange = doShortCircuitedLoad &&
sameExceptHashes &&
!curHash.Equals(newHash);
// Get the position of the scrollers.
if (doShortCircuitedLoad) {
// Save the current URI; we need it if we fire a hashchange later.
nsCOMPtr<nsIURI> oldURI = mCurrentURI;
// Save the position of the scrollers.
nscoord cx = 0, cy = 0;
GetCurScrollPos(ScrollOrientation_X, &cx);
GetCurScrollPos(ScrollOrientation_Y, &cy);
if (allowScroll) {
NS_ENSURE_SUCCESS(ScrollIfAnchor(aURI, &wasAnchor, aLoadType,
&doHashchange),
NS_ERROR_FAILURE);
// We scroll the window precisely when we fire a hashchange event.
if (doHashchange) {
// Take the '#' off the hashes before passing them to
// ScrollToAnchor.
nsDependentCSubstring curHashName(curHash, 1);
nsDependentCSubstring newHashName(newHash, 1);
rv = ScrollToAnchor(curHashName, newHashName, aLoadType);
NS_ENSURE_SUCCESS(rv, rv);
}
// If this is a history load, aSHEntry will have document identifier X
// if it was created as a result of a History.pushState() from a
// SHEntry with doc ident X, or if it was created by changing the hash
// of the URI corresponding to a SHEntry with doc ident X.
PRBool sameDocIdent = PR_FALSE;
if (mOSHE && aSHEntry) {
PRUint64 ourDocIdent, otherDocIdent;
mOSHE->GetDocIdentifier(&ourDocIdent);
aSHEntry->GetDocIdentifier(&otherDocIdent);
sameDocIdent = (ourDocIdent == otherDocIdent);
}
// Do a short-circuited load if the new URI differs from the current
// URI only in the hash, or if the two entries belong to the same
// document and don't point to the same object.
//
// (If we didn't check that the SHEntries are different objects,
// history.go(0) would short-circuit instead of triggering a true
// load, and we wouldn't dispatch an onload event to the page.)
if (wasAnchor || (sameDocIdent && (mOSHE != aSHEntry))) {
mLoadType = aLoadType;
mURIResultedInDocument = PR_TRUE;
@ -8307,7 +8322,7 @@ nsDocShell::InternalLoad(nsIURI * aURI,
OnNewURI(aURI, nsnull, owner, mLoadType, PR_TRUE, PR_TRUE, PR_TRUE);
nsCOMPtr<nsIInputStream> postData;
PRUint32 pageIdent = PR_UINT32_MAX;
PRUint64 docIdent = PRUint64(-1);
nsCOMPtr<nsISupports> cacheKey;
if (mOSHE) {
@ -8321,20 +8336,9 @@ nsDocShell::InternalLoad(nsIURI * aURI,
// wouldn't want here.
if (aLoadType & LOAD_CMD_NORMAL) {
mOSHE->GetPostData(getter_AddRefs(postData));
mOSHE->GetPageIdentifier(&pageIdent);
mOSHE->GetDocIdentifier(&docIdent);
mOSHE->GetCacheKey(getter_AddRefs(cacheKey));
}
if (mLSHE && wasAnchor) {
// If it's an anchor load, set mLSHE's doc identifier to
// mOSHE's doc identifier -- These are the same documents,
// as far as HTML5 is concerned.
PRUint64 docIdent;
rv = mOSHE->GetDocIdentifier(&docIdent);
if (NS_SUCCEEDED(rv)) {
mLSHE->SetDocIdentifier(docIdent);
}
}
}
/* Assign mOSHE to mLSHE. This will either be a new entry created
@ -8354,10 +8358,10 @@ nsDocShell::InternalLoad(nsIURI * aURI,
if (cacheKey)
mOSHE->SetCacheKey(cacheKey);
// Propagate our page ident to the new mOSHE so that
// we'll know it just differed by a scroll on the page.
if (pageIdent != PR_UINT32_MAX)
mOSHE->SetPageIdentifier(pageIdent);
// Propagate our document identifier to the new mOSHE so that
// we'll know it's related by an anchor navigation or pushState.
if (docIdent != PRUint64(-1))
mOSHE->SetDocIdentifier(docIdent);
}
/* restore previous position of scroller(s), if we're moving
@ -8425,8 +8429,11 @@ nsDocShell::InternalLoad(nsIURI * aURI,
window->DispatchSyncPopState();
}
if (doHashchange)
window->DispatchAsyncHashchange();
if (doHashchange) {
// Make sure to use oldURI here, not mCurrentURI, because by
// now, mCurrentURI has changed!
window->DispatchAsyncHashchange(oldURI, aURI);
}
}
return NS_OK;
@ -9052,20 +9059,9 @@ nsresult nsDocShell::DoChannelLoad(nsIChannel * aChannel,
}
nsresult
nsDocShell::ScrollIfAnchor(nsIURI * aURI, PRBool * aWasAnchor,
PRUint32 aLoadType, PRBool * aDoHashchange)
nsDocShell::ScrollToAnchor(nsACString & aCurHash, nsACString & aNewHash,
PRUint32 aLoadType)
{
NS_ASSERTION(aURI, "null uri arg");
NS_ASSERTION(aWasAnchor, "null anchor arg");
NS_PRECONDITION(aDoHashchange, "null hashchange arg");
if (!aURI || !aWasAnchor) {
return NS_ERROR_FAILURE;
}
*aWasAnchor = PR_FALSE;
*aDoHashchange = PR_FALSE;
if (!mCurrentURI) {
return NS_OK;
}
@ -9075,116 +9071,28 @@ nsDocShell::ScrollIfAnchor(nsIURI * aURI, PRBool * aWasAnchor,
if (NS_FAILED(rv) || !shell) {
// If we failed to get the shell, or if there is no shell,
// nothing left to do here.
return rv;
}
// NOTE: we assume URIs are absolute for comparison purposes
nsCAutoString currentSpec;
NS_ENSURE_SUCCESS(mCurrentURI->GetSpec(currentSpec),
NS_ERROR_FAILURE);
nsCAutoString newSpec;
NS_ENSURE_SUCCESS(aURI->GetSpec(newSpec), NS_ERROR_FAILURE);
// Search for hash marks in the current URI and the new URI and
// take a copy of everything to the left of the hash for
// comparison.
const char kHash = '#';
// Split the new URI into a left and right part
// (assume we're parsing it out right)
nsACString::const_iterator urlStart, urlEnd, refStart, refEnd;
newSpec.BeginReading(urlStart);
newSpec.EndReading(refEnd);
PRInt32 hashNew = newSpec.FindChar(kHash);
if (hashNew == 0) {
return NS_OK; // Strange URI
}
if (hashNew > 0) {
// found it
urlEnd = urlStart;
urlEnd.advance(hashNew);
refStart = urlEnd;
++refStart; // advanced past '#'
}
else {
// no hash at all
urlEnd = refStart = refEnd;
}
const nsACString& sNewLeft = Substring(urlStart, urlEnd);
const nsACString& sNewRef = Substring(refStart, refEnd);
// Split the current URI in a left and right part
nsACString::const_iterator currentLeftStart, currentLeftEnd,
currentRefStart, currentRefEnd;
currentSpec.BeginReading(currentLeftStart);
currentSpec.EndReading(currentRefEnd);
PRInt32 hashCurrent = currentSpec.FindChar(kHash);
if (hashCurrent == 0) {
return NS_OK; // Strange URI
}
if (hashCurrent > 0) {
currentLeftEnd = currentLeftStart;
currentLeftEnd.advance(hashCurrent);
currentRefStart = currentLeftEnd;
++currentRefStart; // advance past '#'
}
else {
// no hash at all in currentSpec
currentLeftEnd = currentRefStart = currentRefEnd;
}
// If we have no new anchor, we do not want to scroll, unless there is a
// current anchor and we are doing a history load. So return if we have no
// new anchor, and there is no current anchor or the load is not a history
// load.
NS_ASSERTION(hashNew != 0 && hashCurrent != 0,
"What happened to the early returns above?");
if (hashNew == kNotFound &&
(hashCurrent == kNotFound || aLoadType != LOAD_HISTORY)) {
if ((aCurHash.IsEmpty() || aLoadType != LOAD_HISTORY) &&
aNewHash.IsEmpty()) {
return NS_OK;
}
// Compare the URIs.
//
// NOTE: this is a case sensitive comparison because some parts of the
// URI are case sensitive, and some are not. i.e. the domain name
// is case insensitive but the the paths are not.
//
// This means that comparing "http://www.ABC.com/" to "http://www.abc.com/"
// will fail this test.
if (!Substring(currentLeftStart, currentLeftEnd).Equals(sNewLeft)) {
return NS_OK; // URIs not the same
}
// Now we know we are dealing with an anchor
*aWasAnchor = PR_TRUE;
// We should fire a hashchange event once we're done here if the two hashes
// are different.
*aDoHashchange = !Substring(currentRefStart, currentRefEnd).Equals(sNewRef);
// Both the new and current URIs refer to the same page. We can now
// browse to the hash stored in the new URI.
if (!sNewRef.IsEmpty()) {
if (!aNewHash.IsEmpty()) {
// anchor is there, but if it's a load from history,
// we don't have any anchor jumping to do
PRBool scroll = aLoadType != LOAD_HISTORY &&
aLoadType != LOAD_RELOAD_NORMAL;
char *str = ToNewCString(sNewRef);
char *str = ToNewCString(aNewHash);
if (!str) {
return NS_ERROR_OUT_OF_MEMORY;
}
@ -9226,7 +9134,7 @@ nsDocShell::ScrollIfAnchor(nsIURI * aURI, PRBool * aWasAnchor,
nsXPIDLString uStr;
rv = textToSubURI->UnEscapeAndConvert(PromiseFlatCString(aCharset).get(),
PromiseFlatCString(sNewRef).get(),
PromiseFlatCString(aNewHash).get(),
getter_Copies(uStr));
NS_ENSURE_SUCCESS(rv, rv);

Просмотреть файл

@ -332,8 +332,8 @@ protected:
nsIURILoader * aURILoader,
PRBool aBypassClassifier);
nsresult ScrollIfAnchor(nsIURI * aURI, PRBool * aWasAnchor,
PRUint32 aLoadType, PRBool * aDoHashchange);
nsresult ScrollToAnchor(nsACString & curHash, nsACString & newHash,
PRUint32 aLoadType);
// Tries to stringify a given variant by converting it to JSON. This only
// works if the variant is backed by a JSVal.

Просмотреть файл

@ -58,7 +58,7 @@ class nsDocShellEditorData;
[ptr] native nsDocShellEditorDataPtr(nsDocShellEditorData);
[scriptable, uuid(39b73c3a-48eb-4189-8069-247279c3c42d)]
[scriptable, uuid(5f3ebf43-6944-45fb-b1b1-78a05bf9370b)]
interface nsISHEntry : nsIHistoryEntry
{
/** URI for the document */
@ -139,22 +139,12 @@ interface nsISHEntry : nsIHistoryEntry
*/
attribute unsigned long ID;
/**
* pageIdentifier is an integer that should be the same for two entries
* attached to the same docshell only if the two entries are entries for
* the same page in the sense that one could go from the state represented
* by one to the state represented by the other simply by scrolling (so the
* entries are separated by an anchor traversal or a subframe navigation in
* some other frame).
*/
attribute unsigned long pageIdentifier;
/**
* docIdentifier is an integer that should be the same for two entries
* attached to the same docshell if and only if the two entries are entries
* for the same document. In practice, two entries A and B will have the
* same docIdentifier if they have the same pageIdentifier or if B was
* created by A calling history.pushState().
* same docIdentifier if we arrived at B by clicking an anchor link in A or
* if B was created by A's calling history.pushState().
*/
attribute unsigned long long docIdentifier;

Просмотреть файл

@ -105,7 +105,6 @@ static void StopTrackingEntry(nsSHEntry *aEntry)
nsSHEntry::nsSHEntry()
: mLoadType(0)
, mID(gEntryID++)
, mPageIdentifier(mID)
, mDocIdentifier(gEntryDocIdentifier++)
, mScrollPositionX(0)
, mScrollPositionY(0)
@ -130,7 +129,6 @@ nsSHEntry::nsSHEntry(const nsSHEntry &other)
, mLayoutHistoryState(other.mLayoutHistoryState)
, mLoadType(0) // XXX why not copy?
, mID(other.mID)
, mPageIdentifier(other.mPageIdentifier)
, mDocIdentifier(other.mDocIdentifier)
, mScrollPositionX(0) // XXX why not copy?
, mScrollPositionY(0) // XXX why not copy?
@ -391,18 +389,6 @@ NS_IMETHODIMP nsSHEntry::SetID(PRUint32 aID)
return NS_OK;
}
NS_IMETHODIMP nsSHEntry::GetPageIdentifier(PRUint32 * aResult)
{
*aResult = mPageIdentifier;
return NS_OK;
}
NS_IMETHODIMP nsSHEntry::SetPageIdentifier(PRUint32 aPageIdentifier)
{
mPageIdentifier = aPageIdentifier;
return NS_OK;
}
NS_IMETHODIMP nsSHEntry::GetDocIdentifier(PRUint64 * aResult)
{
*aResult = mDocIdentifier;

Просмотреть файл

@ -99,7 +99,6 @@ private:
nsCOMArray<nsISHEntry> mChildren;
PRUint32 mLoadType;
PRUint32 mID;
PRUint32 mPageIdentifier;
PRInt64 mDocIdentifier;
PRInt32 mScrollPositionX;
PRInt32 mScrollPositionY;

Просмотреть файл

@ -97,6 +97,9 @@ _TEST_FILES = \
test_bug634834.html \
file_bug634834.html \
test_bug637644.html \
test_bug640387_1.html \
test_bug640387_2.html \
file_bug640387.html \
test_framedhistoryframes.html \
test_windowedhistoryframes.html \
historyframes.html \

Просмотреть файл

@ -0,0 +1,26 @@
<html>
<body onhashchange='hashchange()' onload='load()' onpopstate='popstate()'>
<script>
function hashchange() {
var f = (opener || parent).childHashchange;
if (f)
f();
}
function load() {
var f = (opener || parent).childLoad;
if (f)
f();
}
function popstate() {
var f = (opener || parent).childPopstate;
if (f)
f();
}
</script>
Not much to see here...
</body>
</html>

Просмотреть файл

@ -135,10 +135,6 @@ function run_test() {
yield;
eventExpected("Going forward should trigger a hashchange.");
frameCw.window.location.hash = "";
yield;
eventExpected("Changing window.location.hash should trigger a hashchange.");
// window.location has a trailing '#' right now, so we append "link1", not
// "#link1".
frameCw.window.location = frameCw.window.location + "link1";
@ -187,8 +183,8 @@ function run_test() {
"Event type should be 'hashchange'.");
is(gSampleEvent.cancelable, false,
"The hashchange event shouldn't be cancelable.");
is(gSampleEvent.bubbles, false,
"The hashchange event shouldn't bubble.");
is(gSampleEvent.bubbles, true,
"The hashchange event should bubble.");
/*
* TEST 3 tests that:

Просмотреть файл

@ -0,0 +1,110 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=640387
-->
<head>
<title>Test for Bug 640387</title>
<script type="application/javascript" src="/MochiKit/packed.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=640387">Mozilla Bug 640387</a>
<script type='application/javascript;version=1.7'>
SimpleTest.waitForExplicitFinish();
function test() {
/* Spin the event loop so we get out of the onload handler. */
SimpleTest.executeSoon(function() { gGen.next() });
yield;
popup.history.pushState('', '', '#hash1');
popup.history.pushState('', '', '#hash2');
// Now the history looks like:
// file_bug640387.html
// file_bug640387.html#hash1
// file_bug640387.html#hash2 <-- current
// Going back should trigger a hashchange, which will wake us up from the
// yield.
popup.history.back();
yield;
ok(true, 'Got first hashchange.');
// Going back should wake us up again.
popup.history.back();
yield;
ok(true, 'Got second hashchange.');
// Now the history looks like:
// file_bug640387.html <-- current
// file_bug640387.html#hash1
// file_bug640387.html#hash2
// Going forward should trigger a hashchange.
popup.history.forward();
yield;
ok(true, 'Got third hashchange.');
// Now modify the history so it looks like:
// file_bug640387.html
// file_bug640387.html#hash1
// file_bug640387.html#hash1 <-- current
popup.history.pushState('', '', '#hash1');
// Now when we go back, we should not get a hashchange. Instead, wait for a
// popstate. We need to asynchronously go back because popstate is fired
// sync.
gHashchangeExpected = false;
gCallbackOnPopstate = true;
SimpleTest.executeSoon(function() { popup.history.back() });
yield;
ok(true, 'Got popstate.');
gCallbackOnPopstate = false;
// Spin the event loop so hashchange has a chance to fire, if it's going to.
SimpleTest.executeSoon(function() { gGen.next() });
yield;
popup.close();
SimpleTest.finish();
yield;
}
gGen = null;
function childLoad() {
gGen = test();
gGen.next();
}
gHashchangeExpected = true;
function childHashchange() {
if (gHashchangeExpected) {
gGen.next();
}
else {
ok(false, "Got hashchange when we weren't expecting one.");
}
}
gCallbackOnPopstate = false;
function childPopstate() {
if (gCallbackOnPopstate) {
gGen.next();
}
}
/* We need to run this test in a popup, because navigating an iframe
* back/forwards tends to cause intermittent orange. */
popup = window.open('file_bug640387.html');
/* Control now flows up to childLoad(), called once the popup loads. */
</script>
</body>
</html>

Просмотреть файл

@ -0,0 +1,91 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=640387
-->
<head>
<title>Test for Bug 640387</title>
<script type="application/javascript" src="/MochiKit/packed.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=640387">Mozilla Bug 640387</a>
<!-- Test that, when going from
http://example.com/#foo
to
http://example.com/
via a non-history load, we do a true load, rather than a scroll. -->
<script type='application/javascript;version=1.7'>
SimpleTest.waitForExplicitFinish();
callbackOnLoad = false;
function childLoad() {
if (callbackOnLoad) {
callbackOnLoad = false;
gGen.next();
}
}
errorOnHashchange = false;
callbackOnHashchange = false;
function childHashchange() {
if (errorOnHashchange) {
ok(false, 'Got unexpected hashchange.');
}
if (callbackOnHashchange) {
callbackOnHashchange = false;
gGen.next();
}
}
function run_test() {
var iframe = $('iframe').contentWindow;
ok(true, 'Got first load');
// Spin the event loop so we exit the onload handler.
SimpleTest.executeSoon(function() { gGen.next() });
yield;
let origLocation = iframe.location + '';
callbackOnHashchange = true;
iframe.location.hash = '#1';
// Wait for a hashchange event.
yield;
ok(true, 'Got hashchange.');
iframe.location = origLocation;
// This should produce a load event and *not* a hashchange, because the
// result of the load is a different document than we had previously.
callbackOnLoad = true;
errorOnHashchange = true;
yield;
ok(true, 'Got final load.');
// Spin the event loop to give hashchange a chance to fire, if it's going to.
SimpleTest.executeSoon(function() { gGen.next() });
yield;
SimpleTest.finish();
yield;
}
callbackOnLoad = true;
gGen = run_test();
</script>
<iframe id='iframe' src='file_bug640387.html'></iframe>
</body>
</html>

Просмотреть файл

@ -87,6 +87,7 @@
#include "nsIDOMKeyEvent.h"
#include "nsIDOMEventListener.h"
#include "nsIDOMPopStateEvent.h"
#include "nsIDOMHashChangeEvent.h"
#include "nsContentUtils.h"
#include "nsDOMWindowUtils.h"
#include "nsIDOMGlobalPropertyInitializer.h"
@ -1440,6 +1441,8 @@ static nsDOMClassInfoData sClassInfoData[] = {
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(PopStateEvent, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(HashChangeEvent, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(EventListenerInfo, nsDOMGenericSH,
DOM_DEFAULT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(TransitionEvent, nsDOMGenericSH,
@ -2580,6 +2583,11 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_EVENT_MAP_ENTRIES
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(HashChangeEvent, nsIDOMHashChangeEvent)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMHashChangeEvent)
DOM_CLASSINFO_DOCUMENT_MAP_ENTRIES
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(HTMLDocument, nsIDOMHTMLDocument)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMHTMLDocument)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSHTMLDocument)

Просмотреть файл

@ -478,6 +478,7 @@ DOMCI_CLASS(PaintRequestList)
DOMCI_CLASS(ScrollAreaEvent)
DOMCI_CLASS(PopStateEvent)
DOMCI_CLASS(HashChangeEvent)
DOMCI_CLASS(EventListenerInfo)

Просмотреть файл

@ -119,6 +119,7 @@
#include "nsIDOMMessageEvent.h"
#include "nsIDOMPopupBlockedEvent.h"
#include "nsIDOMPopStateEvent.h"
#include "nsIDOMHashChangeEvent.h"
#include "nsIDOMOfflineResourceList.h"
#include "nsIDOMGeoGeolocation.h"
#include "nsIDOMDesktopNotification.h"
@ -7681,19 +7682,59 @@ nsGlobalWindow::PageHidden()
mNeedsFocus = PR_TRUE;
}
nsresult
nsGlobalWindow::DispatchAsyncHashchange()
class HashchangeCallback : public nsRunnable
{
FORWARD_TO_INNER(DispatchAsyncHashchange, (), NS_OK);
public:
HashchangeCallback(const nsAString &aOldURL,
const nsAString &aNewURL,
nsGlobalWindow* aWindow)
: mWindow(aWindow)
{
mOldURL.Assign(aOldURL);
mNewURL.Assign(aNewURL);
}
nsCOMPtr<nsIRunnable> event =
NS_NewRunnableMethod(this, &nsGlobalWindow::FireHashchange);
NS_IMETHOD Run()
{
NS_PRECONDITION(NS_IsMainThread(), "Should be called on the main thread.");
return mWindow->FireHashchange(mOldURL, mNewURL);
}
return NS_DispatchToCurrentThread(event);
private:
nsString mOldURL;
nsString mNewURL;
nsRefPtr<nsGlobalWindow> mWindow;
};
nsresult
nsGlobalWindow::DispatchAsyncHashchange(nsIURI *aOldURI, nsIURI *aNewURI)
{
FORWARD_TO_INNER(DispatchAsyncHashchange, (aOldURI, aNewURI), NS_OK);
// Make sure that aOldURI and aNewURI are identical up to the '#', and that
// their hashes are different.
nsCAutoString oldBeforeHash, oldHash, newBeforeHash, newHash;
nsContentUtils::SplitURIAtHash(aOldURI, oldBeforeHash, oldHash);
nsContentUtils::SplitURIAtHash(aNewURI, newBeforeHash, newHash);
NS_ENSURE_STATE(oldBeforeHash.Equals(newBeforeHash));
NS_ENSURE_STATE(!oldHash.Equals(newHash));
nsCAutoString oldSpec, newSpec;
aOldURI->GetSpec(oldSpec);
aNewURI->GetSpec(newSpec);
NS_ConvertUTF8toUTF16 oldWideSpec(oldSpec);
NS_ConvertUTF8toUTF16 newWideSpec(newSpec);
nsCOMPtr<nsIRunnable> callback =
new HashchangeCallback(oldWideSpec, newWideSpec, this);
return NS_DispatchToMainThread(callback);
}
nsresult
nsGlobalWindow::FireHashchange()
nsGlobalWindow::FireHashchange(const nsAString &aOldURL,
const nsAString &aNewURL)
{
NS_ENSURE_TRUE(IsInnerWindow(), NS_ERROR_FAILURE);
@ -7701,11 +7742,40 @@ nsGlobalWindow::FireHashchange()
if (IsFrozen())
return NS_OK;
// Dispatch the hashchange event, which doesn't bubble and isn't cancelable,
// to the outer window.
return nsContentUtils::DispatchTrustedEvent(mDoc, GetOuterWindow(),
NS_LITERAL_STRING("hashchange"),
PR_FALSE, PR_FALSE);
// Get a presentation shell for use in creating the hashchange event.
NS_ENSURE_STATE(mDoc);
nsIPresShell *shell = mDoc->GetShell();
nsRefPtr<nsPresContext> presContext;
if (shell) {
presContext = shell->GetPresContext();
}
// Create a new hashchange event.
nsCOMPtr<nsIDOMEvent> domEvent;
nsresult rv =
nsEventDispatcher::CreateEvent(presContext, nsnull,
NS_LITERAL_STRING("hashchangeevent"),
getter_AddRefs(domEvent));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIPrivateDOMEvent> privateEvent = do_QueryInterface(domEvent);
NS_ENSURE_TRUE(privateEvent, NS_ERROR_UNEXPECTED);
nsCOMPtr<nsIDOMHashChangeEvent> hashchangeEvent = do_QueryInterface(domEvent);
NS_ENSURE_TRUE(hashchangeEvent, NS_ERROR_UNEXPECTED);
// The hashchange event bubbles and isn't cancellable.
rv = hashchangeEvent->InitHashChangeEvent(NS_LITERAL_STRING("hashchange"),
PR_TRUE, PR_FALSE,
aOldURL, aNewURL);
NS_ENSURE_SUCCESS(rv, rv);
rv = privateEvent->SetTrusted(PR_TRUE);
NS_ENSURE_SUCCESS(rv, rv);
PRBool dummy;
return DispatchEvent(hashchangeEvent, &dummy);
}
nsresult

Просмотреть файл

@ -548,7 +548,7 @@ public:
virtual PRBool TakeFocus(PRBool aFocus, PRUint32 aFocusMethod);
virtual void SetReadyForFocus();
virtual void PageHidden();
virtual nsresult DispatchAsyncHashchange();
virtual nsresult DispatchAsyncHashchange(nsIURI *aOldURI, nsIURI *aNewURI);
virtual nsresult DispatchSyncPopState();
virtual nsresult SetArguments(nsIArray *aArguments, nsIPrincipal *aOrigin);
@ -588,6 +588,8 @@ private:
void DisableAccelerationUpdates();
protected:
friend class HashchangeCallback;
// Object Management
virtual ~nsGlobalWindow();
void CleanUp(PRBool aIgnoreModalDialog);
@ -716,7 +718,7 @@ protected:
const nsAString &aPopupWindowName,
const nsAString &aPopupWindowFeatures);
void FireOfflineStatusEvent();
nsresult FireHashchange();
nsresult FireHashchange(const nsAString &aOldURL, const nsAString &aNewURL);
void FlushPendingNotifications(mozFlushType aType);
void EnsureReflowFlushAndPaint();

Просмотреть файл

@ -49,6 +49,7 @@
#include "nsIDOMDocument.h"
#include "nsCOMPtr.h"
#include "nsEvent.h"
#include "nsIURI.h"
#define DOM_WINDOW_DESTROYED_TOPIC "dom-window-destroyed"
@ -537,7 +538,8 @@ public:
* Instructs this window to asynchronously dispatch a hashchange event. This
* method must be called on an inner window.
*/
virtual nsresult DispatchAsyncHashchange() = 0;
virtual nsresult DispatchAsyncHashchange(nsIURI *aOldURI,
nsIURI *aNewURI) = 0;
/**
* Instructs this window to synchronously dispatch a popState event.

Просмотреть файл

@ -88,6 +88,7 @@ XPIDLSRCS = \
nsIDOMPopStateEvent.idl \
nsIDOMCloseEvent.idl \
nsIDOMEventException.idl \
nsIDOMHashChangeEvent.idl \
$(NULL)
ifdef MOZ_CSS_ANIMATIONS

Просмотреть файл

@ -0,0 +1,48 @@
/* -*- 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.org code.
*
* The Initial Developer of the Original Code is the Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* 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 "nsIDOMEvent.idl"
[scriptable, uuid(34850f11-8b88-43ce-8d55-9aa8b18753bd)]
interface nsIDOMHashChangeEvent : nsIDOMEvent
{
readonly attribute DOMString oldURL;
readonly attribute DOMString newURL;
void initHashChangeEvent(in DOMString typeArg,
in boolean canBubbleArg,
in boolean cancelableArg,
in DOMString oldURLArg,
in DOMString newURLArg);
};

Просмотреть файл

@ -50,6 +50,9 @@ _TEST_FILES = \
historyframes.html \
test_497898.html \
test_bug504220.html \
test_bug628069_1.html \
test_bug628069_2.html \
file_bug628069.html \
test_bug631440.html \
test_consoleAPI.html \
test_domWindowUtils.html \

Просмотреть файл

@ -0,0 +1,16 @@
<html>
<body onhashchange='hashchange(event)' onload='load()'>
<script>
function hashchange(e) {
(opener || parent).childHashchange(e);
}
function load() {
(opener || parent).childLoad();
}
</script>
Just a shell of a page.
</body>
</html>

Просмотреть файл

@ -0,0 +1,50 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=628069
-->
<head>
<title>Test for Bug 628069</title>
<script type="application/javascript" src="/MochiKit/packed.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=628069">Mozilla Bug 628069</a>
<p id="display"></p>
<div id="content">
<iframe id="frame" style="height:100px; width:100px; border:0"></iframe>
<div id="status" style="display: none"></div>
</div>
<pre id="test">
<script type="application/javascript;version=1.7">
/** Test for Bug 628069 **/
SimpleTest.waitForExplicitFinish();
popup = window.open('file_bug628069.html');
// Control flows into childLoad, once the popup loads.
gOrigURL = null;
function childLoad() {
gOrigURL = popup.location + '';
popup.location.hash = '#hash';
// This should trigger a hashchange, so control should flow down to
// childHashchange.
}
function childHashchange(e) {
is(e.oldURL, gOrigURL, 'event.oldURL');
is(e.newURL, gOrigURL + '#hash', 'event.newURL');
popup.close();
SimpleTest.finish();
}
</script>
</body>
</html>

Просмотреть файл

@ -0,0 +1,39 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=628069
-->
<head>
<title>Test for Bug 628069</title>
<script type="application/javascript" src="/MochiKit/packed.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=628069">Mozilla Bug 628069</a>
<p id="display"></p>
<div id="content">
<iframe id="frame" style="height:100px; width:100px; border:0"></iframe>
<div id="status" style="display: none"></div>
</div>
<pre id="test">
<script type="application/javascript;version=1.7">
/** Test for Bug 628069 **/
gotHashChange = 0;
document.addEventListener("hashChange", function(e) {
gotHashChange = 1;
is(e.oldURL, "oldURL");
is(e.newURL, "newURL");
}, true);
let hc = document.createEvent("HashChangeEvent");
hc.initHashChangeEvent("hashChange", true, false, "oldURL", "newURL");
document.documentElement.dispatchEvent(hc);
is(gotHashChange, 1, 'Document received hashchange event.');
</script>
</body>
</html>

Просмотреть файл

@ -15,7 +15,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=600570
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=600570">Mozilla Bug 600570</a>
<p id="display"></p>
<div id="content">
<textarea>
<textarea spellcheck="false">
aaa
[bbb]</textarea>
</div>
@ -45,6 +45,7 @@ SimpleTest.waitForFocus(function() {
t.addEventListener("input", function() {
t.removeEventListener("input", arguments.callee, false);
setTimeout(function() { // Avoid the assertion in bug 649797
is(t.value, "[aaa\nbbb]", "The value of the textarea should be correct");
synthesizeKey("A", {accelKey: true});
is(t.selectionStart, 0, "Select all should set the selection start to the beginning of textarea");
@ -56,6 +57,7 @@ SimpleTest.waitForFocus(function() {
ok(res[0], "Pasting and setting the value directly should result in the same rendering");
SimpleTest.finish();
}, 0);
}, false);
synthesizeKey("VK_RIGHT", {});
synthesizeKey("V", {accelKey: true});

Просмотреть файл

@ -80,7 +80,7 @@ typedef struct _cairo_d2d_device cairo_d2d_device_t;
struct _cairo_d2d_surface {
_cairo_d2d_surface() : d2d_clip(NULL), clipping(false), isDrawing(false),
textRenderingInit(true)
textRenderingInit(false)
{
_cairo_clip_init (&this->clip);
}

Просмотреть файл

@ -3583,7 +3583,11 @@ _cairo_dwrite_manual_show_glyphs_on_d2d_surface(void *surface,
}
// Deal with rendering modes CreateGlyphRunAnalysis doesn't accept.
if (renderMode == DWRITE_RENDERING_MODE_DEFAULT) {
switch (renderMode) {
case DWRITE_RENDERING_MODE_ALIASED:
// ClearType texture creation will fail in this mode, so bail out
return CAIRO_INT_STATUS_UNSUPPORTED;
case DWRITE_RENDERING_MODE_DEFAULT:
// As per DWRITE_RENDERING_MODE documentation, pick Natural for font
// sizes under 16 ppem
if (scaled_font->base.font_matrix.yy < 16.0f) {
@ -3591,15 +3595,24 @@ _cairo_dwrite_manual_show_glyphs_on_d2d_surface(void *surface,
} else {
renderMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC;
}
} else if (renderMode == DWRITE_RENDERING_MODE_OUTLINE) {
break;
case DWRITE_RENDERING_MODE_OUTLINE:
renderMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC;
break;
default:
break;
}
DWRITE_MEASURING_MODE measureMode =
renderMode <= DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC ? DWRITE_MEASURING_MODE_GDI_CLASSIC :
renderMode == DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL ? DWRITE_MEASURING_MODE_GDI_NATURAL :
DWRITE_MEASURING_MODE_NATURAL;
hr = DWriteFactory::Instance()->CreateGlyphRunAnalysis(&run,
1.0f,
transform ? &dwmat : 0,
renderMode,
DWRITE_MEASURING_MODE_NATURAL,
measureMode,
0,
0,
&analysis);
@ -3919,18 +3932,62 @@ _cairo_dwrite_show_glyphs_on_d2d_surface(void *surface,
cleartype_quality = D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE;
}
switch (dwritesf->antialias_mode) {
case CAIRO_ANTIALIAS_NONE:
target_rt->SetTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_ALIASED);
RefPtr<IDWriteRenderingParams> params;
target_rt->GetTextRenderingParams(&params);
DWRITE_RENDERING_MODE renderMode = DWRITE_RENDERING_MODE_DEFAULT;
if (params) {
HRESULT hr = dwriteff->dwriteface->GetRecommendedRenderingMode(
(FLOAT)dwritesf->base.font_matrix.yy,
1.0f,
DWRITE_MEASURING_MODE_NATURAL,
params,
&renderMode);
if (FAILED(hr)) {
// this probably never happens, but let's play it safe
renderMode = DWRITE_RENDERING_MODE_DEFAULT;
}
}
// Deal with rendering modes CreateGlyphRunAnalysis doesn't accept
switch (renderMode) {
case DWRITE_RENDERING_MODE_DEFAULT:
// As per DWRITE_RENDERING_MODE documentation, pick Natural for font
// sizes under 16 ppem
if (dwritesf->base.font_matrix.yy < 16.0f) {
renderMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL;
} else {
renderMode = DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC;
}
break;
case CAIRO_ANTIALIAS_GRAY:
target_rt->SetTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE);
break;
case CAIRO_ANTIALIAS_SUBPIXEL:
target_rt->SetTextAntialiasMode(cleartype_quality);
case DWRITE_RENDERING_MODE_OUTLINE:
return CAIRO_INT_STATUS_UNSUPPORTED;
default:
break;
}
switch (dwritesf->antialias_mode) {
case CAIRO_ANTIALIAS_NONE:
cleartype_quality = D2D1_TEXT_ANTIALIAS_MODE_ALIASED;
break;
case CAIRO_ANTIALIAS_GRAY:
cleartype_quality = D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE;
break;
case CAIRO_ANTIALIAS_SUBPIXEL:
break;
}
if (renderMode == DWRITE_RENDERING_MODE_ALIASED) {
cleartype_quality = D2D1_TEXT_ANTIALIAS_MODE_ALIASED;
}
target_rt->SetTextAntialiasMode(cleartype_quality);
DWRITE_MEASURING_MODE measureMode =
renderMode <= DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC ? DWRITE_MEASURING_MODE_GDI_CLASSIC :
renderMode == DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL ? DWRITE_MEASURING_MODE_GDI_NATURAL :
DWRITE_MEASURING_MODE_NATURAL;
cairo_bool_t transform = FALSE;
DWRITE_GLYPH_RUN run;
@ -3949,8 +4006,8 @@ _cairo_dwrite_show_glyphs_on_d2d_surface(void *surface,
DWriteFactory::Instance()->CreateGlyphRunAnalysis(&run,
1.0f,
transform ? &dwmat : 0,
DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC,
DWRITE_MEASURING_MODE_NATURAL,
renderMode,
measureMode,
0,
0,
&analysis);
@ -3987,7 +4044,7 @@ _cairo_dwrite_show_glyphs_on_d2d_surface(void *surface,
brush->SetTransform(&mat_brush);
}
target_rt->DrawGlyphRun(D2D1::Point2F(0, 0), &run, brush, dwritesf->measuring_mode);
target_rt->DrawGlyphRun(D2D1::Point2F(0, 0), &run, brush, measureMode);
if (transform) {
target_rt->SetTransform(D2D1::Matrix3x2F::Identity());
@ -4019,8 +4076,7 @@ _cairo_d2d_show_glyphs (void *surface,
}
cairo_d2d_surface_t *d2dsurf = static_cast<cairo_d2d_surface_t*>(surface);
if (!d2dsurf->textRenderingInit) {
RefPtr<IDWriteRenderingParams> params;
DWriteFactory::Instance()->CreateRenderingParams(&params);
RefPtr<IDWriteRenderingParams> params = DWriteFactory::RenderingParams();
d2dsurf->rt->SetTextRenderingParams(params);
d2dsurf->textRenderingInit = true;
}

Просмотреть файл

@ -119,6 +119,13 @@ private:
IDWriteFactory *DWriteFactory::mFactoryInstance = NULL;
IDWriteFontCollection *DWriteFactory::mSystemCollection = NULL;
IDWriteRenderingParams *DWriteFactory::mRenderingParams = NULL;
FLOAT DWriteFactory::mGamma = -1.0;
FLOAT DWriteFactory::mEnhancedContrast = -1.0;
FLOAT DWriteFactory::mClearTypeLevel = -1.0;
int DWriteFactory::mPixelGeometry = -1;
int DWriteFactory::mRenderingMode = -1;
ID2D1Factory *D2DFactory::mFactoryInstance = NULL;
ID2D1DCRenderTarget *D2DFactory::mRenderTarget = NULL;
@ -298,7 +305,6 @@ _cairo_dwrite_font_face_create_for_toy (cairo_toy_font_face_t *toy_face,
if (SUCCEEDED(hr)) {
// Cannot use C++ style new since cairo deallocates this.
*font_face = (cairo_font_face_t*)face;
_cairo_font_face_init (&(*(_cairo_dwrite_font_face**)font_face)->base, &_cairo_dwrite_font_face_backend);
} else {
free(face);
@ -1070,6 +1076,13 @@ cairo_dwrite_scaled_font_allow_manual_show_glyphs(void* dwrite_scaled_font, cair
font->manual_show_glyphs_allowed = allowed;
}
void
cairo_dwrite_set_cleartype_params(FLOAT gamma, FLOAT contrast, FLOAT level,
int geometry, int mode)
{
DWriteFactory::SetRenderingParams(gamma, contrast, level, geometry, mode);
}
cairo_int_status_t
_dwrite_draw_glyphs_to_gdi_surface_gdi(cairo_win32_surface_t *surface,
DWRITE_MATRIX *transform,
@ -1081,8 +1094,7 @@ _dwrite_draw_glyphs_to_gdi_surface_gdi(cairo_win32_surface_t *surface,
DWriteFactory::Instance()->GetGdiInterop(&gdiInterop);
IDWriteBitmapRenderTarget *rt;
IDWriteRenderingParams *params;
DWriteFactory::Instance()->CreateRenderingParams(&params);
IDWriteRenderingParams *params = DWriteFactory::RenderingParams();
gdiInterop->CreateBitmapRenderTarget(surface->dc,
area.right - area.left,
@ -1370,6 +1382,49 @@ _cairo_dwrite_show_glyphs_on_surface(void *surface,
return CAIRO_INT_STATUS_SUCCESS;
}
#define ENHANCED_CONTRAST_REGISTRY_KEY \
HKEY_CURRENT_USER, "Software\\Microsoft\\Avalon.Graphics\\DISPLAY1\\EnhancedContrastLevel"
void
DWriteFactory::CreateRenderingParams()
{
if (!Instance()) {
return;
}
RefPtr<IDWriteRenderingParams> defaultParams;
Instance()->CreateRenderingParams(&defaultParams);
// For EnhancedContrast, we override the default if the user has not set it
// in the registry (by using the ClearType Tuner).
FLOAT contrast;
if (mEnhancedContrast >= 0.0 && mEnhancedContrast <= 10.0) {
contrast = mEnhancedContrast;
} else {
HKEY hKey;
if (RegOpenKeyExA(ENHANCED_CONTRAST_REGISTRY_KEY,
0, KEY_READ, &hKey) == ERROR_SUCCESS)
{
contrast = defaultParams->GetEnhancedContrast();
RegCloseKey(hKey);
} else {
contrast = 1.0;
}
}
// For parameters that have not been explicitly set via the SetRenderingParams API,
// we copy values from default params (or our overridden value for contrast)
Instance()->CreateCustomRenderingParams(
mGamma >= 1.0 && mGamma <= 2.2 ? mGamma : defaultParams->GetGamma(),
contrast,
mClearTypeLevel >= 0.0 && mClearTypeLevel <= 1.0 ? mClearTypeLevel : defaultParams->GetClearTypeLevel(),
mPixelGeometry >= DWRITE_PIXEL_GEOMETRY_FLAT && mPixelGeometry <= DWRITE_PIXEL_GEOMETRY_BGR ?
(DWRITE_PIXEL_GEOMETRY)mPixelGeometry : defaultParams->GetPixelGeometry(),
mRenderingMode >= DWRITE_RENDERING_MODE_DEFAULT && mRenderingMode <= DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC ?
(DWRITE_RENDERING_MODE)mRenderingMode : defaultParams->GetRenderingMode(),
&mRenderingParams);
}
// Helper for _cairo_win32_printing_surface_show_glyphs to create a win32 equivalent
// of a dwrite scaled_font so that we can print using ExtTextOut instead of drawing
// paths or blitting glyph bitmaps.

Просмотреть файл

@ -92,9 +92,46 @@ public:
return family;
}
static IDWriteRenderingParams *RenderingParams()
{
if (!mRenderingParams) {
CreateRenderingParams();
}
if (mRenderingParams) {
mRenderingParams->AddRef();
}
return mRenderingParams;
}
static void SetRenderingParams(FLOAT aGamma,
FLOAT aEnhancedContrast,
FLOAT aClearTypeLevel,
int aPixelGeometry,
int aRenderingMode)
{
mGamma = aGamma;
mEnhancedContrast = aEnhancedContrast;
mClearTypeLevel = aClearTypeLevel;
mPixelGeometry = aPixelGeometry;
mRenderingMode = aRenderingMode;
// discard any current RenderingParams object
if (mRenderingParams) {
mRenderingParams->Release();
mRenderingParams = NULL;
}
}
private:
static void CreateRenderingParams();
static IDWriteFactory *mFactoryInstance;
static IDWriteFontCollection *mSystemCollection;
static IDWriteRenderingParams *mRenderingParams;
static FLOAT mGamma;
static FLOAT mEnhancedContrast;
static FLOAT mClearTypeLevel;
static int mPixelGeometry;
static int mRenderingMode;
};
/* cairo_font_face_t implementation */

Просмотреть файл

@ -126,6 +126,9 @@ cairo_dwrite_font_face_create_for_dwrite_fontface(void *dwrite_font, void *dwrit
void
cairo_dwrite_scaled_font_allow_manual_show_glyphs(void *dwrite_scaled_font, cairo_bool_t allowed);
void
cairo_dwrite_set_cleartype_params(FLOAT gamma, FLOAT contrast, FLOAT level, int geometry, int mode);
#endif /* CAIRO_HAS_DWRITE_FONT */
#if CAIRO_HAS_D2D_SURFACE

Просмотреть файл

@ -149,7 +149,10 @@ gfxDWriteFont::gfxDWriteFont(gfxFontEntry *aFontEntry,
return;
}
if ((anAAOption == gfxFont::kAntialiasDefault && UsingClearType()) ||
if ((anAAOption == gfxFont::kAntialiasDefault &&
UsingClearType() &&
(gfxWindowsPlatform::GetPlatform()->DWriteMeasuringMode() ==
DWRITE_MEASURING_MODE_NATURAL)) ||
anAAOption == gfxFont::kAntialiasSubpixel)
{
mUseSubpixelPositions = PR_TRUE;
@ -248,16 +251,12 @@ gfxDWriteFont::ComputeMetrics()
mMetrics = new gfxFont::Metrics;
::memset(mMetrics, 0, sizeof(*mMetrics));
mMetrics->xHeight =
((gfxFloat)fontMetrics.xHeight /
fontMetrics.designUnitsPerEm) * mAdjustedSize;
mFUnitsConvFactor = float(mAdjustedSize / fontMetrics.designUnitsPerEm);
mMetrics->maxAscent =
ceil(((gfxFloat)fontMetrics.ascent /
fontMetrics.designUnitsPerEm) * mAdjustedSize);
mMetrics->maxDescent =
ceil(((gfxFloat)fontMetrics.descent /
fontMetrics.designUnitsPerEm) * mAdjustedSize);
mMetrics->xHeight = fontMetrics.xHeight * mFUnitsConvFactor;
mMetrics->maxAscent = ceil(fontMetrics.ascent * mFUnitsConvFactor);
mMetrics->maxDescent = ceil(fontMetrics.descent * mFUnitsConvFactor);
mMetrics->maxHeight = mMetrics->maxAscent + mMetrics->maxDescent;
mMetrics->emHeight = mAdjustedSize;
@ -282,26 +281,21 @@ gfxDWriteFont::ComputeMetrics()
if (exists && len >= sizeof(mozilla::HheaTable)) {
const mozilla::HheaTable* hhea =
reinterpret_cast<const mozilla::HheaTable*>(tableData);
mMetrics->maxAdvance = ((gfxFloat)PRUint16(hhea->advanceWidthMax) /
fontMetrics.designUnitsPerEm) * mAdjustedSize;
mMetrics->maxAdvance =
PRUint16(hhea->advanceWidthMax) * mFUnitsConvFactor;
}
mFontFace->ReleaseFontTable(tableContext);
}
mMetrics->internalLeading = NS_MAX(mMetrics->maxHeight - mMetrics->emHeight, 0.0);
mMetrics->externalLeading =
ceil(((gfxFloat)fontMetrics.lineGap /
fontMetrics.designUnitsPerEm) * mAdjustedSize);
mMetrics->externalLeading = ceil(fontMetrics.lineGap * mFUnitsConvFactor);
UINT16 glyph = (PRUint16)GetSpaceGlyph();
DWRITE_GLYPH_METRICS metrics;
mFontFace->GetDesignGlyphMetrics(&glyph, 1, &metrics);
mMetrics->spaceWidth =
((gfxFloat)metrics.advanceWidth /
fontMetrics.designUnitsPerEm) * mAdjustedSize;
mMetrics->spaceWidth = MeasureGlyphWidth(glyph);
// try to get aveCharWidth from the OS/2 table, fall back to measuring 'x'
// if the table is not available
// if the table is not available or if using hinted/pixel-snapped widths
if (mUseSubpixelPositions) {
mMetrics->aveCharWidth = 0;
hr = mFontFace->TryGetFontTable(DWRITE_MAKE_OPENTYPE_TAG('O', 'S', '/', '2'),
(const void**)&tableData,
@ -315,55 +309,44 @@ gfxDWriteFont::ComputeMetrics()
// two 16-bit fields here.
const mozilla::OS2Table* os2 =
reinterpret_cast<const mozilla::OS2Table*>(tableData);
mMetrics->aveCharWidth = ((gfxFloat)PRInt16(os2->xAvgCharWidth) /
fontMetrics.designUnitsPerEm) * mAdjustedSize;
mMetrics->aveCharWidth =
PRInt16(os2->xAvgCharWidth) * mFUnitsConvFactor;
}
mFontFace->ReleaseFontTable(tableContext);
}
}
UINT32 ucs;
if (mMetrics->aveCharWidth < 1) {
ucs = L'x';
if (SUCCEEDED(mFontFace->GetGlyphIndicesA(&ucs, 1, &glyph)) &&
SUCCEEDED(mFontFace->GetDesignGlyphMetrics(&glyph, 1, &metrics))) {
mMetrics->aveCharWidth =
((gfxFloat)metrics.advanceWidth /
fontMetrics.designUnitsPerEm) * mAdjustedSize;
} else {
if (SUCCEEDED(mFontFace->GetGlyphIndicesA(&ucs, 1, &glyph))) {
mMetrics->aveCharWidth = MeasureGlyphWidth(glyph);
}
if (mMetrics->aveCharWidth < 1) {
// Let's just assume the X is square.
mMetrics->aveCharWidth =
((gfxFloat)fontMetrics.xHeight /
fontMetrics.designUnitsPerEm) * mAdjustedSize;
mMetrics->aveCharWidth = fontMetrics.xHeight * mFUnitsConvFactor;
}
}
ucs = L'0';
if (SUCCEEDED(mFontFace->GetGlyphIndicesA(&ucs, 1, &glyph)) &&
SUCCEEDED(mFontFace->GetDesignGlyphMetrics(&glyph, 1, &metrics))) {
mMetrics->zeroOrAveCharWidth =
((gfxFloat)metrics.advanceWidth /
fontMetrics.designUnitsPerEm) * mAdjustedSize;
} else {
if (SUCCEEDED(mFontFace->GetGlyphIndicesA(&ucs, 1, &glyph))) {
mMetrics->zeroOrAveCharWidth = MeasureGlyphWidth(glyph);
}
if (mMetrics->zeroOrAveCharWidth < 1) {
mMetrics->zeroOrAveCharWidth = mMetrics->aveCharWidth;
}
mMetrics->underlineOffset =
((gfxFloat)fontMetrics.underlinePosition /
fontMetrics.designUnitsPerEm) * mAdjustedSize;
fontMetrics.underlinePosition * mFUnitsConvFactor;
mMetrics->underlineSize =
((gfxFloat)fontMetrics.underlineThickness /
fontMetrics.designUnitsPerEm) * mAdjustedSize;
fontMetrics.underlineThickness * mFUnitsConvFactor;
mMetrics->strikeoutOffset =
((gfxFloat)fontMetrics.strikethroughPosition /
fontMetrics.designUnitsPerEm) * mAdjustedSize;
fontMetrics.strikethroughPosition * mFUnitsConvFactor;
mMetrics->strikeoutSize =
((gfxFloat)fontMetrics.strikethroughThickness /
fontMetrics.designUnitsPerEm) * mAdjustedSize;
fontMetrics.strikethroughThickness * mFUnitsConvFactor;
mMetrics->superscriptOffset = 0;
mMetrics->subscriptOffset = 0;
mFUnitsConvFactor = float(mAdjustedSize / fontMetrics.designUnitsPerEm);
SanitizeMetrics(mMetrics, GetFontEntry()->mIsBadUnderlineFont);
#if 0
@ -697,26 +680,30 @@ gfxDWriteFont::GetGlyphWidth(gfxContext *aCtx, PRUint16 aGID)
return width;
}
DWRITE_GLYPH_METRICS glyphMetrics;
HRESULT hr;
if (mUseSubpixelPositions) {
hr = mFontFace->GetDesignGlyphMetrics(
&aGID, 1, &glyphMetrics, FALSE);
if (SUCCEEDED(hr)) {
width =
NS_lround(glyphMetrics.advanceWidth * mFUnitsConvFactor *
65536.0);
}
} else {
hr = mFontFace->GetGdiCompatibleGlyphMetrics(
FLOAT(mAdjustedSize), 1.0f, nsnull, FALSE,
&aGID, 1, &glyphMetrics, FALSE);
if (SUCCEEDED(hr)) {
width =
NS_lround(glyphMetrics.advanceWidth * mFUnitsConvFactor) << 16;
}
}
width = NS_lround(MeasureGlyphWidth(aGID) * 65536.0);
mGlyphWidths.Put(aGID, width);
return width;
}
gfxFloat
gfxDWriteFont::MeasureGlyphWidth(PRUint16 aGlyph)
{
DWRITE_GLYPH_METRICS metrics;
HRESULT hr;
if (mUseSubpixelPositions) {
hr = mFontFace->GetDesignGlyphMetrics(&aGlyph, 1, &metrics, FALSE);
if (SUCCEEDED(hr)) {
return metrics.advanceWidth * mFUnitsConvFactor;
}
} else {
hr = mFontFace->GetGdiCompatibleGlyphMetrics(
FLOAT(mAdjustedSize), 1.0f, nsnull,
gfxWindowsPlatform::GetPlatform()->DWriteMeasuringMode() ==
DWRITE_MEASURING_MODE_GDI_NATURAL,
&aGlyph, 1, &metrics, FALSE);
if (SUCCEEDED(hr)) {
return NS_lround(metrics.advanceWidth * mFUnitsConvFactor);
}
}
return 0;
}

Просмотреть файл

@ -98,6 +98,8 @@ protected:
cairo_scaled_font_t *CairoScaledFont();
gfxFloat MeasureGlyphWidth(PRUint16 aGlyph);
static void DestroyBlobFunc(void* userArg);
nsRefPtr<IDWriteFontFace> mFontFace;

Просмотреть файл

@ -2666,7 +2666,6 @@ gfxFontGroup::GetGeneration()
void
gfxFontGroup::UpdateFontList()
{
// if user font set is set, check to see if font list needs updating
if (mUserFontSet && mCurrGeneration != GetGeneration()) {
// xxx - can probably improve this to detect when all fonts were found, so no need to update list
mFonts.Clear();

Просмотреть файл

@ -58,6 +58,10 @@
#include "nsUnicodeRange.h"
#include "nsCRT.h"
#if defined(XP_WIN)
#include "gfxWindowsPlatform.h"
#endif
#define FloatToFixed(f) (65536 * (f))
#define FixedToFloat(f) ((f) * (1.0 / 65536.0))
// Right shifts of negative (signed) integers are undefined, as are overflows
@ -946,8 +950,12 @@ GetRoundOffsetsToPixels(gfxContext *aContext,
#if CAIRO_HAS_DWRITE_FONT // dwrite backend is not in std cairo releases yet
case CAIRO_FONT_TYPE_DWRITE:
// show_glyphs is implemented on the font and so is used for
// all surface types.
// all surface types; however, it may pixel-snap depending on
// the dwrite rendering mode
if (gfxWindowsPlatform::GetPlatform()->DWriteMeasuringMode() ==
DWRITE_MEASURING_MODE_NATURAL) {
return;
}
#endif
case CAIRO_FONT_TYPE_QUARTZ:
// Quartz surfaces implement show_glyphs for Quartz fonts

Просмотреть файл

@ -158,6 +158,13 @@ NS_IMPL_ISUPPORTS1(D2DVRAMReporter, nsIMemoryReporter)
#define GFX_USE_CLEARTYPE_ALWAYS "gfx.font_rendering.cleartype.always_use_for_content"
#define GFX_DOWNLOADABLE_FONTS_USE_CLEARTYPE "gfx.font_rendering.cleartype.use_for_downloadable_fonts"
#define GFX_CLEARTYPE_PARAMS "gfx.font_rendering.cleartype_params."
#define GFX_CLEARTYPE_PARAMS_GAMMA "gfx.font_rendering.cleartype_params.gamma"
#define GFX_CLEARTYPE_PARAMS_CONTRAST "gfx.font_rendering.cleartype_params.enhanced_contrast"
#define GFX_CLEARTYPE_PARAMS_LEVEL "gfx.font_rendering.cleartype_params.cleartype_level"
#define GFX_CLEARTYPE_PARAMS_STRUCTURE "gfx.font_rendering.cleartype_params.pixel_structure"
#define GFX_CLEARTYPE_PARAMS_MODE "gfx.font_rendering.cleartype_params.rendering_mode"
#ifdef MOZ_FT2_FONTS
static FT_Library gPlatformFTLibrary = NULL;
#endif
@ -343,6 +350,8 @@ gfxWindowsPlatform::UpdateRenderMode()
mDWriteFactory = factory;
factory->Release();
SetupClearTypeParams(pref);
if (hr == S_OK)
reporter.SetSuccessful();
}
@ -790,6 +799,8 @@ gfxWindowsPlatform::FontsPrefsChanged(nsIPrefBranch *aPrefBranch, const char *aP
mUseClearTypeForDownloadableFonts = UNINITIALIZED_VALUE;
} else if (!strcmp(GFX_USE_CLEARTYPE_ALWAYS, aPref)) {
mUseClearTypeAlways = UNINITIALIZED_VALUE;
} else if (!strncmp(GFX_CLEARTYPE_PARAMS, aPref, strlen(GFX_CLEARTYPE_PARAMS))) {
SetupClearTypeParams(aPrefBranch);
} else {
clearTextFontCaches = PR_FALSE;
}
@ -803,6 +814,67 @@ gfxWindowsPlatform::FontsPrefsChanged(nsIPrefBranch *aPrefBranch, const char *aP
}
}
void
gfxWindowsPlatform::SetupClearTypeParams(nsIPrefBranch *aPrefBranch)
{
#if CAIRO_HAS_DWRITE_FONT
if (GetDWriteFactory()) {
// any missing prefs will default to invalid (-1) and be ignored;
// out-of-range values will also be ignored
FLOAT gamma = -1.0;
FLOAT contrast = -1.0;
FLOAT level = -1.0;
int geometry = -1;
int mode = -1;
PRInt32 value;
if (NS_SUCCEEDED(aPrefBranch->GetIntPref(GFX_CLEARTYPE_PARAMS_GAMMA,
&value))) {
if (value >= 1000 && value <= 2200) {
gamma = (FLOAT)value / 1000.0;
}
}
if (NS_SUCCEEDED(aPrefBranch->GetIntPref(GFX_CLEARTYPE_PARAMS_CONTRAST,
&value))) {
if (value >= 0 && value <= 1000) {
contrast = (FLOAT)value / 100.0;
}
}
if (NS_SUCCEEDED(aPrefBranch->GetIntPref(GFX_CLEARTYPE_PARAMS_LEVEL,
&value))) {
if (value >= 0 && value <= 100) {
level = (FLOAT)value / 100.0;
}
}
if (NS_SUCCEEDED(aPrefBranch->GetIntPref(GFX_CLEARTYPE_PARAMS_STRUCTURE,
&value))) {
if (value >= 0 && value <= 2) {
geometry = value;
}
}
if (NS_SUCCEEDED(aPrefBranch->GetIntPref(GFX_CLEARTYPE_PARAMS_MODE,
&value))) {
if (value >= 0 && value <= 5) {
mode = value;
}
}
cairo_dwrite_set_cleartype_params(gamma, contrast, level, geometry, mode);
switch (mode) {
case DWRITE_RENDERING_MODE_ALIASED:
case DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC:
mMeasuringMode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
break;
case DWRITE_RENDERING_MODE_CLEARTYPE_GDI_NATURAL:
mMeasuringMode = DWRITE_MEASURING_MODE_GDI_NATURAL;
break;
default:
mMeasuringMode = DWRITE_MEASURING_MODE_NATURAL;
break;
}
}
#endif
}
bool
gfxWindowsPlatform::IsOptimus()
{

Просмотреть файл

@ -238,9 +238,12 @@ public:
virtual void FontsPrefsChanged(nsIPrefBranch *aPrefBranch, const char *aPref);
void SetupClearTypeParams(nsIPrefBranch *aPrefBranch);
#ifdef CAIRO_HAS_DWRITE_FONT
IDWriteFactory *GetDWriteFactory() { return mDWriteFactory; }
inline PRBool DWriteEnabled() { return mUseDirectWrite; }
inline DWRITE_MEASURING_MODE DWriteMeasuringMode() { return mMeasuringMode; }
#else
inline PRBool DWriteEnabled() { return PR_FALSE; }
#endif
@ -270,6 +273,7 @@ private:
#ifdef CAIRO_HAS_DWRITE_FONT
nsRefPtr<IDWriteFactory> mDWriteFactory;
DWRITE_MEASURING_MODE mMeasuringMode;
#endif
#ifdef CAIRO_HAS_D2D_SURFACE
cairo_device_t *mD2DDevice;

Просмотреть файл

@ -82,11 +82,7 @@ else
ELOG :=
endif
ifeq ($(OS_ARCH),WINNT)
_VPATH_SRCS = $(abspath $<)
else
_VPATH_SRCS = $<
endif
# Add $(DIST)/lib to VPATH so that -lfoo dependencies are followed
VPATH += $(DIST)/lib

Просмотреть файл

@ -50,7 +50,7 @@
#elif defined(XP_MACOSX) || defined(DARWIN) || defined(XP_UNIX)
# include <pthread.h>
# if defined(__FreeBSD__)
# if defined(__FreeBSD__) || defined(__OpenBSD__)
# include <pthread_np.h>
# endif

Просмотреть файл

@ -446,8 +446,10 @@ public:
PRBool SendNativeEvents()
{
#ifdef XP_WIN
// XXX we should remove the plugin name check
return mPluginWindow->type == NPWindowTypeDrawable &&
MatchPluginName("Shockwave Flash");
(MatchPluginName("Shockwave Flash") ||
MatchPluginName("Test Plug-in"));
#elif defined(MOZ_X11) || defined(XP_MACOSX)
return PR_TRUE;
#else

Просмотреть файл

@ -62,8 +62,8 @@ fails-if(Android) == 386339.html 386339-ref.html
== 409375.html 409375-ref.html
== 413542-1.html 413542-1-ref.html
== 413542-2.html 413542-2-ref.html
fails-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == 413928-1.html 413928-1-ref.html
fails-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == 413928-2.html 413928-2-ref.html
== 413928-1.html 413928-1-ref.html
== 413928-2.html 413928-2-ref.html
== 425338-1a.html 425338-1-ref.html
== 425338-1b.html 425338-1-ref.html
== 489517-1.html 489517-1-ref.html

Просмотреть файл

@ -675,7 +675,7 @@ fails-if(Android) != 376532-3.html 376532-3-ref.html
== 379178-html.html 379178-html-ref.html
== 379178-svg.svg 379178-svg-ref.svg
== 379316-1.html 379316-1-ref.html
fails-if(Android) random-if(cocoaWidget) == 379316-2.html 379316-2-ref.html # bug 379786
fails-if(Android) random-if(cocoaWidget) fails-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == 379316-2.html 379316-2-ref.html # bug 379786
== 379328-1.html 379328-1-ref.html
== 379349-1a.xhtml 379349-1-ref.xhtml
== 379349-1b.xhtml 379349-1-ref.xhtml

Просмотреть файл

@ -196,6 +196,8 @@ fails-if(Android) random-if(gtk2Widget) != text-language-01.xhtml text-language-
== text-layout-03.svg text-layout-03-ref.svg
== text-scale-01.svg text-scale-01-ref.svg
== text-stroke-scaling-01.svg text-stroke-scaling-01-ref.svg
== stroke-linecap-square-w-zero-length-segs-01.svg pass.svg
== stroke-linecap-square-w-zero-length-segs-02.svg pass.svg
== text-style-01a.svg text-style-01-ref.svg
== text-style-01b.svg text-style-01-ref.svg
== text-style-01c.svg text-style-01-ref.svg

Просмотреть файл

@ -0,0 +1,143 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/licenses/publicdomain/
-->
<svg xmlns="http://www.w3.org/2000/svg">
<title>Test 'stroke-linecap: square' with zero length path segments</title>
<!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=589648 -->
<style>
path {
stroke-width: 20px;
stroke-linecap: square;
}
rect {
fill: red;
}
/* expect lime squares to cover red rects */
path.squares-expected {
stroke: lime;
}
path.squares-not-expected {
stroke: red;
}
/* thicker stroke to cover squares-not-expected paths */
path.coverer {
stroke: lime;
stroke-width: 24px;
}
/* to show edges of shapes to help in debugging:
g > rect {
stroke: red;
stroke-width: 5px;
}
path.coverer {
stroke: lime;
stroke-width: 18px;
}
*/
</style>
<rect width="100%" height="100%" style="fill:lime"/>
<!-- Column 1: test single segment zero-length subpaths: -->
<g transform="translate(25,25)">
<rect x="-9" y="-9" width="18" height="18"/>
<rect x="41" y="41" width="18" height="18"/>
<rect x="91" y="91" width="18" height="18"/>
<path class="squares-expected" d="M0,0 L0,0 M20,20 L30,30 M50,50 L50,50 M70,70 L80,80 M100,100 L100,100"/>
</g>
<g transform="translate(25,75)">
<rect x="-9" y="-9" width="18" height="18"/>
<rect x="41" y="41" width="18" height="18"/>
<rect x="91" y="91" width="18" height="18"/>
<path class="squares-expected" d="M0,0 C0,0 0,0 0,0 M20,20 L30,30 M50,50 C50,50 50,50 50,50 M70,70 L80,80 M100,100 C100,100 100,100 100,100"/>
</g>
<g transform="translate(25,125)">
<path class="squares-not-expected" d="M0,0 A0,10 0 0 0 0,0 M20,20 L30,30 M50,50 A0,10 0 0 0 50,50 M70,70 L80,80 M100,100 A0,10 0 0 0 100,100"/>
<path class="coverer" d="M20,20 L30,30 M70,70 L80,80"/>
</g>
<g transform="translate(25,175)">
<rect x="-9" y="-9" width="18" height="18"/>
<rect x="41" y="41" width="18" height="18"/>
<rect x="91" y="91" width="18" height="18"/>
<path class="squares-expected" d="M0,0 Z M20,20 L30,30 M50,50 Z M70,70 L80,80 M100,100 Z"/>
</g>
<!-- Column 2: test multi-segment zero-length subpaths: -->
<g transform="translate(175,25)">
<rect x="-9" y="-9" width="18" height="18"/>
<rect x="41" y="41" width="18" height="18"/>
<rect x="91" y="91" width="18" height="18"/>
<path class="squares-expected" d="M0,0 L0,0 M0,0 L0,0 M20,20 L30,30 M50,50 L50,50 L50,50 M70,70 L80,80 M100,100 L100,100 L100,100"/>
</g>
<g transform="translate(177,75)">
<rect x="-9" y="-9" width="18" height="18"/>
<rect x="41" y="41" width="18" height="18"/>
<rect x="91" y="91" width="18" height="18"/>
<path class="squares-expected" d="M0,0 C0,0 0,0 0,0 C0,0 0,0 0,0 M20,20 L30,30 M50,50 C50,50 50,50 50,50 C50,50 50,50 50,50 M70,70 L80,80 M100,100 C100,100 100,100 100,100 C100,100 100,100 100,100"/>
</g>
<g transform="translate(175,125)">
<path class="squares-not-expected" d="M0,0 A0,10 0 0 0 0,0 A0,10 0 0 0 0,0 M20,20 L30,30 M50,50 A0,10 0 0 0 50,50 A0,10 0 0 0 50,50 M70,70 L80,80 M100,100 A0,10 0 0 0 100,100 A0,10 0 0 0 100,100"/>
<path class="coverer" d="M20,20 L30,30 M70,70 L80,80"/>
</g>
<g transform="translate(175,175)">
<rect x="-9" y="-9" width="18" height="18"/>
<rect x="41" y="41" width="18" height="18"/>
<rect x="91" y="91" width="18" height="18"/>
<path class="squares-expected" d="M0,0 Z Z M20,20 L30,30 M50,50 Z Z M70,70 L80,80 M100,100 Z Z"/>
</g>
<!-- Column 3: test non-zero-length subpaths that begin, end and contain
zero length segments: -->
<g transform="translate(325,25)">
<path class="squares-not-expected" d="M20,20 L20,20 L30,30 L30,30 L40,40 L40,40"/>
<path class="coverer" d="M20,20 L40,40"/>
</g>
<g transform="translate(325,75)">
<path class="squares-not-expected" d="M20,20 C20,20 20,20 20,20 C20,20 30,30 30,30 C30,30 30,30 30,30 C30,30 40,40 40,40 C40,40 40,40 40,40"/>
<path class="coverer" d="M20,20 L40,40"/>
</g>
<g transform="translate(325,125)">
<path class="squares-not-expected" d="M20,20 A0,10 0 0 0 20,20 A0,10 0 0 0 30,30 A0,10 0 0 0 30,30 A0,10 0 0 0 40,40 A0,10 0 0 0 40,40"/>
<path class="coverer" d="M20,20 L40,40"/>
</g>
<!-- this one is shorter because the Z's mean we only have path end points
at 20,20 -->
<g transform="translate(325,175)">
<rect x="11" y="11" width="18" height="18"/>
<path class="squares-expected" d="M20,20 Z L30,30 Z L40,40 Z"/>
</g>
<!-- Column 4: test loan movetos -->
<g transform="translate(425,25)">
<path class="squares-not-expected" d="M0,0 M0,0 M20,20 L30,30 M50,50 M50,50 M70,70 L80,80 M100,100 M100,100"/>
<path class="coverer" d="M20,20 L30,30 M70,70 L80,80"/>
</g>
</svg>

После

Ширина:  |  Высота:  |  Размер: 4.7 KiB

Просмотреть файл

@ -0,0 +1,28 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/licenses/publicdomain/
-->
<svg xmlns="http://www.w3.org/2000/svg" class="reftest-wait">
<title>Test 'stroke-linecap: square' with zero length path segments</title>
<!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=589648 -->
<script>
function run()
{
document.getElementById('path').setAttribute('stroke-linecap', 'butt');
document.documentElement.removeAttribute('class');
}
window.addEventListener("MozReftestInvalidate", run, false);
</script>
<rect width="100%" height="100%" style="fill:lime"/>
<path id="path" stroke="red" stroke-width="200" stroke-linecap="square"
d="M100,100 L100,100"/>
</svg>

После

Ширина:  |  Высота:  |  Размер: 735 B

Просмотреть файл

@ -105,11 +105,6 @@ public:
NS_IMETHOD NotifyRedrawSuspended()=0;
NS_IMETHOD NotifyRedrawUnsuspended()=0;
// Set whether we should stop multiplying matrices when building up
// the current transformation matrix at this frame.
NS_IMETHOD SetMatrixPropagation(PRBool aPropagate)=0;
virtual PRBool GetMatrixPropagation()=0;
/**
* Get this frame's contribution to the rect returned by a GetBBox() call
* that occurred either on this element, or on one of its ancestors.

Просмотреть файл

@ -93,7 +93,7 @@ nsSVGContainerFrame::Init(nsIContent* aContent,
nsIFrame* aParent,
nsIFrame* aPrevInFlow)
{
AddStateBits(NS_STATE_SVG_NONDISPLAY_CHILD | NS_STATE_SVG_PROPAGATE_TRANSFORM);
AddStateBits(NS_STATE_SVG_NONDISPLAY_CHILD);
nsresult rv = nsSVGContainerFrameBase::Init(aContent, aParent, aPrevInFlow);
return rv;
}
@ -103,7 +103,6 @@ nsSVGDisplayContainerFrame::Init(nsIContent* aContent,
nsIFrame* aParent,
nsIFrame* aPrevInFlow)
{
AddStateBits(NS_STATE_SVG_PROPAGATE_TRANSFORM);
if (!(GetStateBits() & NS_STATE_IS_OUTER_SVG)) {
AddStateBits(aParent->GetStateBits() &
(NS_STATE_SVG_NONDISPLAY_CHILD | NS_STATE_SVG_CLIPPATH_CHILD));
@ -283,20 +282,3 @@ nsSVGDisplayContainerFrame::GetBBoxContribution(const gfxMatrix &aToBBoxUserspac
return bboxUnion;
}
NS_IMETHODIMP
nsSVGDisplayContainerFrame::SetMatrixPropagation(PRBool aPropagate)
{
if (aPropagate) {
AddStateBits(NS_STATE_SVG_PROPAGATE_TRANSFORM);
} else {
RemoveStateBits(NS_STATE_SVG_PROPAGATE_TRANSFORM);
}
return NS_OK;
}
PRBool
nsSVGDisplayContainerFrame::GetMatrixPropagation()
{
return (GetStateBits() & NS_STATE_SVG_PROPAGATE_TRANSFORM) != 0;
}

Просмотреть файл

@ -112,8 +112,6 @@ public:
virtual void NotifySVGChanged(PRUint32 aFlags);
NS_IMETHOD NotifyRedrawSuspended();
NS_IMETHOD NotifyRedrawUnsuspended();
NS_IMETHOD SetMatrixPropagation(PRBool aPropagate);
virtual PRBool GetMatrixPropagation();
virtual gfxRect GetBBoxContribution(const gfxMatrix &aToBBoxUserspace);
NS_IMETHOD_(PRBool) IsDisplayContainer() { return PR_TRUE; }
NS_IMETHOD_(PRBool) HasValidCoveredRect() { return PR_FALSE; }

Просмотреть файл

@ -91,9 +91,8 @@ nsSVGForeignObjectFrame::Init(nsIContent* aContent,
#endif
nsresult rv = nsSVGForeignObjectFrameBase::Init(aContent, aParent, aPrevInFlow);
AddStateBits(NS_STATE_SVG_PROPAGATE_TRANSFORM |
(aParent->GetStateBits() &
(NS_STATE_SVG_NONDISPLAY_CHILD | NS_STATE_SVG_CLIPPATH_CHILD)));
AddStateBits(aParent->GetStateBits() &
(NS_STATE_SVG_NONDISPLAY_CHILD | NS_STATE_SVG_CLIPPATH_CHILD));
if (NS_SUCCEEDED(rv)) {
nsSVGUtils::GetOuterSVGFrame(this)->RegisterForeignObject(this);
}
@ -432,23 +431,6 @@ nsSVGForeignObjectFrame::NotifyRedrawUnsuspended()
return NS_OK;
}
NS_IMETHODIMP
nsSVGForeignObjectFrame::SetMatrixPropagation(PRBool aPropagate)
{
if (aPropagate) {
AddStateBits(NS_STATE_SVG_PROPAGATE_TRANSFORM);
} else {
RemoveStateBits(NS_STATE_SVG_PROPAGATE_TRANSFORM);
}
return NS_OK;
}
PRBool
nsSVGForeignObjectFrame::GetMatrixPropagation()
{
return (GetStateBits() & NS_STATE_SVG_PROPAGATE_TRANSFORM) != 0;
}
gfxRect
nsSVGForeignObjectFrame::GetBBoxContribution(const gfxMatrix &aToBBoxUserspace)
{

Просмотреть файл

@ -128,8 +128,6 @@ public:
virtual void NotifySVGChanged(PRUint32 aFlags);
NS_IMETHOD NotifyRedrawSuspended();
NS_IMETHOD NotifyRedrawUnsuspended();
NS_IMETHOD SetMatrixPropagation(PRBool aPropagate);
virtual PRBool GetMatrixPropagation();
virtual gfxRect GetBBoxContribution(const gfxMatrix &aToBBoxUserspace);
NS_IMETHOD_(PRBool) IsDisplayContainer() { return PR_TRUE; }
NS_IMETHOD_(PRBool) HasValidCoveredRect() { return PR_TRUE; }

Просмотреть файл

@ -52,9 +52,8 @@ nsSVGGeometryFrame::Init(nsIContent* aContent,
nsIFrame* aParent,
nsIFrame* aPrevInFlow)
{
AddStateBits((aParent->GetStateBits() &
(NS_STATE_SVG_NONDISPLAY_CHILD | NS_STATE_SVG_CLIPPATH_CHILD)) |
NS_STATE_SVG_PROPAGATE_TRANSFORM);
AddStateBits(aParent->GetStateBits() &
(NS_STATE_SVG_NONDISPLAY_CHILD | NS_STATE_SVG_CLIPPATH_CHILD));
nsresult rv = nsSVGGeometryFrameBase::Init(aContent, aParent, aPrevInFlow);
return rv;
}

Просмотреть файл

@ -491,11 +491,11 @@ nsSVGGlyphFrame::UpdateCoveredRegion()
return NS_OK;
}
SetMatrixPropagation(PR_FALSE);
mPropagateTransform = PR_FALSE;
CharacterIterator iter(this, PR_TRUE);
iter.SetInitialMatrix(tmpCtx);
AddBoundingBoxesToPath(&iter, tmpCtx);
SetMatrixPropagation(PR_TRUE);
mPropagateTransform = PR_TRUE;
tmpCtx->IdentityMatrix();
// Be careful when replacing the following logic to get the fill and stroke
@ -1479,7 +1479,7 @@ nsSVGGlyphFrame::NotifyGlyphMetricsChange()
PRBool
nsSVGGlyphFrame::GetGlobalTransform(gfxMatrix *aMatrix)
{
if (!GetMatrixPropagation()) {
if (!mPropagateTransform) {
aMatrix->Reset();
return PR_TRUE;
}
@ -1635,23 +1635,6 @@ nsSVGGlyphFrame::EnsureTextRun(float *aDrawScale, float *aMetricsScale,
return PR_TRUE;
}
NS_IMETHODIMP
nsSVGGlyphFrame::SetMatrixPropagation(PRBool aPropagate)
{
if (aPropagate) {
AddStateBits(NS_STATE_SVG_PROPAGATE_TRANSFORM);
} else {
RemoveStateBits(NS_STATE_SVG_PROPAGATE_TRANSFORM);
}
return NS_OK;
}
PRBool
nsSVGGlyphFrame::GetMatrixPropagation()
{
return (GetStateBits() & NS_STATE_SVG_PROPAGATE_TRANSFORM) != 0;
}
//----------------------------------------------------------------------
// helper class

Просмотреть файл

@ -66,7 +66,8 @@ protected:
: nsSVGGlyphFrameBase(aContext),
mTextRun(nsnull),
mStartIndex(0),
mWhitespaceHandling(COMPRESS_WHITESPACE)
mWhitespaceHandling(COMPRESS_WHITESPACE),
mPropagateTransform(PR_TRUE)
{}
~nsSVGGlyphFrame()
{
@ -126,8 +127,6 @@ public:
virtual void NotifySVGChanged(PRUint32 aFlags);
NS_IMETHOD NotifyRedrawSuspended();
NS_IMETHOD NotifyRedrawUnsuspended();
NS_IMETHOD SetMatrixPropagation(PRBool aPropagate);
virtual PRBool GetMatrixPropagation();
NS_IMETHOD_(PRBool) IsDisplayContainer() { return PR_FALSE; }
NS_IMETHOD_(PRBool) HasValidCoveredRect() { return PR_TRUE; }
@ -229,6 +228,7 @@ protected:
// The start index into the position and rotation data
PRUint32 mStartIndex;
PRUint8 mWhitespaceHandling;
PRPackedBool mPropagateTransform;
};
#endif

Просмотреть файл

@ -335,23 +335,6 @@ nsSVGPathGeometryFrame::NotifyRedrawUnsuspended()
return NS_OK;
}
NS_IMETHODIMP
nsSVGPathGeometryFrame::SetMatrixPropagation(PRBool aPropagate)
{
if (aPropagate) {
AddStateBits(NS_STATE_SVG_PROPAGATE_TRANSFORM);
} else {
RemoveStateBits(NS_STATE_SVG_PROPAGATE_TRANSFORM);
}
return NS_OK;
}
PRBool
nsSVGPathGeometryFrame::GetMatrixPropagation()
{
return (GetStateBits() & NS_STATE_SVG_PROPAGATE_TRANSFORM) != 0;
}
gfxRect
nsSVGPathGeometryFrame::GetBBoxContribution(const gfxMatrix &aToBBoxUserspace)
{
@ -500,6 +483,12 @@ nsSVGPathGeometryFrame::GeneratePath(gfxContext* aContext,
aContext->Multiply(matrix);
// Hack to let SVGPathData::ConstructPath know if we have square caps:
const nsStyleSVG* style = GetStyleSVG();
if (style->mStrokeLinecap == NS_STYLE_STROKE_LINECAP_SQUARE) {
aContext->SetLineCap(gfxContext::LINE_CAP_SQUARE);
}
aContext->NewPath();
static_cast<nsSVGPathGeometryElement*>(mContent)->ConstructPath(aContext);
}

Просмотреть файл

@ -100,8 +100,6 @@ protected:
virtual void NotifySVGChanged(PRUint32 aFlags);
NS_IMETHOD NotifyRedrawSuspended();
NS_IMETHOD NotifyRedrawUnsuspended();
NS_IMETHOD SetMatrixPropagation(PRBool aPropagate);
virtual PRBool GetMatrixPropagation();
virtual gfxRect GetBBoxContribution(const gfxMatrix &aToBBoxUserspace);
NS_IMETHOD_(PRBool) IsDisplayContainer() { return PR_FALSE; }
NS_IMETHOD_(PRBool) HasValidCoveredRect() { return PR_TRUE; }

Просмотреть файл

@ -98,10 +98,8 @@ class Element;
/* are we the child of a non-display container? */
#define NS_STATE_SVG_NONDISPLAY_CHILD NS_FRAME_STATE_BIT(22)
#define NS_STATE_SVG_PROPAGATE_TRANSFORM NS_FRAME_STATE_BIT(23)
// If this bit is set, we are a <clipPath> element or descendant.
#define NS_STATE_SVG_CLIPPATH_CHILD NS_FRAME_STATE_BIT(24)
#define NS_STATE_SVG_CLIPPATH_CHILD NS_FRAME_STATE_BIT(23)
/**
* Byte offsets of channels in a native packed gfxColor or cairo image surface.

Просмотреть файл

@ -1753,6 +1753,39 @@ pref("gfx.font_rendering.cleartype.use_for_downloadable_fonts", true);
// use cleartype rendering for all fonts always (win xp only)
pref("gfx.font_rendering.cleartype.always_use_for_content", false);
// ClearType tuning parameters for directwrite/d2d.
//
// Allows overriding of underlying registry values in:
// HKCU/Software/Microsoft/Avalon.Graphics/<display> (contrast and level)
// HKLM/Software/Microsoft/Avalon.Graphics/<display> (gamma, pixel structure)
// and selection of the ClearType/antialiasing mode.
//
// A value of -1 implies use the default value, otherwise value ranges
// follow registry settings:
// gamma [1000, 2200] default: based on screen, typically 2200 (== 2.2)
// enhanced contrast [0, 1000] default: 50
// cleartype level [0, 100] default: 100
// pixel structure [0, 2] default: 0 (flat/RGB/BGR)
// rendering mode [0, 5] default: 0
// 0 = use default for font & size;
// 1 = aliased;
// 2 = GDI Classic;
// 3 = GDI Natural Widths;
// 4 = Natural;
// 5 = Natural Symmetric
//
// See:
// http://msdn.microsoft.com/en-us/library/aa970267.aspx
// http://msdn.microsoft.com/en-us/library/dd368190%28v=VS.85%29.aspx
// Note: DirectWrite uses the "Enhanced Contrast Level" value rather than the
// "Text Contrast Level" value
pref("gfx.font_rendering.cleartype_params.gamma", -1);
pref("gfx.font_rendering.cleartype_params.enhanced_contrast", -1);
pref("gfx.font_rendering.cleartype_params.cleartype_level", -1);
pref("gfx.font_rendering.cleartype_params.pixel_structure", -1);
pref("gfx.font_rendering.cleartype_params.rendering_mode", -1);
pref("ui.key.menuAccessKeyFocuses", true);
// override double-click word selection behavior.

Просмотреть файл

@ -4,13 +4,9 @@
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<body>
<iframe id="iframe1" src="crashing_subpage.html" width="600" height="600"></iframe>
<script class="testbody" type="application/javascript">
SimpleTest.waitForExplicitFinish();
var iframe = document.getElementById('iframe1');
window.frameLoaded = function frameLoaded_toCrash() {
if (!SimpleTest.testPluginIsOOP()) {
ok(true, "Skipping this test when test plugin is not OOP.");
@ -18,6 +14,7 @@
return;
}
var iframe = document.getElementById('iframe1');
var p = iframe.contentDocument.getElementById('plugin1');
// This test is for bug 550026, which is inherently nondeterministic.
@ -50,3 +47,4 @@
}
</script>
<iframe id="iframe1" src="crashing_subpage.html" width="600" height="600"></iframe>

Просмотреть файл

@ -4,13 +4,9 @@
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<body>
<iframe id="iframe1" src="crashing_subpage.html" width="600" height="600"></iframe>
<script class="testbody" type="application/javascript">
SimpleTest.waitForExplicitFinish();
var iframe = document.getElementById('iframe1');
window.frameLoaded = function frameLoaded_toCrash() {
if (!SimpleTest.testPluginIsOOP()) {
ok(true, "Skipping this test when test plugin is not OOP.");
@ -18,6 +14,7 @@
return;
}
var iframe = document.getElementById('iframe1');
var p = iframe.contentDocument.getElementById('plugin1');
p.setColor("FFFF00FF");
@ -65,3 +62,4 @@
}
</script>
<iframe id="iframe1" src="crashing_subpage.html" width="600" height="600"></iframe>

Просмотреть файл

@ -4,13 +4,9 @@
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<body>
<iframe id="iframe1" src="crashing_subpage.html" width="600" height="600"></iframe>
<script class="testbody" type="application/javascript">
SimpleTest.waitForExplicitFinish();
var iframe = document.getElementById('iframe1');
window.frameLoaded = function frameLoaded_toCrash() {
if (!SimpleTest.testPluginIsOOP()) {
ok(true, "Skipping this test when test plugin is not OOP.");
@ -26,6 +22,7 @@
var timeoutPref = "dom.ipc.plugins.timeoutSecs";
prefs.setIntPref(timeoutPref, 5);
var iframe = document.getElementById('iframe1');
var p = iframe.contentDocument.getElementById('plugin1');
p.setColor("FFFF00FF");
@ -74,3 +71,4 @@
}
</script>
<iframe id="iframe1" src="crashing_subpage.html" width="600" height="600"></iframe>

Просмотреть файл

@ -225,6 +225,13 @@ getClipRegionRectCount(), this will throw an error. The coordinates are
the same as for getEdge. See getClipRegionRectCount() above for
notes on platform plugin limitations.
== Keyboard events ==
* getLastKeyText()
Returns the text which was inputted by last keyboard events. This is cleared at
every keydown event.
NOTE: Currently, this is implemented only on Windows.
== Mouse events ==
The test plugin supports the following scriptable methods:

Просмотреть файл

@ -165,6 +165,7 @@ static bool getWindowPosition(NPObject* npobj, const NPVariant* args, uint32_t a
static bool constructObject(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
static bool setSitesWithData(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
static bool setSitesWithDataCapabilities(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
static bool getLastKeyText(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
static const NPUTF8* sPluginMethodIdentifierNames[] = {
"npnEvaluateTest",
@ -221,7 +222,8 @@ static const NPUTF8* sPluginMethodIdentifierNames[] = {
"getWindowPosition",
"constructObject",
"setSitesWithData",
"setSitesWithDataCapabilities"
"setSitesWithDataCapabilities",
"getLastKeyText"
};
static NPIdentifier sPluginMethodIdentifiers[ARRAY_LENGTH(sPluginMethodIdentifierNames)];
static const ScriptableFunction sPluginMethodFunctions[] = {
@ -279,7 +281,8 @@ static const ScriptableFunction sPluginMethodFunctions[] = {
getWindowPosition,
constructObject,
setSitesWithData,
setSitesWithDataCapabilities
setSitesWithDataCapabilities,
getLastKeyText
};
STATIC_ASSERT(ARRAY_LENGTH(sPluginMethodIdentifierNames) ==
@ -3436,3 +3439,15 @@ bool setSitesWithDataCapabilities(NPObject* npobj, const NPVariant* args, uint32
return true;
}
bool getLastKeyText(NPObject* npobj, const NPVariant* args, uint32_t argCount,
NPVariant* result)
{
if (argCount != 0) {
return false;
}
NPP npp = static_cast<TestNPObject*>(npobj)->npp;
InstanceData* id = static_cast<InstanceData*>(npp->pdata);
STRINGZ_TO_NPVARIANT(NPN_StrDup(id->lastKeyText.c_str()), *result);
return true;
}

Просмотреть файл

@ -138,6 +138,7 @@ typedef struct InstanceData {
int32_t focusEventCount;
int32_t eventModel;
bool closeStream;
std::string lastKeyText;
} InstanceData;
void notifyDidPaint(InstanceData* instanceData);

Просмотреть файл

@ -458,6 +458,27 @@ handleEventInternal(InstanceData* instanceData, NPEvent* pe, LRESULT* result)
return true;
}
case WM_KEYDOWN:
instanceData->lastKeyText.erase();
*result = 0;
return true;
case WM_CHAR: {
*result = 0;
wchar_t uniChar = static_cast<wchar_t>(pe->wParam);
if (!uniChar) {
return true;
}
char utf8Char[6];
int len =
::WideCharToMultiByte(CP_UTF8, 0, &uniChar, 1, utf8Char, 6, NULL, NULL);
if (len == 0 || len > 6) {
return true;
}
instanceData->lastKeyText.append(utf8Char, len);
return true;
}
default:
return false;
}

Просмотреть файл

@ -14,7 +14,7 @@ function makeEngine() {
}
var syncTesting = new SyncTestingInfrastructure(makeEngine);
function test_ID_caching() {
add_test(function test_ID_caching() {
_("Ensure that Places IDs are not cached.");
let engine = new BookmarksEngine();
@ -50,12 +50,12 @@ function test_ID_caching() {
do_check_eq(newMobileID, store.idForGUID("mobile", false));
do_check_eq(store.GUIDForId(mobileID), "abcdefghijkl");
}
run_next_test();
});
function test_processIncoming_error_orderChildren() {
add_test(function test_processIncoming_error_orderChildren() {
_("Ensure that _orderChildren() is called even when _processIncoming() throws an error.");
do_test_pending();
Svc.Prefs.set("clusterURL", "http://localhost:8080/");
Svc.Prefs.set("username", "foo");
@ -126,16 +126,15 @@ function test_processIncoming_error_orderChildren() {
} finally {
store.wipe();
server.stop(do_test_finished);
Svc.Prefs.resetBranch("");
Records.clearCache();
syncTesting = new SyncTestingInfrastructure(makeEngine);
server.stop(run_next_test);
}
}
});
function test_restorePromptsReupload() {
add_test(function test_restorePromptsReupload() {
_("Ensure that restoring from a backup will reupload all records.");
do_test_pending();
Svc.Prefs.set("username", "foo");
Service.serverURL = "http://localhost:8080/";
Service.clusterURL = "http://localhost:8080/";
@ -266,15 +265,15 @@ function test_restorePromptsReupload() {
} finally {
store.wipe();
server.stop(do_test_finished);
Svc.Prefs.resetBranch("");
Records.clearCache();
syncTesting = new SyncTestingInfrastructure(makeEngine);
server.stop(run_next_test);
}
}
});
// Bug 632287.
function test_mismatched_types() {
add_test(function test_mismatched_types() {
_("Ensure that handling a record that changes type causes deletion " +
"then re-adding.");
@ -309,7 +308,6 @@ function test_mismatched_types() {
"parentid": "toolbar"
};
do_test_pending();
Svc.Prefs.set("username", "foo");
Service.serverURL = "http://localhost:8080/";
Service.clusterURL = "http://localhost:8080/";
@ -351,12 +349,12 @@ function test_mismatched_types() {
} finally {
store.wipe();
server.stop(do_test_finished);
Svc.Prefs.resetBranch("");
Records.clearCache();
syncTesting = new SyncTestingInfrastructure(makeEngine);
server.stop(run_next_test);
}
}
});
function run_test() {
initTestLogging("Trace");
@ -364,8 +362,5 @@ function run_test() {
CollectionKeys.generateNewKeys();
test_processIncoming_error_orderChildren();
test_ID_caching();
test_mismatched_types();
test_restorePromptsReupload();
run_next_test();
}

Просмотреть файл

@ -9,7 +9,7 @@ Cu.import("resource://services-sync/service.js");
const MORE_THAN_CLIENTS_TTL_REFRESH = 691200; // 8 days
const LESS_THAN_CLIENTS_TTL_REFRESH = 86400; // 1 day
function test_bad_hmac() {
add_test(function test_bad_hmac() {
_("Ensure that Clients engine deletes corrupt records.");
let global = new ServerWBO('global',
{engines: {clients: {version: Clients.version,
@ -41,7 +41,6 @@ function test_bad_hmac() {
};
let server = httpd_setup(handlers);
do_test_pending();
try {
let passphrase = "abcdeabcdeabcdeabcdeabcdea";
@ -133,15 +132,15 @@ function test_bad_hmac() {
do_check_false(oldKey.equals(newKey));
} finally {
server.stop(do_test_finished);
Svc.Prefs.resetBranch("");
Records.clearCache();
server.stop(run_next_test);
}
}
});
function test_properties() {
try {
add_test(function test_properties() {
_("Test lastRecordUpload property");
try {
do_check_eq(Svc.Prefs.get("clients.lastRecordUpload"), undefined);
do_check_eq(Clients.lastRecordUpload, 0);
@ -150,10 +149,11 @@ function test_properties() {
do_check_eq(Clients.lastRecordUpload, Math.floor(now / 1000));
} finally {
Svc.Prefs.resetBranch("");
run_next_test();
}
}
});
function test_sync() {
add_test(function test_sync() {
_("Ensure that Clients engine uploads a new client record once a week.");
Svc.Prefs.set("clusterURL", "http://localhost:8080/");
Svc.Prefs.set("username", "foo");
@ -172,8 +172,6 @@ function test_sync() {
server.registerPathHandler(
"/1.1/foo/storage/clients/" + Clients.localID, clientwbo.handler());
do_test_pending();
try {
_("First sync, client record is uploaded");
@ -203,17 +201,14 @@ function test_sync() {
do_check_eq(Clients.lastRecordUpload, yesterday);
} finally {
server.stop(do_test_finished);
Svc.Prefs.resetBranch("");
Records.clearCache();
server.stop(run_next_test);
}
}
});
function run_test() {
initTestLogging("Trace");
Log4Moz.repository.getLogger("Engine.Clients").level = Log4Moz.Level.Trace;
test_bad_hmac();
test_properties();
test_sync();
run_next_test();
}

Просмотреть файл

@ -551,13 +551,22 @@ var gViewController = {
},
loadView: function(aViewId) {
if (aViewId == this.currentViewId)
var isRefresh = false;
if (aViewId == this.currentViewId) {
if (this.isLoading)
return;
if (!("refresh" in this.currentViewObj))
return;
if (!this.currentViewObj.canRefresh())
return;
isRefresh = true;
}
var state = {
view: aViewId,
previousView: this.currentViewId
};
if (!isRefresh)
gHistory.pushState(state);
this.loadViewInternal(aViewId, this.currentViewId, state);
},
@ -598,7 +607,7 @@ var gViewController = {
if (!viewObj.node)
throw new Error("Root node doesn't exist for '" + view.type + "' view");
if (this.currentViewObj) {
if (this.currentViewObj && aViewId != aPreviousView) {
try {
let canHide = this.currentViewObj.hide();
if (canHide === false)
@ -617,6 +626,10 @@ var gViewController = {
this.viewPort.selectedPanel = this.currentViewObj.node;
this.viewPort.selectedPanel.setAttribute("loading", "true");
if (aViewId == aPreviousView)
this.currentViewObj.refresh(view.param, ++this.currentViewRequest, aState);
else
this.currentViewObj.show(view.param, ++this.currentViewRequest, aState);
},
@ -1655,7 +1668,7 @@ var gDiscoverView = {
Ci.nsIWebProgress.NOTIFY_STATE_ALL);
if (self.loaded)
self._loadURL(self.homepageURL.spec, notifyInitialized);
self._loadURL(self.homepageURL.spec, false, notifyInitialized);
else
notifyInitialized();
}
@ -1689,7 +1702,7 @@ var gDiscoverView = {
});
},
show: function(aParam, aRequest, aState) {
show: function(aParam, aRequest, aState, aIsRefresh) {
gViewController.updateCommands();
// If we're being told to load a specific URL then just do that
@ -1698,9 +1711,11 @@ var gDiscoverView = {
this._loadURL(aState.url);
}
// If the view has loaded before and the error page is not visible then
// there is nothing else to do
if (this.loaded && this.node.selectedPanel != this._error) {
// If the view has loaded before and still at the homepage (if refreshing),
// and the error page is not visible then there is nothing else to do
if (this.loaded && this.node.selectedPanel != this._error &&
(!aIsRefresh || (this._browser.currentURI &&
this._browser.currentURI.spec == this._browser.homePage))) {
gViewController.notifyViewChanged();
return;
}
@ -1714,17 +1729,28 @@ var gDiscoverView = {
return;
}
this._loadURL(this.homepageURL.spec,
this._loadURL(this.homepageURL.spec, aIsRefresh,
gViewController.notifyViewChanged.bind(gViewController));
},
canRefresh: function() {
if (this._browser.currentURI &&
this._browser.currentURI.spec == this._browser.homePage)
return false;
return true;
},
refresh: function(aParam, aRequest, aState) {
this.show(aParam, aRequest, aState, true);
},
hide: function() { },
showError: function() {
this.node.selectedPanel = this._error;
},
_loadURL: function(aURL, aCallback) {
_loadURL: function(aURL, aKeepHistory, aCallback) {
if (this._browser.currentURI.spec == aURL) {
if (aCallback)
aCallback();
@ -1734,8 +1760,11 @@ var gDiscoverView = {
if (aCallback)
this._loadListeners.push(aCallback);
this._browser.loadURIWithFlags(aURL,
Ci.nsIWebNavigation.LOAD_FLAGS_REPLACE_HISTORY);
var flags = 0;
if (!aKeepHistory)
flags |= Ci.nsIWebNavigation.LOAD_FLAGS_REPLACE_HISTORY;
this._browser.loadURIWithFlags(aURL, flags);
},
onLocationChange: function(aWebProgress, aRequest, aLocation) {

Просмотреть файл

@ -844,3 +844,63 @@ add_test(function() {
});
}, true);
});
// Tests that refreshing the disicovery pane integrates properly with history
add_test(function() {
open_manager("addons://list/plugin", function(aManager) {
is_in_list(aManager, "addons://list/plugin", false, false);
EventUtils.synthesizeMouseAtCenter(aManager.document.getElementById("category-discover"), { }, aManager);
wait_for_view_load(aManager, function(aManager) {
is_in_discovery(aManager, MAIN_URL, true, false);
clickLink(aManager, "link-good", function() {
is_in_discovery(aManager, SECOND_URL, true, false);
EventUtils.synthesizeMouseAtCenter(aManager.document.getElementById("category-discover"), { }, aManager);
waitForLoad(aManager, function() {
is_in_discovery(aManager, MAIN_URL, true, false);
go_back(aManager);
waitForLoad(aManager, function() {
is_in_discovery(aManager, SECOND_URL, true, true);
go_back(aManager);
waitForLoad(aManager, function() {
is_in_discovery(aManager, MAIN_URL, true, true);
go_back(aManager);
wait_for_view_load(aManager, function(aManager) {
is_in_list(aManager, "addons://list/plugin", false, true);
go_forward(aManager);
wait_for_view_load(aManager, function(aManager) {
is_in_discovery(aManager, MAIN_URL, true, true);
waitForLoad(aManager, function() {
is_in_discovery(aManager, SECOND_URL, true, true);
waitForLoad(aManager, function() {
is_in_discovery(aManager, MAIN_URL, true, false);
close_manager(aManager, run_next_test);
});
go_forward(aManager);
});
go_forward(aManager);
});
});
});
});
});
});
});
});
});

Просмотреть файл

@ -410,7 +410,7 @@ add_test(function() {
gCategoryUtilities.openType("extension", function() {
gCategoryUtilities.openType("discover", function() {
is(getURL(browser), "https://example.com/" + RELATIVE_DIR + "releaseNotes.xhtml", "Should have loaded the right url");
is(getURL(browser), MAIN_URL, "Should have loaded the right url");
close_manager(gManagerWindow, run_next_test);
});

189
toolkit/xre/EventTracer.cpp Normal file
Просмотреть файл

@ -0,0 +1,189 @@
/* ***** 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.org code.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ted Mielczarek <ted.mielczarek@gmail.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 ***** */
/*
* Event loop instrumentation. This code attempts to measure the
* latency of the UI-thread event loop by firing native events at it from
* a background thread, and measuring how long it takes for them
* to be serviced. The measurement interval (kMeasureInterval, below)
* is also used as the upper bound of acceptable response time.
* When an event takes longer than that interval to be serviced,
* a sample will be written to the log.
*
* Usage:
*
* Set MOZ_INSTRUMENT_EVENT_LOOP=1 in the environment to enable
* this instrumentation. Currently only the UI process is instrumented.
*
* Set MOZ_INSTRUMENT_EVENT_LOOP_OUTPUT in the environment to a
* file path to contain the log output, the default is to log to stdout.
*
* All logged output lines start with MOZ_EVENT_TRACE. All timestamps
* output are milliseconds since the epoch (PRTime / 1000).
*
* On startup, a line of the form:
* MOZ_EVENT_TRACE start <timestamp>
* will be output.
*
* On shutdown, a line of the form:
* MOZ_EVENT_TRACE stop <timestamp>
* will be output.
*
* When an event servicing time exceeds the threshold, a line of the form:
* MOZ_EVENT_TRACE sample <timestamp> <duration>
* will be output, where <duration> is the number of milliseconds that
* it took for the event to be serviced.
*/
#include "EventTracer.h"
#include <stdio.h>
#include "mozilla/TimeStamp.h"
#include "mozilla/WidgetTraceEvent.h"
#include <prenv.h>
#include <prinrval.h>
#include <prthread.h>
#include <prtime.h>
using mozilla::TimeDuration;
using mozilla::TimeStamp;
using mozilla::FireAndWaitForTracerEvent;
namespace {
PRThread* sTracerThread = NULL;
bool sExit = false;
/*
* The tracer thread fires events at the native event loop roughly
* every kMeasureInterval. It will sleep to attempt not to send them
* more quickly, but if the response time is longer than kMeasureInterval
* it will not send another event until the previous response is received.
*
* The output defaults to stdout, but can be redirected to a file by
* settting the environment variable MOZ_INSTRUMENT_EVENT_LOOP_OUTPUT
* to the name of a file to use.
*/
void TracerThread(void *arg)
{
// This should be set to the maximum latency we'd like to allow
// for responsiveness.
const PRIntervalTime kMeasureInterval = PR_MillisecondsToInterval(50);
FILE* log = NULL;
char* envfile = PR_GetEnv("MOZ_INSTRUMENT_EVENT_LOOP_OUTPUT");
if (envfile) {
log = fopen(envfile, "w");
}
if (log == NULL)
log = stdout;
fprintf(log, "MOZ_EVENT_TRACE start %llu\n", PR_Now() / PR_USEC_PER_MSEC);
while (!sExit) {
TimeStamp start(TimeStamp::Now());
PRIntervalTime next_sleep = kMeasureInterval;
//TODO: only wait up to a maximum of kMeasureInterval, return
// early if that threshold is exceeded and dump a stack trace
// or do something else useful.
if (FireAndWaitForTracerEvent()) {
TimeDuration duration = TimeStamp::Now() - start;
// Only report samples that exceed our measurement interval.
if (duration.ToMilliseconds() > kMeasureInterval) {
fprintf(log, "MOZ_EVENT_TRACE sample %llu %d\n",
PR_Now() / PR_USEC_PER_MSEC,
int(duration.ToSecondsSigDigits() * 1000));
}
if (next_sleep > duration.ToMilliseconds()) {
next_sleep -= int(duration.ToMilliseconds());
}
else {
// Don't sleep at all if this event took longer than the measure
// interval to deliver.
next_sleep = 0;
}
}
if (next_sleep != 0 && !sExit) {
PR_Sleep(next_sleep);
}
}
fprintf(log, "MOZ_EVENT_TRACE stop %llu\n", PR_Now() / PR_USEC_PER_MSEC);
if (log != stdout)
fclose(log);
}
} // namespace
namespace mozilla {
bool InitEventTracing()
{
// Initialize the widget backend.
if (!InitWidgetTracing())
return false;
// Create a thread that will fire events back at the
// main thread to measure responsiveness.
NS_ABORT_IF_FALSE(!sTracerThread, "Event tracing already initialized!");
sTracerThread = PR_CreateThread(PR_USER_THREAD,
TracerThread,
NULL,
PR_PRIORITY_NORMAL,
PR_GLOBAL_THREAD,
PR_JOINABLE_THREAD,
0);
return sTracerThread != NULL;
}
void ShutdownEventTracing()
{
sExit = true;
if (sTracerThread)
PR_JoinThread(sTracerThread);
sTracerThread = NULL;
// Allow the widget backend to clean up.
CleanUpWidgetTracing();
}
} // namespace mozilla

54
toolkit/xre/EventTracer.h Normal file
Просмотреть файл

@ -0,0 +1,54 @@
/* ***** 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.org code.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ted Mielczarek <ted.mielczarek@gmail.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 ***** */
#ifndef XRE_EVENTTRACER_H_
#define XRE_EVENTTRACER_H_
namespace mozilla {
// Create a thread that will fire events back at the
// main thread to measure responsiveness. Return true
// if the thread was created successfully.
bool InitEventTracing();
// Signal the background thread to stop, and join it.
// Must be called from the same thread that called InitEventTracing.
void ShutdownEventTracing();
} // namespace mozilla
#endif /* XRE_EVENTTRACER_H_ */

Просмотреть файл

@ -88,6 +88,8 @@ private:
static PRBool sProcessedGetURLEvent = PR_FALSE;
@class GeckoNSApplication;
// Methods that can be called from non-Objective-C code.
// This is needed, on relaunch, to force the OS to use the "Cocoa Dock API"
@ -97,7 +99,7 @@ EnsureUseCocoaDockAPI()
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
[NSApplication sharedApplication];
[GeckoNSApplication sharedApplication];
NS_OBJC_END_TRY_ABORT_BLOCK;
}
@ -112,7 +114,7 @@ SetupMacApplicationDelegate()
AutoAutoreleasePool pool;
// Ensure that ProcessPendingGetURLAppleEvents() doesn't regress bug 377166.
[NSApplication sharedApplication];
[GeckoNSApplication sharedApplication];
// This call makes it so that application:openFile: doesn't get bogus calls
// from Cocoa doing its own parsing of the argument string. And yes, we need

Просмотреть файл

@ -66,6 +66,10 @@ CPPSRCS = \
nsSigHandlers.cpp \
$(NULL)
ifdef MOZ_INSTRUMENT_EVENT_LOOP
CPPSRCS += EventTracer.cpp
endif
ifdef MOZ_SPLASHSCREEN
ifeq ($(OS_ARCH),WINCE)
CPPSRCS += nsSplashScreenWin.cpp

Просмотреть файл

@ -62,6 +62,10 @@ using mozilla::dom::ContentParent;
#include "nsAppRunner.h"
#include "nsUpdateDriver.h"
#ifdef MOZ_INSTRUMENT_EVENT_LOOP
#include "EventTracer.h"
#endif
#ifdef XP_MACOSX
#include "MacLaunchHelper.h"
#include "MacApplicationDelegate.h"
@ -3744,6 +3748,13 @@ XRE_main(int argc, char* argv[], const nsXREAppData* aAppData)
nativeApp->Enable();
}
#ifdef MOZ_INSTRUMENT_EVENT_LOOP
bool event_tracing_running = false;
if (PR_GetEnv("MOZ_INSTRUMENT_EVENT_LOOP")) {
event_tracing_running = mozilla::InitEventTracing();
}
#endif /* MOZ_INSTRUMENT_EVENT_LOOP */
NS_TIME_FUNCTION_MARK("Next: Run");
NS_TIME_FUNCTION_MARK("appStartup->Run");
@ -3763,6 +3774,11 @@ XRE_main(int argc, char* argv[], const nsXREAppData* aAppData)
NS_TIME_FUNCTION_MARK("appStartup->Run done");
#ifdef MOZ_INSTRUMENT_EVENT_LOOP
if (event_tracing_running)
mozilla::ShutdownEventTracing();
#endif
// Check for an application initiated restart. This is one that
// corresponds to nsIAppStartup.quit(eRestart)
if (rv == NS_SUCCESS_RESTART_APP)

Просмотреть файл

@ -52,6 +52,12 @@ EXPORTS_IPC = \
nsGUIEventIPC.h \
$(NULL)
ifdef MOZ_INSTRUMENT_EVENT_LOOP
EXPORTS_NAMESPACES += mozilla
EXPORTS_mozilla = \
WidgetTraceEvent.h
endif
EXPORTS = \
nsIWidget.h \
nsGUIEvent.h \

Просмотреть файл

@ -0,0 +1,60 @@
/* ***** 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.org code.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ted Mielczarek <ted.mielczarek@gmail.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 ***** */
#ifndef WIDGET_PUBLIC_WIDGETTRACEEVENT_H_
#define WIDGET_PUBLIC_WIDGETTRACEEVENT_H_
namespace mozilla {
// Perform any required initialization in the widget backend for
// event tracing. Return true if initialization was successful.
bool InitWidgetTracing();
// Perform any required cleanup in the widget backend for event tracing.
void CleanUpWidgetTracing();
// Fire a tracer event at the UI-thread event loop, and block until
// the event is processed. This should only be called by
// a thread that's not the UI thread.
bool FireAndWaitForTracerEvent();
// Signal that the event has been received by the event loop.
void SignalTracerThread();
}
#endif // WIDGET_PUBLIC_WIDGETTRACEEVENT_H_

Просмотреть файл

@ -1826,7 +1826,8 @@ inline PRBool NS_IsEventUsingCoordinates(nsEvent* aEvent)
inline PRBool NS_IsEventTargetedAtFocusedWindow(nsEvent* aEvent)
{
return NS_IS_KEY_EVENT(aEvent) || NS_IS_IME_RELATED_EVENT(aEvent) ||
NS_IS_CONTEXT_MENU_KEY(aEvent) || NS_IS_CONTENT_COMMAND_EVENT(aEvent);
NS_IS_CONTEXT_MENU_KEY(aEvent) ||
NS_IS_CONTENT_COMMAND_EVENT(aEvent) || NS_IS_PLUGIN_EVENT(aEvent);
}
/**

Просмотреть файл

@ -0,0 +1,51 @@
/* ***** 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.org code.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ted Mielczarek <ted.mielczarek@gmail.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 ***** */
/*
* This file defines constants to be used in the "subtype" field of
* NSApplicationDefined type NSEvents.
*/
#ifndef WIDGET_COCOA_CUSTOMCOCOAEVENTS_H_
#define WIDGET_COCOA_CUSTOMCOCOAEVENTS_H_
// Empty event, just used for prodding the event loop into responding.
const short kEventSubtypeNone = 0;
// Tracer event, used for timing the event loop responsiveness.
const short kEventSubtypeTrace = 1;
#endif /* WIDGET_COCOA_CUSTOMCOCOAEVENTS_H_ */

Просмотреть файл

@ -93,6 +93,7 @@ CMMSRCS = \
nsMacDockSupport.mm \
nsStandaloneNativeMenu.mm \
GfxInfo.mm \
WidgetTraceEvent.mm \
$(NULL)
ifeq (x86_64,$(TARGET_CPU))

Просмотреть файл

@ -0,0 +1,110 @@
/* ***** 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.org code.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ted Mielczarek <ted.mielczarek@gmail.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 <Cocoa/Cocoa.h>
#include "CustomCocoaEvents.h"
#include <Foundation/NSAutoreleasePool.h>
#include <mozilla/CondVar.h>
#include <mozilla/Mutex.h>
#include "mozilla/WidgetTraceEvent.h"
using mozilla::CondVar;
using mozilla::Mutex;
using mozilla::MutexAutoLock;
namespace {
Mutex* sMutex = NULL;
CondVar* sCondVar = NULL;
bool sTracerProcessed = false;
}
namespace mozilla {
bool InitWidgetTracing()
{
sMutex = new Mutex("Event tracer thread mutex");
sCondVar = new CondVar(*sMutex, "Event tracer thread condvar");
return sMutex && sCondVar;
}
void CleanUpWidgetTracing()
{
delete sMutex;
delete sCondVar;
sMutex = NULL;
sCondVar = NULL;
}
// This function is called from the main (UI) thread.
void SignalTracerThread()
{
MutexAutoLock lock(*sMutex);
NS_ABORT_IF_FALSE(!sTracerProcessed, "Tracer synchronization state is wrong");
sTracerProcessed = true;
sCondVar->Notify();
}
// This function is called from the background tracer thread.
bool FireAndWaitForTracerEvent()
{
NS_ABORT_IF_FALSE(sMutex && sCondVar, "Tracing not initialized!");
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
MutexAutoLock lock(*sMutex);
NS_ABORT_IF_FALSE(!sTracerProcessed, "Tracer synchronization state is wrong");
// Post an application-defined event to the main thread's event queue
// and wait for it to get processed.
[NSApp postEvent:[NSEvent otherEventWithType:NSApplicationDefined
location:NSMakePoint(0,0)
modifierFlags:0
timestamp:0
windowNumber:0
context:NULL
subtype:kEventSubtypeTrace
data1:0
data2:0]
atStart:NO];
while (!sTracerProcessed)
sCondVar->Wait();
sTracerProcessed = false;
[pool release];
return true;
}
} // namespace mozilla

Просмотреть файл

@ -43,6 +43,8 @@
#import <Cocoa/Cocoa.h>
#include <dlfcn.h>
#include "CustomCocoaEvents.h"
#include "mozilla/WidgetTraceEvent.h"
#include "nsAppShell.h"
#include "nsCOMPtr.h"
#include "nsIFile.h"
@ -169,6 +171,27 @@ PRBool nsCocoaAppModalWindowList::GeckoModalAboveCocoaModal()
return (topItem.mWidget != nsnull);
}
// GeckoNSApplication
//
// Subclass of NSApplication for filtering out certain events.
@interface GeckoNSApplication : NSApplication
{
}
@end
@implementation GeckoNSApplication
- (void)sendEvent:(NSEvent *)anEvent
{
if ([anEvent type] == NSApplicationDefined &&
[anEvent subtype] == kEventSubtypeTrace) {
mozilla::SignalTracerThread();
return;
}
[super sendEvent:anEvent];
}
@end
// AppShellDelegate
//
// Cocoa bridge class. An object of this class is registered to receive
@ -286,7 +309,7 @@ nsAppShell::Init()
[NSBundle loadNibFile:
[NSString stringWithUTF8String:(const char*)nibPath.get()]
externalNameTable:
[NSDictionary dictionaryWithObject:[NSApplication sharedApplication]
[NSDictionary dictionaryWithObject:[GeckoNSApplication sharedApplication]
forKey:@"NSOwner"]
withZone:NSDefaultMallocZone()];
@ -388,7 +411,7 @@ nsAppShell::ProcessGeckoEvents(void* aInfo)
timestamp:0
windowNumber:0
context:NULL
subtype:0
subtype:kEventSubtypeNone
data1:0
data2:0]
atStart:NO];
@ -410,7 +433,7 @@ nsAppShell::ProcessGeckoEvents(void* aInfo)
timestamp:0
windowNumber:0
context:NULL
subtype:0
subtype:kEventSubtypeNone
data1:0
data2:0]
atStart:NO];

Просмотреть файл

@ -5649,6 +5649,15 @@ static const char* ToEscapedString(NSString* aString, nsCAutoString& aBuf)
return;
}
}
// Don't send complex text input to a plugin in Cocoa event mode if
// either the Control key or the Command key is pressed -- even if the
// plugin has requested it, or we are already in IME composition. This
// conforms to our behavior in 64-bit mode and fixes bug 619217.
NSUInteger modifierFlags = [theEvent modifierFlags];
if ((modifierFlags & NSControlKeyMask) || (modifierFlags & NSCommandKeyMask)) {
return;
}
}
// This will take care of all Carbon plugin events and also send Cocoa plugin

Просмотреть файл

@ -78,6 +78,7 @@ CPPSRCS = \
nsImageToPixbuf.cpp \
nsAccessibilityHelper.cpp \
nsGtkIMModule.cpp \
WidgetTraceEvent.cpp \
$(NULL)
ifdef MOZ_X11

Просмотреть файл

@ -0,0 +1,103 @@
/* ***** 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.org code.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ted Mielczarek <ted.mielczarek@gmail.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 "mozilla/WidgetTraceEvent.h"
#include <glib.h>
#include <mozilla/CondVar.h>
#include <mozilla/Mutex.h>
#include <stdio.h>
using mozilla::CondVar;
using mozilla::Mutex;
using mozilla::MutexAutoLock;
namespace {
Mutex* sMutex = NULL;
CondVar* sCondVar = NULL;
bool sTracerProcessed = false;
// This function is called from the main (UI) thread.
gboolean TracerCallback(gpointer data)
{
MutexAutoLock lock(*sMutex);
NS_ABORT_IF_FALSE(!sTracerProcessed, "Tracer synchronization state is wrong");
sTracerProcessed = true;
sCondVar->Notify();
return FALSE;
}
} // namespace
namespace mozilla {
bool InitWidgetTracing()
{
sMutex = new Mutex("Event tracer thread mutex");
sCondVar = new CondVar(*sMutex, "Event tracer thread condvar");
return sMutex && sCondVar;
}
void CleanUpWidgetTracing()
{
delete sMutex;
delete sCondVar;
sMutex = NULL;
sCondVar = NULL;
}
// This function is called from the background tracer thread.
bool FireAndWaitForTracerEvent()
{
NS_ABORT_IF_FALSE(sMutex && sCondVar, "Tracing not initialized!");
// Send a default-priority idle event through the
// event loop, and wait for it to finish.
MutexAutoLock lock(*sMutex);
NS_ABORT_IF_FALSE(!sTracerProcessed, "Tracer synchronization state is wrong");
g_idle_add_full(G_PRIORITY_DEFAULT,
TracerCallback,
NULL,
NULL);
while (!sTracerProcessed)
sCondVar->Wait();
sTracerProcessed = false;
return true;
}
} // namespace mozilla

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше