зеркало из https://github.com/mozilla/pjs.git
merge m-c to devtools
This commit is contained in:
Коммит
133619c33d
|
@ -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
|
||||
|
|
14
configure.in
14
configure.in
|
@ -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],
|
||||
mData[i+3] != 0, mData[i+4] != 0);
|
||||
while (converter.GetNextSegment(&cp1, &cp2, &end)) {
|
||||
aCtx->CurveTo(cp1, cp2, end);
|
||||
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, &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);
|
||||
|
@ -8215,33 +8216,6 @@ nsDocShell::InternalLoad(nsIURI * aURI,
|
|||
mAllowKeywordFixup =
|
||||
(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);
|
||||
#ifdef DEBUG
|
||||
if (allowScroll) {
|
||||
nsCOMPtr<nsIInputStream> currentPostData;
|
||||
mOSHE->GetPostData(getter_AddRefs(currentPostData));
|
||||
NS_ASSERTION(currentPostData == aPostData,
|
||||
"Different POST data for entries for the same page?");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (aLoadType == LOAD_NORMAL ||
|
||||
aLoadType == LOAD_STOP_CONTENT ||
|
||||
|
@ -8249,40 +8223,81 @@ nsDocShell::InternalLoad(nsIURI * aURI,
|
|||
aLoadType == LOAD_HISTORY ||
|
||||
aLoadType == LOAD_LINK) {
|
||||
|
||||
PRBool wasAnchor = PR_FALSE;
|
||||
PRBool doHashchange = PR_FALSE;
|
||||
// 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);
|
||||
|
||||
// Get the position of the scrollers.
|
||||
nscoord cx = 0, cy = 0;
|
||||
GetCurScrollPos(ScrollOrientation_X, &cx);
|
||||
GetCurScrollPos(ScrollOrientation_Y, &cy);
|
||||
PRBool sameExceptHashes = NS_SUCCEEDED(splitRv1) &&
|
||||
NS_SUCCEEDED(splitRv2) &&
|
||||
curBeforeHash.Equals(newBeforeHash);
|
||||
|
||||
if (allowScroll) {
|
||||
NS_ENSURE_SUCCESS(ScrollIfAnchor(aURI, &wasAnchor, aLoadType,
|
||||
&doHashchange),
|
||||
NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
// 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);
|
||||
// We're doing a history load.
|
||||
|
||||
PRUint64 ourDocIdent, otherDocIdent;
|
||||
mOSHE->GetDocIdentifier(&ourDocIdent);
|
||||
aSHEntry->GetDocIdentifier(&otherDocIdent);
|
||||
sameDocIdent = (ourDocIdent == otherDocIdent);
|
||||
|
||||
#ifdef DEBUG
|
||||
if (sameDocIdent) {
|
||||
nsCOMPtr<nsIInputStream> currentPostData;
|
||||
mOSHE->GetPostData(getter_AddRefs(currentPostData));
|
||||
NS_ASSERTION(currentPostData == aPostData,
|
||||
"Different POST data for entries for the same page?");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// 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.
|
||||
// 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
|
||||
//
|
||||
// (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))) {
|
||||
// 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());
|
||||
|
||||
// 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);
|
||||
|
||||
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);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
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,17 +45,19 @@ SimpleTest.waitForFocus(function() {
|
|||
t.addEventListener("input", function() {
|
||||
t.removeEventListener("input", arguments.callee, false);
|
||||
|
||||
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");
|
||||
is(t.selectionEnd, 9, "Select all should set the selection end to the end of textarea");
|
||||
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");
|
||||
is(t.selectionEnd, 9, "Select all should set the selection end to the end of textarea");
|
||||
|
||||
var afterPaste = snapshotWindow(window);
|
||||
var afterPaste = snapshotWindow(window);
|
||||
|
||||
var res = compareSnapshots(afterSetValue, afterPaste, true);
|
||||
ok(res[0], "Pasting and setting the value directly should result in the same rendering");
|
||||
var res = compareSnapshots(afterSetValue, afterPaste, true);
|
||||
ok(res[0], "Pasting and setting the value directly should result in the same rendering");
|
||||
|
||||
SimpleTest.finish();
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -176,7 +176,7 @@ cairo_d2d_create_device_from_d3d10device(ID3D10Device1 *d3d10device)
|
|||
CD3D10_BUFFER_DESC bufferDesc(sizeof(vertices), D3D10_BIND_VERTEX_BUFFER);
|
||||
D3D10_SUBRESOURCE_DATA data;
|
||||
CD3D10_TEXTURE2D_DESC textDesc(DXGI_FORMAT_B8G8R8A8_UNORM,
|
||||
TEXT_TEXTURE_WIDTH,
|
||||
TEXT_TEXTURE_WIDTH,
|
||||
TEXT_TEXTURE_HEIGHT,
|
||||
1, 1);
|
||||
|
||||
|
@ -352,10 +352,10 @@ cairo_release_device(cairo_device_t *device)
|
|||
if (!newrefcnt) {
|
||||
// Call the correct destructor
|
||||
cairo_d2d_device_t *d2d_device = reinterpret_cast<cairo_d2d_device_t*>(device);
|
||||
HMODULE d3d10_1 = d2d_device->mD3D10_1;
|
||||
HMODULE d3d10_1 = d2d_device->mD3D10_1;
|
||||
delete d2d_device;
|
||||
_cairo_d2d_release_factory();
|
||||
FreeLibrary(d3d10_1);
|
||||
FreeLibrary(d3d10_1);
|
||||
}
|
||||
return newrefcnt;
|
||||
}
|
||||
|
@ -779,7 +779,7 @@ _cairo_d2d_get_buffer_texture(cairo_d2d_surface_t *surface)
|
|||
surface->surface->QueryInterface(&surf);
|
||||
surf->GetDesc(&surfDesc);
|
||||
CD3D10_TEXTURE2D_DESC softDesc(surfDesc.Format, surfDesc.Width, surfDesc.Height);
|
||||
softDesc.MipLevels = 1;
|
||||
softDesc.MipLevels = 1;
|
||||
softDesc.Usage = D3D10_USAGE_DEFAULT;
|
||||
softDesc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
|
||||
surface->device->mD3D10Device->CreateTexture2D(&softDesc, NULL, &surface->bufferTexture);
|
||||
|
@ -1158,9 +1158,9 @@ _cairo_d2d_create_strokestyle_for_stroke_style(const cairo_stroke_style_t *style
|
|||
(FLOAT)style->miter_limit,
|
||||
dashStyle,
|
||||
(FLOAT)style->dash_offset),
|
||||
dashes,
|
||||
style->num_dashes,
|
||||
&strokeStyle);
|
||||
dashes,
|
||||
style->num_dashes,
|
||||
&strokeStyle);
|
||||
delete [] dashes;
|
||||
return strokeStyle;
|
||||
}
|
||||
|
@ -1225,7 +1225,7 @@ static void _d2d_snapshot_detached(cairo_surface_t *surface)
|
|||
}
|
||||
if (!--existingBitmap->refs) {
|
||||
cache_usage -= _d2d_compute_bitmap_mem_size(existingBitmap->bitmap);
|
||||
delete existingBitmap;
|
||||
delete existingBitmap;
|
||||
}
|
||||
cairo_surface_destroy(surface);
|
||||
}
|
||||
|
@ -1463,8 +1463,8 @@ _cairo_d2d_create_radial_gradient_brush(cairo_d2d_surface_t *d2dsurf,
|
|||
} else if (source_pattern->base.base.extend == CAIRO_EXTEND_NONE) {
|
||||
float offset_factor = (outer_radius - inner_radius) / outer_radius;
|
||||
float global_offset = inner_radius / outer_radius;
|
||||
|
||||
num_stops++; // Add a stop on the outer radius.
|
||||
|
||||
num_stops++; // Add a stop on the outer radius.
|
||||
if (inner_radius != 0) {
|
||||
num_stops++; // Add a stop on the inner radius.
|
||||
}
|
||||
|
@ -1572,11 +1572,11 @@ _cairo_d2d_create_linear_gradient_brush(cairo_d2d_surface_t *d2dsurf,
|
|||
|
||||
double max_dist, min_dist;
|
||||
max_dist = MAX(_cairo_d2d_dot_product(u, _cairo_d2d_subtract_point(top_left, p1)),
|
||||
_cairo_d2d_dot_product(u, _cairo_d2d_subtract_point(top_right, p1)));
|
||||
_cairo_d2d_dot_product(u, _cairo_d2d_subtract_point(top_right, p1)));
|
||||
max_dist = MAX(max_dist, _cairo_d2d_dot_product(u, _cairo_d2d_subtract_point(bottom_left, p1)));
|
||||
max_dist = MAX(max_dist, _cairo_d2d_dot_product(u, _cairo_d2d_subtract_point(bottom_right, p1)));
|
||||
min_dist = MIN(_cairo_d2d_dot_product(u, _cairo_d2d_subtract_point(top_left, p1)),
|
||||
_cairo_d2d_dot_product(u, _cairo_d2d_subtract_point(top_right, p1)));
|
||||
_cairo_d2d_dot_product(u, _cairo_d2d_subtract_point(top_right, p1)));
|
||||
min_dist = MIN(min_dist, _cairo_d2d_dot_product(u, _cairo_d2d_subtract_point(bottom_left, p1)));
|
||||
min_dist = MIN(min_dist, _cairo_d2d_dot_product(u, _cairo_d2d_subtract_point(bottom_right, p1)));
|
||||
|
||||
|
@ -1758,7 +1758,7 @@ _cairo_d2d_create_brush_for_pattern(cairo_d2d_surface_t *d2dsurf,
|
|||
*/
|
||||
return NULL;
|
||||
}
|
||||
if (srcSurf->device != d2dsurf->device) {
|
||||
if (srcSurf->device != d2dsurf->device) {
|
||||
/* This code does not work if the source surface does not use
|
||||
* the same device. Some work could be done to do something
|
||||
* fairly efficient here, for now, fallback.
|
||||
|
@ -1830,7 +1830,7 @@ _cairo_d2d_create_brush_for_pattern(cairo_d2d_surface_t *d2dsurf,
|
|||
/* First we check which part of the image is inside the viewable area. */
|
||||
_cairo_d2d_calculate_visible_rect(d2dsurf, srcSurf, &mat, &xoffset, &yoffset, &width, &height);
|
||||
|
||||
cairo_matrix_translate(&mat, xoffset, yoffset);
|
||||
cairo_matrix_translate(&mat, xoffset, yoffset);
|
||||
|
||||
if (width > maxSize || height > maxSize) {
|
||||
/*
|
||||
|
@ -1840,11 +1840,11 @@ _cairo_d2d_create_brush_for_pattern(cairo_d2d_surface_t *d2dsurf,
|
|||
* We need to size it to at least the diagonal size of this surface, in order to prevent ever
|
||||
* upsampling this again when drawing it to the surface. We want the resized surface
|
||||
* to be as small as possible to limit pixman required fill rate.
|
||||
*
|
||||
* Note this isn't necessarily perfect. Imagine having a 5x5 pixel destination and
|
||||
* a 10x5 image containing a line of blackpixels, white pixels, black pixels, if you rotate
|
||||
* this by 45 degrees and scale it to a size of 5x5 pixels and composite it to the destination,
|
||||
* the composition will require all 10 original columns to do the best possible sampling.
|
||||
*
|
||||
* Note this isn't necessarily perfect. Imagine having a 5x5 pixel destination and
|
||||
* a 10x5 image containing a line of blackpixels, white pixels, black pixels, if you rotate
|
||||
* this by 45 degrees and scale it to a size of 5x5 pixels and composite it to the destination,
|
||||
* the composition will require all 10 original columns to do the best possible sampling.
|
||||
*/
|
||||
RefPtr<IDXGISurface> surf;
|
||||
d2dsurf->surface->QueryInterface(&surf);
|
||||
|
@ -1978,10 +1978,10 @@ _cairo_d2d_create_brush_for_pattern(cairo_d2d_surface_t *d2dsurf,
|
|||
cachebitmap->dirty = false;
|
||||
cachebitmap->bitmap = sourceBitmap;
|
||||
cachebitmap->device = d2dsurf->device;
|
||||
/*
|
||||
* This will start out with two references, one on the snapshot
|
||||
* and one more in the user data structure.
|
||||
*/
|
||||
/*
|
||||
* This will start out with two references, one on the snapshot
|
||||
* and one more in the user data structure.
|
||||
*/
|
||||
cachebitmap->refs = 2;
|
||||
cairo_surface_set_user_data(surfacePattern->surface,
|
||||
key,
|
||||
|
@ -2272,7 +2272,7 @@ _cairo_d2d_clear (cairo_d2d_surface_t *d2dsurf,
|
|||
|
||||
d2dsurf->rt->PushAxisAlignedClip(
|
||||
D2D1::RectF((FLOAT)rect.x,
|
||||
(FLOAT)rect.y,
|
||||
(FLOAT)rect.y,
|
||||
(FLOAT)rect.x + rect.width,
|
||||
(FLOAT)rect.y + rect.height),
|
||||
D2D1_ANTIALIAS_MODE_ALIASED);
|
||||
|
@ -2288,7 +2288,7 @@ _cairo_d2d_clear (cairo_d2d_surface_t *d2dsurf,
|
|||
}
|
||||
|
||||
static cairo_operator_t _cairo_d2d_simplify_operator(cairo_operator_t op,
|
||||
const cairo_pattern_t *source)
|
||||
const cairo_pattern_t *source)
|
||||
{
|
||||
if (op == CAIRO_OPERATOR_SOURCE) {
|
||||
/** Operator over is easier for D2D! If the source if opaque, change */
|
||||
|
@ -2655,7 +2655,7 @@ _cairo_d2d_copy_surface(cairo_d2d_surface_t *dst,
|
|||
src->device->mD3D10Device->CopyResource(srcResource, src->surface);
|
||||
} else {
|
||||
// Need to flush the source too if it's a different surface.
|
||||
_cairo_d2d_flush(src);
|
||||
_cairo_d2d_flush(src);
|
||||
}
|
||||
|
||||
// One copy for each rectangle in the final clipping region.
|
||||
|
@ -2705,7 +2705,7 @@ _cairo_d2d_blend_surface(cairo_d2d_surface_t *dst,
|
|||
const cairo_matrix_t *transform,
|
||||
cairo_box_t *box,
|
||||
cairo_clip_t *clip,
|
||||
cairo_filter_t filter,
|
||||
cairo_filter_t filter,
|
||||
float opacity)
|
||||
{
|
||||
if (dst == src) {
|
||||
|
@ -2804,12 +2804,12 @@ _cairo_d2d_blend_surface(cairo_d2d_surface_t *dst,
|
|||
*/
|
||||
static cairo_int_status_t
|
||||
_cairo_d2d_try_fastblit(cairo_d2d_surface_t *dst,
|
||||
cairo_surface_t *src,
|
||||
cairo_box_t *box,
|
||||
const cairo_matrix_t *matrix,
|
||||
cairo_clip_t *clip,
|
||||
cairo_operator_t op,
|
||||
cairo_filter_t filter,
|
||||
cairo_surface_t *src,
|
||||
cairo_box_t *box,
|
||||
const cairo_matrix_t *matrix,
|
||||
cairo_clip_t *clip,
|
||||
cairo_operator_t op,
|
||||
cairo_filter_t filter,
|
||||
float opacity = 1.0f)
|
||||
{
|
||||
if (op == CAIRO_OPERATOR_OVER && src->content == CAIRO_CONTENT_COLOR) {
|
||||
|
@ -3102,8 +3102,8 @@ _cairo_d2d_paint(void *surface,
|
|||
reinterpret_cast<const cairo_surface_pattern_t*>(source);
|
||||
|
||||
status = _cairo_d2d_try_fastblit(d2dsurf, surf_pattern->surface,
|
||||
NULL, &source->matrix, clip,
|
||||
op, source->filter);
|
||||
NULL, &source->matrix, clip,
|
||||
op, source->filter);
|
||||
|
||||
if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
|
||||
return status;
|
||||
|
@ -3230,7 +3230,7 @@ _cairo_d2d_mask(void *surface,
|
|||
&source->matrix,
|
||||
clip,
|
||||
op,
|
||||
source->filter,
|
||||
source->filter,
|
||||
solidAlphaValue);
|
||||
if (rv != CAIRO_INT_STATUS_UNSUPPORTED) {
|
||||
return rv;
|
||||
|
@ -3432,8 +3432,8 @@ _cairo_d2d_fill(void *surface,
|
|||
const cairo_surface_pattern_t *surf_pattern =
|
||||
reinterpret_cast<const cairo_surface_pattern_t*>(source);
|
||||
cairo_int_status_t rv = _cairo_d2d_try_fastblit(d2dsurf, surf_pattern->surface,
|
||||
&box, &source->matrix, clip, op,
|
||||
source->filter);
|
||||
&box, &source->matrix, clip, op,
|
||||
source->filter);
|
||||
|
||||
if (rv != CAIRO_INT_STATUS_UNSUPPORTED) {
|
||||
return rv;
|
||||
|
@ -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);
|
||||
|
@ -3799,7 +3812,7 @@ _cairo_dwrite_manual_show_glyphs_on_d2d_surface(void *surface,
|
|||
ID3D10EffectVectorVariable *textColor = effect->GetVariableByName("TextColor")->AsVector();
|
||||
|
||||
float colorVal[] = { float(source->color.red * source->color.alpha),
|
||||
float(source->color.green * source->color.alpha),
|
||||
float(source->color.green * source->color.alpha),
|
||||
float(source->color.blue * source->color.alpha),
|
||||
float(source->color.alpha) };
|
||||
textColor->SetFloatVector(colorVal);
|
||||
|
@ -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);
|
||||
break;
|
||||
case CAIRO_ANTIALIAS_GRAY:
|
||||
target_rt->SetTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE);
|
||||
break;
|
||||
case CAIRO_ANTIALIAS_SUBPIXEL:
|
||||
target_rt->SetTextAntialiasMode(cleartype_quality);
|
||||
break;
|
||||
RefPtr<IDWriteRenderingParams> params;
|
||||
target_rt->GetTextRenderingParams(¶ms);
|
||||
|
||||
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 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,14 +4076,13 @@ _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(¶ms);
|
||||
RefPtr<IDWriteRenderingParams> params = DWriteFactory::RenderingParams();
|
||||
d2dsurf->rt->SetTextRenderingParams(params);
|
||||
d2dsurf->textRenderingInit = true;
|
||||
}
|
||||
cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
if (scaled_font->backend->type == CAIRO_FONT_TYPE_DWRITE) {
|
||||
status = (cairo_int_status_t)
|
||||
status = (cairo_int_status_t)
|
||||
_cairo_dwrite_show_glyphs_on_d2d_surface(surface, op, source, glyphs, num_glyphs, scaled_font, clip);
|
||||
}
|
||||
|
||||
|
@ -4131,7 +4187,7 @@ cairo_d2d_surface_create_for_hwnd(cairo_device_t *cairo_device,
|
|||
}
|
||||
/** Get the backbuffer surface from the swap chain */
|
||||
hr = newSurf->dxgiChain->GetBuffer(0,
|
||||
IID_PPV_ARGS(&newSurf->surface));
|
||||
IID_PPV_ARGS(&newSurf->surface));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
goto FAIL_HWND;
|
||||
|
@ -4176,8 +4232,8 @@ FAIL_HWND:
|
|||
cairo_surface_t *
|
||||
cairo_d2d_surface_create(cairo_device_t *device,
|
||||
cairo_format_t format,
|
||||
int width,
|
||||
int height)
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
if (width == 0 || height == 0) {
|
||||
return _cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_INVALID_SIZE));
|
||||
|
@ -4474,7 +4530,7 @@ FAIL_CREATE:
|
|||
void cairo_d2d_scroll(cairo_surface_t *surface, int x, int y, cairo_rectangle_t *clip)
|
||||
{
|
||||
if (surface->type != CAIRO_SURFACE_TYPE_D2D) {
|
||||
return;
|
||||
return;
|
||||
}
|
||||
cairo_d2d_surface_t *d2dsurf = reinterpret_cast<cairo_d2d_surface_t*>(surface);
|
||||
|
||||
|
@ -4537,7 +4593,7 @@ HDC
|
|||
cairo_d2d_get_dc(cairo_surface_t *surface, cairo_bool_t retain_contents)
|
||||
{
|
||||
if (surface->type != CAIRO_SURFACE_TYPE_D2D) {
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
cairo_d2d_surface_t *d2dsurf = reinterpret_cast<cairo_d2d_surface_t*>(surface);
|
||||
|
||||
|
@ -4578,7 +4634,7 @@ void
|
|||
cairo_d2d_release_dc(cairo_surface_t *surface, const cairo_rectangle_int_t *updated_rect)
|
||||
{
|
||||
if (surface->type != CAIRO_SURFACE_TYPE_D2D) {
|
||||
return;
|
||||
return;
|
||||
}
|
||||
cairo_d2d_surface_t *d2dsurf = reinterpret_cast<cairo_d2d_surface_t*>(surface);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
@ -349,7 +355,7 @@ _cairo_dwrite_glyph_run_from_glyphs(cairo_glyph_t *glyphs,
|
|||
scaled_font->mat.xx == scaled_font->base.font_matrix.xx &&
|
||||
scaled_font->mat.yy == scaled_font->base.font_matrix.yy) {
|
||||
// Fast route, don't actually use a transform but just
|
||||
// set the correct font size.
|
||||
// set the correct font size.
|
||||
*transformed = 0;
|
||||
|
||||
run->fontEmSize = (FLOAT)scaled_font->base.font_matrix.yy;
|
||||
|
@ -371,14 +377,14 @@ _cairo_dwrite_glyph_run_from_glyphs(cairo_glyph_t *glyphs,
|
|||
cairo_matrix_transform_point(&scaled_font->mat_inverse, &x, &y);
|
||||
// Since we will multiply by our ctm matrix later for rotation effects
|
||||
// and such, adjust positions by the inverse matrix now. Y-axis is
|
||||
// inverted! Therefor the offset is -y.
|
||||
// inverted! Therefor the offset is -y.
|
||||
offsets[i].ascenderOffset = -(FLOAT)y;
|
||||
offsets[i].advanceOffset = (FLOAT)x;
|
||||
advances[i] = 0.0;
|
||||
}
|
||||
// The font matrix takes care of the scaling if we have a transform,
|
||||
// emSize should be 1.
|
||||
run->fontEmSize = 1.0f;
|
||||
run->fontEmSize = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -715,22 +721,22 @@ _cairo_dwrite_scaled_font_init_glyph_metrics(cairo_dwrite_scaled_font_t *scaled_
|
|||
|
||||
// TODO: Treat swap_xy.
|
||||
extents.width = (FLOAT)(metrics.advanceWidth - metrics.leftSideBearing - metrics.rightSideBearing) /
|
||||
fontMetrics.designUnitsPerEm;
|
||||
fontMetrics.designUnitsPerEm;
|
||||
extents.height = (FLOAT)(metrics.advanceHeight - metrics.topSideBearing - metrics.bottomSideBearing) /
|
||||
fontMetrics.designUnitsPerEm;
|
||||
fontMetrics.designUnitsPerEm;
|
||||
extents.x_advance = (FLOAT)metrics.advanceWidth / fontMetrics.designUnitsPerEm;
|
||||
extents.x_bearing = (FLOAT)metrics.leftSideBearing / fontMetrics.designUnitsPerEm;
|
||||
extents.y_advance = 0.0;
|
||||
extents.y_bearing = (FLOAT)(metrics.topSideBearing - metrics.verticalOriginY) /
|
||||
fontMetrics.designUnitsPerEm;
|
||||
fontMetrics.designUnitsPerEm;
|
||||
|
||||
// We pad the extents here because GetDesignGlyphMetrics returns "ideal" metrics
|
||||
// for the glyph outline, without accounting for hinting/gridfitting/antialiasing,
|
||||
// and therefore it does not always cover all pixels that will actually be touched.
|
||||
if (scaled_font->base.options.antialias != CAIRO_ANTIALIAS_NONE &&
|
||||
extents.width > 0 && extents.height > 0) {
|
||||
extents.width += scaled_font->mat_inverse.xx * 2;
|
||||
extents.x_bearing -= scaled_font->mat_inverse.xx;
|
||||
extents.width > 0 && extents.height > 0) {
|
||||
extents.width += scaled_font->mat_inverse.xx * 2;
|
||||
extents.x_bearing -= scaled_font->mat_inverse.xx;
|
||||
}
|
||||
|
||||
_cairo_scaled_glyph_set_metrics (scaled_glyph,
|
||||
|
@ -753,22 +759,22 @@ public:
|
|||
// IUnknown interface
|
||||
IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject)
|
||||
{
|
||||
if (iid != __uuidof(IDWriteGeometrySink))
|
||||
return E_NOINTERFACE;
|
||||
if (iid != __uuidof(IDWriteGeometrySink))
|
||||
return E_NOINTERFACE;
|
||||
|
||||
*ppObject = static_cast<IDWriteGeometrySink*>(this);
|
||||
|
||||
return S_OK;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHOD_(ULONG, AddRef)()
|
||||
{
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
IFACEMETHOD_(ULONG, Release)()
|
||||
{
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_(void) SetFillMode(D2D1_FILL_MODE fillMode)
|
||||
|
@ -822,7 +828,7 @@ public:
|
|||
|
||||
IFACEMETHODIMP_(void) AddBeziers(
|
||||
const D2D1_BEZIER_SEGMENT *beziers,
|
||||
UINT beziersCount)
|
||||
UINT beziersCount)
|
||||
{
|
||||
for (unsigned int i = 0; i < beziersCount; i++) {
|
||||
cairo_status_t status = _cairo_path_fixed_curve_to(mCairoPath,
|
||||
|
@ -837,7 +843,7 @@ public:
|
|||
|
||||
IFACEMETHODIMP_(void) AddLines(
|
||||
const D2D1_POINT_2F *points,
|
||||
UINT pointsCount)
|
||||
UINT pointsCount)
|
||||
{
|
||||
for (unsigned int i = 0; i < pointsCount; i++) {
|
||||
cairo_status_t status = _cairo_path_fixed_line_to(mCairoPath,
|
||||
|
@ -853,7 +859,7 @@ private:
|
|||
|
||||
cairo_int_status_t
|
||||
_cairo_dwrite_scaled_font_init_glyph_path(cairo_dwrite_scaled_font_t *scaled_font,
|
||||
cairo_scaled_glyph_t *scaled_glyph)
|
||||
cairo_scaled_glyph_t *scaled_glyph)
|
||||
{
|
||||
cairo_path_fixed_t *path;
|
||||
path = _cairo_path_fixed_create();
|
||||
|
@ -999,8 +1005,8 @@ _cairo_dwrite_scaled_font_init_glyph_surface(cairo_dwrite_scaled_font_t *scaled_
|
|||
|
||||
cairo_surface_set_device_offset (image, -x1, -y1);
|
||||
_cairo_scaled_glyph_set_surface (scaled_glyph,
|
||||
&scaled_font->base,
|
||||
(cairo_image_surface_t *) image);
|
||||
&scaled_font->base,
|
||||
(cairo_image_surface_t *) image);
|
||||
|
||||
FAIL:
|
||||
cairo_surface_destroy (&surface->base);
|
||||
|
@ -1009,7 +1015,7 @@ _cairo_dwrite_scaled_font_init_glyph_surface(cairo_dwrite_scaled_font_t *scaled_
|
|||
}
|
||||
|
||||
cairo_int_status_t
|
||||
_cairo_dwrite_load_truetype_table(void *scaled_font,
|
||||
_cairo_dwrite_load_truetype_table(void *scaled_font,
|
||||
unsigned long tag,
|
||||
long offset,
|
||||
unsigned char *buffer,
|
||||
|
@ -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(¶ms);
|
||||
IDWriteRenderingParams *params = DWriteFactory::RenderingParams();
|
||||
|
||||
gdiInterop->CreateBitmapRenderTarget(surface->dc,
|
||||
area.right - area.left,
|
||||
|
@ -1304,7 +1316,7 @@ _cairo_dwrite_show_glyphs_on_surface(void *surface,
|
|||
offsets[i].advanceOffset = (FLOAT)(glyphs[i].x - fontArea.left);
|
||||
advances[i] = 0.0;
|
||||
}
|
||||
run.fontEmSize = (FLOAT)scaled_font->font_matrix.yy;
|
||||
run.fontEmSize = (FLOAT)scaled_font->font_matrix.yy;
|
||||
} else {
|
||||
transform = TRUE;
|
||||
|
||||
|
@ -1314,10 +1326,10 @@ _cairo_dwrite_show_glyphs_on_surface(void *surface,
|
|||
double y = glyphs[i].y - fontArea.top;
|
||||
cairo_matrix_transform_point(&dwritesf->mat_inverse, &x, &y);
|
||||
/**
|
||||
* Since we will multiply by our ctm matrix later for rotation effects
|
||||
* Since we will multiply by our ctm matrix later for rotation effects
|
||||
* and such, adjust positions by the inverse matrix now. The Y-axis
|
||||
* is inverted so the offset becomes negative.
|
||||
*/
|
||||
* is inverted so the offset becomes negative.
|
||||
*/
|
||||
offsets[i].ascenderOffset = -(FLOAT)y;
|
||||
offsets[i].advanceOffset = (FLOAT)x;
|
||||
advances[i] = 0.0;
|
||||
|
@ -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,88 +281,72 @@ 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
|
||||
mMetrics->aveCharWidth = 0;
|
||||
hr = mFontFace->TryGetFontTable(DWRITE_MAKE_OPENTYPE_TAG('O', 'S', '/', '2'),
|
||||
(const void**)&tableData,
|
||||
&len,
|
||||
&tableContext,
|
||||
&exists);
|
||||
if (SUCCEEDED(hr)) {
|
||||
if (exists && len >= 4) {
|
||||
// Not checking against sizeof(mozilla::OS2Table) here because older
|
||||
// versions of the table have different sizes; we only need the first
|
||||
// two 16-bit fields here.
|
||||
const mozilla::OS2Table* os2 =
|
||||
reinterpret_cast<const mozilla::OS2Table*>(tableData);
|
||||
mMetrics->aveCharWidth = ((gfxFloat)PRInt16(os2->xAvgCharWidth) /
|
||||
fontMetrics.designUnitsPerEm) * mAdjustedSize;
|
||||
// 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,
|
||||
&len,
|
||||
&tableContext,
|
||||
&exists);
|
||||
if (SUCCEEDED(hr)) {
|
||||
if (exists && len >= 4) {
|
||||
// Not checking against sizeof(mozilla::OS2Table) here because older
|
||||
// versions of the table have different sizes; we only need the first
|
||||
// two 16-bit fields here.
|
||||
const mozilla::OS2Table* os2 =
|
||||
reinterpret_cast<const mozilla::OS2Table*>(tableData);
|
||||
mMetrics->aveCharWidth =
|
||||
PRInt16(os2->xAvgCharWidth) * mFUnitsConvFactor;
|
||||
}
|
||||
mFontFace->ReleaseFontTable(tableContext);
|
||||
}
|
||||
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;
|
||||
mMetrics->underlineOffset =
|
||||
fontMetrics.underlinePosition * mFUnitsConvFactor;
|
||||
mMetrics->underlineSize =
|
||||
((gfxFloat)fontMetrics.underlineThickness /
|
||||
fontMetrics.designUnitsPerEm) * mAdjustedSize;
|
||||
mMetrics->strikeoutOffset =
|
||||
((gfxFloat)fontMetrics.strikethroughPosition /
|
||||
fontMetrics.designUnitsPerEm) * mAdjustedSize;
|
||||
mMetrics->strikeoutSize =
|
||||
((gfxFloat)fontMetrics.strikethroughThickness /
|
||||
fontMetrics.designUnitsPerEm) * mAdjustedSize;
|
||||
fontMetrics.underlineThickness * mFUnitsConvFactor;
|
||||
mMetrics->strikeoutOffset =
|
||||
fontMetrics.strikethroughPosition * mFUnitsConvFactor;
|
||||
mMetrics->strikeoutSize =
|
||||
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.
|
||||
return;
|
||||
// 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();
|
||||
}
|
||||
|
|
|
@ -7,9 +7,9 @@ Cu.import("resource://services-sync/engines/clients.js");
|
|||
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
|
||||
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() {
|
||||
add_test(function test_properties() {
|
||||
_("Test lastRecordUpload property");
|
||||
try {
|
||||
_("Test lastRecordUpload property");
|
||||
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,14 +551,23 @@ var gViewController = {
|
|||
},
|
||||
|
||||
loadView: function(aViewId) {
|
||||
if (aViewId == this.currentViewId)
|
||||
return;
|
||||
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
|
||||
};
|
||||
gHistory.pushState(state);
|
||||
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,7 +626,11 @@ var gViewController = {
|
|||
|
||||
this.viewPort.selectedPanel = this.currentViewObj.node;
|
||||
this.viewPort.selectedPanel.setAttribute("loading", "true");
|
||||
this.currentViewObj.show(view.param, ++this.currentViewRequest, aState);
|
||||
|
||||
if (aViewId == aPreviousView)
|
||||
this.currentViewObj.refresh(view.param, ++this.currentViewRequest, aState);
|
||||
else
|
||||
this.currentViewObj.show(view.param, ++this.currentViewRequest, aState);
|
||||
},
|
||||
|
||||
// Moves back in the document history and removes the current history entry
|
||||
|
@ -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,9 +1729,20 @@ 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() { },
|
||||
|
||||
|
@ -1724,7 +1750,7 @@ var gDiscoverView = {
|
|||
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);
|
||||
});
|
||||
|
|
|
@ -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
|
|
@ -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_ */
|
|
@ -60,40 +60,41 @@ EXPORTS = \
|
|||
$(NULL)
|
||||
|
||||
CMMSRCS = \
|
||||
nsBidiKeyboard.mm \
|
||||
nsClipboard.mm \
|
||||
nsMenuX.mm \
|
||||
nsMenuBarX.mm \
|
||||
nsMenuItemX.mm \
|
||||
nsMenuItemIconX.mm \
|
||||
nsMenuUtilsX.mm \
|
||||
nsMenuGroupOwnerX.mm \
|
||||
nsFilePicker.mm \
|
||||
nsDragService.mm \
|
||||
nsToolkit.mm \
|
||||
nsAppShell.mm \
|
||||
nsCocoaUtils.mm \
|
||||
nsCocoaWindow.mm \
|
||||
nsChildView.mm \
|
||||
nsWindowMap.mm \
|
||||
nsWidgetFactory.mm \
|
||||
nsCursorManager.mm \
|
||||
nsMacCursor.mm \
|
||||
nsScreenCocoa.mm \
|
||||
nsScreenManagerCocoa.mm \
|
||||
nsSound.mm \
|
||||
nsLookAndFeel.mm \
|
||||
nsNativeThemeCocoa.mm \
|
||||
nsDeviceContextSpecX.mm \
|
||||
nsPrintDialogX.mm \
|
||||
nsPrintOptionsX.mm \
|
||||
nsPrintSettingsX.mm \
|
||||
nsIdleServiceX.mm \
|
||||
nsCocoaTextInputHandler.mm \
|
||||
nsMacDockSupport.mm \
|
||||
nsStandaloneNativeMenu.mm \
|
||||
GfxInfo.mm \
|
||||
$(NULL)
|
||||
nsBidiKeyboard.mm \
|
||||
nsClipboard.mm \
|
||||
nsMenuX.mm \
|
||||
nsMenuBarX.mm \
|
||||
nsMenuItemX.mm \
|
||||
nsMenuItemIconX.mm \
|
||||
nsMenuUtilsX.mm \
|
||||
nsMenuGroupOwnerX.mm \
|
||||
nsFilePicker.mm \
|
||||
nsDragService.mm \
|
||||
nsToolkit.mm \
|
||||
nsAppShell.mm \
|
||||
nsCocoaUtils.mm \
|
||||
nsCocoaWindow.mm \
|
||||
nsChildView.mm \
|
||||
nsWindowMap.mm \
|
||||
nsWidgetFactory.mm \
|
||||
nsCursorManager.mm \
|
||||
nsMacCursor.mm \
|
||||
nsScreenCocoa.mm \
|
||||
nsScreenManagerCocoa.mm \
|
||||
nsSound.mm \
|
||||
nsLookAndFeel.mm \
|
||||
nsNativeThemeCocoa.mm \
|
||||
nsDeviceContextSpecX.mm \
|
||||
nsPrintDialogX.mm \
|
||||
nsPrintOptionsX.mm \
|
||||
nsPrintSettingsX.mm \
|
||||
nsIdleServiceX.mm \
|
||||
nsCocoaTextInputHandler.mm \
|
||||
nsMacDockSupport.mm \
|
||||
nsStandaloneNativeMenu.mm \
|
||||
GfxInfo.mm \
|
||||
WidgetTraceEvent.mm \
|
||||
$(NULL)
|
||||
|
||||
ifeq (x86_64,$(TARGET_CPU))
|
||||
CMMSRCS += ComplexTextInputPanel.mm
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -62,23 +62,24 @@ ifdef ACCESSIBILITY
|
|||
CSRCS += maiRedundantObjectFactory.c
|
||||
endif
|
||||
|
||||
CPPSRCS = \
|
||||
nsWindow.cpp \
|
||||
nsAppShell.cpp \
|
||||
nsWidgetFactory.cpp \
|
||||
nsToolkit.cpp \
|
||||
nsBidiKeyboard.cpp \
|
||||
nsLookAndFeel.cpp \
|
||||
nsGtkKeyUtils.cpp \
|
||||
nsFilePicker.cpp \
|
||||
nsSound.cpp \
|
||||
nsNativeKeyBindings.cpp \
|
||||
nsScreenGtk.cpp \
|
||||
nsScreenManagerGtk.cpp \
|
||||
nsImageToPixbuf.cpp \
|
||||
nsAccessibilityHelper.cpp \
|
||||
nsGtkIMModule.cpp \
|
||||
$(NULL)
|
||||
CPPSRCS = \
|
||||
nsWindow.cpp \
|
||||
nsAppShell.cpp \
|
||||
nsWidgetFactory.cpp \
|
||||
nsToolkit.cpp \
|
||||
nsBidiKeyboard.cpp \
|
||||
nsLookAndFeel.cpp \
|
||||
nsGtkKeyUtils.cpp \
|
||||
nsFilePicker.cpp \
|
||||
nsSound.cpp \
|
||||
nsNativeKeyBindings.cpp \
|
||||
nsScreenGtk.cpp \
|
||||
nsScreenManagerGtk.cpp \
|
||||
nsImageToPixbuf.cpp \
|
||||
nsAccessibilityHelper.cpp \
|
||||
nsGtkIMModule.cpp \
|
||||
WidgetTraceEvent.cpp \
|
||||
$(NULL)
|
||||
|
||||
ifdef MOZ_X11
|
||||
CPPSRCS += nsIdleServiceGTK.cpp
|
||||
|
|
|
@ -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
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче