merge mozilla-inbound to mozilla-central a=merge

This commit is contained in:
Carsten "Tomcat" Book 2015-09-18 13:19:00 +02:00
commit 1f8a1e2a96
95 changed files with 1145 additions and 622 deletions

View File

@ -1199,6 +1199,41 @@ AccessibleWrap::GetNativeInterface(void** aOutAccessible)
NS_ADDREF_THIS();
}
void
AccessibleWrap::FireWinEvent(Accessible* aTarget, uint32_t aEventType)
{
static_assert(sizeof(gWinEventMap)/sizeof(gWinEventMap[0]) == nsIAccessibleEvent::EVENT_LAST_ENTRY,
"MSAA event map skewed");
NS_ASSERTION(aEventType > 0 && aEventType < ArrayLength(gWinEventMap), "invalid event type");
uint32_t winEvent = gWinEventMap[aEventType];
if (!winEvent)
return;
int32_t childID = GetChildIDFor(aTarget);
if (!childID)
return; // Can't fire an event without a child ID
HWND hwnd = GetHWNDFor(aTarget);
if (!hwnd) {
return;
}
// Fire MSAA event for client area window.
::NotifyWinEvent(winEvent, hwnd, OBJID_CLIENT, childID);
// JAWS announces collapsed combobox navigation based on focus events.
if (aEventType == nsIAccessibleEvent::EVENT_SELECTION &&
Compatibility::IsJAWS()) {
roles::Role role = aTarget->IsProxy() ? aTarget->Proxy()->Role() :
aTarget->Role();
if (role == roles::COMBOBOX_OPTION) {
::NotifyWinEvent(EVENT_OBJECT_FOCUS, hwnd, OBJID_CLIENT, childID);
}
}
}
////////////////////////////////////////////////////////////////////////////////
// Accessible
@ -1214,15 +1249,6 @@ AccessibleWrap::HandleAccEvent(AccEvent* aEvent)
uint32_t eventType = aEvent->GetEventType();
static_assert(sizeof(gWinEventMap)/sizeof(gWinEventMap[0]) == nsIAccessibleEvent::EVENT_LAST_ENTRY,
"MSAA event map skewed");
NS_ENSURE_TRUE(eventType > 0 && eventType < ArrayLength(gWinEventMap), NS_ERROR_FAILURE);
uint32_t winEvent = gWinEventMap[eventType];
if (!winEvent)
return NS_OK;
// Means we're not active.
NS_ENSURE_TRUE(!IsDefunct(), NS_ERROR_FAILURE);
@ -1235,41 +1261,7 @@ AccessibleWrap::HandleAccEvent(AccEvent* aEvent)
UpdateSystemCaretFor(accessible);
}
int32_t childID = GetChildIDFor(accessible); // get the id for the accessible
if (!childID)
return NS_OK; // Can't fire an event without a child ID
HWND hWnd = GetHWNDFor(accessible);
NS_ENSURE_TRUE(hWnd, NS_ERROR_FAILURE);
nsAutoString tag;
nsAutoCString id;
nsIContent* cnt = accessible->GetContent();
if (cnt) {
cnt->NodeInfo()->NameAtom()->ToString(tag);
nsIAtom* aid = cnt->GetID();
if (aid)
aid->ToUTF8String(id);
}
#ifdef A11Y_LOG
if (logging::IsEnabled(logging::ePlatforms)) {
printf("\n\nMSAA event: event: %d, target: %s@id='%s', childid: %d, hwnd: %p\n\n",
eventType, NS_ConvertUTF16toUTF8(tag).get(), id.get(),
childID, hWnd);
}
#endif
// Fire MSAA event for client area window.
::NotifyWinEvent(winEvent, hWnd, OBJID_CLIENT, childID);
// JAWS announces collapsed combobox navigation based on focus events.
if (Compatibility::IsJAWS()) {
if (eventType == nsIAccessibleEvent::EVENT_SELECTION &&
accessible->Role() == roles::COMBOBOX_OPTION) {
::NotifyWinEvent(EVENT_OBJECT_FOCUS, hWnd, OBJID_CLIENT, childID);
}
}
FireWinEvent(accessible, eventType);
return NS_OK;
}

View File

@ -159,6 +159,8 @@ public: // construction, destruction
static int32_t GetChildIDFor(Accessible* aAccessible);
static HWND GetHWNDFor(Accessible* aAccessible);
static void FireWinEvent(Accessible* aTarget, uint32_t aEventType);
/**
* System caret support: update the Windows caret position.
* The system caret works more universally than the MSAA caret

View File

@ -76,18 +76,23 @@ a11y::ProxyDestroyed(ProxyAccessible* aProxy)
}
void
a11y::ProxyEvent(ProxyAccessible*, uint32_t)
a11y::ProxyEvent(ProxyAccessible* aTarget, uint32_t aEventType)
{
AccessibleWrap::FireWinEvent(WrapperFor(aTarget), aEventType);
}
void
a11y::ProxyStateChangeEvent(ProxyAccessible*, uint64_t, bool)
a11y::ProxyStateChangeEvent(ProxyAccessible* aTarget, uint64_t, bool)
{
AccessibleWrap::FireWinEvent(WrapperFor(aTarget),
nsIAccessibleEvent::EVENT_STATE_CHANGE);
}
void
a11y::ProxyCaretMoveEvent(ProxyAccessible* aTarget, int32_t aOffset)
{
AccessibleWrap::FireWinEvent(WrapperFor(aTarget),
nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED);
}
void
@ -104,4 +109,8 @@ a11y::ProxyTextChangeEvent(ProxyAccessible* aText, const nsString& aStr,
if (text) {
ia2AccessibleText::UpdateTextChangeData(text, aInsert, aStr, aStart, aLen);
}
uint32_t eventType = aInsert ? nsIAccessibleEvent::EVENT_TEXT_INSERTED :
nsIAccessibleEvent::EVENT_TEXT_REMOVED;
AccessibleWrap::FireWinEvent(wrapper, eventType);
}

View File

@ -120,12 +120,31 @@ var gTests = [
}
];
function checkState(expectedStates, contentStates) {
is(contentStates.inDOMFullscreen, expectedStates.inDOMFullscreen,
"The DOM fullscreen state of the content should match");
// TODO window.fullScreen is not updated as soon as the fullscreen
// state flips in child process, hence checking it could cause
// anonying intermittent failure. As we just want to confirm the
// fullscreen state of the browser window, we can just check the
// that on the chrome window below.
// is(contentStates.inFullscreen, expectedStates.inFullscreen,
// "The fullscreen state of the content should match");
is(document.mozFullScreen, expectedStates.inDOMFullscreen,
"The DOM fullscreen state of the chrome should match");
is(window.fullScreen, expectedStates.inFullscreen,
"The fullscreen state of the chrome should match");
}
const kPage = "http://example.org/browser/browser/" +
"base/content/test/general/dummy_page.html";
add_task(function* () {
yield pushPrefs(
["full-screen-api.transition-duration.enter", "0 0"],
["full-screen-api.transition-duration.leave", "0 0"]);
let tab = gBrowser.addTab("about:robots");
let tab = gBrowser.addTab(kPage);
let browser = tab.linkedBrowser;
gBrowser.selectedTab = tab;
yield waitForDocLoadComplete();
@ -148,63 +167,53 @@ add_task(function* () {
yield new Promise(resolve => listenOneMessage("Test:Activated", resolve));
for (let test of gTests) {
let contentStates;
info("Testing exit DOM fullscreen via " + test.desc);
var { inDOMFullscreen, inFullscreen } = yield queryFullscreenState();
ok(!inDOMFullscreen, "Shouldn't have been in DOM fullscreen");
ok(!inFullscreen, "Shouldn't have been in fullscreen");
contentStates = yield queryFullscreenState();
checkState({inDOMFullscreen: false, inFullscreen: false}, contentStates);
/* DOM fullscreen without fullscreen mode */
// Enter DOM fullscreen
info("> Enter DOM fullscreen");
gMessageManager.sendAsyncMessage("Test:RequestFullscreen");
var { inDOMFullscreen, inFullscreen } =
yield waitForFullscreenChanges(FS_CHANGE_BOTH);
ok(inDOMFullscreen, "Should now be in DOM fullscreen");
ok(inFullscreen, "Should now be in fullscreen");
contentStates = yield waitForFullscreenChanges(FS_CHANGE_BOTH);
checkState({inDOMFullscreen: true, inFullscreen: true}, contentStates);
// Exit DOM fullscreen
info("> Exit DOM fullscreen");
test.exitFunc();
var { inDOMFullscreen, inFullscreen } =
yield waitForFullscreenChanges(FS_CHANGE_BOTH);
ok(!inDOMFullscreen, "Should no longer be in DOM fullscreen");
ok(!inFullscreen, "Should no longer be in fullscreen");
contentStates = yield waitForFullscreenChanges(FS_CHANGE_BOTH);
checkState({inDOMFullscreen: false, inFullscreen: false}, contentStates);
/* DOM fullscreen with fullscreen mode */
// Enter fullscreen mode
info("> Enter fullscreen mode");
// Need to be asynchronous because sizemodechange event could be
// dispatched synchronously, which would cause the event listener
// miss that event and wait infinitely.
executeSoon(() => BrowserFullScreen());
var { inDOMFullscreen, inFullscreen } =
yield waitForFullscreenChanges(FS_CHANGE_SIZE);
ok(!inDOMFullscreen, "Shouldn't have been in DOM fullscreen");
ok(inFullscreen, "Should now be in fullscreen mode");
contentStates = yield waitForFullscreenChanges(FS_CHANGE_SIZE);
checkState({inDOMFullscreen: false, inFullscreen: true}, contentStates);
// Enter DOM fullscreen
info("> Enter DOM fullscreen in fullscreen mode");
gMessageManager.sendAsyncMessage("Test:RequestFullscreen");
var { inDOMFullscreen, inFullscreen } =
yield waitForFullscreenChanges(FS_CHANGE_DOM);
ok(inDOMFullscreen, "Should now be in DOM fullscreen");
ok(inFullscreen, "Should still be in fullscreen");
contentStates = yield waitForFullscreenChanges(FS_CHANGE_DOM);
checkState({inDOMFullscreen: true, inFullscreen: true}, contentStates);
// Exit DOM fullscreen
info("> Exit DOM fullscreen in fullscreen mode");
test.exitFunc();
var { inDOMFullscreen, inFullscreen } =
yield waitForFullscreenChanges(test.affectsFullscreenMode ?
FS_CHANGE_BOTH : FS_CHANGE_DOM);
ok(!inDOMFullscreen, "Should no longer be in DOM fullscreen");
if (test.affectsFullscreenMode) {
ok(!inFullscreen, "Should no longer be in fullscreen mode");
} else {
ok(inFullscreen, "Should still be in fullscreen mode");
}
contentStates = yield waitForFullscreenChanges(
test.affectsFullscreenMode ? FS_CHANGE_BOTH : FS_CHANGE_DOM);
checkState({
inDOMFullscreen: false,
inFullscreen: !test.affectsFullscreenMode
}, contentStates);
/* Cleanup */
// Exit fullscreen mode if we are still in
if (browser.contentWindow.fullScreen) {
if (window.fullScreen) {
info("> Cleanup");
executeSoon(() => BrowserFullScreen());
yield waitForFullscreenChanges(FS_CHANGE_SIZE);
}

View File

@ -145,6 +145,7 @@ MACH_MODULES = [
'tools/docs/mach_commands.py',
'tools/mercurial/mach_commands.py',
'tools/mach_commands.py',
'tools/power/mach_commands.py',
'mobile/android/mach_commands.py',
]

View File

@ -232,12 +232,11 @@ using namespace mozilla;
using namespace mozilla::dom;
using mozilla::dom::workers::ServiceWorkerManager;
// True means sUseErrorPages and sInterceptionEnabled has been added to
// True means sUseErrorPages has been added to
// preferences var cache.
static bool gAddedPreferencesVarCache = false;
bool nsDocShell::sUseErrorPages = false;
bool nsDocShell::sInterceptionEnabled = false;
// Number of documents currently loading
static int32_t gNumberOfDocumentsLoading = 0;
@ -5536,9 +5535,6 @@ nsDocShell::Create()
Preferences::AddBoolVarCache(&sUseErrorPages,
"browser.xul.error_pages.enabled",
mUseErrorPages);
Preferences::AddBoolVarCache(&sInterceptionEnabled,
"dom.serviceWorkers.interception.enabled",
false);
gAddedPreferencesVarCache = true;
}
@ -13858,7 +13854,7 @@ nsDocShell::ShouldPrepareForIntercept(nsIURI* aURI, bool aIsNavigate,
{
*aShouldIntercept = false;
// Preffed off.
if (!sInterceptionEnabled) {
if (!nsContentUtils::ServiceWorkerInterceptionEnabled()) {
return NS_OK;
}

View File

@ -887,9 +887,6 @@ protected:
// Cached value of the "browser.xul.error_pages.enabled" preference.
static bool sUseErrorPages;
// Cached value of the "dom.serviceWorkers.interception.enabled" preference.
static bool sInterceptionEnabled;
bool mCreated;
bool mAllowSubframes;
bool mAllowPlugins;

View File

@ -1064,6 +1064,12 @@ nsContentSink::ProcessOfflineManifest(const nsAString& aManifestSpec)
return;
}
// If this document has been interecepted, let's skip the processing of the
// manifest.
if (nsContentUtils::IsControlledByServiceWorker(mDocument)) {
return;
}
// If the docshell's in private browsing mode, we don't want to do any
// manifest processing.
nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(mDocShell);

View File

@ -52,6 +52,7 @@
#include "mozilla/dom/TouchEvent.h"
#include "mozilla/dom/ShadowRoot.h"
#include "mozilla/dom/WorkerPrivate.h"
#include "mozilla/dom/workers/ServiceWorkerManager.h"
#include "mozilla/EventDispatcher.h"
#include "mozilla/EventListenerManager.h"
#include "mozilla/EventStateManager.h"
@ -267,6 +268,7 @@ bool nsContentUtils::sEncodeDecodeURLHash = false;
bool nsContentUtils::sGettersDecodeURLHash = false;
bool nsContentUtils::sPrivacyResistFingerprinting = false;
bool nsContentUtils::sSendPerformanceTimingNotifications = false;
bool nsContentUtils::sSWInterceptionEnabled = false;
uint32_t nsContentUtils::sHandlingInputTimeout = 1000;
@ -559,6 +561,10 @@ nsContentUtils::Init()
Preferences::AddBoolVarCache(&sPrivacyResistFingerprinting,
"privacy.resistFingerprinting", false);
Preferences::AddBoolVarCache(&sSWInterceptionEnabled,
"dom.serviceWorkers.interception.enabled",
false);
Preferences::AddUintVarCache(&sHandlingInputTimeout,
"dom.event.handling-user-input-time-limit",
1000);
@ -1736,10 +1742,38 @@ nsContentUtils::ParseLegacyFontSize(const nsAString& aValue)
return clamped(value, 1, 7);
}
/* static */
bool
nsContentUtils::IsControlledByServiceWorker(nsIDocument* aDocument)
{
if (!ServiceWorkerInterceptionEnabled() ||
nsContentUtils::IsInPrivateBrowsing(aDocument)) {
return false;
}
nsRefPtr<workers::ServiceWorkerManager> swm =
workers::ServiceWorkerManager::GetInstance();
MOZ_ASSERT(swm);
ErrorResult rv;
bool controlled = swm->IsControlled(aDocument, rv);
NS_WARN_IF(rv.Failed());
return !rv.Failed() && controlled;
}
/* static */
void
nsContentUtils::GetOfflineAppManifest(nsIDocument *aDocument, nsIURI **aURI)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aDocument);
*aURI = nullptr;
if (IsControlledByServiceWorker(aDocument)) {
return;
}
Element* docElement = aDocument->GetRootElement();
if (!docElement) {
return;
@ -5230,7 +5264,6 @@ nsContentUtils::LeaveMicroTask()
MOZ_ASSERT(NS_IsMainThread());
if (--sMicroTaskLevel == 0) {
PerformMainThreadMicroTaskCheckpoint();
nsDocument::ProcessBaseElementQueue();
}
}

View File

@ -1955,6 +1955,14 @@ public:
return sSendPerformanceTimingNotifications;
}
/*
* Returns true if ServiceWorker Interception is enabled by pref.
*/
static bool ServiceWorkerInterceptionEnabled()
{
return sSWInterceptionEnabled;
}
/*
* Returns true if the frame timing APIs are enabled.
*/
@ -1995,6 +2003,11 @@ public:
*/
static bool HasPluginWithUncontrolledEventDispatch(nsIDocument* aDoc);
/**
* Return true if this doc is controlled by a ServiceWorker.
*/
static bool IsControlledByServiceWorker(nsIDocument* aDocument);
/**
* Fire mutation events for changes caused by parsing directly into a
* context node.
@ -2607,6 +2620,7 @@ private:
static bool sGettersDecodeURLHash;
static bool sPrivacyResistFingerprinting;
static bool sSendPerformanceTimingNotifications;
static bool sSWInterceptionEnabled;
static uint32_t sCookiesLifetimePolicy;
static uint32_t sCookiesBehavior;

View File

@ -5895,29 +5895,6 @@ nsDocument::RegisterUnresolvedElement(Element* aElement, nsIAtom* aTypeName)
return NS_OK;
}
namespace {
class ProcessStackRunner final : public nsIRunnable
{
~ProcessStackRunner() {}
public:
explicit ProcessStackRunner(bool aIsBaseQueue = false)
: mIsBaseQueue(aIsBaseQueue)
{
}
NS_DECL_ISUPPORTS
NS_IMETHOD Run() override
{
nsDocument::ProcessTopElementQueue(mIsBaseQueue);
return NS_OK;
}
bool mIsBaseQueue;
};
NS_IMPL_ISUPPORTS(ProcessStackRunner, nsIRunnable);
} // namespace
void
nsDocument::EnqueueLifecycleCallback(nsIDocument::ElementCallbackType aType,
Element* aCustomElement,
@ -6019,10 +5996,7 @@ nsDocument::EnqueueLifecycleCallback(nsIDocument::ElementCallbackType aType,
// A new element queue needs to be pushed if the queue at the
// top of the stack is associated with another microtask level.
// Don't push a queue for the level 0 microtask (base element queue)
// because we don't want to process the queue until the
// microtask checkpoint.
bool shouldPushElementQueue = nsContentUtils::MicroTaskLevel() > 0 &&
bool shouldPushElementQueue =
(!lastData || lastData->mAssociatedMicroTask <
static_cast<int32_t>(nsContentUtils::MicroTaskLevel()));
@ -6045,39 +6019,22 @@ nsDocument::EnqueueLifecycleCallback(nsIDocument::ElementCallbackType aType,
// should be invoked prior to returning control back to script.
// Create a script runner to process the top of the processing
// stack as soon as it is safe to run script.
nsContentUtils::AddScriptRunner(new ProcessStackRunner());
nsCOMPtr<nsIRunnable> runnable =
NS_NewRunnableFunction(&nsDocument::ProcessTopElementQueue);
nsContentUtils::AddScriptRunner(runnable);
}
}
}
// static
void
nsDocument::ProcessBaseElementQueue()
{
// Prevent re-entrance. Also, if a microtask checkpoint is reached
// and there is no processing stack to process, then we are done.
if (sProcessingBaseElementQueue || !sProcessingStack) {
return;
}
MOZ_ASSERT(nsContentUtils::MicroTaskLevel() == 0);
sProcessingBaseElementQueue = true;
nsContentUtils::AddScriptRunner(new ProcessStackRunner(true));
}
// static
void
nsDocument::ProcessTopElementQueue(bool aIsBaseQueue)
nsDocument::ProcessTopElementQueue()
{
MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
nsTArray<nsRefPtr<CustomElementData>>& stack = *sProcessingStack;
uint32_t firstQueue = stack.LastIndexOf((CustomElementData*) nullptr);
if (aIsBaseQueue && firstQueue != 0) {
return;
}
for (uint32_t i = firstQueue + 1; i < stack.Length(); ++i) {
// Callback queue may have already been processed in an earlier
// element queue or in an element queue that was popped
@ -6095,7 +6052,6 @@ nsDocument::ProcessTopElementQueue(bool aIsBaseQueue)
} else {
// Don't pop sentinel for base element queue.
stack.SetLength(1);
sProcessingBaseElementQueue = false;
}
}
@ -6111,10 +6067,6 @@ nsDocument::RegisterEnabled()
Maybe<nsTArray<nsRefPtr<mozilla::dom::CustomElementData>>>
nsDocument::sProcessingStack;
// static
bool
nsDocument::sProcessingBaseElementQueue;
void
nsDocument::RegisterElement(JSContext* aCx, const nsAString& aType,
const ElementRegistrationOptions& aOptions,
@ -11734,6 +11686,41 @@ GetRootWindow(nsIDocument* aDoc)
return rootItem ? rootItem->GetWindow() : nullptr;
}
static bool
ShouldApplyFullscreenDirectly(nsIDocument* aDoc,
nsPIDOMWindow* aRootWin)
{
if (XRE_GetProcessType() == GeckoProcessType_Content) {
// If we are in the content process, we can apply the fullscreen
// state directly only if we have been in DOM fullscreen, because
// otherwise we always need to notify the chrome.
return nsContentUtils::GetRootDocument(aDoc)->IsFullScreenDoc();
} else {
// If we are in the chrome process, and the window has not been in
// fullscreen, we certainly need to make that fullscreen first.
bool fullscreen;
NS_WARN_IF(NS_FAILED(aRootWin->GetFullScreen(&fullscreen)));
if (!fullscreen) {
return false;
}
// The iterator not being at end indicates there is still some
// pending fullscreen request relates to this document. We have to
// push the request to the pending queue so requests are handled
// in the correct order.
PendingFullscreenRequestList::Iterator
iter(aDoc, PendingFullscreenRequestList::eDocumentsWithSameRoot);
if (!iter.AtEnd()) {
return false;
}
// We have to apply the fullscreen state directly in this case,
// because nsGlobalWindow::SetFullscreenInternal() will do nothing
// if it is already in fullscreen. If we do not apply the state but
// instead add it to the queue and wait for the window as normal,
// we would get stuck.
return true;
}
}
void
nsDocument::RequestFullScreen(UniquePtr<FullscreenRequest>&& aRequest)
{
@ -11742,19 +11729,7 @@ nsDocument::RequestFullScreen(UniquePtr<FullscreenRequest>&& aRequest)
return;
}
// If we have been in fullscreen, apply the new state directly.
// Note that we should check both condition, because if we are in
// child process, our window may not report to be in fullscreen.
// Also, it is possible that the root window reports that it is in
// fullscreen while there exists pending fullscreen request because
// of ongoing fullscreen transition. In that case, we shouldn't
// apply the state before any previous request.
if ((static_cast<nsGlobalWindow*>(rootWin.get())->FullScreen() &&
// The iterator being at end at the beginning indicates there is
// no pending fullscreen request which relates to this document.
PendingFullscreenRequestList::Iterator(
this, PendingFullscreenRequestList::eDocumentsWithSameRoot).AtEnd()) ||
nsContentUtils::GetRootDocument(this)->IsFullScreenDoc()) {
if (ShouldApplyFullscreenDirectly(this, rootWin)) {
ApplyFullscreen(*aRequest);
return;
}
@ -13043,6 +13018,24 @@ nsDocument::ReportUseCounters()
// that feature were removed. Whereas with a document/top-level
// page split, we can see that N documents would be affected, but
// only a single web page would be affected.
// The difference between the values of these two histograms and the
// related use counters below tell us how many pages did *not* use
// the feature in question. For instance, if we see that a given
// session has destroyed 30 content documents, but a particular use
// counter shows only a count of 5, we can infer that the use
// counter was *not* used in 25 of those 30 documents.
//
// We do things this way, rather than accumulating a boolean flag
// for each use counter, to avoid sending histograms for features
// that don't get widely used. Doing things in this fashion means
// smaller telemetry payloads and faster processing on the server
// side.
Telemetry::Accumulate(Telemetry::CONTENT_DOCUMENTS_DESTROYED, 1);
if (IsTopLevelContentDocument()) {
Telemetry::Accumulate(Telemetry::TOP_LEVEL_CONTENT_DOCUMENTS_DESTROYED, 1);
}
for (int32_t c = 0;
c < eUseCounter_Count; ++c) {
UseCounter uc = static_cast<UseCounter>(c);
@ -13051,7 +13044,8 @@ nsDocument::ReportUseCounters()
static_cast<Telemetry::ID>(Telemetry::HistogramFirstUseCounter + uc * 2);
bool value = GetUseCounter(uc);
if (sDebugUseCounters && value) {
if (value) {
if (sDebugUseCounters) {
const char* name = Telemetry::GetHistogramName(id);
if (name) {
printf(" %s", name);
@ -13061,14 +13055,16 @@ nsDocument::ReportUseCounters()
printf(": %d\n", value);
}
Telemetry::Accumulate(id, value);
Telemetry::Accumulate(id, 1);
}
if (IsTopLevelContentDocument()) {
id = static_cast<Telemetry::ID>(Telemetry::HistogramFirstUseCounter +
uc * 2 + 1);
value = GetUseCounter(uc) || GetChildDocumentUseCounter(uc);
if (sDebugUseCounters && value) {
if (value) {
if (sDebugUseCounters) {
const char* name = Telemetry::GetHistogramName(id);
if (name) {
printf(" %s", name);
@ -13078,7 +13074,8 @@ nsDocument::ReportUseCounters()
printf(": %d\n", value);
}
Telemetry::Accumulate(id, value);
Telemetry::Accumulate(id, 1);
}
}
}
}

View File

@ -1303,7 +1303,7 @@ public:
mozilla::dom::LifecycleCallbackArgs* aArgs = nullptr,
mozilla::dom::CustomElementDefinition* aDefinition = nullptr) override;
static void ProcessTopElementQueue(bool aIsBaseQueue = false);
static void ProcessTopElementQueue();
void GetCustomPrototype(int32_t aNamespaceID,
nsIAtom* aAtom,
@ -1600,15 +1600,9 @@ private:
// queue in the stack is the base element queue.
static mozilla::Maybe<nsTArray<nsRefPtr<mozilla::dom::CustomElementData>>> sProcessingStack;
// Flag to prevent re-entrance into base element queue as described in the
// custom elements speicification.
static bool sProcessingBaseElementQueue;
static bool CustomElementConstructor(JSContext* aCx, unsigned aArgc, JS::Value* aVp);
public:
static void ProcessBaseElementQueue();
// Enqueue created callback or register upgrade candidate for
// newly created custom elements, possibly extending an existing type.
// ex. <x-button>, <button is="x-button> (type extension)

View File

@ -635,7 +635,7 @@ public:
virtual bool has(JSContext *cx, JS::Handle<JSObject*> proxy,
JS::Handle<jsid> id, bool *bp) const override;
virtual bool get(JSContext *cx, JS::Handle<JSObject*> proxy,
JS::Handle<JSObject*> receiver,
JS::Handle<JS::Value> receiver,
JS::Handle<jsid> id,
JS::MutableHandle<JS::Value> vp) const override;
virtual bool set(JSContext *cx, JS::Handle<JSObject*> proxy,
@ -900,7 +900,7 @@ nsOuterWindowProxy::hasOwn(JSContext *cx, JS::Handle<JSObject*> proxy,
bool
nsOuterWindowProxy::get(JSContext *cx, JS::Handle<JSObject*> proxy,
JS::Handle<JSObject*> receiver,
JS::Handle<JS::Value> receiver,
JS::Handle<jsid> id,
JS::MutableHandle<JS::Value> vp) const
{

View File

@ -104,11 +104,14 @@ function grabHistogramsFromContent(browser, use_counter_middlefix) {
return telemetry.getHistogramById(name).snapshot();
}
let histogram_page_name = "USE_COUNTER_" + arg.middlefix + "_PAGE";
let histogram_document_name = "USE_COUNTER_" + arg.middlefix + "_DOCUMENT";
let histogram_page_name = "USE_COUNTER2_" + arg.middlefix + "_PAGE";
let histogram_document_name = "USE_COUNTER2_" + arg.middlefix + "_DOCUMENT";
let histogram_page = snapshot_histogram(histogram_page_name);
let histogram_document = snapshot_histogram(histogram_document_name);
return [histogram_page.sum, histogram_document.sum];
let histogram_docs = snapshot_histogram("CONTENT_DOCUMENTS_DESTROYED");
let histogram_toplevel_docs = snapshot_histogram("TOP_LEVEL_CONTENT_DOCUMENTS_DESTROYED");
return [histogram_page.sum, histogram_document.sum,
histogram_docs.sum, histogram_toplevel_docs.sum];
});
}
@ -121,7 +124,8 @@ var check_use_counter_iframe = Task.async(function* (file, use_counter_middlefix
// Hold on to the current values of the telemetry histograms we're
// interested in.
let [histogram_page_before, histogram_document_before] =
let [histogram_page_before, histogram_document_before,
histogram_docs_before, histogram_toplevel_docs_before] =
yield grabHistogramsFromContent(gBrowser.selectedBrowser, use_counter_middlefix);
gBrowser.selectedBrowser.loadURI(gHttpTestRoot + "file_use_counter_outer.html");
@ -161,14 +165,17 @@ var check_use_counter_iframe = Task.async(function* (file, use_counter_middlefix
yield waitForDestroyedDocuments();
// Grab histograms again and compare.
let [histogram_page_after, histogram_document_after] =
let [histogram_page_after, histogram_document_after,
histogram_docs_after, histogram_toplevel_docs_after] =
yield grabHistogramsFromContent(gBrowser.selectedBrowser, use_counter_middlefix);
is(histogram_page_after, histogram_page_before + 1,
"page counts for " + use_counter_middlefix + " after are correct");
ok(histogram_toplevel_docs_after >= histogram_toplevel_docs_before + 1,
"top level document counts are correct");
if (check_documents) {
is(histogram_document_after, histogram_document_before + 1,
"document counts " + use_counter_middlefix + " after are correct");
"document counts for " + use_counter_middlefix + " after are correct");
}
});
@ -181,7 +188,8 @@ var check_use_counter_img = Task.async(function* (file, use_counter_middlefix) {
// Hold on to the current values of the telemetry histograms we're
// interested in.
let [histogram_page_before, histogram_document_before] =
let [histogram_page_before, histogram_document_before,
histogram_docs_before, histogram_toplevel_docs_before] =
yield grabHistogramsFromContent(gBrowser.selectedBrowser, use_counter_middlefix);
gBrowser.selectedBrowser.loadURI(gHttpTestRoot + "file_use_counter_outer.html");
@ -222,12 +230,19 @@ var check_use_counter_img = Task.async(function* (file, use_counter_middlefix) {
yield waitForDestroyedDocuments();
// Grab histograms again and compare.
let [histogram_page_after, histogram_document_after] =
let [histogram_page_after, histogram_document_after,
histogram_docs_after, histogram_toplevel_docs_after] =
yield grabHistogramsFromContent(gBrowser.selectedBrowser, use_counter_middlefix);
is(histogram_page_after, histogram_page_before + 1,
"page counts for " + use_counter_middlefix + " after are correct");
is(histogram_document_after, histogram_document_before + 1,
"document counts " + use_counter_middlefix + " after are correct");
"document counts for " + use_counter_middlefix + " after are correct");
ok(histogram_toplevel_docs_after >= histogram_toplevel_docs_before + 1,
"top level document counts are correct");
// 2 documents: one for the outer html page containing the <img> element, and
// one for the SVG image itself.
ok(histogram_docs_after >= histogram_docs_before + 2,
"document counts are correct");
});
var check_use_counter_direct = Task.async(function* (file, use_counter_middlefix, xfail=false) {
@ -239,7 +254,8 @@ var check_use_counter_direct = Task.async(function* (file, use_counter_middlefix
// Hold on to the current values of the telemetry histograms we're
// interested in.
let [histogram_page_before, histogram_document_before] =
let [histogram_page_before, histogram_document_before,
histogram_docs_before, histogram_toplevel_docs_before] =
yield grabHistogramsFromContent(gBrowser.selectedBrowser, use_counter_middlefix);
gBrowser.selectedBrowser.loadURI(gHttpTestRoot + file);
@ -267,10 +283,15 @@ var check_use_counter_direct = Task.async(function* (file, use_counter_middlefix
yield waitForDestroyedDocuments();
// Grab histograms again and compare.
let [histogram_page_after, histogram_document_after] =
let [histogram_page_after, histogram_document_after,
histogram_docs_after, histogram_toplevel_docs_after] =
yield grabHistogramsFromContent(gBrowser.selectedBrowser, use_counter_middlefix);
(xfail ? todo_is : is)(histogram_page_after, histogram_page_before + 1,
"page counts for " + use_counter_middlefix + " after are correct");
(xfail ? todo_is : is)(histogram_document_after, histogram_document_before + 1,
"document counts " + use_counter_middlefix + " after are correct");
"document counts for " + use_counter_middlefix + " after are correct");
ok(histogram_toplevel_docs_after >= histogram_toplevel_docs_before + 1,
"top level document counts are correct");
ok(histogram_docs_after >= histogram_docs_before + 1,
"document counts are correct");
});

View File

@ -62,8 +62,8 @@ def generate_histograms(filename):
'description': desc }
def append_counters(name, desc):
append_counter('USE_COUNTER_%s_DOCUMENT' % name, 'Whether a document %s' % desc)
append_counter('USE_COUNTER_%s_PAGE' % name, 'Whether a page %s' % desc)
append_counter('USE_COUNTER2_%s_DOCUMENT' % name, 'Whether a document %s' % desc)
append_counter('USE_COUNTER2_%s_PAGE' % name, 'Whether a page %s' % desc)
if counter['type'] == 'method':
method = '%s.%s' % (counter['interface_name'], counter['method_name'])

View File

@ -1699,8 +1699,8 @@ NativePropertyHooks sEmptyNativePropertyHooks = {
bool
GetPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
JS::Handle<jsid> id, bool* found,
JS::MutableHandle<JS::Value> vp)
JS::Handle<JS::Value> receiver, JS::Handle<jsid> id,
bool* found, JS::MutableHandle<JS::Value> vp)
{
JS::Rooted<JSObject*> proto(cx);
if (!js::GetObjectProto(cx, proxy, &proto)) {
@ -1719,7 +1719,7 @@ GetPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
return true;
}
return JS_ForwardGetPropertyTo(cx, proto, id, proxy, vp);
return JS_ForwardGetPropertyTo(cx, proto, id, receiver, vp);
}
bool

View File

@ -1847,8 +1847,8 @@ ThrowConstructorWithoutNew(JSContext* cx, const char* name);
bool
GetPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
JS::Handle<jsid> id, bool* found,
JS::MutableHandle<JS::Value> vp);
JS::Handle<JS::Value> receiver, JS::Handle<jsid> id,
bool* found, JS::MutableHandle<JS::Value> vp);
//
bool

View File

@ -11039,7 +11039,7 @@ class CGDOMJSProxyHandler_get(ClassMethod):
def __init__(self, descriptor):
args = [Argument('JSContext*', 'cx'),
Argument('JS::Handle<JSObject*>', 'proxy'),
Argument('JS::Handle<JSObject*>', 'receiver'),
Argument('JS::Handle<JS::Value>', 'receiver'),
Argument('JS::Handle<jsid>', 'id'),
Argument('JS::MutableHandle<JS::Value>', 'vp')]
ClassMethod.__init__(self, "get", "bool", args,
@ -11094,7 +11094,7 @@ class CGDOMJSProxyHandler_get(ClassMethod):
getOnPrototype = dedent("""
bool foundOnPrototype;
if (!GetPropertyOnPrototype(cx, proxy, id, &foundOnPrototype, vp)) {
if (!GetPropertyOnPrototype(cx, proxy, receiver, id, &foundOnPrototype, vp)) {
return false;
}

View File

@ -224,7 +224,6 @@ void
TextureClient::RecycleTexture(TextureFlags aFlags)
{
MOZ_ASSERT(GetFlags() & TextureFlags::RECYCLE);
MOZ_ASSERT(!HasRecycleCallback());
mAddedToCompositableClient = false;
if (mFlags != aFlags) {

View File

@ -53,6 +53,24 @@ TextureClientRecycleAllocator::SetMaxPoolSize(uint32_t aMax)
mMaxPooledSize = aMax;
}
class TextureClientRecycleTask : public Task
{
public:
explicit TextureClientRecycleTask(TextureClient* aClient, TextureFlags aFlags)
: mTextureClient(aClient)
, mFlags(aFlags)
{}
virtual void Run() override
{
mTextureClient->RecycleTexture(mFlags);
}
private:
mozilla::RefPtr<TextureClient> mTextureClient;
TextureFlags mFlags;
};
already_AddRefed<TextureClient>
TextureClientRecycleAllocator::CreateOrRecycle(gfx::SurfaceFormat aFormat,
gfx::IntSize aSize,
@ -74,17 +92,18 @@ TextureClientRecycleAllocator::CreateOrRecycle(gfx::SurfaceFormat aFormat,
if (!mPooledClients.empty()) {
textureHolder = mPooledClients.top();
mPooledClients.pop();
Task* task = nullptr;
// If a pooled TextureClient is not compatible, release it.
if (textureHolder->GetTextureClient()->GetFormat() != aFormat ||
textureHolder->GetTextureClient()->GetSize() != aSize) {
TextureClientReleaseTask* task = new TextureClientReleaseTask(textureHolder->GetTextureClient());
// Release TextureClient.
task = new TextureClientReleaseTask(textureHolder->GetTextureClient());
textureHolder->ClearTextureClient();
textureHolder = nullptr;
// Release TextureClient.
mSurfaceAllocator->GetMessageLoop()->PostTask(FROM_HERE, task);
} else {
textureHolder->GetTextureClient()->RecycleTexture(aTextureFlags);
task = new TextureClientRecycleTask(textureHolder->GetTextureClient(), aTextureFlags);
}
mSurfaceAllocator->GetMessageLoop()->PostTask(FROM_HERE, task);
}
}

View File

@ -312,17 +312,17 @@ qcms_bool qcms_profile_is_bogus(qcms_profile *profile)
sum[2] = rZ + gZ + bZ;
// Build our target vector (see mozilla bug 460629)
target[0] = 0.96420;
target[1] = 1.00000;
target[2] = 0.82491;
target[0] = 0.96420f;
target[1] = 1.00000f;
target[2] = 0.82491f;
// Our tolerance vector - Recommended by Chris Murphy based on
// conversion from the LAB space criterion of no more than 3 in any one
// channel. This is similar to, but slightly more tolerant than Adobe's
// criterion.
tolerance[0] = 0.02;
tolerance[1] = 0.02;
tolerance[2] = 0.04;
tolerance[0] = 0.02f;
tolerance[1] = 0.02f;
tolerance[2] = 0.04f;
// Compare with our tolerance
for (i = 0; i < 3; ++i) {
@ -751,7 +751,7 @@ static struct lutType *read_tag_lutType(struct mem_source *src, struct tag_index
lut->e21 = read_s15Fixed16Number(src, offset+40);
lut->e22 = read_s15Fixed16Number(src, offset+44);
for (i = 0; i < lut->num_input_table_entries * in_chan; i++) {
for (i = 0; i < (uint32_t)(lut->num_input_table_entries * in_chan); i++) {
if (type == LUT8_TYPE) {
lut->input_table[i] = uInt8Number_to_float(read_uInt8Number(src, offset + 52 + i * entry_size));
} else {
@ -773,7 +773,7 @@ static struct lutType *read_tag_lutType(struct mem_source *src, struct tag_index
}
output_offset = clut_offset + clut_size * out_chan * entry_size;
for (i = 0; i < lut->num_output_table_entries * out_chan; i++) {
for (i = 0; i < (uint32_t)(lut->num_output_table_entries * out_chan); i++) {
if (type == LUT8_TYPE) {
lut->output_table[i] = uInt8Number_to_float(read_uInt8Number(src, output_offset + i*entry_size));
} else {
@ -1310,7 +1310,7 @@ void qcms_data_from_unicode_path(const wchar_t *path, void **mem, size_t *size)
#define ICC_PROFILE_HEADER_LENGTH 128
void qcms_data_create_rgb_with_gamma(qcms_CIE_xyY white_point, qcms_CIE_xyYTRIPLE primaries, float gamma, void **mem, size_t *size)
{
uint32_t length, offset, index, xyz_count, trc_count;
uint32_t length, index, xyz_count, trc_count;
size_t tag_table_offset, tag_data_offset;
void *data;
struct matrix colorants;

View File

@ -17,9 +17,6 @@ SOURCES += [
'transform_util.c',
]
# XXX: We should fix these warnings.
ALLOW_COMPILER_WARNINGS = True
FINAL_LIBRARY = 'xul'
if CONFIG['GNU_CC']:

View File

@ -259,9 +259,9 @@ static struct matrix
adaption_matrix(struct CIE_XYZ source_illumination, struct CIE_XYZ target_illumination)
{
struct matrix lam_rigg = {{ // Bradford matrix
{ 0.8951, 0.2664, -0.1614 },
{ -0.7502, 1.7135, 0.0367 },
{ 0.0389, -0.0685, 1.0296 }
{ 0.8951f, 0.2664f, -0.1614f },
{ -0.7502f, 1.7135f, 0.0367f },
{ 0.0389f, -0.0685f, 1.0296f }
}};
return compute_chromatic_adaption(source_illumination, target_illumination, lam_rigg);
}
@ -1394,7 +1394,7 @@ qcms_transform* qcms_transform_create(
return transform;
}
#if defined(__GNUC__) && !defined(__x86_64__) && !defined(__amd64__)
#if defined(__GNUC__) && defined(__i386__)
/* we need this to avoid crashes when gcc assumes the stack is 128bit aligned */
__attribute__((__force_align_arg_pointer__))
#endif

View File

@ -1,5 +1,3 @@
#define _ISOC99_SOURCE /* for INFINITY */
#include <math.h>
#include <assert.h>
#include <string.h> //memcpy
@ -7,10 +5,6 @@
#include "transform_util.h"
#include "matrix.h"
#if !defined(INFINITY)
#define INFINITY HUGE_VAL
#endif
#define PARAMETRIC_CURVE_TYPE 0x70617261 //'para'
/* value must be a value between 0 and 1 */
@ -131,7 +125,7 @@ void compute_curve_gamma_table_type_parametric(float gamma_table[256], float par
c = 0;
e = 0;
f = 0;
interval = -INFINITY;
interval = -1;
} else if(count == 1) {
a = parameter[1];
b = parameter[2];
@ -167,12 +161,12 @@ void compute_curve_gamma_table_type_parametric(float gamma_table[256], float par
c = 0;
e = 0;
f = 0;
interval = -INFINITY;
interval = -1;
}
for (X = 0; X < 256; X++) {
if (X >= interval) {
// XXX The equations are not exactly as definied in the spec but are
// algebraic equivilent.
// XXX The equations are not exactly as defined in the spec but are
// algebraically equivalent.
// TODO Should division by 255 be for the whole expression.
gamma_table[X] = clamp_float(pow(a * X / 255. + b, y) + c + e);
} else {

View File

@ -27,6 +27,7 @@ FONT_PREF_LANG(Gujarati, "x-gujr", x_gujr),
FONT_PREF_LANG(Gurmukhi, "x-guru", x_guru),
FONT_PREF_LANG(Khmer, "x-khmr", x_khmr),
FONT_PREF_LANG(Malayalam, "x-mlym", x_mlym),
FONT_PREF_LANG(Mathematics, "x-math", x_math),
FONT_PREF_LANG(Oriya, "x-orya", x_orya),
FONT_PREF_LANG(Telugu, "x-telu", x_telu),
FONT_PREF_LANG(Kannada, "x-knda", x_knda),

View File

@ -281,5 +281,36 @@ Downscaler::DownscaleInputLine()
}
}
Deinterlacer::Deinterlacer(const nsIntSize& aImageSize)
: mImageSize(aImageSize)
, mBuffer(MakeUnique<uint8_t[]>(mImageSize.width *
mImageSize.height *
sizeof(uint32_t)))
{ }
uint32_t
Deinterlacer::RowSize() const
{
return mImageSize.width * sizeof(uint32_t);
}
uint8_t*
Deinterlacer::RowBuffer(uint32_t aRow)
{
uint32_t offset = aRow * RowSize();
MOZ_ASSERT(offset < mImageSize.width * mImageSize.height * sizeof(uint32_t),
"Row is outside of image");
return mBuffer.get() + offset;
}
void
Deinterlacer::PropagatePassToDownscaler(Downscaler& aDownscaler)
{
for (int32_t row = 0 ; row < mImageSize.height ; ++row) {
memcpy(aDownscaler.RowBuffer(), RowBuffer(row), RowSize());
aDownscaler.CommitRow();
}
}
} // namespace image
} // namespace mozilla

View File

@ -162,6 +162,34 @@ public:
#endif // MOZ_ENABLE_SKIA
/**
* Deinterlacer is a utility class to allow Downscaler to work with interlaced
* images.
* Since Downscaler needs to receive rows in top-to-bottom or
* bottom-to-top order, it can't natively handle interlaced images, in which the
* rows arrive in an interleaved order. Deinterlacer solves this problem by
* acting as an intermediate buffer that records decoded rows. Unlike
* Downscaler, it allows the rows to be written in arbitrary order. After each
* pass, calling PropagatePassToDownscaler() will downscale every buffered row
* in a single operation. The rows remain in the buffer, so rows that were
* written in one pass will be included in subsequent passes.
*/
class Deinterlacer
{
public:
explicit Deinterlacer(const nsIntSize& aImageSize);
uint8_t* RowBuffer(uint32_t aRow);
void PropagatePassToDownscaler(Downscaler& aDownscaler);
private:
uint32_t RowSize() const;
nsIntSize mImageSize;
UniquePtr<uint8_t[]> mBuffer;
};
} // namespace image
} // namespace mozilla

View File

@ -39,7 +39,8 @@ ShouldDownscaleDuringDecode(const nsCString& aMimeType)
return type == DecoderType::JPEG ||
type == DecoderType::ICON ||
type == DecoderType::PNG ||
type == DecoderType::BMP;
type == DecoderType::BMP ||
type == DecoderType::GIF;
}
static uint32_t

View File

@ -99,6 +99,54 @@ nsGIFDecoder2::~nsGIFDecoder2()
free(mGIFStruct.hold);
}
nsresult
nsGIFDecoder2::SetTargetSize(const nsIntSize& aSize)
{
// Make sure the size is reasonable.
if (MOZ_UNLIKELY(aSize.width <= 0 || aSize.height <= 0)) {
return NS_ERROR_FAILURE;
}
// Create a downscaler that we'll filter our output through.
mDownscaler.emplace(aSize);
return NS_OK;
}
uint8_t*
nsGIFDecoder2::GetCurrentRowBuffer()
{
if (!mDownscaler) {
MOZ_ASSERT(!mDeinterlacer, "Deinterlacer without downscaler?");
uint32_t bpp = mGIFStruct.images_decoded == 0 ? sizeof(uint32_t)
: sizeof(uint8_t);
return mImageData + mGIFStruct.irow * mGIFStruct.width * bpp;
}
if (!mDeinterlacer) {
return mDownscaler->RowBuffer();
}
return mDeinterlacer->RowBuffer(mGIFStruct.irow);
}
uint8_t*
nsGIFDecoder2::GetRowBuffer(uint32_t aRow)
{
MOZ_ASSERT(mGIFStruct.images_decoded == 0,
"Calling GetRowBuffer on a frame other than the first suggests "
"we're deinterlacing animated frames");
MOZ_ASSERT(!mDownscaler || mDeinterlacer,
"Can't get buffer for a specific row if downscaling "
"but not deinterlacing");
if (mDownscaler) {
return mDeinterlacer->RowBuffer(aRow);
}
return mImageData + aRow * mGIFStruct.width * sizeof(uint32_t);
}
void
nsGIFDecoder2::FinishInternal()
{
@ -128,6 +176,15 @@ nsGIFDecoder2::FlushImageData(uint32_t fromRow, uint32_t rows)
void
nsGIFDecoder2::FlushImageData()
{
if (mDownscaler) {
if (mDownscaler->HasInvalidation()) {
DownscalerInvalidRect invalidRect = mDownscaler->TakeInvalidRect();
PostInvalidation(invalidRect.mOriginalSizeRect,
Some(invalidRect.mTargetSizeRect));
}
return;
}
switch (mCurrentPass - mLastFlushedPass) {
case 0: // same pass
if (mCurrentRow - mLastFlushedRow) {
@ -202,21 +259,44 @@ nsGIFDecoder2::BeginImageFrame(uint16_t aDepth)
CheckForTransparency(frameRect);
// Make sure there's no animation if we're downscaling.
MOZ_ASSERT_IF(mDownscaler, !GetImageMetadata().HasAnimation());
IntSize targetSize = mDownscaler ? mDownscaler->TargetSize()
: GetSize();
// Rescale the frame rect for the target size.
IntRect targetFrameRect = frameRect;
if (mDownscaler) {
IntSize originalSize = GetSize();
targetFrameRect.ScaleRoundOut(double(targetSize.width) / originalSize.width,
double(targetSize.height) / originalSize.height);
}
// Use correct format, RGB for first frame, PAL for following frames
// and include transparency to allow for optimization of opaque images
nsresult rv = NS_OK;
if (mGIFStruct.images_decoded) {
// Image data is stored with original depth and palette.
rv = AllocateFrame(mGIFStruct.images_decoded, GetSize(),
frameRect, format, aDepth);
rv = AllocateFrame(mGIFStruct.images_decoded, targetSize,
targetFrameRect, format, aDepth);
} else {
// Regardless of depth of input, the first frame is decoded into 24bit RGB.
rv = AllocateFrame(mGIFStruct.images_decoded, GetSize(),
frameRect, format);
rv = AllocateFrame(mGIFStruct.images_decoded, targetSize,
targetFrameRect, format);
}
mCurrentFrameIndex = mGIFStruct.images_decoded;
if (NS_FAILED(rv)) {
return rv;
}
if (mDownscaler) {
rv = mDownscaler->BeginFrame(frameRect.Size(), mImageData,
mGIFStruct.is_transparent);
}
return rv;
}
@ -237,11 +317,16 @@ nsGIFDecoder2::EndImageFrame()
// This will clear the remaining bits of the placeholder. (Bug 37589)
const uint32_t realFrameHeight = mGIFStruct.height + mGIFStruct.y_offset;
if (realFrameHeight < mGIFStruct.screen_height) {
if (mDownscaler) {
IntRect targetRect = IntRect(IntPoint(), mDownscaler->TargetSize());
PostInvalidation(IntRect(IntPoint(), GetSize()), Some(targetRect));
} else {
nsIntRect r(0, realFrameHeight,
mGIFStruct.screen_width,
mGIFStruct.screen_height - realFrameHeight);
PostInvalidation(r);
}
}
// The first frame was preallocated with alpha; if it wasn't transparent, we
// should fix that. We can also mark it opaque unconditionally if we didn't
@ -291,8 +376,11 @@ nsGIFDecoder2::EndImageFrame()
uint32_t
nsGIFDecoder2::OutputRow()
{
int drow_start, drow_end;
drow_start = drow_end = mGIFStruct.irow;
// Initialize the region in which we're duplicating rows (for the
// Haeberli-inspired hack below) to |irow|, which is the row we're writing to
// now.
int drow_start = mGIFStruct.irow;
int drow_end = mGIFStruct.irow;
// Protect against too much image data
if ((unsigned)drow_start >= mGIFStruct.height) {
@ -329,8 +417,7 @@ nsGIFDecoder2::OutputRow()
}
// Row to process
const uint32_t bpr = sizeof(uint32_t) * mGIFStruct.width;
uint8_t* rowp = mImageData + (mGIFStruct.irow * bpr);
uint8_t* rowp = GetCurrentRowBuffer();
// Convert color indices to Cairo pixels
uint8_t* from = rowp + mGIFStruct.width;
@ -351,12 +438,24 @@ nsGIFDecoder2::OutputRow()
}
}
// Duplicate rows
// If we're downscaling but not deinterlacing, we're done with this row and
// can commit it now. Otherwise, we'll let Deinterlacer do the committing
// when we call PropagatePassToDownscaler() at the end of this pass.
if (mDownscaler && !mDeinterlacer) {
mDownscaler->CommitRow();
}
if (drow_end > drow_start) {
// irow is the current row filled
// Duplicate rows if needed to reduce the "venetian blind" effect mentioned
// above. This writes out scanlines of the image in a way that isn't ordered
// vertically, which is incompatible with the filter that we use for
// downscale-during-decode, so we can't do this if we're downscaling.
MOZ_ASSERT_IF(mDownscaler, mDeinterlacer);
const uint32_t bpr = sizeof(uint32_t) * mGIFStruct.width;
for (int r = drow_start; r <= drow_end; r++) {
// Skip the row we wrote to above; that's what we're copying *from*.
if (r != int(mGIFStruct.irow)) {
memcpy(mImageData + (r * bpr), rowp, bpr);
memcpy(GetRowBuffer(r), rowp, bpr);
}
}
}
@ -369,9 +468,12 @@ nsGIFDecoder2::OutputRow()
}
if (!mGIFStruct.interlaced) {
MOZ_ASSERT(!mDeinterlacer);
mGIFStruct.irow++;
} else {
static const uint8_t kjump[5] = { 1, 8, 8, 4, 2 };
int currentPass = mGIFStruct.ipass;
do {
// Row increments resp. per 8,8,4,2 rows
mGIFStruct.irow += kjump[mGIFStruct.ipass];
@ -381,6 +483,15 @@ nsGIFDecoder2::OutputRow()
mGIFStruct.ipass++;
}
} while (mGIFStruct.irow >= mGIFStruct.height);
// We've finished a pass. If we're downscaling, it's time to propagate the
// rows we've decoded so far from our Deinterlacer to our Downscaler.
if (mGIFStruct.ipass > currentPass && mDownscaler) {
MOZ_ASSERT(mDeinterlacer);
mDeinterlacer->PropagatePassToDownscaler(*mDownscaler);
FlushImageData();
mDownscaler->ResetForNextProgressivePass();
}
}
return --mGIFStruct.rows_remaining;
@ -413,17 +524,13 @@ nsGIFDecoder2::DoLzw(const uint8_t* q)
uint8_t* stack = mGIFStruct.stack;
uint8_t* rowp = mGIFStruct.rowp;
uint32_t bpr = mGIFStruct.width;
if (!mGIFStruct.images_decoded) {
bpr *= sizeof(uint32_t);
}
uint8_t* rowend = mImageData + (bpr * mGIFStruct.irow) + mGIFStruct.width;
uint8_t* rowend = GetCurrentRowBuffer() + mGIFStruct.width;
#define OUTPUT_ROW() \
PR_BEGIN_MACRO \
if (!OutputRow()) \
goto END; \
rowp = mImageData + mGIFStruct.irow * bpr; \
rowp = GetCurrentRowBuffer(); \
rowend = rowp + mGIFStruct.width; \
PR_END_MACRO
@ -934,12 +1041,19 @@ nsGIFDecoder2::WriteInternal(const char* aBuffer, uint32_t aCount)
// below, so that RasterImage can detect that this happened.
PostIsAnimated(/* aFirstFrameTimeout = */ 0);
}
if (IsFirstFrameDecode()) {
// We're about to get a second frame, but we only want the first. Stop
// decoding now.
mGIFStruct.state = gif_done;
break;
}
if (mDownscaler) {
MOZ_ASSERT_UNREACHABLE("Doing downscale-during-decode "
"for an animated image?");
mDownscaler.reset();
}
}
// Get image offsets, with respect to the screen origin
@ -1025,14 +1139,22 @@ nsGIFDecoder2::WriteInternal(const char* aBuffer, uint32_t aCount)
// offset. Otherwise, the area may never be refreshed and the
// placeholder will remain on the screen. (Bug 37589)
if (mGIFStruct.y_offset > 0) {
if (mDownscaler) {
IntRect targetRect = IntRect(IntPoint(), mDownscaler->TargetSize());
PostInvalidation(IntRect(IntPoint(), GetSize()), Some(targetRect));
} else {
nsIntRect r(0, 0, mGIFStruct.screen_width, mGIFStruct.y_offset);
PostInvalidation(r);
}
}
}
if (q[8] & 0x40) {
mGIFStruct.interlaced = true;
mGIFStruct.ipass = 1;
if (mDownscaler) {
mDeinterlacer.emplace(mDownscaler->OriginalSize());
}
} else {
mGIFStruct.interlaced = false;
mGIFStruct.ipass = 0;
@ -1044,7 +1166,7 @@ nsGIFDecoder2::WriteInternal(const char* aBuffer, uint32_t aCount)
// Clear state from last image
mGIFStruct.irow = 0;
mGIFStruct.rows_remaining = mGIFStruct.height;
mGIFStruct.rowp = mImageData;
mGIFStruct.rowp = GetCurrentRowBuffer();
// Depth of colors is determined by colormap
// (q[8] & 0x80) indicates local colormap

View File

@ -8,6 +8,7 @@
#define mozilla_image_decoders_nsGIFDecoder2_h
#include "Decoder.h"
#include "Downscaler.h"
#include "GIF2.h"
#include "nsCOMPtr.h"
@ -24,6 +25,8 @@ class nsGIFDecoder2 : public Decoder
public:
~nsGIFDecoder2();
nsresult SetTargetSize(const nsIntSize& aSize) override;
virtual void WriteInternal(const char* aBuffer, uint32_t aCount) override;
virtual void FinishInternal() override;
virtual Telemetry::ID SpeedHistogram() override;
@ -34,6 +37,9 @@ private:
// Decoders should only be instantiated via DecoderFactory.
explicit nsGIFDecoder2(RasterImage* aImage);
uint8_t* GetCurrentRowBuffer();
uint8_t* GetRowBuffer(uint32_t aRow);
// These functions will be called when the decoder has a decoded row,
// frame size information, etc.
void BeginGIF();
@ -67,6 +73,8 @@ private:
bool mSawTransparency;
gif_struct mGIFStruct;
Maybe<Downscaler> mDownscaler;
Maybe<Deinterlacer> mDeinterlacer;
};
} // namespace image

View File

@ -10,6 +10,8 @@
#include <mach/vm_map.h>
#include <mach/mach_port.h>
#include <mach/mach_vm.h>
#include <pthread.h>
#include <unistd.h>
#include "SharedMemoryBasic.h"
#include "chrome/common/mach_ipc_mac.h"

View File

@ -66,8 +66,7 @@ class JavaScriptBase : public WrapperOwner, public WrapperAnswer, public Base
ReturnStatus* rs, bool* bp) {
return Answer::RecvHasOwn(ObjectId::deserialize(objId), id, rs, bp);
}
bool RecvGet(const uint64_t& objId, const ObjectVariant& receiverVar,
const JSIDVariant& id,
bool RecvGet(const uint64_t& objId, const JSVariant& receiverVar, const JSIDVariant& id,
ReturnStatus* rs, JSVariant* result) {
return Answer::RecvGet(ObjectId::deserialize(objId), receiverVar, id, rs, result);
}
@ -155,8 +154,7 @@ class JavaScriptBase : public WrapperOwner, public WrapperAnswer, public Base
ReturnStatus* rs, bool* bp) {
return Base::SendHasOwn(objId.serialize(), id, rs, bp);
}
bool SendGet(const ObjectId& objId, const ObjectVariant& receiverVar,
const JSIDVariant& id,
bool SendGet(const ObjectId& objId, const JSVariant& receiverVar, const JSIDVariant& id,
ReturnStatus* rs, JSVariant* result) {
return Base::SendGet(objId.serialize(), receiverVar, id, rs, result);
}

View File

@ -32,7 +32,7 @@ both:
prio(high) sync Has(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs, bool has);
prio(high) sync HasOwn(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs, bool has);
prio(high) sync Get(uint64_t objId, ObjectVariant receiver, JSIDVariant id) returns (ReturnStatus rs, JSVariant result);
prio(high) sync Get(uint64_t objId, JSVariant receiver, JSIDVariant id) returns (ReturnStatus rs, JSVariant result);
prio(high) sync Set(uint64_t objId, JSIDVariant id, JSVariant value, JSVariant receiver) returns (ReturnStatus rs);
prio(high) sync IsExtensible(uint64_t objId) returns (ReturnStatus rs, bool result);

View File

@ -272,7 +272,7 @@ WrapperAnswer::RecvHasOwn(const ObjectId& objId, const JSIDVariant& idVar, Retur
}
bool
WrapperAnswer::RecvGet(const ObjectId& objId, const ObjectVariant& receiverVar,
WrapperAnswer::RecvGet(const ObjectId& objId, const JSVariant& receiverVar,
const JSIDVariant& idVar, ReturnStatus* rs, JSVariant* result)
{
// We may run scripted getters.
@ -289,8 +289,8 @@ WrapperAnswer::RecvGet(const ObjectId& objId, const ObjectVariant& receiverVar,
if (!obj)
return fail(aes, rs);
RootedObject receiver(cx, fromObjectVariant(cx, receiverVar));
if (!receiver)
RootedValue receiver(cx);
if (!fromVariant(cx, receiverVar, &receiver))
return fail(aes, rs);
RootedId id(cx);

View File

@ -39,7 +39,7 @@ class WrapperAnswer : public virtual JavaScriptShared
ReturnStatus* rs, bool* foundp);
bool RecvHasOwn(const ObjectId& objId, const JSIDVariant& id,
ReturnStatus* rs, bool* foundp);
bool RecvGet(const ObjectId& objId, const ObjectVariant& receiverVar,
bool RecvGet(const ObjectId& objId, const JSVariant& receiverVar,
const JSIDVariant& id,
ReturnStatus* rs, JSVariant* result);
bool RecvSet(const ObjectId& objId, const JSIDVariant& id, const JSVariant& value,

View File

@ -111,7 +111,7 @@ class CPOWProxyHandler : public BaseProxyHandler
ObjectOpResult& result) const override;
virtual bool isExtensible(JSContext* cx, HandleObject proxy, bool* extensible) const override;
virtual bool has(JSContext* cx, HandleObject proxy, HandleId id, bool* bp) const override;
virtual bool get(JSContext* cx, HandleObject proxy, HandleObject receiver,
virtual bool get(JSContext* cx, HandleObject proxy, HandleValue receiver,
HandleId id, MutableHandleValue vp) const override;
virtual bool set(JSContext* cx, JS::HandleObject proxy, JS::HandleId id, JS::HandleValue v,
JS::HandleValue receiver, JS::ObjectOpResult& result) const override;
@ -341,7 +341,7 @@ WrapperOwner::hasOwn(JSContext* cx, HandleObject proxy, HandleId id, bool* bp)
}
bool
CPOWProxyHandler::get(JSContext* cx, HandleObject proxy, HandleObject receiver,
CPOWProxyHandler::get(JSContext* cx, HandleObject proxy, HandleValue receiver,
HandleId id, MutableHandleValue vp) const
{
FORWARD(get, (cx, proxy, receiver, id, vp));
@ -458,13 +458,13 @@ WrapperOwner::DOMQI(JSContext* cx, JS::HandleObject proxy, JS::CallArgs& args)
}
bool
WrapperOwner::get(JSContext* cx, HandleObject proxy, HandleObject receiver,
WrapperOwner::get(JSContext* cx, HandleObject proxy, HandleValue receiver,
HandleId id, MutableHandleValue vp)
{
ObjectId objId = idOf(proxy);
ObjectVariant receiverVar;
if (!toObjectVariant(cx, receiver, &receiverVar))
JSVariant receiverVar;
if (!toVariant(cx, receiver, &receiverVar))
return false;
JSIDVariant idVar;

View File

@ -40,7 +40,7 @@ class WrapperOwner : public virtual JavaScriptShared
bool preventExtensions(JSContext* cx, JS::HandleObject proxy, JS::ObjectOpResult& result);
bool isExtensible(JSContext* cx, JS::HandleObject proxy, bool* extensible);
bool has(JSContext* cx, JS::HandleObject proxy, JS::HandleId id, bool* bp);
bool get(JSContext* cx, JS::HandleObject proxy, JS::HandleObject receiver,
bool get(JSContext* cx, JS::HandleObject proxy, JS::HandleValue receiver,
JS::HandleId id, JS::MutableHandleValue vp);
bool set(JSContext* cx, JS::HandleObject proxy, JS::HandleId id, JS::HandleValue v,
JS::HandleValue receiver, JS::ObjectOpResult& result);
@ -125,7 +125,7 @@ class WrapperOwner : public virtual JavaScriptShared
ReturnStatus* rs, bool* bp) = 0;
virtual bool SendHasOwn(const ObjectId& objId, const JSIDVariant& id,
ReturnStatus* rs, bool* bp) = 0;
virtual bool SendGet(const ObjectId& objId, const ObjectVariant& receiverVar,
virtual bool SendGet(const ObjectId& objId, const JSVariant& receiverVar,
const JSIDVariant& id,
ReturnStatus* rs, JSVariant* result) = 0;
virtual bool SendSet(const ObjectId& objId, const JSIDVariant& id, const JSVariant& value,

View File

@ -358,7 +358,7 @@ typedef bool
typedef bool
(* HasPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* foundp);
typedef bool
(* GetPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleObject receiver, JS::HandleId id,
(* GetPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleValue receiver, JS::HandleId id,
JS::MutableHandleValue vp);
typedef bool
(* SetPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue v,

View File

@ -293,7 +293,7 @@ class JS_FRIEND_API(BaseProxyHandler)
* They do not follow any standard. When in doubt, override them.
*/
virtual bool has(JSContext* cx, HandleObject proxy, HandleId id, bool* bp) const;
virtual bool get(JSContext* cx, HandleObject proxy, HandleObject receiver,
virtual bool get(JSContext* cx, HandleObject proxy, HandleValue receiver,
HandleId id, MutableHandleValue vp) const;
virtual bool set(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v,
HandleValue receiver, ObjectOpResult& result) const;
@ -394,7 +394,7 @@ class JS_FRIEND_API(DirectProxyHandler) : public BaseProxyHandler
virtual bool isExtensible(JSContext* cx, HandleObject proxy, bool* extensible) const override;
virtual bool has(JSContext* cx, HandleObject proxy, HandleId id,
bool* bp) const override;
virtual bool get(JSContext* cx, HandleObject proxy, HandleObject receiver,
virtual bool get(JSContext* cx, HandleObject proxy, HandleValue receiver,
HandleId id, MutableHandleValue vp) const override;
virtual bool set(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v,
HandleValue receiver, ObjectOpResult& result) const override;

View File

@ -1793,7 +1793,7 @@ TypedObject::obj_hasProperty(JSContext* cx, HandleObject obj, HandleId id, bool*
}
bool
TypedObject::obj_getProperty(JSContext* cx, HandleObject obj, HandleObject receiver,
TypedObject::obj_getProperty(JSContext* cx, HandleObject obj, HandleValue receiver,
HandleId id, MutableHandleValue vp)
{
Rooted<TypedObject*> typedObj(cx, &obj->as<TypedObject>());
@ -1850,7 +1850,7 @@ TypedObject::obj_getProperty(JSContext* cx, HandleObject obj, HandleObject recei
}
bool
TypedObject::obj_getElement(JSContext* cx, HandleObject obj, HandleObject receiver,
TypedObject::obj_getElement(JSContext* cx, HandleObject obj, HandleValue receiver,
uint32_t index, MutableHandleValue vp)
{
MOZ_ASSERT(obj->is<TypedObject>());

View File

@ -529,10 +529,10 @@ class TypedObject : public JSObject
static bool obj_hasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp);
static bool obj_getProperty(JSContext* cx, HandleObject obj, HandleObject receiver,
static bool obj_getProperty(JSContext* cx, HandleObject obj, HandleValue receiver,
HandleId id, MutableHandleValue vp);
static bool obj_getElement(JSContext* cx, HandleObject obj, HandleObject receiver,
static bool obj_getElement(JSContext* cx, HandleObject obj, HandleValue receiver,
uint32_t index, MutableHandleValue vp);
static bool obj_setProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,

View File

@ -6869,8 +6869,9 @@ ICGetProp_DOMProxyShadowed::Compiler::getStub(ICStubSpace* space)
static bool
ProxyGet(JSContext* cx, HandleObject proxy, HandlePropertyName name, MutableHandleValue vp)
{
RootedValue receiver(cx, ObjectValue(*proxy));
RootedId id(cx, NameToId(name));
return Proxy::get(cx, proxy, proxy, id, vp);
return Proxy::get(cx, proxy, receiver, id, vp);
}
typedef bool (*ProxyGetFn)(JSContext* cx, HandleObject proxy, HandlePropertyName name,

View File

@ -1539,6 +1539,20 @@ PushObjectOpResult(MacroAssembler& masm)
masm.Push(ImmWord(ObjectOpResult::Uninitialized));
}
static bool
ProxyGetProperty(JSContext* cx, HandleObject proxy, HandleId id, MutableHandleValue vp)
{
RootedValue receiver(cx, ObjectValue(*proxy));
return Proxy::get(cx, proxy, receiver, id, vp);
}
static bool
ProxyCallProperty(JSContext* cx, HandleObject proxy, HandleId id, MutableHandleValue vp)
{
RootedValue receiver(cx, ObjectValue(*proxy));
return Proxy::callProp(cx, proxy, receiver, id, vp);
}
static bool
EmitCallProxyGet(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& attacher,
PropertyName* name, LiveRegisterSet liveRegs, Register object,
@ -1552,7 +1566,7 @@ EmitCallProxyGet(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& at
AllocatableRegisterSet regSet(RegisterSet::All());
regSet.take(AnyRegister(object));
// Proxy::get(JSContext* cx, HandleObject proxy, HandleObject receiver, HandleId id,
// ProxyGetProperty(JSContext* cx, HandleObject proxy, HandleId id,
// MutableHandleValue vp)
Register argJSContextReg = regSet.takeAnyGeneral();
Register argProxyReg = regSet.takeAnyGeneral();
@ -1562,8 +1576,8 @@ EmitCallProxyGet(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& at
Register scratch = regSet.takeAnyGeneral();
void* getFunction = JSOp(*pc) == JSOP_CALLPROP ?
JS_FUNC_TO_DATA_PTR(void*, Proxy::callProp) :
JS_FUNC_TO_DATA_PTR(void*, Proxy::get);
JS_FUNC_TO_DATA_PTR(void*, ProxyCallProperty) :
JS_FUNC_TO_DATA_PTR(void*, ProxyGetProperty);
// Push stubCode for marking.
attacher.pushStubCodePointer(masm);
@ -1576,9 +1590,7 @@ EmitCallProxyGet(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& at
masm.Push(propId, scratch);
masm.moveStackPtrTo(argIdReg);
// Pushing object and receiver. Both are the same, so Handle to one is equivalent to
// handle to other.
masm.Push(object);
// Push the proxy. Also used as receiver.
masm.Push(object);
masm.moveStackPtrTo(argProxyReg);
@ -1592,7 +1604,6 @@ EmitCallProxyGet(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& at
masm.setupUnalignedABICall(scratch);
masm.passABIArg(argJSContextReg);
masm.passABIArg(argProxyReg);
masm.passABIArg(argProxyReg);
masm.passABIArg(argIdReg);
masm.passABIArg(argVpReg);
masm.callWithABI(getFunction);
@ -2284,9 +2295,7 @@ EmitCallProxySet(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& at
masm.Push(propId, scratch);
masm.moveStackPtrTo(argIdReg);
// Pushing object and receiver. Both are the same, so Handle to one is equivalent to
// handle to other.
masm.Push(object);
// Push object.
masm.Push(object);
masm.moveStackPtrTo(argProxyReg);

View File

@ -1401,7 +1401,6 @@ MarkJitExitFrame(JSTracer* trc, const JitFrameIterator& frame)
TraceRoot(trc, oolproxy->vp(), "ion-ool-proxy-vp");
TraceRoot(trc, oolproxy->id(), "ion-ool-proxy-id");
TraceRoot(trc, oolproxy->proxy(), "ion-ool-proxy-proxy");
TraceRoot(trc, oolproxy->receiver(), "ion-ool-proxy-receiver");
return;
}

View File

@ -699,8 +699,8 @@ class IonOOLSetterOpExitFrameLayout : public IonOOLPropertyOpExitFrameLayout
}
};
// Proxy::get(JSContext* cx, HandleObject proxy, HandleObject receiver, HandleId id,
// MutableHandleValue vp)
// ProxyGetProperty(JSContext* cx, HandleObject proxy, HandleId id, MutableHandleValue vp)
// ProxyCallProperty(JSContext* cx, HandleObject proxy, HandleId id, MutableHandleValue vp)
// ProxySetProperty(JSContext* cx, HandleObject proxy, HandleId id, MutableHandleValue vp,
// bool strict)
class IonOOLProxyExitFrameLayout
@ -712,9 +712,6 @@ class IonOOLProxyExitFrameLayout
// The proxy object.
JSObject* proxy_;
// Object for HandleObject
JSObject* receiver_;
// id for HandleId
jsid id_;
@ -746,9 +743,6 @@ class IonOOLProxyExitFrameLayout
inline jsid* id() {
return &id_;
}
inline JSObject** receiver() {
return &receiver_;
}
inline JSObject** proxy() {
return &proxy_;
}

View File

@ -2920,12 +2920,16 @@ JS_GetPropertyDescriptor(JSContext* cx, HandleObject obj, const char* name,
JS_PUBLIC_API(bool)
JS_GetPropertyById(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue vp)
{
return JS_ForwardGetPropertyTo(cx, obj, id, obj, vp);
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
assertSameCompartment(cx, obj, id);
return GetProperty(cx, obj, obj, id, vp);
}
JS_PUBLIC_API(bool)
JS_ForwardGetPropertyTo(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject onBehalfOf,
JS::MutableHandleValue vp)
JS_ForwardGetPropertyTo(JSContext* cx, HandleObject obj, HandleId id, HandleValue onBehalfOf,
MutableHandleValue vp)
{
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
@ -2935,9 +2939,13 @@ JS_ForwardGetPropertyTo(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS
}
JS_PUBLIC_API(bool)
JS_GetElement(JSContext* cx, HandleObject objArg, uint32_t index, MutableHandleValue vp)
JS_GetElement(JSContext* cx, HandleObject obj, uint32_t index, MutableHandleValue vp)
{
return JS_ForwardGetElementTo(cx, objArg, index, objArg, vp);
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
assertSameCompartment(cx, obj);
return GetElement(cx, obj, obj, index, vp);
}
JS_PUBLIC_API(bool)

View File

@ -2853,7 +2853,7 @@ extern JS_PUBLIC_API(bool)
JS_GetPropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue vp);
extern JS_PUBLIC_API(bool)
JS_ForwardGetPropertyTo(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject onBehalfOf,
JS_ForwardGetPropertyTo(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue onBehalfOf,
JS::MutableHandleValue vp);
extern JS_PUBLIC_API(bool)

View File

@ -377,7 +377,7 @@ proxy_DefineProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
extern JS_FRIEND_API(bool)
proxy_HasProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* foundp);
extern JS_FRIEND_API(bool)
proxy_GetProperty(JSContext* cx, JS::HandleObject obj, JS::HandleObject receiver, JS::HandleId id,
proxy_GetProperty(JSContext* cx, JS::HandleObject obj, JS::HandleValue receiver, JS::HandleId id,
JS::MutableHandleValue vp);
extern JS_FRIEND_API(bool)
proxy_SetProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue bp,

View File

@ -819,30 +819,65 @@ HasProperty(JSContext* cx, HandleObject obj, PropertyName* name, bool* foundp);
* `receiver[id]`, and we've already searched the prototype chain up to `obj`.
*/
inline bool
GetProperty(JSContext* cx, HandleObject obj, HandleObject receiver, HandleId id,
GetProperty(JSContext* cx, HandleObject obj, HandleValue receiver, HandleId id,
MutableHandleValue vp);
inline bool
GetProperty(JSContext* cx, HandleObject obj, HandleObject receiver, PropertyName* name,
GetProperty(JSContext* cx, HandleObject obj, HandleValue receiver, PropertyName* name,
MutableHandleValue vp)
{
RootedId id(cx, NameToId(name));
return GetProperty(cx, obj, receiver, id, vp);
}
inline bool
GetProperty(JSContext* cx, HandleObject obj, HandleObject receiver, HandleId id,
MutableHandleValue vp)
{
RootedValue receiverValue(cx, ObjectValue(*receiver));
return GetProperty(cx, obj, receiverValue, id, vp);
}
inline bool
GetProperty(JSContext* cx, HandleObject obj, HandleObject receiver, PropertyName* name,
MutableHandleValue vp)
{
RootedValue receiverValue(cx, ObjectValue(*receiver));
return GetProperty(cx, obj, receiverValue, name, vp);
}
inline bool
GetElement(JSContext* cx, HandleObject obj, HandleValue receiver, uint32_t index,
MutableHandleValue vp);
inline bool
GetElement(JSContext* cx, HandleObject obj, HandleObject receiver, uint32_t index,
MutableHandleValue vp);
inline bool
GetPropertyNoGC(JSContext* cx, JSObject* obj, JSObject* receiver, jsid id, Value* vp);
GetPropertyNoGC(JSContext* cx, JSObject* obj, const Value& receiver, jsid id, Value* vp);
inline bool
GetPropertyNoGC(JSContext* cx, JSObject* obj, JSObject* receiver, jsid id, Value* vp)
{
return GetPropertyNoGC(cx, obj, ObjectValue(*receiver), id, vp);
}
inline bool
GetPropertyNoGC(JSContext* cx, JSObject* obj, const Value& receiver, PropertyName* name, Value* vp)
{
return GetPropertyNoGC(cx, obj, receiver, NameToId(name), vp);
}
inline bool
GetPropertyNoGC(JSContext* cx, JSObject* obj, JSObject* receiver, PropertyName* name, Value* vp)
{
return GetPropertyNoGC(cx, obj, receiver, NameToId(name), vp);
return GetPropertyNoGC(cx, obj, ObjectValue(*receiver), name, vp);
}
inline bool
GetElementNoGC(JSContext* cx, JSObject* obj, const Value& receiver, uint32_t index, Value* vp);
inline bool
GetElementNoGC(JSContext* cx, JSObject* obj, JSObject* receiver, uint32_t index, Value* vp);

View File

@ -180,7 +180,7 @@ js::HasProperty(JSContext* cx, HandleObject obj, PropertyName* name, bool* found
}
inline bool
js::GetElement(JSContext* cx, HandleObject obj, HandleObject receiver, uint32_t index,
js::GetElement(JSContext* cx, HandleObject obj, HandleValue receiver, uint32_t index,
MutableHandleValue vp)
{
RootedId id(cx);
@ -190,7 +190,15 @@ js::GetElement(JSContext* cx, HandleObject obj, HandleObject receiver, uint32_t
}
inline bool
js::GetElementNoGC(JSContext* cx, JSObject* obj, JSObject* receiver, uint32_t index, Value* vp)
js::GetElement(JSContext* cx, HandleObject obj, HandleObject receiver, uint32_t index,
MutableHandleValue vp)
{
RootedValue receiverValue(cx, ObjectValue(*receiver));
return GetElement(cx, obj, receiverValue, index, vp);
}
inline bool
js::GetElementNoGC(JSContext* cx, JSObject* obj, const Value& receiver, uint32_t index, Value* vp)
{
if (obj->getOps()->getProperty)
return false;
@ -200,6 +208,12 @@ js::GetElementNoGC(JSContext* cx, JSObject* obj, JSObject* receiver, uint32_t in
return GetPropertyNoGC(cx, obj, receiver, INT_TO_JSID(index), vp);
}
inline bool
js::GetElementNoGC(JSContext* cx, JSObject* obj, JSObject* receiver, uint32_t index, Value* vp)
{
return GetElementNoGC(cx, obj, ObjectValue(*receiver), index, vp);
}
inline bool
js::DeleteProperty(JSContext* cx, HandleObject obj, HandleId id, ObjectOpResult& result)
{

View File

@ -133,7 +133,7 @@ class JS_FRIEND_API(CrossCompartmentWrapper) : public Wrapper
ObjectOpResult& result) const override;
virtual bool isExtensible(JSContext* cx, HandleObject wrapper, bool* extensible) const override;
virtual bool has(JSContext* cx, HandleObject wrapper, HandleId id, bool* bp) const override;
virtual bool get(JSContext* cx, HandleObject wrapper, HandleObject receiver,
virtual bool get(JSContext* cx, HandleObject wrapper, HandleValue receiver,
HandleId id, MutableHandleValue vp) const override;
virtual bool set(JSContext* cx, HandleObject wrapper, HandleId id, HandleValue v,
HandleValue receiver, ObjectOpResult& result) const override;
@ -191,7 +191,7 @@ class JS_FRIEND_API(OpaqueCrossCompartmentWrapper) : public CrossCompartmentWrap
virtual bool isExtensible(JSContext* cx, HandleObject wrapper, bool* extensible) const override;
virtual bool has(JSContext* cx, HandleObject wrapper, HandleId id,
bool* bp) const override;
virtual bool get(JSContext* cx, HandleObject wrapper, HandleObject receiver,
virtual bool get(JSContext* cx, HandleObject wrapper, HandleValue receiver,
HandleId id, MutableHandleValue vp) const override;
virtual bool set(JSContext* cx, HandleObject wrapper, HandleId id, HandleValue v,
HandleValue receiver, ObjectOpResult& result) const override;

View File

@ -65,7 +65,7 @@ BaseProxyHandler::hasOwn(JSContext* cx, HandleObject proxy, HandleId id, bool* b
}
bool
BaseProxyHandler::get(JSContext* cx, HandleObject proxy, HandleObject receiver,
BaseProxyHandler::get(JSContext* cx, HandleObject proxy, HandleValue receiver,
HandleId id, MutableHandleValue vp) const
{
assertEnteredPolicy(cx, proxy, id, GET);

View File

@ -153,10 +153,10 @@ CrossCompartmentWrapper::hasOwn(JSContext* cx, HandleObject wrapper, HandleId id
}
bool
CrossCompartmentWrapper::get(JSContext* cx, HandleObject wrapper, HandleObject receiver,
CrossCompartmentWrapper::get(JSContext* cx, HandleObject wrapper, HandleValue receiver,
HandleId id, MutableHandleValue vp) const
{
RootedObject receiverCopy(cx, receiver);
RootedValue receiverCopy(cx, receiver);
{
AutoCompartment call(cx, wrappedObject(wrapper));
if (!cx->compartment()->wrap(cx, &receiverCopy))

View File

@ -217,7 +217,7 @@ DirectProxyHandler::hasOwn(JSContext* cx, HandleObject proxy, HandleId id, bool*
}
bool
DirectProxyHandler::get(JSContext* cx, HandleObject proxy, HandleObject receiver,
DirectProxyHandler::get(JSContext* cx, HandleObject proxy, HandleValue receiver,
HandleId id, MutableHandleValue vp) const
{
assertEnteredPolicy(cx, proxy, id, GET);

View File

@ -95,7 +95,7 @@ OpaqueCrossCompartmentWrapper::has(JSContext* cx, HandleObject wrapper, HandleId
}
bool
OpaqueCrossCompartmentWrapper::get(JSContext* cx, HandleObject wrapper, HandleObject receiver,
OpaqueCrossCompartmentWrapper::get(JSContext* cx, HandleObject wrapper, HandleValue receiver,
HandleId id, MutableHandleValue vp) const
{
return BaseProxyHandler::get(cx, wrapper, receiver, id, vp);

View File

@ -271,7 +271,7 @@ OuterizeValue(JSContext* cx, HandleValue v)
}
bool
Proxy::get(JSContext* cx, HandleObject proxy, HandleObject receiver_, HandleId id,
Proxy::get(JSContext* cx, HandleObject proxy, HandleValue receiver_, HandleId id,
MutableHandleValue vp)
{
JS_CHECK_RECURSION(cx, return false);
@ -283,7 +283,7 @@ Proxy::get(JSContext* cx, HandleObject proxy, HandleObject receiver_, HandleId i
// Outerize the receiver. Proxy handlers shouldn't have to know about
// the Window/WindowProxy distinction.
RootedObject receiver(cx, GetOuterObject(cx, receiver_));
RootedValue receiver(cx, OuterizeValue(cx, receiver_));
if (handler->hasPrototype()) {
bool own;
@ -303,7 +303,7 @@ Proxy::get(JSContext* cx, HandleObject proxy, HandleObject receiver_, HandleId i
}
bool
Proxy::callProp(JSContext* cx, HandleObject proxy, HandleObject receiver, HandleId id,
Proxy::callProp(JSContext* cx, HandleObject proxy, HandleValue receiver, HandleId id,
MutableHandleValue vp)
{
// The inline caches need an access point for JSOP_CALLPROP sites that accounts
@ -594,7 +594,7 @@ js::proxy_HasProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool
}
bool
js::proxy_GetProperty(JSContext* cx, HandleObject obj, HandleObject receiver, HandleId id,
js::proxy_GetProperty(JSContext* cx, HandleObject obj, HandleValue receiver, HandleId id,
MutableHandleValue vp)
{
return Proxy::get(cx, obj, receiver, id, vp);

View File

@ -40,7 +40,7 @@ class Proxy
ObjectOpResult& result);
static bool setImmutablePrototype(JSContext* cx, HandleObject proxy, bool* succeeded);
static bool has(JSContext* cx, HandleObject proxy, HandleId id, bool* bp);
static bool get(JSContext* cx, HandleObject proxy, HandleObject receiver, HandleId id,
static bool get(JSContext* cx, HandleObject proxy, HandleValue receiver, HandleId id,
MutableHandleValue vp);
static bool set(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v,
HandleValue receiver, ObjectOpResult& result);
@ -72,8 +72,9 @@ class Proxy
static void trace(JSTracer* trc, JSObject* obj);
/* IC entry path for handling __noSuchMethod__ on access. */
static bool callProp(JSContext* cx, HandleObject proxy, HandleObject reveiver, HandleId id,
static bool callProp(JSContext* cx, HandleObject proxy, HandleValue reveiver, HandleId id,
MutableHandleValue vp);
};
} /* namespace js */

View File

@ -846,7 +846,7 @@ ScriptedDirectProxyHandler::has(JSContext* cx, HandleObject proxy, HandleId id,
// ES6 (22 May, 2014) 9.5.8 Proxy.[[GetP]](P, Receiver)
bool
ScriptedDirectProxyHandler::get(JSContext* cx, HandleObject proxy, HandleObject receiver,
ScriptedDirectProxyHandler::get(JSContext* cx, HandleObject proxy, HandleValue receiver,
HandleId id, MutableHandleValue vp) const
{
// step 2
@ -877,7 +877,7 @@ ScriptedDirectProxyHandler::get(JSContext* cx, HandleObject proxy, HandleObject
Value argv[] = {
ObjectOrNullValue(target),
value,
ObjectOrNullValue(receiver)
receiver
};
RootedValue trapResult(cx);
if (!Invoke(cx, ObjectValue(*handler), trap, ArrayLength(argv), argv, &trapResult))

View File

@ -44,7 +44,7 @@ class ScriptedDirectProxyHandler : public BaseProxyHandler {
virtual bool isExtensible(JSContext* cx, HandleObject proxy, bool* extensible) const override;
virtual bool has(JSContext* cx, HandleObject proxy, HandleId id, bool* bp) const override;
virtual bool get(JSContext* cx, HandleObject proxy, HandleObject receiver, HandleId id,
virtual bool get(JSContext* cx, HandleObject proxy, HandleValue receiver, HandleId id,
MutableHandleValue vp) const override;
virtual bool set(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v,
HandleValue receiver, ObjectOpResult& result) const override;

View File

@ -285,7 +285,7 @@ ScriptedIndirectProxyHandler::hasOwn(JSContext* cx, HandleObject proxy, HandleId
}
bool
ScriptedIndirectProxyHandler::get(JSContext* cx, HandleObject proxy, HandleObject receiver,
ScriptedIndirectProxyHandler::get(JSContext* cx, HandleObject proxy, HandleValue receiver,
HandleId id, MutableHandleValue vp) const
{
RootedObject handler(cx, GetIndirectProxyHandlerObject(proxy));
@ -293,7 +293,7 @@ ScriptedIndirectProxyHandler::get(JSContext* cx, HandleObject proxy, HandleObjec
if (!IdToStringOrSymbol(cx, id, &idv))
return false;
JS::AutoValueArray<2> argv(cx);
argv[0].setObjectOrNull(receiver);
argv[0].set(receiver);
argv[1].set(idv);
RootedValue fval(cx);
if (!GetDerivedTrap(cx, handler, cx->names().get, &fval))

View File

@ -35,7 +35,7 @@ class ScriptedIndirectProxyHandler : public BaseProxyHandler
ObjectOpResult& result) const override;
virtual bool isExtensible(JSContext* cx, HandleObject proxy, bool* extensible) const override;
virtual bool has(JSContext* cx, HandleObject proxy, HandleId id, bool* bp) const override;
virtual bool get(JSContext* cx, HandleObject proxy, HandleObject receiver, HandleId id,
virtual bool get(JSContext* cx, HandleObject proxy, HandleValue receiver, HandleId id,
MutableHandleValue vp) const override;
virtual bool set(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v,
HandleValue receiver, ObjectOpResult& result) const override;

View File

@ -453,41 +453,42 @@ GetObjectElementOperation(JSContext* cx, JSOp op, JS::HandleObject obj, JS::Hand
}
static MOZ_ALWAYS_INLINE bool
GetPrimitiveElementOperation(JSContext* cx, JSOp op, JS::HandleValue receiver,
GetPrimitiveElementOperation(JSContext* cx, JSOp op, JS::HandleValue receiver_,
HandleValue key, MutableHandleValue res)
{
MOZ_ASSERT(op == JSOP_GETELEM || op == JSOP_CALLELEM);
// FIXME: We shouldn't be boxing here or exposing the boxed object as
// receiver anywhere below (bug 603201).
RootedObject boxed(cx, ToObjectFromStack(cx, receiver));
RootedObject boxed(cx, ToObjectFromStack(cx, receiver_));
if (!boxed)
return false;
RootedValue receiver(cx, ObjectValue(*boxed));
do {
uint32_t index;
if (IsDefinitelyIndex(key, &index)) {
if (GetElementNoGC(cx, boxed, boxed, index, res.address()))
if (GetElementNoGC(cx, boxed, receiver, index, res.address()))
break;
if (!GetElement(cx, boxed, boxed, index, res))
if (!GetElement(cx, boxed, receiver, index, res))
return false;
break;
}
if (IsSymbolOrSymbolWrapper(key)) {
RootedId id(cx, SYMBOL_TO_JSID(ToSymbolPrimitive(key)));
if (!GetProperty(cx, boxed, boxed, id, res))
if (!GetProperty(cx, boxed, receiver, id, res))
return false;
break;
}
if (JSAtom* name = ToAtom<NoGC>(cx, key)) {
if (name->isIndex(&index)) {
if (GetElementNoGC(cx, boxed, boxed, index, res.address()))
if (GetElementNoGC(cx, boxed, receiver, index, res.address()))
break;
} else {
if (GetPropertyNoGC(cx, boxed, boxed, name->asPropertyName(), res.address()))
if (GetPropertyNoGC(cx, boxed, receiver, name->asPropertyName(), res.address()))
break;
}
}
@ -497,10 +498,10 @@ GetPrimitiveElementOperation(JSContext* cx, JSOp op, JS::HandleValue receiver,
return false;
if (name->isIndex(&index)) {
if (!GetElement(cx, boxed, boxed, index, res))
if (!GetElement(cx, boxed, receiver, index, res))
return false;
} else {
if (!GetProperty(cx, boxed, boxed, name->asPropertyName(), res))
if (!GetProperty(cx, boxed, receiver, name->asPropertyName(), res))
return false;
}
} while (false);
@ -555,8 +556,10 @@ GetElementOperation(JSContext* cx, JSOp op, MutableHandleValue lref, HandleValue
}
}
if (lref.isPrimitive())
return GetPrimitiveElementOperation(cx, op, lref, rref, res);
if (lref.isPrimitive()) {
RootedValue thisv(cx, lref);
return GetPrimitiveElementOperation(cx, op, thisv, rref, res);
}
RootedObject thisv(cx, &lref.toObject());
return GetObjectElementOperation(cx, op, thisv, thisv, rref, res);

View File

@ -255,7 +255,9 @@ GetPropertyOperation(JSContext* cx, InterpreterFrame* fp, HandleScript script, j
}
MOZ_ASSERT(op == JSOP_GETPROP || op == JSOP_LENGTH);
return GetProperty(cx, lval, name, vp);
// Copy lval, because it might alias vp.
RootedValue v(cx, lval);
return GetProperty(cx, v, name, vp);
}
static inline bool
@ -916,7 +918,7 @@ js::InternalConstructWithProvidedThis(JSContext* cx, HandleValue fval, HandleVal
}
bool
js::InvokeGetter(JSContext* cx, JSObject* obj, Value fval, MutableHandleValue rval)
js::InvokeGetter(JSContext* cx, const Value& thisv, Value fval, MutableHandleValue rval)
{
/*
* Invoke could result in another try to get or set the same id again, see
@ -924,7 +926,7 @@ js::InvokeGetter(JSContext* cx, JSObject* obj, Value fval, MutableHandleValue rv
*/
JS_CHECK_RECURSION(cx, return false);
return Invoke(cx, ObjectValue(*obj), fval, 0, nullptr, rval);
return Invoke(cx, thisv, fval, 0, nullptr, rval);
}
bool
@ -4200,7 +4202,9 @@ js::GetProperty(JSContext* cx, HandleValue v, HandlePropertyName name, MutableHa
if (!obj)
return false;
return GetProperty(cx, obj, obj, name, vp);
// Bug 603201: Pass primitive receiver here.
RootedValue receiver(cx, ObjectValue(*obj));
return GetProperty(cx, obj, receiver, name, vp);
}
bool

View File

@ -80,7 +80,7 @@ Invoke(JSContext* cx, const Value& thisv, const Value& fval, unsigned argc, cons
* getter/setter calls.
*/
extern bool
InvokeGetter(JSContext* cx, JSObject* obj, Value fval, MutableHandleValue rval);
InvokeGetter(JSContext* cx, const Value& thisv, Value fval, MutableHandleValue rval);
extern bool
InvokeSetter(JSContext* cx, const Value& thisv, Value fval, HandleValue v);

View File

@ -1194,7 +1194,7 @@ static bool IsDataDescriptor(unsigned attrs) {
template <AllowGC allowGC>
static MOZ_ALWAYS_INLINE bool
GetExistingProperty(JSContext* cx,
typename MaybeRooted<JSObject*, allowGC>::HandleType receiver,
typename MaybeRooted<Value, allowGC>::HandleType receiver,
typename MaybeRooted<NativeObject*, allowGC>::HandleType obj,
typename MaybeRooted<Shape*, allowGC>::HandleType shape,
typename MaybeRooted<Value, allowGC>::MutableHandleType vp);
@ -1213,7 +1213,8 @@ GetExistingPropertyValue(ExclusiveContext* cx, HandleNativeObject obj, HandleId
MOZ_ASSERT(shape->propid() == id);
MOZ_ASSERT(obj->contains(cx, shape));
return GetExistingProperty<CanGC>(cx->asJSContext(), obj, obj, shape, vp);
RootedValue receiver(cx, ObjectValue(*obj));
return GetExistingProperty<CanGC>(cx->asJSContext(), receiver, obj, shape, vp);
}
/*
@ -1644,7 +1645,7 @@ js::NativeHasProperty(JSContext* cx, HandleNativeObject obj, HandleId id, bool*
/*** [[Get]] *************************************************************************************/
static inline bool
CallGetter(JSContext* cx, HandleObject obj, HandleObject receiver, HandleShape shape,
CallGetter(JSContext* cx, HandleObject obj, HandleValue receiver, HandleShape shape,
MutableHandleValue vp)
{
MOZ_ASSERT(!shape->hasDefaultGetter());
@ -1662,7 +1663,7 @@ CallGetter(JSContext* cx, HandleObject obj, HandleObject receiver, HandleShape s
template <AllowGC allowGC>
static MOZ_ALWAYS_INLINE bool
GetExistingProperty(JSContext* cx,
typename MaybeRooted<JSObject*, allowGC>::HandleType receiver,
typename MaybeRooted<Value, allowGC>::HandleType receiver,
typename MaybeRooted<NativeObject*, allowGC>::HandleType obj,
typename MaybeRooted<Shape*, allowGC>::HandleType shape,
typename MaybeRooted<Value, allowGC>::MutableHandleType vp)
@ -1701,7 +1702,7 @@ GetExistingProperty(JSContext* cx,
if (!CallGetter(cx,
MaybeRooted<JSObject*, allowGC>::toHandle(obj),
MaybeRooted<JSObject*, allowGC>::toHandle(receiver),
MaybeRooted<Value, allowGC>::toHandle(receiver),
MaybeRooted<Shape*, allowGC>::toHandle(shape),
MaybeRooted<Value, allowGC>::toMutableHandle(vp)))
{
@ -1721,7 +1722,8 @@ bool
js::NativeGetExistingProperty(JSContext* cx, HandleObject receiver, HandleNativeObject obj,
HandleShape shape, MutableHandleValue vp)
{
return GetExistingProperty<CanGC>(cx, receiver, obj, shape, vp);
RootedValue receiverValue(cx, ObjectValue(*receiver));
return GetExistingProperty<CanGC>(cx, receiverValue, obj, shape, vp);
}
/*
@ -1784,7 +1786,7 @@ enum IsNameLookup { NotNameLookup = false, NameLookup = true };
*/
static bool
GetNonexistentProperty(JSContext* cx, HandleNativeObject obj, HandleId id,
HandleObject receiver, IsNameLookup nameLookup, MutableHandleValue vp)
HandleValue receiver, IsNameLookup nameLookup, MutableHandleValue vp)
{
vp.setUndefined();
@ -1849,14 +1851,14 @@ GetNonexistentProperty(JSContext* cx, HandleNativeObject obj, HandleId id,
/* The NoGC version of GetNonexistentProperty, present only to make types line up. */
bool
GetNonexistentProperty(JSContext* cx, NativeObject* obj, jsid id, JSObject* receiver,
GetNonexistentProperty(JSContext* cx, NativeObject* obj, jsid id, Value& receiver,
IsNameLookup nameLookup, FakeMutableHandle<Value> vp)
{
return false;
}
static inline bool
GeneralizedGetProperty(JSContext* cx, HandleObject obj, HandleId id, HandleObject receiver,
GeneralizedGetProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue receiver,
IsNameLookup nameLookup, MutableHandleValue vp)
{
JS_CHECK_RECURSION(cx, return false);
@ -1881,7 +1883,7 @@ GeneralizedGetProperty(JSContext* cx, HandleObject obj, HandleId id, HandleObjec
}
static inline bool
GeneralizedGetProperty(JSContext* cx, JSObject* obj, jsid id, JSObject* receiver,
GeneralizedGetProperty(JSContext* cx, JSObject* obj, jsid id, const Value& receiver,
IsNameLookup nameLookup, FakeMutableHandle<Value> vp)
{
JS_CHECK_RECURSION_DONT_REPORT(cx, return false);
@ -1894,7 +1896,7 @@ template <AllowGC allowGC>
static MOZ_ALWAYS_INLINE bool
NativeGetPropertyInline(JSContext* cx,
typename MaybeRooted<NativeObject*, allowGC>::HandleType obj,
typename MaybeRooted<JSObject*, allowGC>::HandleType receiver,
typename MaybeRooted<Value, allowGC>::HandleType receiver,
typename MaybeRooted<jsid, allowGC>::HandleType id,
IsNameLookup nameLookup,
typename MaybeRooted<Value, allowGC>::MutableHandleType vp)
@ -1948,14 +1950,14 @@ NativeGetPropertyInline(JSContext* cx,
}
bool
js::NativeGetProperty(JSContext* cx, HandleNativeObject obj, HandleObject receiver, HandleId id,
js::NativeGetProperty(JSContext* cx, HandleNativeObject obj, HandleValue receiver, HandleId id,
MutableHandleValue vp)
{
return NativeGetPropertyInline<CanGC>(cx, obj, receiver, id, NotNameLookup, vp);
}
bool
js::NativeGetPropertyNoGC(JSContext* cx, NativeObject* obj, JSObject* receiver, jsid id, Value* vp)
js::NativeGetPropertyNoGC(JSContext* cx, NativeObject* obj, const Value& receiver, jsid id, Value* vp)
{
AutoAssertNoException noexc(cx);
return NativeGetPropertyInline<NoGC>(cx, obj, receiver, id, NotNameLookup, vp);
@ -1964,9 +1966,10 @@ js::NativeGetPropertyNoGC(JSContext* cx, NativeObject* obj, JSObject* receiver,
bool
js::GetPropertyForNameLookup(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue vp)
{
RootedValue receiver(cx, ObjectValue(*obj));
if (obj->getOps()->getProperty)
return GeneralizedGetProperty(cx, obj, id, obj, NameLookup, vp);
return NativeGetPropertyInline<CanGC>(cx, obj.as<NativeObject>(), obj, id, NameLookup, vp);
return GeneralizedGetProperty(cx, obj, id, receiver, NameLookup, vp);
return NativeGetPropertyInline<CanGC>(cx, obj.as<NativeObject>(), receiver, id, NameLookup, vp);
}

View File

@ -1288,26 +1288,28 @@ extern bool
NativeHasProperty(JSContext* cx, HandleNativeObject obj, HandleId id, bool* foundp);
extern bool
NativeGetProperty(JSContext* cx, HandleNativeObject obj, HandleObject receiver, HandleId id,
NativeGetProperty(JSContext* cx, HandleNativeObject obj, HandleValue receiver, HandleId id,
MutableHandleValue vp);
extern bool
NativeGetPropertyNoGC(JSContext* cx, NativeObject* obj, JSObject* receiver, jsid id, Value* vp);
NativeGetPropertyNoGC(JSContext* cx, NativeObject* obj, const Value& receiver, jsid id, Value* vp);
extern bool
NativeGetElement(JSContext* cx, HandleNativeObject obj, HandleObject receiver, uint32_t index,
NativeGetElement(JSContext* cx, HandleNativeObject obj, HandleValue receiver, uint32_t index,
MutableHandleValue vp);
inline bool
NativeGetProperty(JSContext* cx, HandleNativeObject obj, HandleId id, MutableHandleValue vp)
{
return NativeGetProperty(cx, obj, obj, id, vp);
RootedValue receiver(cx, ObjectValue(*obj));
return NativeGetProperty(cx, obj, receiver, id, vp);
}
inline bool
NativeGetElement(JSContext* cx, HandleNativeObject obj, uint32_t index, MutableHandleValue vp)
{
return NativeGetElement(cx, obj, obj, index, vp);
RootedValue receiver(cx, ObjectValue(*obj));
return NativeGetElement(cx, obj, receiver, index, vp);
}
bool
@ -1409,7 +1411,7 @@ js::HasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp)
}
inline bool
js::GetProperty(JSContext* cx, HandleObject obj, HandleObject receiver, HandleId id,
js::GetProperty(JSContext* cx, HandleObject obj, HandleValue receiver, HandleId id,
MutableHandleValue vp)
{
if (GetPropertyOp op = obj->getOps()->getProperty)
@ -1418,7 +1420,7 @@ js::GetProperty(JSContext* cx, HandleObject obj, HandleObject receiver, HandleId
}
inline bool
js::GetPropertyNoGC(JSContext* cx, JSObject* obj, JSObject* receiver, jsid id, Value* vp)
js::GetPropertyNoGC(JSContext* cx, JSObject* obj, const Value& receiver, jsid id, Value* vp)
{
if (obj->getOps()->getProperty)
return false;

View File

@ -504,11 +504,14 @@ with_HasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp)
}
static bool
with_GetProperty(JSContext* cx, HandleObject obj, HandleObject receiver, HandleId id,
with_GetProperty(JSContext* cx, HandleObject obj, HandleValue receiver, HandleId id,
MutableHandleValue vp)
{
RootedObject actual(cx, &obj->as<DynamicWithObject>().object());
return GetProperty(cx, actual, actual, id, vp);
RootedValue actualReceiver(cx, receiver);
if (receiver.isObject() && &receiver.toObject() == obj)
actualReceiver.setObject(*actual);
return GetProperty(cx, actual, actualReceiver, id, vp);
}
static bool
@ -982,7 +985,7 @@ uninitialized_HasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* fo
}
static bool
uninitialized_GetProperty(JSContext* cx, HandleObject obj, HandleObject receiver, HandleId id,
uninitialized_GetProperty(JSContext* cx, HandleObject obj, HandleValue receiver, HandleId id,
MutableHandleValue vp)
{
ReportUninitializedLexicalId(cx, id);
@ -1624,7 +1627,7 @@ class DebugScopeProxy : public BaseProxyHandler
return true;
}
bool get(JSContext* cx, HandleObject proxy, HandleObject receiver, HandleId id,
bool get(JSContext* cx, HandleObject proxy, HandleValue receiver, HandleId id,
MutableHandleValue vp) const override
{
Rooted<DebugScopeObject*> debugScope(cx, &proxy->as<DebugScopeObject>());

View File

@ -780,7 +780,7 @@ UnboxedPlainObject::obj_hasProperty(JSContext* cx, HandleObject obj, HandleId id
}
/* static */ bool
UnboxedPlainObject::obj_getProperty(JSContext* cx, HandleObject obj, HandleObject receiver,
UnboxedPlainObject::obj_getProperty(JSContext* cx, HandleObject obj, HandleValue receiver,
HandleId id, MutableHandleValue vp)
{
const UnboxedLayout& layout = obj->as<UnboxedPlainObject>().layout();
@ -793,7 +793,9 @@ UnboxedPlainObject::obj_getProperty(JSContext* cx, HandleObject obj, HandleObjec
if (UnboxedExpandoObject* expando = obj->as<UnboxedPlainObject>().maybeExpando()) {
if (expando->containsShapeOrElement(cx, id)) {
RootedObject nexpando(cx, expando);
RootedObject nreceiver(cx, (obj == receiver) ? expando : receiver.get());
RootedValue nreceiver(cx, receiver);
if (receiver.isObject() && &receiver.toObject() == obj)
nreceiver.setObject(*expando);
return GetProperty(cx, nexpando, nreceiver, id, vp);
}
}
@ -1482,7 +1484,7 @@ UnboxedArrayObject::obj_hasProperty(JSContext* cx, HandleObject obj, HandleId id
}
/* static */ bool
UnboxedArrayObject::obj_getProperty(JSContext* cx, HandleObject obj, HandleObject receiver,
UnboxedArrayObject::obj_getProperty(JSContext* cx, HandleObject obj, HandleValue receiver,
HandleId id, MutableHandleValue vp)
{
if (obj->as<UnboxedArrayObject>().containsProperty(cx, id)) {

View File

@ -250,7 +250,7 @@ class UnboxedPlainObject : public JSObject
static bool obj_hasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp);
static bool obj_getProperty(JSContext* cx, HandleObject obj, HandleObject receiver,
static bool obj_getProperty(JSContext* cx, HandleObject obj, HandleValue receiver,
HandleId id, MutableHandleValue vp);
static bool obj_setProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
@ -386,7 +386,7 @@ class UnboxedArrayObject : public JSObject
static bool obj_hasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp);
static bool obj_getProperty(JSContext* cx, HandleObject obj, HandleObject receiver,
static bool obj_getProperty(JSContext* cx, HandleObject obj, HandleValue receiver,
HandleId id, MutableHandleValue vp);
static bool obj_setProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,

View File

@ -828,7 +828,7 @@ xpc::SandboxProxyHandler::hasOwn(JSContext* cx, JS::Handle<JSObject*> proxy,
bool
xpc::SandboxProxyHandler::get(JSContext* cx, JS::Handle<JSObject*> proxy,
JS::Handle<JSObject*> receiver,
JS::Handle<JS::Value> receiver,
JS::Handle<jsid> id,
JS::MutableHandle<Value> vp) const
{

View File

@ -169,7 +169,7 @@ AddonWrapper<Base>::getOwnPropertyDescriptor(JSContext* cx, HandleObject wrapper
template<typename Base>
bool
AddonWrapper<Base>::get(JSContext* cx, JS::Handle<JSObject*> wrapper, JS::Handle<JSObject*> receiver,
AddonWrapper<Base>::get(JSContext* cx, JS::Handle<JSObject*> wrapper, JS::Handle<Value> receiver,
JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp) const
{
Rooted<JSPropertyDescriptor> desc(cx);
@ -180,10 +180,7 @@ AddonWrapper<Base>::get(JSContext* cx, JS::Handle<JSObject*> wrapper, JS::Handle
return Base::get(cx, wrapper, receiver, id, vp);
if (desc.getter()) {
MOZ_ASSERT(desc.hasGetterObject());
AutoValueVector args(cx);
RootedValue fval(cx, ObjectValue(*desc.getterObject()));
return JS_CallFunctionValue(cx, receiver, fval, args, vp);
return Call(cx, receiver, desc.getterObject(), HandleValueArray::empty(), vp);
} else {
vp.set(desc.value());
return true;

View File

@ -36,7 +36,7 @@ class AddonWrapper : public Base {
JS::ObjectOpResult& result) const override;
virtual bool delete_(JSContext* cx, JS::HandleObject proxy, JS::HandleId id,
JS::ObjectOpResult& result) const override;
virtual bool get(JSContext* cx, JS::Handle<JSObject*> wrapper, JS::Handle<JSObject*> receiver,
virtual bool get(JSContext* cx, JS::Handle<JSObject*> wrapper, JS::Handle<JS::Value> receiver,
JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp) const override;
virtual bool set(JSContext* cx, JS::HandleObject wrapper, JS::HandleId id, JS::HandleValue v,
JS::HandleValue receiver, JS::ObjectOpResult& result) const override;

View File

@ -50,8 +50,7 @@ WaiveXrayWrapper::getOwnPropertyDescriptor(JSContext* cx, HandleObject wrapper,
}
bool
WaiveXrayWrapper::get(JSContext* cx, HandleObject wrapper,
HandleObject receiver, HandleId id,
WaiveXrayWrapper::get(JSContext* cx, HandleObject wrapper, HandleValue receiver, HandleId id,
MutableHandleValue vp) const
{
return CrossCompartmentWrapper::get(cx, wrapper, receiver, id, vp) &&

View File

@ -22,7 +22,7 @@ class WaiveXrayWrapper : public js::CrossCompartmentWrapper {
JS::MutableHandle<JSPropertyDescriptor> desc) const override;
virtual bool getPrototype(JSContext* cx, JS::Handle<JSObject*> wrapper,
JS::MutableHandle<JSObject*> protop) const override;
virtual bool get(JSContext* cx, JS::Handle<JSObject*> wrapper, JS::Handle<JSObject*> receiver,
virtual bool get(JSContext* cx, JS::Handle<JSObject*> wrapper, JS::Handle<JS::Value> receiver,
JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp) const override;
virtual bool call(JSContext* cx, JS::Handle<JSObject*> wrapper,
const JS::CallArgs& args) const override;

View File

@ -2092,13 +2092,18 @@ XrayWrapper<Base, Traits>::delete_(JSContext* cx, HandleObject wrapper,
template <typename Base, typename Traits>
bool
XrayWrapper<Base, Traits>::get(JSContext* cx, HandleObject wrapper,
HandleObject receiver, HandleId id,
HandleValue receiver, HandleId id,
MutableHandleValue vp) const
{
// Skip our Base if it isn't already ProxyHandler.
// NB: None of the functions we call are prepared for the receiver not
// being the wrapper, so ignore the receiver here.
return js::BaseProxyHandler::get(cx, wrapper, Traits::HasPrototype ? receiver : wrapper, id, vp);
RootedValue thisv(cx);
if (Traits::HasPrototype)
thisv = receiver;
else
thisv.setObject(*wrapper);
return js::BaseProxyHandler::get(cx, wrapper, thisv, id, vp);
}
template <typename Base, typename Traits>

View File

@ -446,7 +446,7 @@ class XrayWrapper : public Base {
virtual bool isExtensible(JSContext* cx, JS::Handle<JSObject*> wrapper, bool* extensible) const override;
virtual bool has(JSContext* cx, JS::Handle<JSObject*> wrapper, JS::Handle<jsid> id,
bool* bp) const override;
virtual bool get(JSContext* cx, JS::Handle<JSObject*> wrapper, JS::Handle<JSObject*> receiver,
virtual bool get(JSContext* cx, JS::Handle<JSObject*> wrapper, JS::HandleValue receiver,
JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp) const override;
virtual bool set(JSContext* cx, JS::Handle<JSObject*> wrapper, JS::Handle<jsid> id,
JS::Handle<JS::Value> v, JS::Handle<JS::Value> receiver,
@ -520,7 +520,7 @@ public:
// which implement them in terms of lower-level methods.
virtual bool has(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
bool* bp) const override;
virtual bool get(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<JSObject*> receiver,
virtual bool get(JSContext* cx, JS::Handle<JSObject*> proxy, JS::HandleValue receiver,
JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp) const override;
virtual bool set(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
JS::Handle<JS::Value> v, JS::Handle<JS::Value> receiver,

View File

@ -3691,7 +3691,11 @@ nsDocumentViewer::Print(nsIPrintSettings* aPrintSettings,
if (GetIsPrinting()) {
// Let the user know we are not ready to print.
rv = NS_ERROR_NOT_AVAILABLE;
nsPrintEngine::ShowPrintErrorDialog(rv);
if (mPrintEngine) {
mPrintEngine->FirePrintingErrorEvent(rv);
}
return rv;
}

View File

@ -11,6 +11,7 @@
#include "mozilla/AsyncEventDispatcher.h"
#include "mozilla/dom/Selection.h"
#include "mozilla/dom/CustomEvent.h"
#include "nsIScriptGlobalObject.h"
#include "nsPIDOMWindow.h"
#include "nsIDocShell.h"
@ -121,6 +122,7 @@ static const char kPrintingPromptService[] = "@mozilla.org/embedcomp/printingpro
#include "nsContentList.h"
#include "nsIChannel.h"
#include "xpcpublic.h"
#include "nsVariant.h"
using namespace mozilla;
using namespace mozilla::dom;
@ -414,8 +416,9 @@ nsPrintEngine::CommonPrint(bool aIsPrintPreview,
}
if (mProgressDialogIsShown)
CloseProgressDialog(aWebProgressListener);
if (rv != NS_ERROR_ABORT && rv != NS_ERROR_OUT_OF_MEMORY)
ShowPrintErrorDialog(rv, !aIsPrintPreview);
if (rv != NS_ERROR_ABORT && rv != NS_ERROR_OUT_OF_MEMORY) {
FirePrintingErrorEvent(rv);
}
delete mPrt;
mPrt = nullptr;
}
@ -783,7 +786,7 @@ nsPrintEngine::PrintPreview(nsIPrintSettings* aPrintSettings,
if (NS_FAILED(docShell->GetBusyFlags(&busyFlags)) ||
busyFlags != nsIDocShell::BUSY_FLAGS_NONE) {
CloseProgressDialog(aWebProgressListener);
ShowPrintErrorDialog(NS_ERROR_GFX_PRINTER_DOC_IS_BUSY, false);
FirePrintingErrorEvent(NS_ERROR_GFX_PRINTER_DOC_IS_BUSY);
return NS_ERROR_FAILURE;
}
@ -1505,7 +1508,7 @@ nsresult nsPrintEngine::CleanupOnFailure(nsresult aResult, bool aIsPrinting)
* print job without displaying any error messages
*/
if (aResult != NS_ERROR_ABORT) {
ShowPrintErrorDialog(aResult, aIsPrinting);
FirePrintingErrorEvent(aResult);
}
FirePrintCompletionEvent();
@ -1516,81 +1519,28 @@ nsresult nsPrintEngine::CleanupOnFailure(nsresult aResult, bool aIsPrinting)
//---------------------------------------------------------------------
void
nsPrintEngine::ShowPrintErrorDialog(nsresult aPrintError, bool aIsPrinting)
nsPrintEngine::FirePrintingErrorEvent(nsresult aPrintError)
{
nsAutoCString stringName;
nsXPIDLString msg, title;
nsresult rv = NS_OK;
nsCOMPtr<nsIContentViewer> cv = do_QueryInterface(mDocViewerPrint);
nsCOMPtr<nsIDocument> doc = cv->GetDocument();
nsCOMPtr<nsIDOMCustomEvent> event =
NS_NewDOMCustomEvent(doc, nullptr, nullptr);
switch(aPrintError)
{
#define ENTITY_FOR_ERROR(label) \
case NS_ERROR_##label: stringName.AssignLiteral("PERR_" #label); break
MOZ_ASSERT(event);
nsCOMPtr<nsIWritableVariant> resultVariant = new nsVariant();
// nsresults are Uint32_t's, but XPConnect will interpret it as a double
// when any JS attempts to access it, and will therefore interpret it
// incorrectly. We preempt this by casting and setting as a double.
resultVariant->SetAsDouble(static_cast<double>(aPrintError));
ENTITY_FOR_ERROR(GFX_PRINTER_NO_PRINTER_AVAILABLE);
ENTITY_FOR_ERROR(GFX_PRINTER_NAME_NOT_FOUND);
ENTITY_FOR_ERROR(GFX_PRINTER_COULD_NOT_OPEN_FILE);
ENTITY_FOR_ERROR(GFX_PRINTER_STARTDOC);
ENTITY_FOR_ERROR(GFX_PRINTER_ENDDOC);
ENTITY_FOR_ERROR(GFX_PRINTER_STARTPAGE);
ENTITY_FOR_ERROR(GFX_PRINTER_DOC_IS_BUSY);
event->InitCustomEvent(NS_LITERAL_STRING("PrintingError"), false, false,
resultVariant);
event->SetTrusted(true);
ENTITY_FOR_ERROR(ABORT);
ENTITY_FOR_ERROR(NOT_AVAILABLE);
ENTITY_FOR_ERROR(NOT_IMPLEMENTED);
ENTITY_FOR_ERROR(OUT_OF_MEMORY);
ENTITY_FOR_ERROR(UNEXPECTED);
default:
ENTITY_FOR_ERROR(FAILURE);
#undef ENTITY_FOR_ERROR
}
if (!aIsPrinting) {
// Try first with _PP suffix.
stringName.AppendLiteral("_PP");
rv = nsContentUtils::GetLocalizedString(
nsContentUtils::ePRINTING_PROPERTIES, stringName.get(), msg);
if (NS_FAILED(rv)) {
stringName.Truncate(stringName.Length() - 3);
}
}
if (aIsPrinting || NS_FAILED(rv)) {
rv = nsContentUtils::GetLocalizedString(
nsContentUtils::ePRINTING_PROPERTIES, stringName.get(), msg);
}
if (NS_FAILED(rv)) {
return;
}
rv = nsContentUtils::GetLocalizedString(
nsContentUtils::ePRINTING_PROPERTIES,
aIsPrinting ? "print_error_dialog_title"
: "printpreview_error_dialog_title",
title);
if (NS_FAILED(rv)) {
return;
}
nsCOMPtr<nsIWindowWatcher> wwatch =
do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
if (NS_FAILED(rv)) {
return;
}
nsCOMPtr<nsIDOMWindow> active;
wwatch->GetActiveWindow(getter_AddRefs(active));
nsCOMPtr<nsIPrompt> dialog;
/* |GetNewPrompter| allows that |active| is |nullptr|
* (see bug 234982 ("nsPrintEngine::ShowPrintErrorDialog() fails in many cases")) */
wwatch->GetNewPrompter(active, getter_AddRefs(dialog));
if (!dialog) {
return;
}
dialog->Alert(title.get(), msg.get());
nsRefPtr<AsyncEventDispatcher> asyncDispatcher =
new AsyncEventDispatcher(doc, event);
asyncDispatcher->mOnlyChromeDispatch = true;
asyncDispatcher->RunDOMEventWhenSafe();
}
//-----------------------------------------------------------------
@ -2696,7 +2646,7 @@ nsPrintEngine::PrePrintPage()
// Shouldn't |mPrt->mIsAborted| set to true all the time if something
// wents wrong?
if (rv != NS_ERROR_ABORT) {
ShowPrintErrorDialog(rv);
FirePrintingErrorEvent(rv);
mPrt->mIsAborted = true;
}
done = true;
@ -2715,7 +2665,7 @@ nsPrintEngine::PrintPage(nsPrintObject* aPO,
// Although these should NEVER be nullptr
// This is added insurance, to make sure we don't crash in optimized builds
if (!mPrt || !aPO || !mPageSeqFrame) {
ShowPrintErrorDialog(NS_ERROR_FAILURE);
FirePrintingErrorEvent(NS_ERROR_FAILURE);
return true; // means we are done printing
}
@ -2777,7 +2727,7 @@ nsPrintEngine::PrintPage(nsPrintObject* aPO,
nsresult rv = mPageSeqFrame->PrintNextPage();
if (NS_FAILED(rv)) {
if (rv != NS_ERROR_ABORT) {
ShowPrintErrorDialog(rv);
FirePrintingErrorEvent(rv);
mPrt->mIsAborted = true;
}
return true;

View File

@ -137,6 +137,7 @@ public:
bool IsThereARangeSelection(nsIDOMWindow * aDOMWin);
void FirePrintingErrorEvent(nsresult aPrintError);
//---------------------------------------------------------------------
@ -165,8 +166,6 @@ public:
nsAString& aTitle,
nsAString& aURLStr,
eDocTitleDefault aDefType);
static void ShowPrintErrorDialog(nsresult printerror,
bool aIsPrinting = true);
static bool HasFramesetChild(nsIContent* aContent);

View File

@ -1965,7 +1965,7 @@ pref("security.mixed_content.block_active_content", false);
pref("security.mixed_content.block_display_content", false);
// Sub-resource integrity
pref("security.sri.enable", false);
pref("security.sri.enable", true);
// Disable pinning checks by default.
pref("security.cert_pinning.enforcement_level", 0);
@ -2715,7 +2715,10 @@ pref("font.size.fixed.zh-TW", 16);
// mathml.css sets font-size to "inherit" and font-family to "serif" so only
// font.name.*.x-math and font.minimum-size.x-math are really relevant.
pref("font.default.x-math", "serif");
pref("font.minimum-size.x-math", 0);
pref("font.size.variable.x-math", 16);
pref("font.size.fixed.x-math", 13);
/*
* A value greater than zero enables font size inflation for
@ -3165,11 +3168,11 @@ pref("intl.tsf.hack.easy_changjei.do_not_return_no_layout_error", true);
// Whether use previous character rect for the result of
// ITfContextView::GetTextExt() if the specified range is the first character
// of selected clause of composition string.
pref("intl.tsf.hack.google_ja_input.do_not_return_no_layout_error_at_first_char", true);
pref("intl.tsf.hack.ms_japanese_ime.do_not_return_no_layout_error_at_first_char", true);
// Whether use previous character rect for the result of
// ITfContextView::GetTextExt() if the specified range is the caret of
// composition string.
pref("intl.tsf.hack.google_ja_input.do_not_return_no_layout_error_at_caret", true);
pref("intl.tsf.hack.ms_japanese_ime.do_not_return_no_layout_error_at_caret", true);
// Whether hack ITextStoreACP::QueryInsert() or not. The method should return
// new selection after specified length text is inserted at specified range.
// However, Microsoft's some Chinese TIPs expect that the result is same as

View File

@ -95,6 +95,7 @@ Http2Session::Http2Session(nsISocketTransport *aSocketTransport, uint32_t versio
, mCleanShutdown(false)
, mTLSProfileConfirmed(false)
, mGoAwayReason(NO_HTTP_ERROR)
, mClientGoAwayReason(UNASSIGNED)
, mPeerGoAwayReason(UNASSIGNED)
, mGoAwayID(0)
, mOutgoingGoAwayID(0)
@ -195,6 +196,7 @@ Http2Session::~Http2Session()
Telemetry::Accumulate(Telemetry::SPDY_REQUEST_PER_CONN, (mNextStreamID - 1) / 2);
Telemetry::Accumulate(Telemetry::SPDY_SERVER_INITIATED_STREAMS,
mServerPushedResources);
Telemetry::Accumulate(Telemetry::SPDY_GOAWAY_LOCAL, mClientGoAwayReason);
Telemetry::Accumulate(Telemetry::SPDY_GOAWAY_PEER, mPeerGoAwayReason);
}
@ -806,6 +808,7 @@ Http2Session::GenerateGoAway(uint32_t aStatusCode)
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
LOG3(("Http2Session::GenerateGoAway %p code=%X\n", this, aStatusCode));
mClientGoAwayReason = aStatusCode;
uint32_t frameSize = kFrameHeaderBytes + 8;
char *packet = EnsureOutputBuffer(frameSize);
mOutputQueueUsed += frameSize;

View File

@ -424,8 +424,9 @@ private:
// only NO_HTTP_ERROR, PROTOCOL_ERROR, or INTERNAL_ERROR will be sent.
errorType mGoAwayReason;
// The error code received from the peer in a goaway frame. UNASSIGNED/31
// if not received.
// The error code sent/received on the session goaway frame. UNASSIGNED/31
// if not transmitted.
int32_t mClientGoAwayReason;
int32_t mPeerGoAwayReason;
// If a GoAway message was received this is the ID of the last valid

View File

@ -2896,8 +2896,9 @@ nsHttpChannel::OpenCacheEntry(bool isHttps)
return NS_OK;
// Pick up an application cache from the notification
// callbacks if available
if (!mApplicationCache && mInheritApplicationCache) {
// callbacks if available and if we are not an intercepted channel.
if (!PossiblyIntercepted() && !mApplicationCache &&
mInheritApplicationCache) {
nsCOMPtr<nsIApplicationCacheContainer> appCacheContainer;
GetCallback(appCacheContainer);

View File

@ -169,3 +169,11 @@ class TestElements(MarionetteTestCase):
self.assertIsNotNone(re.search(uuid_regex, el.id),
'UUID for the WebElement is not valid. ID is {}'\
.format(el.id))
def test_should_find_elements_by_link_text(self):
test_html = self.marionette.absolute_url("nestedElements.html")
self.marionette.navigate(test_html)
element = self.marionette.find_element(By.NAME, "div1")
children = element.find_elements(By.LINK_TEXT, "hello world")
self.assertEqual(len(children), 2)
self.assertEqual("link1", children[0].get_attribute("name"))
self.assertEqual("link2", children[1].get_attribute("name"))

View File

@ -0,0 +1,9 @@
<!DOCTYPE html>
<a href="1.html">hello world</a>
<a href="1.html">hello world</a><a href="1.html">hello world</a>
<div name="div1">
<a href="2.html" name="link1">hello world</a>
<a href="2.html" name="link2">hello world</a>
</div>
<a href="1.html">hello world</a><a href="1.html">hello world</a><a href="1.html">hello world</a>

View File

@ -681,7 +681,7 @@ ElementManager.prototype = {
break;
case LINK_TEXT:
case PARTIAL_LINK_TEXT:
let allLinks = rootNode.getElementsByTagName('A');
let allLinks = startNode.getElementsByTagName('A');
for (let i = 0; i < allLinks.length; i++) {
let text = allLinks[i].text;
if (PARTIAL_LINK_TEXT == using) {

View File

@ -1,62 +1,5 @@
[subresource-integrity.html]
type: testharness
[Doesn't load scripts with improper integrity URI scheme]
expected: FAIL
[Doesn't load scripts with incorrect content-type]
expected: FAIL
[Doesn't load scripts with non-matching digest]
expected: FAIL
[Doesn't load scripts using weak digest algorithm]
expected: FAIL
[Same-origin script with incorrect hash.]
expected: FAIL
[SHA-512 preferred to SHA-256.]
expected: FAIL
[SHA-512 preferred to SHA-384.]
expected: FAIL
[SHA-384 preferred to SHA-256.]
expected: FAIL
[SHA-256 preferred to MD5.]
expected: FAIL
[getPrioritizedHashFunction('SHA-256', 'SHA-256') returns empty string]
expected: FAIL
[Same-origin script with sha256 match, sha512 mismatch]
expected: FAIL
[<crossorigin='anonymous'> with incorrect hash, ACAO: *]
expected: FAIL
[<crossorigin='use-credentials'> with incorrect hash CORS-eligible]
expected: FAIL
[Resource with Refresh header]
expected: FAIL
[Resource with WWW-Authenticate header]
expected: FAIL
[Script: Same-origin with incorrect hash.]
expected: FAIL
[Script: Same-origin with sha256 match, sha512 mismatch]
expected: FAIL
[Script: <crossorigin='anonymous'> with incorrect hash, ACAO: *]
expected: FAIL
[Script: <crossorigin='use-credentials'> with incorrect hash CORS-eligible]
expected: FAIL
[Style: Same-origin with incorrect hash.]
expected: FAIL
@ -71,16 +14,3 @@
[Style: Same-origin with incorrect sha256 and sha512 hash, rel='alternate stylesheet' enabled]
expected: FAIL
[Script: Cross-origin, not CORS request, with correct hash]
expected: FAIL
[Script: Cross-origin, not CORS request, with hash mismatch]
expected: FAIL
[Style: Cross-origin, not CORS request, with correct hash]
expected: FAIL
[Style: Cross-origin, not CORS request, with hash mismatch]
expected: FAIL

View File

@ -65,6 +65,17 @@ var gSavePrintSettings = false;
var gFocusedElement = null;
var PrintUtils = {
init() {
window.messageManager.addMessageListener("Printing:Error", this);
},
get bundle() {
let stringService = Components.classes["@mozilla.org/intl/stringbundle;1"]
.getService(Components.interfaces.nsIStringBundleService);
delete this.bundle;
return this.bundle = stringService.createBundle("chrome://global/locale/printing.properties");
},
/**
* Shows the page setup dialog, and saves any settings changed in
* that dialog if print.save_print_settings is set to true.
@ -300,7 +311,77 @@ var PrintUtils = {
return this.usingRemoteTabs = usingRemoteTabs;
},
displayPrintingError(nsresult, isPrinting) {
// The nsresults from a printing error are mapped to strings that have
// similar names to the errors themselves. For example, for error
// NS_ERROR_GFX_PRINTER_NO_PRINTER_AVAILABLE, the name of the string
// for the error message is: PERR_GFX_PRINTER_NO_PRINTER_AVAILABLE. What's
// more, if we're in the process of doing a print preview, it's possible
// that there are strings specific for print preview for these errors -
// if so, the names of those strings have _PP as a suffix. It's possible
// that no print preview specific strings exist, in which case it is fine
// to fall back to the original string name.
const MSG_CODES = [
"GFX_PRINTER_NO_PRINTER_AVAILABLE",
"GFX_PRINTER_NAME_NOT_FOUND",
"GFX_PRINTER_COULD_NOT_OPEN_FILE",
"GFX_PRINTER_STARTDOC",
"GFX_PRINTER_ENDDOC",
"GFX_PRINTER_STARTPAGE",
"GFX_PRINTER_DOC_IS_BUSY",
"ABORT",
"NOT_AVAILABLE",
"NOT_IMPLEMENTED",
"OUT_OF_MEMORY",
"UNEXPECTED",
];
// PERR_FAILURE is the catch-all error message if we've gotten one that
// we don't recognize.
msgName = "PERR_FAILURE";
for (let code of MSG_CODES) {
let nsErrorResult = "NS_ERROR_" + code;
if (Components.results[nsErrorResult] == nsresult) {
msgName = "PERR_" + code;
break;
}
}
let msg, title;
if (!isPrinting) {
// Try first with _PP suffix.
let ppMsgName = msgName + "_PP";
try {
msg = this.bundle.GetStringFromName(ppMsgName);
} catch(e) {
// We allow localizers to not have the print preview error string,
// and just fall back to the printing error string.
}
}
if (!msg) {
msg = this.bundle.GetStringFromName(msgName);
}
title = this.bundle.GetStringFromName(isPrinting ? "print_error_dialog_title"
: "printpreview_error_dialog_title");
let promptSvc = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
.getService(Components.interfaces.nsIPromptService);
promptSvc.alert(window, title, msg);
},
receiveMessage(aMessage) {
if (aMessage.name == "Printing:Error") {
this.displayPrintingError(aMessage.data.nsresult,
aMessage.data.isPrinting);
return;
}
// If we got here, then the message we've received must involve
// updating the print progress UI.
if (!this._webProgressPP.value) {
// We somehow didn't get a nsIWebProgressListener to be updated...
// I guess there's nothing to do.
@ -537,3 +618,5 @@ var PrintUtils = {
}
}
}
PrintUtils.init();

View File

@ -1524,6 +1524,12 @@
"extended_statistics_ok": true,
"description": "H2: Settings Initial Window (rounded to KB)"
},
"SPDY_GOAWAY_LOCAL": {
"expires_in_version": "never",
"kind": "enumerated",
"n_values": 32,
"description": "H2: goaway reason client sent from rfc 7540. 31 is none sent."
},
"SPDY_GOAWAY_PEER": {
"expires_in_version": "never",
"kind": "enumerated",
@ -9453,5 +9459,15 @@
"kind": "count",
"releaseChannelCollection": "opt-out",
"description": "Sync cryptoKeys collection HMAC mismatches."
},
"CONTENT_DOCUMENTS_DESTROYED": {
"expires_in_version": "never",
"kind": "count",
"description": "Number of content documents destroyed; used in conjunction with use counter histograms"
},
"TOP_LEVEL_CONTENT_DOCUMENTS_DESTROYED": {
"expires_in_version": "never",
"kind": "count",
"description": "Number of top-level content documents destroyed; used in conjunction with use counter histograms"
}
}

View File

@ -26,10 +26,10 @@ def main(output, *filenames):
print("enum ID : uint32_t {", file=output)
groups = itertools.groupby(histogram_tools.from_files(filenames),
lambda h: h.name().startswith("USE_COUNTER_"))
lambda h: h.name().startswith("USE_COUNTER2_"))
seen_use_counters = False
# Note that histogram_tools.py guarantees that all of the USE_COUNTER_*
# Note that histogram_tools.py guarantees that all of the USE_COUNTER2_*
# histograms are defined in a contiguous block. We therefore assume
# that there's at most one group for which use_counter_group is true.
for (use_counter_group, histograms) in groups:

View File

@ -293,7 +293,7 @@ def from_nsDeprecatedOperationList(filename):
op = match.group(1)
def add_counter(context):
name = 'USE_COUNTER_DEPRECATED_%s_%s' % (op, context.upper())
name = 'USE_COUNTER2_DEPRECATED_%s_%s' % (op, context.upper())
histograms[name] = {
'expires_in_version': 'never',
'kind': 'boolean',
@ -339,9 +339,9 @@ the histograms defined in filenames.
raise DefinitionException, "duplicate histogram name %s" % name
all_histograms[name] = definition
# We require that all USE_COUNTER_* histograms be defined in a contiguous
# We require that all USE_COUNTER2_* histograms be defined in a contiguous
# block.
use_counter_indices = filter(lambda x: x[1].startswith("USE_COUNTER_"),
use_counter_indices = filter(lambda x: x[1].startswith("USE_COUNTER2_"),
enumerate(all_histograms.iterkeys()));
if use_counter_indices:
lower_bound = use_counter_indices[0][0]

View File

@ -377,6 +377,7 @@ var Printing = {
init() {
this.MESSAGES.forEach(msgName => addMessageListener(msgName, this));
addEventListener("PrintingError", this, true);
},
get shouldSavePrintSettings() {
@ -384,6 +385,19 @@ var Printing = {
Services.prefs.getBoolPref("print.save_print_settings", false);
},
handleEvent(event) {
if (event.type == "PrintingError") {
let win = event.target.defaultView;
let wbp = win.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebBrowserPrint);
let nsresult = event.detail;
sendAsyncMessage("Printing:Error", {
isPrinting: wbp.doingPrint,
nsresult: nsresult,
});
}
},
receiveMessage(message) {
let objects = message.objects;
let data = message.data;
@ -489,6 +503,10 @@ var Printing = {
if (e.result != Cr.NS_ERROR_ABORT) {
Cu.reportError(`In Printing:Print:Done handler, got unexpected rv
${e.result}.`);
sendAsyncMessage("Printing:Error", {
isPrinting: true,
nsresult: e.result,
});
}
}

View File

@ -0,0 +1,135 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from __future__ import print_function
from distutils.version import StrictVersion
from mach.decorators import (
Command,
CommandArgument,
CommandProvider,
)
from mozbuild.base import (
MachCommandBase,
MachCommandConditions as conditions,
)
def is_osx_10_10_or_greater(cls):
import platform
release = platform.mac_ver()[0]
return release and StrictVersion(release) >= StrictVersion('10.10')
@CommandProvider
class MachCommands(MachCommandBase):
'''
Get system power consumption and related measurements.
'''
def __init__(self, context):
MachCommandBase.__init__(self, context)
@Command('power', category='misc',
conditions=[is_osx_10_10_or_greater],
description='Get system power consumption and related measurements for '
'all running browsers. Available only on Mac OS X 10.10 and above. '
'Requires root access.')
@CommandArgument('-i', '--interval', type=int, default=30000,
help='The sample period, measured in milliseconds. Defaults to 30000.')
def power(self, interval):
import os
import re
import subprocess
rapl = os.path.join(self.topobjdir, 'dist', 'bin', 'rapl')
interval = str(interval)
# Run a trivial command with |sudo| to gain temporary root privileges
# before |rapl| and |powermetrics| are called. This ensures that |rapl|
# doesn't start measuring while |powermetrics| is waiting for the root
# password to be entered.
try:
subprocess.check_call(['sudo', 'true'])
except:
print('\nsudo failed; aborting')
return 1
# This runs rapl in the background because nothing in this script
# depends on the output. This is good because we want |rapl| and
# |powermetrics| to run at the same time.
subprocess.Popen([rapl, '-n', '1', '-i', interval])
lines = subprocess.check_output(['sudo', 'powermetrics',
'--samplers', 'tasks',
'--show-process-coalition',
'--show-process-gpu',
'-n', '1',
'-i', interval])
# When run with --show-process-coalition, |powermetrics| groups outputs
# into process coalitions, each of which has a leader.
#
# For example, when Firefox runs from the dock, its coalition looks
# like this:
#
# org.mozilla.firefox
# firefox
# plugin-container
#
# When Safari runs from the dock:
#
# com.apple.Safari
# Safari
# com.apple.WebKit.Networking
# com.apple.WebKit.WebContent
# com.apple.WebKit.WebContent
#
# When Chrome runs from the dock:
#
# com.google.Chrome
# Google Chrome
# Google Chrome Helper
# Google Chrome Helper
#
# In these cases, we want to print the whole coalition.
#
# Also, when you run any of them from the command line, things are the
# same except that the leader is com.apple.Terminal and there may be
# non-browser processes in the coalition, e.g.:
#
# com.apple.Terminal
# firefox
# plugin-container
# <and possibly other, non-browser processes>
#
# We want to print all these but omit uninteresting coalitions. We
# could do this by properly parsing powermetrics output, but it's
# simpler and more robust to just grep for a handful of identifying
# strings.
print() # blank line between |rapl| output and |powermetrics| output
for line in lines.splitlines():
# Search for the following things.
#
# - '^Name' is for the columns headings line.
#
# - 'firefox' and 'plugin-container' are for Firefox
#
# - 'Safari\b' and 'WebKit' are for Safari. The '\b' excludes
# SafariCloudHistoryPush, which is a process that always
# runs, even when Safari isn't open.
#
# - 'Chrome' is for Chrome.
#
# - 'Terminal' is for the terminal. If no browser is running from
# within the terminal, it will show up unnecessarily. This is a
# minor disadvantage of this very simple parsing strategy.
#
if re.search(r'(^Name|firefox|plugin-container|Safari\b|WebKit|Chrome|Terminal)', line):
print(line)
return 0

View File

@ -801,11 +801,19 @@ public:
// Note that TIP name may depend on the language of the environment.
// For example, some TIP may use localized name for its target language
// environment but English name for the others.
bool IsGoogleJapaneseInputActive() const
bool IsMSJapaneseIMEActive() const
{
return mActiveTIPKeyboardDescription.Equals(
NS_LITERAL_STRING("Google \x65E5\x672C\x8A9E\x5165\x529B")) ||
mActiveTIPKeyboardDescription.EqualsLiteral("Google Japanese Input");
// FYI: Name of MS-IME for Japanese is same as MS-IME for Korean.
// Therefore, we need to check the langid too.
return mLangID == 0x411 &&
(mActiveTIPKeyboardDescription.EqualsLiteral("Microsoft IME") ||
mActiveTIPKeyboardDescription.Equals(
NS_LITERAL_STRING("Microsoft \xC785\xB825\xAE30")) ||
mActiveTIPKeyboardDescription.Equals(
NS_LITERAL_STRING("\x5FAE\x8F6F\x8F93\x5165\x6CD5")) ||
mActiveTIPKeyboardDescription.Equals(
NS_LITERAL_STRING("\x5FAE\x8EDF\x8F38\x5165\x6CD5")));
}
bool IsATOKActive() const
@ -897,6 +905,8 @@ private:
// Cookie of installing ITfActiveLanguageProfileNotifySink
DWORD mLangProfileCookie;
LANGID mLangID;
// True if current IME is implemented with IMM.
bool mIsIMM_IME;
// True if OnActivated() is already called
@ -917,6 +927,7 @@ StaticRefPtr<TSFStaticSink> TSFStaticSink::sInstance;
TSFStaticSink::TSFStaticSink()
: mIPProfileCookie(TF_INVALID_COOKIE)
, mLangProfileCookie(TF_INVALID_COOKIE)
, mLangID(0)
, mIsIMM_IME(false)
, mOnActivatedCalled(false)
{
@ -1035,14 +1046,13 @@ TSFStaticSink::OnActivated(REFCLSID clsid, REFGUID guidProfile,
mOnActivatedCalled = true;
mIsIMM_IME = IsIMM_IME(::GetKeyboardLayout(0));
LANGID langID;
HRESULT hr = mInputProcessorProfiles->GetCurrentLanguage(&langID);
HRESULT hr = mInputProcessorProfiles->GetCurrentLanguage(&mLangID);
if (FAILED(hr)) {
MOZ_LOG(sTextStoreLog, LogLevel::Error,
("TSF: TSFStaticSink::OnActivated() FAILED due to "
"GetCurrentLanguage() failure, hr=0x%08X", hr));
} else if (IsTIPCategoryKeyboard(clsid, langID, guidProfile)) {
GetTIPDescription(clsid, langID, guidProfile,
} else if (IsTIPCategoryKeyboard(clsid, mLangID, guidProfile)) {
GetTIPDescription(clsid, mLangID, guidProfile,
mActiveTIPKeyboardDescription);
} else if (clsid == CLSID_NULL || guidProfile == GUID_NULL) {
// Perhaps, this case is that keyboard layout without TIP is activated.
@ -1076,8 +1086,9 @@ TSFStaticSink::OnActivated(DWORD dwProfileType,
(dwProfileType == TF_PROFILETYPE_KEYBOARDLAYOUT ||
catid == GUID_TFCAT_TIP_KEYBOARD)) {
mOnActivatedCalled = true;
mLangID = langid;
mIsIMM_IME = IsIMM_IME(hkl);
GetTIPDescription(rclsid, langid, guidProfile,
GetTIPDescription(rclsid, mLangID, guidProfile,
mActiveTIPKeyboardDescription);
}
MOZ_LOG(sTextStoreLog, LogLevel::Info,
@ -1272,8 +1283,8 @@ bool TSFTextStore::sDoNotReturnNoLayoutErrorToMSSimplifiedTIP = false;
bool TSFTextStore::sDoNotReturnNoLayoutErrorToMSTraditionalTIP = false;
bool TSFTextStore::sDoNotReturnNoLayoutErrorToFreeChangJie = false;
bool TSFTextStore::sDoNotReturnNoLayoutErrorToEasyChangjei = false;
bool TSFTextStore::sDoNotReturnNoLayoutErrorToGoogleJaInputAtFirstChar = false;
bool TSFTextStore::sDoNotReturnNoLayoutErrorToGoogleJaInputAtCaret = false;
bool TSFTextStore::sDoNotReturnNoLayoutErrorToMSJapaneseIMEAtFirstChar = false;
bool TSFTextStore::sDoNotReturnNoLayoutErrorToMSJapaneseIMEAtCaret = false;
bool TSFTextStore::sHackQueryInsertForMSSimplifiedTIP = false;
bool TSFTextStore::sHackQueryInsertForMSTraditionalTIP = false;
@ -3496,41 +3507,43 @@ TSFTextStore::GetTextExt(TsViewCookie vcView,
if (mComposition.IsComposing() && mComposition.mStart < acpEnd &&
mLockedContent.IsLayoutChangedAfter(acpEnd)) {
const Selection& currentSel = CurrentSelection();
if ((sDoNotReturnNoLayoutErrorToGoogleJaInputAtFirstChar ||
sDoNotReturnNoLayoutErrorToGoogleJaInputAtCaret) &&
kSink->IsGoogleJapaneseInputActive()) {
// Google Japanese Input doesn't handle ITfContextView::GetTextExt()
// properly due to the same bug of TSF mentioned above. Google Japanese
// Input calls this twice for the first character of changing range of
// composition string and the caret which is typically at the end of
// composition string. The formar is used for showing candidate window.
// This is typically shown at wrong position. We should avoid only this
// case. This is not necessary on Windows 10.
if (sDoNotReturnNoLayoutErrorToGoogleJaInputAtFirstChar &&
if ((sDoNotReturnNoLayoutErrorToMSJapaneseIMEAtFirstChar ||
sDoNotReturnNoLayoutErrorToMSJapaneseIMEAtCaret) &&
kSink->IsMSJapaneseIMEActive()) {
// MS IME for Japanese doesn't support asynchronous handling at deciding
// its suggest list window position. The feature was implemented
// starting from Windows 8.
if (IsWin8OrLater()) {
// Basically, MS-IME tries to retrieve whole composition string rect
// at deciding suggest window immediately after unlocking the document.
// However, in e10s mode, the content hasn't updated yet in most cases.
// Therefore, if the first character at the retrieving range rect is
// available, we should use it as the result.
if (sDoNotReturnNoLayoutErrorToMSJapaneseIMEAtFirstChar &&
!mLockedContent.IsLayoutChangedAfter(acpStart) &&
acpStart < acpEnd) {
acpEnd = acpStart;
MOZ_LOG(sTextStoreLog, LogLevel::Debug,
("TSF: 0x%p TSFTextStore::GetTextExt() hacked the offsets of "
"the first character of changing range of the composition "
("TSF: 0x%p TSFTextStore::GetTextExt() hacked the offsets "
"of the first character of changing range of the composition "
"string for TIP acpStart=%d, acpEnd=%d",
this, acpStart, acpEnd));
}
// Google Japanese Input sometimes uses caret position for deciding its
// candidate window position. In such case, we should return the previous
// offset of selected clause. However, it's difficult to get where is
// selected clause for now. Instead, we should use the first character
// which is modified. This is useful in most cases.
else if (sDoNotReturnNoLayoutErrorToGoogleJaInputAtCaret &&
// Although, the condition is not clear, MS-IME sometimes retrieves the
// caret rect immediately after modifying the composition string but
// before unlocking the document. In such case, we should return the
// nearest character rect.
else if (sDoNotReturnNoLayoutErrorToMSJapaneseIMEAtCaret &&
acpStart == acpEnd &&
currentSel.IsCollapsed() && currentSel.EndOffset() == acpEnd) {
acpEnd = acpStart = mLockedContent.MinOffsetOfLayoutChanged();
MOZ_LOG(sTextStoreLog, LogLevel::Debug,
("TSF: 0x%p TSFTextStore::GetTextExt() hacked the offsets of "
"the caret of the composition string for TIP acpStart=%d, "
("TSF: 0x%p TSFTextStore::GetTextExt() hacked the offsets "
"of the caret of the composition string for TIP acpStart=%d, "
"acpEnd=%d", this, acpStart, acpEnd));
}
}
}
// Free ChangJie 2010 and Easy Changjei 1.0.12.0 doesn't handle
// ITfContextView::GetTextExt() properly. Prehaps, it's due to the bug of
// TSF. We need to check if this is necessary on Windows 10 before
@ -5226,13 +5239,13 @@ TSFTextStore::Initialize()
sDoNotReturnNoLayoutErrorToEasyChangjei =
Preferences::GetBool(
"intl.tsf.hack.easy_changjei.do_not_return_no_layout_error", true);
sDoNotReturnNoLayoutErrorToGoogleJaInputAtFirstChar =
sDoNotReturnNoLayoutErrorToMSJapaneseIMEAtFirstChar =
Preferences::GetBool(
"intl.tsf.hack.google_ja_input."
"intl.tsf.hack.ms_japanese_ime."
"do_not_return_no_layout_error_at_first_char", true);
sDoNotReturnNoLayoutErrorToGoogleJaInputAtCaret =
sDoNotReturnNoLayoutErrorToMSJapaneseIMEAtCaret =
Preferences::GetBool(
"intl.tsf.hack.google_ja_input.do_not_return_no_layout_error_at_caret",
"intl.tsf.hack.ms_japanese_ime.do_not_return_no_layout_error_at_caret",
true);
sHackQueryInsertForMSSimplifiedTIP =
Preferences::GetBool(
@ -5248,15 +5261,15 @@ TSFTextStore::Initialize()
"sCreateNativeCaretForATOK=%s, "
"sDoNotReturnNoLayoutErrorToFreeChangJie=%s, "
"sDoNotReturnNoLayoutErrorToEasyChangjei=%s, "
"sDoNotReturnNoLayoutErrorToGoogleJaInputAtFirstChar=%s, "
"sDoNotReturnNoLayoutErrorToGoogleJaInputAtCaret=%s",
"sDoNotReturnNoLayoutErrorToMSJapaneseIMEAtFirstChar=%s, "
"sDoNotReturnNoLayoutErrorToMSJapaneseIMEAtCaret=%s",
sThreadMgr.get(), sClientId, sDisplayAttrMgr.get(),
sCategoryMgr.get(), sDisabledDocumentMgr.get(), sDisabledContext.get(),
GetBoolName(sCreateNativeCaretForATOK),
GetBoolName(sDoNotReturnNoLayoutErrorToFreeChangJie),
GetBoolName(sDoNotReturnNoLayoutErrorToEasyChangjei),
GetBoolName(sDoNotReturnNoLayoutErrorToGoogleJaInputAtFirstChar),
GetBoolName(sDoNotReturnNoLayoutErrorToGoogleJaInputAtCaret)));
GetBoolName(sDoNotReturnNoLayoutErrorToMSJapaneseIMEAtFirstChar),
GetBoolName(sDoNotReturnNoLayoutErrorToMSJapaneseIMEAtCaret)));
}
// static

View File

@ -839,8 +839,8 @@ protected:
static bool sDoNotReturnNoLayoutErrorToMSTraditionalTIP;
static bool sDoNotReturnNoLayoutErrorToFreeChangJie;
static bool sDoNotReturnNoLayoutErrorToEasyChangjei;
static bool sDoNotReturnNoLayoutErrorToGoogleJaInputAtFirstChar;
static bool sDoNotReturnNoLayoutErrorToGoogleJaInputAtCaret;
static bool sDoNotReturnNoLayoutErrorToMSJapaneseIMEAtFirstChar;
static bool sDoNotReturnNoLayoutErrorToMSJapaneseIMEAtCaret;
static bool sHackQueryInsertForMSSimplifiedTIP;
static bool sHackQueryInsertForMSTraditionalTIP;
};