mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-05 23:38:38 +09:00
Merge remote-tracking branch 'origin/tracking' into custom
This commit is contained in:
commit
e78e741a17
45 changed files with 1137 additions and 43 deletions
36
dom/base/UseCounter.h
Normal file
36
dom/base/UseCounter.h
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#ifndef UseCounter_h_
|
||||
#define UseCounter_h_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
enum UseCounter : int16_t {
|
||||
eUseCounter_UNKNOWN = -1,
|
||||
#define USE_COUNTER_DOM_METHOD(interface_, name_) \
|
||||
eUseCounter_##interface_##_##name_,
|
||||
#define USE_COUNTER_DOM_ATTRIBUTE(interface_, name_) \
|
||||
eUseCounter_##interface_##_##name_##_getter, \
|
||||
eUseCounter_##interface_##_##name_##_setter,
|
||||
#define USE_COUNTER_CSS_PROPERTY(name_, id_) \
|
||||
eUseCounter_property_##id_,
|
||||
#include "mozilla/dom/UseCounterList.h"
|
||||
#undef USE_COUNTER_DOM_METHOD
|
||||
#undef USE_COUNTER_DOM_ATTRIBUTE
|
||||
#undef USE_COUNTER_CSS_PROPERTY
|
||||
|
||||
#define DEPRECATED_OPERATION(op_) \
|
||||
eUseCounter_##op_,
|
||||
#include "nsDeprecatedOperationList.h"
|
||||
#undef DEPRECATED_OPERATION
|
||||
|
||||
eUseCounter_Count
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
63
dom/base/UseCounters.conf
Normal file
63
dom/base/UseCounters.conf
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
// 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/.
|
||||
|
||||
// This file defines a list of use counters, which are things that can
|
||||
// record usage of Web platform features and then report this information
|
||||
// through Telemetry.
|
||||
//
|
||||
// The format of this file is very strict. Each line can be:
|
||||
//
|
||||
// (a) a blank line
|
||||
//
|
||||
// (b) a comment, which is a line that begins with "//"
|
||||
//
|
||||
// (c) one of three possible use counter declarations:
|
||||
//
|
||||
// method <IDL interface name>.<IDL operation name>
|
||||
// attribute <IDL interface name>.<IDL attribute name>
|
||||
// property <CSS property method name>
|
||||
//
|
||||
// The |CSS property method name| should be identical to the |method|
|
||||
// argument to CSS_PROP and related macros. The method name is
|
||||
// identical to the name of the property, except that all hyphens are
|
||||
// removed and CamelCase naming is used. See nsCSSPropList.h for
|
||||
// further details.
|
||||
//
|
||||
// To actually cause use counters to be incremented, DOM methods
|
||||
// and attributes must have a [UseCounter] extended attribute in
|
||||
// the Web IDL file. CSS properties require no special treatment
|
||||
// beyond being listed below.
|
||||
//
|
||||
// You might reasonably ask why we have this file and we require
|
||||
// annotating things with [UseCounter] in the relevant WebIDL file as
|
||||
// well. Generating things from bindings codegen and ensuring all the
|
||||
// dependencies were correct would have been rather difficult, and
|
||||
// annotating the WebIDL files does nothing for identifying CSS
|
||||
// property usage, which we would also like to track.
|
||||
|
||||
method SVGSVGElement.getElementById
|
||||
attribute SVGSVGElement.currentScale
|
||||
property Fill
|
||||
property FillOpacity
|
||||
|
||||
// Push API
|
||||
method PushManager.subscribe
|
||||
method PushSubscription.unsubscribe
|
||||
|
||||
// window.sidebar.addSearchEngine
|
||||
attribute Window.sidebar
|
||||
method External.addSearchEngine
|
||||
|
||||
// AppCache API
|
||||
method OfflineResourceList.swapCache
|
||||
method OfflineResourceList.update
|
||||
attribute OfflineResourceList.status
|
||||
attribute OfflineResourceList.onchecking
|
||||
attribute OfflineResourceList.onerror
|
||||
attribute OfflineResourceList.onnoupdate
|
||||
attribute OfflineResourceList.ondownloading
|
||||
attribute OfflineResourceList.onprogress
|
||||
attribute OfflineResourceList.onupdateready
|
||||
attribute OfflineResourceList.oncached
|
||||
attribute OfflineResourceList.onobsolete
|
||||
80
dom/base/gen-usecounters.py
Normal file
80
dom/base/gen-usecounters.py
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# 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
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
sys.path.append(os.path.dirname(__file__))
|
||||
|
||||
import usecounters
|
||||
|
||||
AUTOGENERATED_WARNING_COMMENT = "/* THIS FILE IS AUTOGENERATED BY gen-usecounters.py - DO NOT EDIT */"
|
||||
|
||||
def generate_list(f, counters):
|
||||
def print_optional_macro_declare(name):
|
||||
print('''
|
||||
#ifndef %(name)s
|
||||
#define %(name)s(interface_, name_) // nothing
|
||||
#define DEFINED_%(name)s
|
||||
#endif
|
||||
''' % { 'name': name }, file=f)
|
||||
|
||||
def print_optional_macro_undeclare(name):
|
||||
print('''
|
||||
#ifdef DEFINED_%(name)s
|
||||
#undef DEFINED_%(name)s
|
||||
#undef %(name)s
|
||||
#endif
|
||||
''' % { 'name': name }, file=f)
|
||||
|
||||
print(AUTOGENERATED_WARNING_COMMENT, file=f)
|
||||
|
||||
print_optional_macro_declare('USE_COUNTER_DOM_METHOD')
|
||||
print_optional_macro_declare('USE_COUNTER_DOM_ATTRIBUTE')
|
||||
print_optional_macro_declare('USE_COUNTER_CSS_PROPERTY')
|
||||
|
||||
for counter in counters:
|
||||
if counter['type'] == 'method':
|
||||
print('USE_COUNTER_DOM_METHOD(%s, %s)' % (counter['interface_name'], counter['method_name']), file=f)
|
||||
elif counter['type'] == 'attribute':
|
||||
print('USE_COUNTER_DOM_ATTRIBUTE(%s, %s)' % (counter['interface_name'], counter['attribute_name']), file=f)
|
||||
elif counter['type'] == 'property':
|
||||
prop = counter['property_name']
|
||||
print('USE_COUNTER_CSS_PROPERTY(%s, %s)' % (prop, prop), file=f)
|
||||
|
||||
print_optional_macro_undeclare('USE_COUNTER_DOM_METHOD')
|
||||
print_optional_macro_undeclare('USE_COUNTER_DOM_ATTRIBUTE')
|
||||
print_optional_macro_undeclare('USE_COUNTER_CSS_PROPERTY')
|
||||
|
||||
def generate_property_map(f, counters):
|
||||
print(AUTOGENERATED_WARNING_COMMENT, file=f)
|
||||
print('''
|
||||
enum {
|
||||
#define CSS_PROP_PUBLIC_OR_PRIVATE(publicname_, privatename_) privatename_
|
||||
#define CSS_PROP_LIST_INCLUDE_LOGICAL
|
||||
#define CSS_PROP(name_, id_, method_, flags_, pref_, parsevariant_, \\
|
||||
kwtable_, stylestruct_, stylestructoffset_, animtype_) \\
|
||||
USE_COUNTER_FOR_CSS_PROPERTY_##method_ = eUseCounter_UNKNOWN,
|
||||
#include "nsCSSPropList.h"
|
||||
#undef CSS_PROP
|
||||
#undef CSS_PROP_LIST_INCLUDE_LOGICAL
|
||||
#undef CSS_PROP_PUBLIC_OR_PRIVATE
|
||||
};
|
||||
''', file=f)
|
||||
for counter in counters:
|
||||
if counter['type'] == 'property':
|
||||
prop = counter['property_name']
|
||||
print('#define USE_COUNTER_FOR_CSS_PROPERTY_%s eUseCounter_property_%s' % (prop, prop), file=f)
|
||||
|
||||
def use_counter_list(output_header, conf_filename):
|
||||
counters = usecounters.read_conf(conf_filename)
|
||||
generate_list(output_header, counters)
|
||||
|
||||
def property_map(output_map, conf_filename):
|
||||
counters = usecounters.read_conf(conf_filename)
|
||||
generate_property_map(output_map, counters)
|
||||
|
|
@ -141,9 +141,11 @@ EXPORTS.mozilla += [
|
|||
'FeedWriterEnabled.h',
|
||||
'TextInputProcessor.h',
|
||||
'TimerClamping.h',
|
||||
'UseCounter.h',
|
||||
]
|
||||
|
||||
EXPORTS.mozilla.dom += [
|
||||
'!UseCounterList.h',
|
||||
'AnonymousContent.h',
|
||||
'Attr.h',
|
||||
'BarProps.h',
|
||||
|
|
@ -469,5 +471,18 @@ if CONFIG['MOZ_PHOENIX'] or CONFIG['MOZ_XULRUNNER']:
|
|||
if CONFIG['MOZ_X11']:
|
||||
CXXFLAGS += CONFIG['TK_CFLAGS']
|
||||
|
||||
GENERATED_FILES += [
|
||||
'PropertyUseCounterMap.inc',
|
||||
'UseCounterList.h',
|
||||
]
|
||||
|
||||
countermap = GENERATED_FILES['PropertyUseCounterMap.inc']
|
||||
countermap.script = 'gen-usecounters.py:property_map'
|
||||
countermap.inputs = ['UseCounters.conf']
|
||||
|
||||
counterlist = GENERATED_FILES['UseCounterList.h']
|
||||
counterlist.script = 'gen-usecounters.py:use_counter_list'
|
||||
counterlist.inputs = ['UseCounters.conf']
|
||||
|
||||
if CONFIG['GNU_CXX']:
|
||||
CXXFLAGS += ['-Wno-error=shadow']
|
||||
|
|
|
|||
|
|
@ -104,6 +104,9 @@
|
|||
#include "nsContentPermissionHelper.h"
|
||||
#include "nsCSSPseudoElements.h" // for CSSPseudoElementType
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsDocument.h"
|
||||
#include "HTMLImageElement.h"
|
||||
#include "mozilla/css/ImageLoader.h"
|
||||
#include "mozilla/layers/APZCTreeManager.h" // for layers::ZoomToRectBehavior
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/StyleSheetInlines.h"
|
||||
|
|
@ -4022,6 +4025,27 @@ nsDOMWindowUtils::LeaveChaosMode()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::ForceUseCounterFlush(nsIDOMNode *aNode)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aNode);
|
||||
|
||||
if (nsCOMPtr<nsIDocument> doc = do_QueryInterface(aNode)) {
|
||||
mozilla::css::ImageLoader* loader = doc->StyleImageLoader();
|
||||
loader->FlushUseCounters();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (nsCOMPtr<nsIContent> content = do_QueryInterface(aNode)) {
|
||||
if (HTMLImageElement* img = HTMLImageElement::FromContent(content)) {
|
||||
img->FlushUseCounters();
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::HasRuleProcessorUsedByMultipleStyleSets(uint32_t aSheetType,
|
||||
bool* aRetVal)
|
||||
|
|
|
|||
|
|
@ -9718,6 +9718,19 @@ static const char* kDocumentWarnings[] = {
|
|||
};
|
||||
#undef DOCUMENT_WARNING
|
||||
|
||||
static UseCounter
|
||||
OperationToUseCounter(nsIDocument::DeprecatedOperations aOperation)
|
||||
{
|
||||
switch(aOperation) {
|
||||
#define DEPRECATED_OPERATION(_op) \
|
||||
case nsIDocument::e##_op: return eUseCounter_##_op;
|
||||
#include "nsDeprecatedOperationList.h"
|
||||
#undef DEPRECATED_OPERATION
|
||||
default:
|
||||
MOZ_CRASH();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
nsIDocument::HasWarnedAbout(DeprecatedOperations aOperation) const
|
||||
{
|
||||
|
|
@ -9733,6 +9746,7 @@ nsIDocument::WarnOnceAbout(DeprecatedOperations aOperation,
|
|||
return;
|
||||
}
|
||||
mDeprecationWarnedAbout[aOperation] = true;
|
||||
const_cast<nsIDocument*>(this)->SetDocumentAndPageUseCounter(OperationToUseCounter(aOperation));
|
||||
uint32_t flags = asError ? nsIScriptError::errorFlag
|
||||
: nsIScriptError::warningFlag;
|
||||
nsContentUtils::ReportToConsole(flags,
|
||||
|
|
@ -11983,6 +11997,69 @@ nsIDocument::GetTopLevelContentDocument()
|
|||
return parent;
|
||||
}
|
||||
|
||||
void
|
||||
nsIDocument::PropagateUseCounters(nsIDocument* aParentDocument)
|
||||
{
|
||||
MOZ_ASSERT(this != aParentDocument);
|
||||
|
||||
// What really matters here is that our use counters get propagated as
|
||||
// high up in the content document hierarchy as possible. So,
|
||||
// starting with aParentDocument, we need to find the toplevel content
|
||||
// document, and propagate our use counters into its
|
||||
// mChildDocumentUseCounters.
|
||||
nsIDocument* contentParent = aParentDocument->GetTopLevelContentDocument();
|
||||
|
||||
if (!contentParent) {
|
||||
return;
|
||||
}
|
||||
|
||||
contentParent->mChildDocumentUseCounters |= mUseCounters;
|
||||
contentParent->mChildDocumentUseCounters |= mChildDocumentUseCounters;
|
||||
}
|
||||
|
||||
void
|
||||
nsIDocument::SetPageUseCounter(UseCounter aUseCounter)
|
||||
{
|
||||
// We want to set the use counter on the "page" that owns us; the definition
|
||||
// of "page" depends on what kind of document we are. See the comments below
|
||||
// for details. In any event, checking all the conditions below is
|
||||
// reasonably expensive, so we cache whether we've notified our owning page.
|
||||
if (mNotifiedPageForUseCounter[aUseCounter]) {
|
||||
return;
|
||||
}
|
||||
mNotifiedPageForUseCounter[aUseCounter] = true;
|
||||
|
||||
if (mDisplayDocument) {
|
||||
// If we are a resource document, we won't have a docshell and so we won't
|
||||
// record any page use counters on this document. Instead, we should
|
||||
// forward it up to the document that loaded us.
|
||||
MOZ_ASSERT(!mDocumentContainer);
|
||||
mDisplayDocument->SetChildDocumentUseCounter(aUseCounter);
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsBeingUsedAsImage()) {
|
||||
// If this is an SVG image document, we also won't have a docshell.
|
||||
MOZ_ASSERT(!mDocumentContainer);
|
||||
return;
|
||||
}
|
||||
|
||||
// We only care about use counters in content. If we're already a toplevel
|
||||
// content document, then we should have already set the use counter on
|
||||
// ourselves, and we are done.
|
||||
nsIDocument* contentParent = GetTopLevelContentDocument();
|
||||
if (!contentParent) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this == contentParent) {
|
||||
MOZ_ASSERT(GetUseCounter(aUseCounter));
|
||||
return;
|
||||
}
|
||||
|
||||
contentParent->SetChildDocumentUseCounter(aUseCounter);
|
||||
}
|
||||
|
||||
bool
|
||||
nsIDocument::HasScriptsBlockedBySandbox()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include "nsTHashtable.h" // for member
|
||||
#include "mozilla/net/ReferrerPolicy.h" // for member
|
||||
#include "nsWeakReference.h"
|
||||
#include "mozilla/UseCounter.h"
|
||||
#include "mozilla/WeakPtr.h"
|
||||
#include "Units.h"
|
||||
#include "nsContentListDeclarations.h"
|
||||
|
|
@ -2781,6 +2782,23 @@ public:
|
|||
|
||||
bool DidFireDOMContentLoaded() const { return mDidFireDOMContentLoaded; }
|
||||
|
||||
void SetDocumentUseCounter(mozilla::UseCounter aUseCounter)
|
||||
{
|
||||
if (!mUseCounters[aUseCounter]) {
|
||||
mUseCounters[aUseCounter] = true;
|
||||
}
|
||||
}
|
||||
|
||||
void SetPageUseCounter(mozilla::UseCounter aUseCounter);
|
||||
|
||||
void SetDocumentAndPageUseCounter(mozilla::UseCounter aUseCounter)
|
||||
{
|
||||
SetDocumentUseCounter(aUseCounter);
|
||||
SetPageUseCounter(aUseCounter);
|
||||
}
|
||||
|
||||
void PropagateUseCounters(nsIDocument* aParentDocument);
|
||||
|
||||
void SetUserHasInteracted(bool aUserHasInteracted)
|
||||
{
|
||||
mUserHasInteracted = aUserHasInteracted;
|
||||
|
|
@ -2839,6 +2857,24 @@ public:
|
|||
|
||||
virtual void ScheduleResizeObserversNotification() const = 0;
|
||||
|
||||
protected:
|
||||
bool GetUseCounter(mozilla::UseCounter aUseCounter)
|
||||
{
|
||||
return mUseCounters[aUseCounter];
|
||||
}
|
||||
|
||||
void SetChildDocumentUseCounter(mozilla::UseCounter aUseCounter)
|
||||
{
|
||||
if (!mChildDocumentUseCounters[aUseCounter]) {
|
||||
mChildDocumentUseCounters[aUseCounter] = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool GetChildDocumentUseCounter(mozilla::UseCounter aUseCounter)
|
||||
{
|
||||
return mChildDocumentUseCounters[aUseCounter];
|
||||
}
|
||||
|
||||
private:
|
||||
mutable std::bitset<eDeprecatedOperationCount> mDeprecationWarnedAbout;
|
||||
mutable std::bitset<eDocumentWarningCount> mDocWarningWarnedAbout;
|
||||
|
|
@ -3279,7 +3315,15 @@ protected:
|
|||
// Our live MediaQueryLists
|
||||
PRCList mDOMMediaQueryLists;
|
||||
|
||||
// Whether the user has interacted with the document or not:
|
||||
// Flags for use counters used directly by this document.
|
||||
std::bitset<mozilla::eUseCounter_Count> mUseCounters;
|
||||
// Flags for use counters used by any child documents of this document.
|
||||
std::bitset<mozilla::eUseCounter_Count> mChildDocumentUseCounters;
|
||||
// Flags for whether we've notified our top-level "page" of a use counter
|
||||
// for this child document.
|
||||
std::bitset<mozilla::eUseCounter_Count> mNotifiedPageForUseCounter;
|
||||
|
||||
// Whether the user has interacted with the document or not:
|
||||
bool mUserHasInteracted;
|
||||
|
||||
mozilla::TimeStamp mPageUnloadingEventTimeStamp;
|
||||
|
|
|
|||
|
|
@ -198,6 +198,12 @@ nsImageLoadingContent::Notify(imgIRequest* aRequest,
|
|||
}
|
||||
|
||||
if (aType == imgINotificationObserver::DECODE_COMPLETE) {
|
||||
nsCOMPtr<imgIContainer> container;
|
||||
aRequest->GetImage(getter_AddRefs(container));
|
||||
if (container) {
|
||||
container->PropagateUseCounters(GetOurOwnerDoc());
|
||||
}
|
||||
|
||||
UpdateImageState(true);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,13 @@ support-files =
|
|||
file_bug1011748_redirect.sjs
|
||||
file_bug1011748_OK.sjs
|
||||
file_messagemanager_unload.html
|
||||
file_use_counter_outer.html
|
||||
file_use_counter_svg_getElementById.svg
|
||||
file_use_counter_svg_currentScale.svg
|
||||
file_use_counter_svg_fill_pattern_definition.svg
|
||||
file_use_counter_svg_fill_pattern.svg
|
||||
file_use_counter_svg_fill_pattern_internal.svg
|
||||
file_use_counter_svg_fill_pattern_data.svg
|
||||
|
||||
[browser_bug593387.js]
|
||||
[browser_bug902350.js]
|
||||
|
|
@ -17,4 +24,5 @@ tags = mcb
|
|||
skip-if = e10s # this tests non-e10s behavior. it's not expected to work in e10s.
|
||||
[browser_state_notifications.js]
|
||||
skip-if = true # Bug 1271028
|
||||
[browser_use_counters.js]
|
||||
[browser_bug1307747.js]
|
||||
|
|
|
|||
305
dom/base/test/browser_use_counters.js
Normal file
305
dom/base/test/browser_use_counters.js
Normal file
|
|
@ -0,0 +1,305 @@
|
|||
/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
|
||||
requestLongerTimeout(2);
|
||||
|
||||
var {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const gHttpTestRoot = "http://example.com/browser/dom/base/test/";
|
||||
|
||||
/**
|
||||
* Enable local telemetry recording for the duration of the tests.
|
||||
*/
|
||||
var gOldContentCanRecord = false;
|
||||
var gOldParentCanRecord = false;
|
||||
add_task(function* test_initialize() {
|
||||
let Telemetry = Cc["@mozilla.org/base/telemetry;1"].getService(Ci.nsITelemetry);
|
||||
gOldParentCanRecord = Telemetry.canRecordExtended
|
||||
Telemetry.canRecordExtended = true;
|
||||
|
||||
// Because canRecordExtended is a per-process variable, we need to make sure
|
||||
// that all of the pages load in the same content process. Limit the number
|
||||
// of content processes to at most 1 (or 0 if e10s is off entirely).
|
||||
yield SpecialPowers.pushPrefEnv({ set: [[ "dom.ipc.processCount", 1 ]] });
|
||||
|
||||
gOldContentCanRecord = yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function () {
|
||||
let telemetry = Cc["@mozilla.org/base/telemetry;1"].getService(Ci.nsITelemetry);
|
||||
let old = telemetry.canRecordExtended;
|
||||
telemetry.canRecordExtended = true;
|
||||
return old;
|
||||
});
|
||||
info("canRecord for content: " + gOldContentCanRecord);
|
||||
});
|
||||
|
||||
add_task(function* () {
|
||||
// Check that use counters are incremented by SVGs loaded directly in iframes.
|
||||
yield check_use_counter_iframe("file_use_counter_svg_getElementById.svg",
|
||||
"SVGSVGELEMENT_GETELEMENTBYID");
|
||||
yield check_use_counter_iframe("file_use_counter_svg_currentScale.svg",
|
||||
"SVGSVGELEMENT_CURRENTSCALE_getter");
|
||||
yield check_use_counter_iframe("file_use_counter_svg_currentScale.svg",
|
||||
"SVGSVGELEMENT_CURRENTSCALE_setter");
|
||||
|
||||
// Check that even loads from the imglib cache update use counters. The
|
||||
// images should still be there, because we just loaded them in the last
|
||||
// set of tests. But we won't get updated counts for the document
|
||||
// counters, because we won't be re-parsing the SVG documents.
|
||||
yield check_use_counter_iframe("file_use_counter_svg_getElementById.svg",
|
||||
"SVGSVGELEMENT_GETELEMENTBYID", false);
|
||||
yield check_use_counter_iframe("file_use_counter_svg_currentScale.svg",
|
||||
"SVGSVGELEMENT_CURRENTSCALE_getter", false);
|
||||
yield check_use_counter_iframe("file_use_counter_svg_currentScale.svg",
|
||||
"SVGSVGELEMENT_CURRENTSCALE_setter", false);
|
||||
|
||||
// Check that use counters are incremented by SVGs loaded as images.
|
||||
// Note that SVG images are not permitted to execute script, so we can only
|
||||
// check for properties here.
|
||||
yield check_use_counter_img("file_use_counter_svg_getElementById.svg",
|
||||
"PROPERTY_FILL");
|
||||
yield check_use_counter_img("file_use_counter_svg_currentScale.svg",
|
||||
"PROPERTY_FILL");
|
||||
|
||||
// Check that use counters are incremented by directly loading SVGs
|
||||
// that reference patterns defined in another SVG file.
|
||||
yield check_use_counter_direct("file_use_counter_svg_fill_pattern.svg",
|
||||
"PROPERTY_FILLOPACITY", /*xfail=*/true);
|
||||
|
||||
// Check that use counters are incremented by directly loading SVGs
|
||||
// that reference patterns defined in the same file or in data: URLs.
|
||||
yield check_use_counter_direct("file_use_counter_svg_fill_pattern_internal.svg",
|
||||
"PROPERTY_FILLOPACITY");
|
||||
// data: URLs don't correctly propagate to their referring document yet.
|
||||
//yield check_use_counter_direct("file_use_counter_svg_fill_pattern_data.svg",
|
||||
// "PROPERTY_FILL_OPACITY");
|
||||
});
|
||||
|
||||
add_task(function* () {
|
||||
let Telemetry = Cc["@mozilla.org/base/telemetry;1"].getService(Ci.nsITelemetry);
|
||||
Telemetry.canRecordExtended = gOldParentCanRecord;
|
||||
|
||||
yield ContentTask.spawn(gBrowser.selectedBrowser, { oldCanRecord: gOldContentCanRecord }, function (arg) {
|
||||
Cu.import("resource://gre/modules/PromiseUtils.jsm");
|
||||
yield new Promise(resolve => {
|
||||
let telemetry = Cc["@mozilla.org/base/telemetry;1"].getService(Ci.nsITelemetry);
|
||||
telemetry.canRecordExtended = arg.oldCanRecord;
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
function waitForDestroyedDocuments() {
|
||||
let deferred = promise.defer();
|
||||
SpecialPowers.exactGC(deferred.resolve);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function waitForPageLoad(browser) {
|
||||
return ContentTask.spawn(browser, null, function*() {
|
||||
Cu.import("resource://gre/modules/PromiseUtils.jsm");
|
||||
yield new Promise(resolve => {
|
||||
let listener = () => {
|
||||
removeEventListener("load", listener, true);
|
||||
resolve();
|
||||
}
|
||||
addEventListener("load", listener, true);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function grabHistogramsFromContent(use_counter_middlefix, page_before = null) {
|
||||
let telemetry = Cc["@mozilla.org/base/telemetry;1"].getService(Ci.nsITelemetry);
|
||||
let suffix = Services.appinfo.browserTabsRemoteAutostart ? "#content" : "";
|
||||
let gather = () => [
|
||||
telemetry.getHistogramById("USE_COUNTER2_" + use_counter_middlefix + "_PAGE" + suffix).snapshot().sum,
|
||||
telemetry.getHistogramById("USE_COUNTER2_" + use_counter_middlefix + "_DOCUMENT" + suffix).snapshot().sum,
|
||||
telemetry.getHistogramById("CONTENT_DOCUMENTS_DESTROYED" + suffix).snapshot().sum,
|
||||
telemetry.getHistogramById("TOP_LEVEL_CONTENT_DOCUMENTS_DESTROYED" + suffix).snapshot().sum,
|
||||
];
|
||||
return BrowserTestUtils.waitForCondition(() => {
|
||||
return page_before != telemetry.getHistogramById("USE_COUNTER2_" + use_counter_middlefix + "_PAGE" + suffix).snapshot().sum;
|
||||
}).then(gather, gather);
|
||||
}
|
||||
|
||||
var check_use_counter_iframe = Task.async(function* (file, use_counter_middlefix, check_documents=true) {
|
||||
info("checking " + file + " with histogram " + use_counter_middlefix);
|
||||
|
||||
let newTab = gBrowser.addTab( "about:blank");
|
||||
gBrowser.selectedTab = newTab;
|
||||
newTab.linkedBrowser.stop();
|
||||
|
||||
// Hold on to the current values of the telemetry histograms we're
|
||||
// interested in.
|
||||
let [histogram_page_before, histogram_document_before,
|
||||
histogram_docs_before, histogram_toplevel_docs_before] =
|
||||
yield grabHistogramsFromContent(use_counter_middlefix);
|
||||
|
||||
gBrowser.selectedBrowser.loadURI(gHttpTestRoot + "file_use_counter_outer.html");
|
||||
yield waitForPageLoad(gBrowser.selectedBrowser);
|
||||
|
||||
// Inject our desired file into the iframe of the newly-loaded page.
|
||||
yield ContentTask.spawn(gBrowser.selectedBrowser, { file: file }, function(opts) {
|
||||
Cu.import("resource://gre/modules/PromiseUtils.jsm");
|
||||
let deferred = PromiseUtils.defer();
|
||||
|
||||
let wu = content.window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
|
||||
|
||||
let iframe = content.document.getElementById('content');
|
||||
iframe.src = opts.file;
|
||||
let listener = (event) => {
|
||||
event.target.removeEventListener("load", listener, true);
|
||||
|
||||
// We flush the main document first, then the iframe's document to
|
||||
// ensure any propagation that might happen from content->parent should
|
||||
// have already happened when counters are reported to telemetry.
|
||||
wu.forceUseCounterFlush(content.document);
|
||||
wu.forceUseCounterFlush(iframe.contentDocument);
|
||||
|
||||
deferred.resolve();
|
||||
};
|
||||
iframe.addEventListener("load", listener, true);
|
||||
|
||||
return deferred.promise;
|
||||
});
|
||||
|
||||
// Tear down the page.
|
||||
gBrowser.removeTab(newTab);
|
||||
|
||||
// The histograms only get recorded when the document actually gets
|
||||
// destroyed, which might not have happened yet due to GC/CC effects, etc.
|
||||
// Try to force document destruction.
|
||||
yield waitForDestroyedDocuments();
|
||||
|
||||
// Grab histograms again and compare.
|
||||
let [histogram_page_after, histogram_document_after,
|
||||
histogram_docs_after, histogram_toplevel_docs_after] =
|
||||
yield grabHistogramsFromContent(use_counter_middlefix, histogram_page_before);
|
||||
|
||||
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 for " + use_counter_middlefix + " after are correct");
|
||||
}
|
||||
});
|
||||
|
||||
var check_use_counter_img = Task.async(function* (file, use_counter_middlefix) {
|
||||
info("checking " + file + " as image with histogram " + use_counter_middlefix);
|
||||
|
||||
let newTab = gBrowser.addTab("about:blank");
|
||||
gBrowser.selectedTab = newTab;
|
||||
newTab.linkedBrowser.stop();
|
||||
|
||||
// Hold on to the current values of the telemetry histograms we're
|
||||
// interested in.
|
||||
let [histogram_page_before, histogram_document_before,
|
||||
histogram_docs_before, histogram_toplevel_docs_before] =
|
||||
yield grabHistogramsFromContent(use_counter_middlefix);
|
||||
|
||||
gBrowser.selectedBrowser.loadURI(gHttpTestRoot + "file_use_counter_outer.html");
|
||||
yield waitForPageLoad(gBrowser.selectedBrowser);
|
||||
|
||||
// Inject our desired file into the img of the newly-loaded page.
|
||||
yield ContentTask.spawn(gBrowser.selectedBrowser, { file: file }, function(opts) {
|
||||
Cu.import("resource://gre/modules/PromiseUtils.jsm");
|
||||
let deferred = PromiseUtils.defer();
|
||||
|
||||
let img = content.document.getElementById('display');
|
||||
img.src = opts.file;
|
||||
let listener = (event) => {
|
||||
img.removeEventListener("load", listener, true);
|
||||
|
||||
// Flush for the image. It matters what order we do these in, so that
|
||||
// the image can propagate its use counters to the document prior to the
|
||||
// document reporting its use counters.
|
||||
let wu = content.window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
|
||||
wu.forceUseCounterFlush(img);
|
||||
|
||||
// Flush for the main window.
|
||||
wu.forceUseCounterFlush(content.document);
|
||||
|
||||
deferred.resolve();
|
||||
};
|
||||
img.addEventListener("load", listener, true);
|
||||
|
||||
return deferred.promise;
|
||||
});
|
||||
|
||||
// Tear down the page.
|
||||
gBrowser.removeTab(newTab);
|
||||
|
||||
// The histograms only get recorded when the document actually gets
|
||||
// destroyed, which might not have happened yet due to GC/CC effects, etc.
|
||||
// Try to force document destruction.
|
||||
yield waitForDestroyedDocuments();
|
||||
|
||||
// Grab histograms again and compare.
|
||||
let [histogram_page_after, histogram_document_after,
|
||||
histogram_docs_after, histogram_toplevel_docs_after] =
|
||||
yield grabHistogramsFromContent(use_counter_middlefix, histogram_page_before);
|
||||
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 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) {
|
||||
info("checking " + file + " with histogram " + use_counter_middlefix);
|
||||
|
||||
let newTab = gBrowser.addTab( "about:blank");
|
||||
gBrowser.selectedTab = newTab;
|
||||
newTab.linkedBrowser.stop();
|
||||
|
||||
// Hold on to the current values of the telemetry histograms we're
|
||||
// interested in.
|
||||
let [histogram_page_before, histogram_document_before,
|
||||
histogram_docs_before, histogram_toplevel_docs_before] =
|
||||
yield grabHistogramsFromContent(use_counter_middlefix);
|
||||
|
||||
gBrowser.selectedBrowser.loadURI(gHttpTestRoot + file);
|
||||
yield ContentTask.spawn(gBrowser.selectedBrowser, null, function*() {
|
||||
Cu.import("resource://gre/modules/PromiseUtils.jsm");
|
||||
yield new Promise(resolve => {
|
||||
let listener = () => {
|
||||
removeEventListener("load", listener, true);
|
||||
|
||||
let wu = content.window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
|
||||
wu.forceUseCounterFlush(content.document);
|
||||
|
||||
setTimeout(resolve, 0);
|
||||
}
|
||||
addEventListener("load", listener, true);
|
||||
});
|
||||
});
|
||||
|
||||
// Tear down the page.
|
||||
gBrowser.removeTab(newTab);
|
||||
|
||||
// The histograms only get recorded when the document actually gets
|
||||
// destroyed, which might not have happened yet due to GC/CC effects, etc.
|
||||
// Try to force document destruction.
|
||||
yield waitForDestroyedDocuments();
|
||||
|
||||
// Grab histograms again and compare.
|
||||
let [histogram_page_after, histogram_document_after,
|
||||
histogram_docs_after, histogram_toplevel_docs_after] =
|
||||
yield grabHistogramsFromContent(use_counter_middlefix, histogram_page_before);
|
||||
if (!xfail) {
|
||||
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 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");
|
||||
});
|
||||
17
dom/base/test/file_use_counter_outer.html
Normal file
17
dom/base/test/file_use_counter_outer.html
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=968923
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 968923</title>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=968923">Mozilla Bug 968923</a>
|
||||
<img id="display" />
|
||||
<iframe id="content">
|
||||
|
||||
</iframe>
|
||||
</body>
|
||||
</html>
|
||||
17
dom/base/test/file_use_counter_svg_currentScale.svg
Normal file
17
dom/base/test/file_use_counter_svg_currentScale.svg
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" standalone="no"?>
|
||||
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="4in" height="3in" version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<desc>Test graphic for hitting currentScale
|
||||
</desc>
|
||||
<script type="text/javascript"> <![CDATA[
|
||||
document.documentElement.currentScale = document.documentElement.currentScale;
|
||||
]]>
|
||||
</script>
|
||||
<image id="i1" x="200" y="200" width="100px" height="80px">
|
||||
</image>
|
||||
<circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 635 B |
15
dom/base/test/file_use_counter_svg_fill_pattern.svg
Normal file
15
dom/base/test/file_use_counter_svg_fill_pattern.svg
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="8cm" height="4cm" viewBox="0 0 800 400" version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<desc>Borrowed from http://www.w3.org/TR/SVG/pservers.html</desc>
|
||||
<!-- Outline the drawing area in blue -->
|
||||
<rect fill="none" stroke="blue"
|
||||
x="1" y="1" width="798" height="398"/>
|
||||
|
||||
<!-- The ellipse is filled using a triangle pattern paint server
|
||||
and stroked with black -->
|
||||
<ellipse fill="url(http://example.com/browser/dom/base/test/file_use_counter_svg_fill_pattern_definition.svg#TrianglePattern)" stroke="black" stroke-width="5"
|
||||
cx="400" cy="200" rx="350" ry="150" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 763 B |
15
dom/base/test/file_use_counter_svg_fill_pattern_data.svg
Normal file
15
dom/base/test/file_use_counter_svg_fill_pattern_data.svg
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="8cm" height="4cm" viewBox="0 0 800 400" version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<desc>Borrowed from http://www.w3.org/TR/SVG/pservers.html</desc>
|
||||
<!-- Outline the drawing area in blue -->
|
||||
<rect fill="none" stroke="blue"
|
||||
x="1" y="1" width="798" height="398"/>
|
||||
|
||||
<!-- The ellipse is filled using a triangle pattern paint server
|
||||
and stroked with black -->
|
||||
<ellipse fill="url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pgo8IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iIAogICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8c3ZnIHdpZHRoPSI4Y20iIGhlaWdodD0iNGNtIiB2aWV3Qm94PSIwIDAgODAwIDQwMCIgdmVyc2lvbj0iMS4xIgogICAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPGRlc2M+Qm9ycm93ZWQgZnJvbSBodHRwOi8vd3d3LnczLm9yZy9UUi9TVkcvcHNlcnZlcnMuaHRtbDwvZGVzYz4KICA8ZGVmcz4KICAgIDxwYXR0ZXJuIGlkPSJUcmlhbmdsZVBhdHRlcm4iIHBhdHRlcm5Vbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICAgICAgICB4PSIwIiB5PSIwIiB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIKICAgICAgICAgICAgIHZpZXdCb3g9IjAgMCAxMCAxMCIgPgogICAgICA8cGF0aCBkPSJNIDAgMCBMIDcgMCBMIDMuNSA3IHoiIGZpbGw9InJlZCIgZmlsbC1vcGFjaXR5PSIwLjciIHN0cm9rZT0iYmx1ZSIgLz4KICAgIDwvcGF0dGVybj4gCiAgPC9kZWZzPgo8L3N2Zz4K#TrianglePattern)" stroke="black" stroke-width="5"
|
||||
cx="400" cy="200" rx="350" ry="150" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="8cm" height="4cm" viewBox="0 0 800 400" version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<desc>Borrowed from http://www.w3.org/TR/SVG/pservers.html</desc>
|
||||
<defs>
|
||||
<pattern id="TrianglePattern" patternUnits="userSpaceOnUse"
|
||||
x="0" y="0" width="100" height="100"
|
||||
viewBox="0 0 10 10" >
|
||||
<path d="M 0 0 L 7 0 L 3.5 7 z" fill="red" fill-opacity="0.7" stroke="blue" />
|
||||
</pattern>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 591 B |
23
dom/base/test/file_use_counter_svg_fill_pattern_internal.svg
Normal file
23
dom/base/test/file_use_counter_svg_fill_pattern_internal.svg
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="8cm" height="4cm" viewBox="0 0 800 400" version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<desc>Borrowed from http://www.w3.org/TR/SVG/pservers.html</desc>
|
||||
<!-- Outline the drawing area in blue -->
|
||||
<rect fill="none" stroke="blue"
|
||||
x="1" y="1" width="798" height="398"/>
|
||||
|
||||
<defs>
|
||||
<pattern id="TrianglePattern" patternUnits="userSpaceOnUse"
|
||||
x="0" y="0" width="100" height="100"
|
||||
viewBox="0 0 10 10" >
|
||||
<path d="M 0 0 L 7 0 L 3.5 7 z" fill="red" fill-opacity="0.7" stroke="blue" />
|
||||
</pattern>
|
||||
</defs>
|
||||
|
||||
<!-- The ellipse is filled using a triangle pattern paint server
|
||||
and stroked with black -->
|
||||
<ellipse fill="url(#TrianglePattern)" stroke="black" stroke-width="5"
|
||||
cx="400" cy="200" rx="350" ry="150" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 944 B |
22
dom/base/test/file_use_counter_svg_getElementById.svg
Normal file
22
dom/base/test/file_use_counter_svg_getElementById.svg
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" standalone="no"?>
|
||||
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="4in" height="3in" version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<desc>Test graphic for hitting getElementById
|
||||
</desc>
|
||||
<image id="i1" x="200" y="200" width="100px" height="80px">
|
||||
</image>
|
||||
<circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red"/>
|
||||
<script type="text/javascript"> <![CDATA[
|
||||
var image = document.documentElement.getElementById("i1");
|
||||
image.addEventListener("load",
|
||||
function() {
|
||||
document.documentElement.removeAttribute("class");
|
||||
},
|
||||
false);
|
||||
]]>
|
||||
</script>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 836 B |
71
dom/base/usecounters.py
Normal file
71
dom/base/usecounters.py
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
# 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/.
|
||||
|
||||
import buildconfig
|
||||
import collections
|
||||
import re
|
||||
import StringIO
|
||||
import sys
|
||||
|
||||
def read_conf(conf_filename):
|
||||
# Can't read/write from a single StringIO, so make a new one for reading.
|
||||
stream = open(conf_filename, 'rU')
|
||||
|
||||
def parse_counters(stream):
|
||||
for line_num, line in enumerate(stream):
|
||||
line = line.rstrip('\n')
|
||||
if not line or line.startswith('//'):
|
||||
# empty line or comment
|
||||
continue
|
||||
m = re.match(r'method ([A-Za-z0-9]+)\.([A-Za-z0-9]+)$', line)
|
||||
if m:
|
||||
interface_name, method_name = m.groups()
|
||||
yield { 'type': 'method',
|
||||
'interface_name': interface_name,
|
||||
'method_name': method_name }
|
||||
continue
|
||||
m = re.match(r'attribute ([A-Za-z0-9]+)\.([A-Za-z0-9]+)$', line)
|
||||
if m:
|
||||
interface_name, attribute_name = m.groups()
|
||||
yield { 'type': 'attribute',
|
||||
'interface_name': interface_name,
|
||||
'attribute_name': attribute_name }
|
||||
continue
|
||||
m = re.match(r'property ([A-Za-z0-9]+)$', line)
|
||||
if m:
|
||||
property_name = m.group(1)
|
||||
yield { 'type': 'property',
|
||||
'property_name': property_name }
|
||||
continue
|
||||
raise ValueError('error parsing %s at line %d' % (conf_filename, line_num))
|
||||
|
||||
return parse_counters(stream)
|
||||
|
||||
def generate_histograms(filename):
|
||||
# The mapping for use counters to telemetry histograms depends on the
|
||||
# ordering of items in the dictionary.
|
||||
items = collections.OrderedDict()
|
||||
for counter in read_conf(filename):
|
||||
def append_counter(name, desc):
|
||||
items[name] = { 'expires_in_version': 'never',
|
||||
'kind' : 'boolean',
|
||||
'description': desc }
|
||||
|
||||
def append_counters(name, 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'])
|
||||
append_counters(method.replace('.', '_').upper(), 'called %s' % method)
|
||||
elif counter['type'] == 'attribute':
|
||||
attr = '%s.%s' % (counter['interface_name'], counter['attribute_name'])
|
||||
counter_name = attr.replace('.', '_').upper()
|
||||
append_counters('%s_getter' % counter_name, 'got %s' % attr)
|
||||
append_counters('%s_setter' % counter_name, 'set %s' % attr)
|
||||
elif counter['type'] == 'property':
|
||||
prop = counter['property_name']
|
||||
append_counters('PROPERTY_%s' % prop.replace('-', '_').upper(), "used the '%s' property" % prop)
|
||||
|
||||
return items
|
||||
|
|
@ -14,6 +14,7 @@
|
|||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/SizePrintfMacros.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "mozilla/UseCounter.h"
|
||||
#include "mozilla/dom/DocGroup.h"
|
||||
|
||||
#include "AccessCheck.h"
|
||||
|
|
@ -58,6 +59,7 @@
|
|||
#include "mozilla/jsipc/CrossProcessObjectWrappers.h"
|
||||
#include "nsDOMClassInfo.h"
|
||||
#include "ipc/ErrorIPCUtils.h"
|
||||
#include "mozilla/UseCounter.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
|
@ -3590,6 +3592,16 @@ AssertReflectorHasGivenProto(JSContext* aCx, JSObject* aReflector,
|
|||
} // namespace binding_detail
|
||||
#endif // DEBUG
|
||||
|
||||
void
|
||||
SetDocumentAndPageUseCounter(JSContext* aCx, JSObject* aObject,
|
||||
UseCounter aUseCounter)
|
||||
{
|
||||
nsGlobalWindow* win = xpc::WindowGlobalOrNull(js::UncheckedUnwrap(aObject));
|
||||
if (win && win->GetDocument()) {
|
||||
win->GetDocument()->SetDocumentAndPageUseCounter(aUseCounter);
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// This runnable is used to write a deprecation message from a worker to the
|
||||
|
|
|
|||
|
|
@ -46,6 +46,8 @@ class nsIJSID;
|
|||
|
||||
namespace mozilla {
|
||||
|
||||
enum UseCounter : int16_t;
|
||||
|
||||
namespace dom {
|
||||
class CustomElementReactionsStack;
|
||||
template<typename KeyType, typename ValueType> class Record;
|
||||
|
|
@ -3426,6 +3428,10 @@ already_AddRefed<nsGenericHTMLElement>
|
|||
CreateHTMLElement(const GlobalObject& aGlobal, const JS::CallArgs& aCallArgs,
|
||||
JS::Handle<JSObject*> aGivenProto, ErrorResult& aRv);
|
||||
|
||||
void
|
||||
SetDocumentAndPageUseCounter(JSContext* aCx, JSObject* aObject,
|
||||
UseCounter aUseCounter);
|
||||
|
||||
// Warnings
|
||||
void
|
||||
DeprecationWarning(JSContext* aCx, JSObject* aObject,
|
||||
|
|
|
|||
|
|
@ -7467,8 +7467,8 @@ class CGPerSignatureCall(CGThing):
|
|||
|
||||
def __init__(self, returnType, arguments, nativeMethodName, static,
|
||||
descriptor, idlNode, argConversionStartsAt=0, getter=False,
|
||||
setter=False, isConstructor=False, resultVar=None,
|
||||
objectName="obj"):
|
||||
setter=False, isConstructor=False, useCounterName=None,
|
||||
resultVar=None, objectName="obj"):
|
||||
assert idlNode.isMethod() == (not getter and not setter)
|
||||
assert idlNode.isAttr() == (getter or setter)
|
||||
# Constructors are always static
|
||||
|
|
@ -7701,6 +7701,11 @@ class CGPerSignatureCall(CGThing):
|
|||
nativeMethodName,
|
||||
static, argsPost=argsPost, resultVar=resultVar))
|
||||
|
||||
if useCounterName:
|
||||
# Generate a telemetry call for when [UseCounter] is used.
|
||||
code = "SetDocumentAndPageUseCounter(cx, obj, eUseCounter_%s);\n" % useCounterName
|
||||
cgThings.append(CGGeneric(code))
|
||||
|
||||
self.cgRoot = CGList(cgThings)
|
||||
|
||||
def getArguments(self):
|
||||
|
|
@ -7929,6 +7934,11 @@ class CGMethodCall(CGThing):
|
|||
methodName = "%s.%s" % (descriptor.interface.identifier.name, method.identifier.name)
|
||||
argDesc = "argument %d of " + methodName
|
||||
|
||||
if method.getExtendedAttribute("UseCounter"):
|
||||
useCounterName = methodName.replace(".", "_")
|
||||
else:
|
||||
useCounterName = None
|
||||
|
||||
if method.isStatic():
|
||||
nativeType = descriptor.nativeType
|
||||
staticTypeOverride = PropertyDefiner.getStringAttr(method, "StaticClassOverride")
|
||||
|
|
@ -7950,7 +7960,8 @@ class CGMethodCall(CGThing):
|
|||
nativeMethodName, static, descriptor,
|
||||
method,
|
||||
argConversionStartsAt=argConversionStartsAt,
|
||||
isConstructor=isConstructor)
|
||||
isConstructor=isConstructor,
|
||||
useCounterName=useCounterName)
|
||||
|
||||
signatures = method.signatures()
|
||||
if len(signatures) == 1:
|
||||
|
|
@ -8326,11 +8337,16 @@ class CGGetterCall(CGPerSignatureCall):
|
|||
getter.
|
||||
"""
|
||||
def __init__(self, returnType, nativeMethodName, descriptor, attr):
|
||||
if attr.getExtendedAttribute("UseCounter"):
|
||||
useCounterName = "%s_%s_getter" % (descriptor.interface.identifier.name,
|
||||
attr.identifier.name)
|
||||
else:
|
||||
useCounterName = None
|
||||
if attr.isStatic():
|
||||
nativeMethodName = "%s::%s" % (descriptor.nativeType, nativeMethodName)
|
||||
CGPerSignatureCall.__init__(self, returnType, [], nativeMethodName,
|
||||
attr.isStatic(), descriptor, attr,
|
||||
getter=True)
|
||||
getter=True, useCounterName=useCounterName)
|
||||
|
||||
|
||||
class CGNavigatorGetterCall(CGPerSignatureCall):
|
||||
|
|
@ -8397,12 +8413,17 @@ class CGSetterCall(CGPerSignatureCall):
|
|||
setter.
|
||||
"""
|
||||
def __init__(self, argType, nativeMethodName, descriptor, attr):
|
||||
if attr.getExtendedAttribute("UseCounter"):
|
||||
useCounterName = "%s_%s_setter" % (descriptor.interface.identifier.name,
|
||||
attr.identifier.name)
|
||||
else:
|
||||
useCounterName = None
|
||||
if attr.isStatic():
|
||||
nativeMethodName = "%s::%s" % (descriptor.nativeType, nativeMethodName)
|
||||
CGPerSignatureCall.__init__(self, None,
|
||||
[FakeArgument(argType, attr, allowTreatNonCallableAsNull=True)],
|
||||
nativeMethodName, attr.isStatic(),
|
||||
descriptor, attr, setter=True)
|
||||
descriptor, attr, setter=True, useCounterName=useCounterName)
|
||||
|
||||
def wrap_return_value(self):
|
||||
attr = self.idlNode
|
||||
|
|
@ -13911,6 +13932,12 @@ class CGBindingRoot(CGThing):
|
|||
bindingHeaders[CGHeaders.getDeclarationFilename(enums[0])] = True
|
||||
bindingHeaders["jsapi.h"] = True
|
||||
|
||||
# For things that have [UseCounter]
|
||||
def descriptorRequiresTelemetry(desc):
|
||||
iface = desc.interface
|
||||
return any(m.getExtendedAttribute("UseCounter") for m in iface.members)
|
||||
bindingHeaders["mozilla/UseCounter.h"] = any(
|
||||
descriptorRequiresTelemetry(d) for d in descriptors)
|
||||
bindingHeaders["mozilla/dom/SimpleGlobalObject.h"] = any(
|
||||
CGDictionary.dictionarySafeToJSONify(d) for d in dictionaries)
|
||||
bindingHeaders["XrayWrapper.h"] = any(
|
||||
|
|
|
|||
|
|
@ -4245,6 +4245,11 @@ class IDLAttribute(IDLInterfaceMember):
|
|||
"readonly attributes" % attr.value(),
|
||||
[attr.location, self.location])
|
||||
self._setDependsOn(attr.value())
|
||||
elif identifier == "UseCounter":
|
||||
if self.stringifier:
|
||||
raise WebIDLError("[UseCounter] must not be used on a "
|
||||
"stringifier attribute",
|
||||
[attr.location, self.location])
|
||||
elif identifier == "Unscopable":
|
||||
if not attr.noArguments():
|
||||
raise WebIDLError("[Unscopable] must take no arguments",
|
||||
|
|
@ -4974,6 +4979,11 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
|
|||
raise WebIDLError("[Alias] takes an identifier or string",
|
||||
[attr.location])
|
||||
self._addAlias(attr.value())
|
||||
elif identifier == "UseCounter":
|
||||
if self.isSpecial():
|
||||
raise WebIDLError("[UseCounter] must not be used on a special "
|
||||
"operation",
|
||||
[attr.location, self.location])
|
||||
elif identifier == "Unscopable":
|
||||
if not attr.noArguments():
|
||||
raise WebIDLError("[Unscopable] must take no arguments",
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include "nsPresContext.h"
|
||||
#include "nsMappedAttributes.h"
|
||||
#include "nsSize.h"
|
||||
#include "nsDocument.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIDOMMutationEvent.h"
|
||||
#include "nsIScriptContext.h"
|
||||
|
|
@ -26,6 +27,7 @@
|
|||
#include "mozilla/dom/HTMLFormElement.h"
|
||||
#include "nsAttrValueOrString.h"
|
||||
#include "imgLoader.h"
|
||||
#include "Image.h"
|
||||
|
||||
// Responsive images!
|
||||
#include "mozilla/dom/HTMLSourceElement.h"
|
||||
|
|
@ -1360,6 +1362,16 @@ HTMLImageElement::MediaFeatureValuesChanged()
|
|||
QueueImageLoadTask(false);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLImageElement::FlushUseCounters()
|
||||
{
|
||||
nsCOMPtr<imgIRequest> request;
|
||||
GetRequest(CURRENT_REQUEST, getter_AddRefs(request));
|
||||
|
||||
nsCOMPtr<imgIContainer> container;
|
||||
request->GetImage(getter_AddRefs(container));
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
|
|
|||
|
|
@ -261,6 +261,12 @@ public:
|
|||
const nsAString& aMediaAttr,
|
||||
nsAString& aResult);
|
||||
|
||||
/**
|
||||
* If this image's src pointers to an SVG document, flush the SVG document's
|
||||
* use counters to telemetry. Only used for testing purposes.
|
||||
*/
|
||||
void FlushUseCounters();
|
||||
|
||||
protected:
|
||||
virtual ~HTMLImageElement();
|
||||
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ interface nsIJSRAIIHelper;
|
|||
interface nsIContentPermissionRequest;
|
||||
interface nsIObserver;
|
||||
|
||||
[scriptable, uuid(7fcc7958-77d9-45ff-8c81-277bde5f0dc8)]
|
||||
[scriptable, uuid(c471d440-004b-4c50-a6f2-747db5f443b6)]
|
||||
interface nsIDOMWindowUtils : nsISupports {
|
||||
|
||||
/**
|
||||
|
|
@ -1938,6 +1938,17 @@ interface nsIDOMWindowUtils : nsISupports {
|
|||
*/
|
||||
bool hasRuleProcessorUsedByMultipleStyleSets(in unsigned long aSheetType);
|
||||
|
||||
/*
|
||||
* Force the use counters for the node's associated document(s) to be
|
||||
* flushed to telemetry. For example, a document node will flush its own
|
||||
* counters and an image node with an SVG source will flush the SVG
|
||||
* document's counters. Normally, use counters are flushed to telemetry
|
||||
* upon document destruction, but as document destruction is somewhat
|
||||
* non-deterministic, we have this method here for more determinism when
|
||||
* running tests.
|
||||
*/
|
||||
void forceUseCounterFlush(in nsIDOMNode aNode);
|
||||
|
||||
void setNextPaintSyncId(in long aSyncId);
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1150,7 +1150,7 @@ public:
|
|||
MappedAttrParser(css::Loader* aLoader,
|
||||
nsIURI* aDocURI,
|
||||
already_AddRefed<nsIURI> aBaseURI,
|
||||
nsIPrincipal* aNodePrincipal);
|
||||
nsSVGElement* aElement);
|
||||
~MappedAttrParser();
|
||||
|
||||
// Parses a mapped attribute value.
|
||||
|
|
@ -1170,18 +1170,20 @@ private:
|
|||
// Arguments for nsCSSParser::ParseProperty
|
||||
nsIURI* mDocURI;
|
||||
nsCOMPtr<nsIURI> mBaseURI;
|
||||
nsIPrincipal* mNodePrincipal;
|
||||
|
||||
// Declaration for storing parsed values (lazily initialized)
|
||||
css::Declaration* mDecl;
|
||||
|
||||
// For reporting use counters
|
||||
nsSVGElement* mElement;
|
||||
};
|
||||
|
||||
MappedAttrParser::MappedAttrParser(css::Loader* aLoader,
|
||||
nsIURI* aDocURI,
|
||||
already_AddRefed<nsIURI> aBaseURI,
|
||||
nsIPrincipal* aNodePrincipal)
|
||||
nsSVGElement* aElement)
|
||||
: mParser(aLoader), mDocURI(aDocURI), mBaseURI(aBaseURI),
|
||||
mNodePrincipal(aNodePrincipal), mDecl(nullptr)
|
||||
mDecl(nullptr), mElement(aElement)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -1206,9 +1208,27 @@ MappedAttrParser::ParseMappedAttrValue(nsIAtom* aMappedAttrName,
|
|||
nsCSSProps::LookupProperty(nsDependentAtomString(aMappedAttrName),
|
||||
CSSEnabledState::eForAllContent);
|
||||
if (propertyID != eCSSProperty_UNKNOWN) {
|
||||
bool changed; // outparam for ParseProperty. (ignored)
|
||||
bool changed = false; // outparam for ParseProperty.
|
||||
mParser.ParseProperty(propertyID, aMappedAttrValue, mDocURI, mBaseURI,
|
||||
mNodePrincipal, mDecl, &changed, false, true);
|
||||
mElement->NodePrincipal(), mDecl, &changed, false, true);
|
||||
if (changed) {
|
||||
// The normal reporting of use counters by the nsCSSParser won't happen
|
||||
// since it doesn't have a sheet.
|
||||
if (nsCSSProps::IsShorthand(propertyID)) {
|
||||
CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(subprop, propertyID,
|
||||
CSSEnabledState::eForAllContent) {
|
||||
UseCounter useCounter = nsCSSProps::UseCounterFor(*subprop);
|
||||
if (useCounter != eUseCounter_UNKNOWN) {
|
||||
mElement->OwnerDoc()->SetDocumentAndPageUseCounter(useCounter);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
UseCounter useCounter = nsCSSProps::UseCounterFor(propertyID);
|
||||
if (useCounter != eUseCounter_UNKNOWN) {
|
||||
mElement->OwnerDoc()->SetDocumentAndPageUseCounter(useCounter);
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(aMappedAttrName == nsGkAtoms::lang,
|
||||
|
|
@ -1255,7 +1275,7 @@ nsSVGElement::UpdateContentStyleRule()
|
|||
|
||||
nsIDocument* doc = OwnerDoc();
|
||||
MappedAttrParser mappedAttrParser(doc->CSSLoader(), doc->GetDocumentURI(),
|
||||
GetBaseURI(), NodePrincipal());
|
||||
GetBaseURI(), this);
|
||||
|
||||
for (uint32_t i = 0; i < attrCount; ++i) {
|
||||
const nsAttrName* attrName = mAttrsAndChildren.AttrNameAt(i);
|
||||
|
|
@ -1346,7 +1366,7 @@ nsSVGElement::UpdateAnimatedContentStyleRule()
|
|||
}
|
||||
|
||||
MappedAttrParser mappedAttrParser(doc->CSSLoader(), doc->GetDocumentURI(),
|
||||
GetBaseURI(), NodePrincipal());
|
||||
GetBaseURI(), this);
|
||||
doc->PropertyTable(SMIL_MAPPED_ATTR_ANIMVAL)->
|
||||
Enumerate(this, ParseMappedAttrAnimValueCallback, &mappedAttrParser);
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ interface External
|
|||
|
||||
// Mozilla extension
|
||||
partial interface External {
|
||||
[UnsafeInPrerendering]
|
||||
[UnsafeInPrerendering, UseCounter]
|
||||
void addSearchEngine(DOMString engineURL, DOMString iconURL,
|
||||
DOMString suggestedTitle, DOMString suggestedCategory);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -25,30 +25,38 @@ interface OfflineResourceList : EventTarget {
|
|||
/* The application cache group is now obsolete. */
|
||||
const unsigned short OBSOLETE = 5;
|
||||
|
||||
[Throws]
|
||||
[Throws, UseCounter]
|
||||
readonly attribute unsigned short status;
|
||||
|
||||
/**
|
||||
* Begin the application update process on the associated application cache.
|
||||
*/
|
||||
[Throws]
|
||||
[Throws, UseCounter]
|
||||
void update();
|
||||
|
||||
/**
|
||||
* Swap in the newest version of the application cache, or disassociate
|
||||
* from the cache if the cache group is obsolete.
|
||||
*/
|
||||
[Throws]
|
||||
[Throws, UseCounter]
|
||||
void swapCache();
|
||||
|
||||
/* Events */
|
||||
[UseCounter]
|
||||
attribute EventHandler onchecking;
|
||||
[UseCounter]
|
||||
attribute EventHandler onerror;
|
||||
[UseCounter]
|
||||
attribute EventHandler onnoupdate;
|
||||
[UseCounter]
|
||||
attribute EventHandler ondownloading;
|
||||
[UseCounter]
|
||||
attribute EventHandler onprogress;
|
||||
[UseCounter]
|
||||
attribute EventHandler onupdateready;
|
||||
[UseCounter]
|
||||
attribute EventHandler oncached;
|
||||
[UseCounter]
|
||||
attribute EventHandler onobsolete;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ interface PushManagerImpl {
|
|||
[Exposed=(Window,Worker), Func="nsContentUtils::PushEnabled",
|
||||
ChromeConstructor(DOMString scope)]
|
||||
interface PushManager {
|
||||
[Throws]
|
||||
[Throws, UseCounter]
|
||||
Promise<PushSubscription> subscribe(optional PushSubscriptionOptionsInit options);
|
||||
[Throws]
|
||||
Promise<PushSubscription?> getSubscription();
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ interface PushSubscription
|
|||
readonly attribute PushSubscriptionOptions options;
|
||||
[Throws]
|
||||
ArrayBuffer? getKey(PushEncryptionKeyName name);
|
||||
[Throws]
|
||||
[Throws, UseCounter]
|
||||
Promise<boolean> unsubscribe();
|
||||
|
||||
// Implements the custom serializer specified in Push API, section 9.
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ interface SVGSVGElement : SVGGraphicsElement {
|
|||
readonly attribute float screenPixelToMillimeterY;
|
||||
readonly attribute boolean useCurrentView;
|
||||
// readonly attribute SVGViewSpec currentView;
|
||||
[UseCounter]
|
||||
attribute float currentScale;
|
||||
readonly attribute SVGPoint currentTranslate;
|
||||
|
||||
|
|
@ -70,6 +71,7 @@ interface SVGSVGElement : SVGGraphicsElement {
|
|||
SVGTransform createSVGTransform();
|
||||
[NewObject]
|
||||
SVGTransform createSVGTransformFromMatrix(SVGMatrix matrix);
|
||||
[UseCounter]
|
||||
Element? getElementById(DOMString elementId);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -368,7 +368,7 @@ Window implements OnErrorEventHandlerForWindow;
|
|||
#ifdef HAVE_SIDEBAR
|
||||
// Mozilla extension
|
||||
partial interface Window {
|
||||
[Replaceable, Throws]
|
||||
[Replaceable, Throws, UseCounter]
|
||||
readonly attribute (External or WindowProxy) sidebar;
|
||||
};
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -337,5 +337,11 @@ DynamicImage::Unwrap()
|
|||
return self.forget();
|
||||
}
|
||||
|
||||
void
|
||||
DynamicImage::PropagateUseCounters(nsIDocument*)
|
||||
{
|
||||
// No use counters.
|
||||
}
|
||||
|
||||
} // namespace image
|
||||
} // namespace mozilla
|
||||
|
|
|
|||
|
|
@ -291,6 +291,12 @@ ImageWrapper::SetAnimationStartTime(const TimeStamp& aTime)
|
|||
mInnerImage->SetAnimationStartTime(aTime);
|
||||
}
|
||||
|
||||
void
|
||||
ImageWrapper::PropagateUseCounters(nsIDocument* aParentDocument)
|
||||
{
|
||||
mInnerImage->PropagateUseCounters(aParentDocument);
|
||||
}
|
||||
|
||||
nsIntSize
|
||||
ImageWrapper::OptimalImageSizeForDest(const gfxSize& aDest,
|
||||
uint32_t aWhichFrame,
|
||||
|
|
|
|||
|
|
@ -1663,6 +1663,12 @@ RasterImage::Unwrap()
|
|||
return self.forget();
|
||||
}
|
||||
|
||||
void
|
||||
RasterImage::PropagateUseCounters(nsIDocument*)
|
||||
{
|
||||
// No use counters.
|
||||
}
|
||||
|
||||
IntSize
|
||||
RasterImage::OptimalImageSizeForDest(const gfxSize& aDest, uint32_t aWhichFrame,
|
||||
SamplingFilter aSamplingFilter, uint32_t aFlags)
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
#include "SVGDocumentWrapper.h"
|
||||
#include "nsIDOMEventListener.h"
|
||||
#include "SurfaceCache.h"
|
||||
#include "nsDocument.h"
|
||||
|
||||
// undef the GetCurrentTime macro defined in WinBase.h from the MS Platform SDK
|
||||
#undef GetCurrentTime
|
||||
|
|
@ -1327,6 +1328,15 @@ VectorImage::InvalidateObserversOnNextRefreshDriverTick()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
VectorImage::PropagateUseCounters(nsIDocument* aParentDocument)
|
||||
{
|
||||
nsIDocument* doc = mSVGDocumentWrapper->GetDocument();
|
||||
if (doc) {
|
||||
doc->PropagateUseCounters(aParentDocument);
|
||||
}
|
||||
}
|
||||
|
||||
nsIntSize
|
||||
VectorImage::OptimalImageSizeForDest(const gfxSize& aDest,
|
||||
uint32_t aWhichFrame,
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@
|
|||
#include "nsSize.h"
|
||||
#include "limits.h"
|
||||
|
||||
class nsIDocument;
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
class LayerManager;
|
||||
|
|
@ -65,6 +67,7 @@ native Orientation(mozilla::image::Orientation);
|
|||
native TempRefSourceSurface(already_AddRefed<mozilla::gfx::SourceSurface>);
|
||||
native TempRefImgIContainer(already_AddRefed<imgIContainer>);
|
||||
native nsIntSizeByVal(nsIntSize);
|
||||
[ptr] native nsIDocument(nsIDocument);
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -74,7 +77,7 @@ native nsIntSizeByVal(nsIntSize);
|
|||
*
|
||||
* Internally, imgIContainer also manages animation of images.
|
||||
*/
|
||||
[scriptable, builtinclass, uuid(7ba72242-28da-4c5f-b53f-54da8874775e)]
|
||||
[scriptable, builtinclass, uuid(a8dbee24-ff86-4755-b40e-51175caf31af)]
|
||||
interface imgIContainer : nsISupports
|
||||
{
|
||||
/**
|
||||
|
|
@ -539,4 +542,10 @@ interface imgIContainer : nsISupports
|
|||
* Removes any ImageWrappers and returns the unwrapped base image.
|
||||
*/
|
||||
[notxpcom, nostdcall] TempRefImgIContainer unwrap();
|
||||
|
||||
/*
|
||||
* Propagate the use counters (if any) from this container to the passed in
|
||||
* document.
|
||||
*/
|
||||
[noscript, notxpcom] void propagateUseCounters(in nsIDocument aDocument);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -775,6 +775,16 @@ nsBulletFrame::Notify(imgIRequest *aRequest, int32_t aType, const nsIntRect* aDa
|
|||
InvalidateFrame();
|
||||
}
|
||||
|
||||
if (aType == imgINotificationObserver::DECODE_COMPLETE) {
|
||||
if (nsIDocument* parent = GetOurCurrentDoc()) {
|
||||
nsCOMPtr<imgIContainer> container;
|
||||
aRequest->GetImage(getter_AddRefs(container));
|
||||
if (container) {
|
||||
container->PropagateUseCounters(parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
#include "FrameLayerBuilder.h"
|
||||
#include "nsSVGEffects.h"
|
||||
#include "imgIContainer.h"
|
||||
#include "Image.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace css {
|
||||
|
|
@ -394,6 +395,14 @@ ImageLoader::Notify(imgIRequest* aRequest, int32_t aType, const nsIntRect* aData
|
|||
return OnFrameUpdate(aRequest);
|
||||
}
|
||||
|
||||
if (aType == imgINotificationObserver::DECODE_COMPLETE) {
|
||||
nsCOMPtr<imgIContainer> image;
|
||||
aRequest->GetImage(getter_AddRefs(image));
|
||||
if (image && mDocument) {
|
||||
image->PropagateUseCounters(mDocument);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
@ -499,5 +508,19 @@ ImageLoader::UnblockOnload(imgIRequest* aRequest)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
ImageLoader::FlushUseCounters()
|
||||
{
|
||||
for (auto iter = mImages.Iter(); !iter.Done(); iter.Next()) {
|
||||
nsPtrHashKey<Image>* key = iter.Get();
|
||||
ImageLoader::Image* image = key->GetKey();
|
||||
|
||||
imgIRequest* request = image->mRequests.GetWeak(mDocument);
|
||||
|
||||
nsCOMPtr<imgIContainer> container;
|
||||
request->GetImage(getter_AddRefs(container));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace css
|
||||
} // namespace mozilla
|
||||
|
|
|
|||
|
|
@ -70,6 +70,8 @@ public:
|
|||
|
||||
void DestroyRequest(imgIRequest* aRequest);
|
||||
|
||||
void FlushUseCounters();
|
||||
|
||||
private:
|
||||
~ImageLoader() {}
|
||||
|
||||
|
|
|
|||
|
|
@ -681,12 +681,14 @@ nsCSSExpandedDataBlock::TransferFromBlock(nsCSSExpandedDataBlock& aFromBlock,
|
|||
bool aIsImportant,
|
||||
bool aOverrideImportant,
|
||||
bool aMustCallValueAppended,
|
||||
css::Declaration* aDeclaration)
|
||||
css::Declaration* aDeclaration,
|
||||
nsIDocument* aSheetDocument)
|
||||
{
|
||||
if (!nsCSSProps::IsShorthand(aPropID)) {
|
||||
return DoTransferFromBlock(aFromBlock, aPropID,
|
||||
aIsImportant, aOverrideImportant,
|
||||
aMustCallValueAppended, aDeclaration);
|
||||
aMustCallValueAppended, aDeclaration,
|
||||
aSheetDocument);
|
||||
}
|
||||
|
||||
// We can pass CSSEnabledState::eIgnore (here, and in ClearProperty
|
||||
|
|
@ -698,7 +700,8 @@ nsCSSExpandedDataBlock::TransferFromBlock(nsCSSExpandedDataBlock& aFromBlock,
|
|||
CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p, aPropID, aEnabledState) {
|
||||
changed |= DoTransferFromBlock(aFromBlock, *p,
|
||||
aIsImportant, aOverrideImportant,
|
||||
aMustCallValueAppended, aDeclaration);
|
||||
aMustCallValueAppended, aDeclaration,
|
||||
aSheetDocument);
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
|
@ -709,7 +712,8 @@ nsCSSExpandedDataBlock::DoTransferFromBlock(nsCSSExpandedDataBlock& aFromBlock,
|
|||
bool aIsImportant,
|
||||
bool aOverrideImportant,
|
||||
bool aMustCallValueAppended,
|
||||
css::Declaration* aDeclaration)
|
||||
css::Declaration* aDeclaration,
|
||||
nsIDocument* aSheetDocument)
|
||||
{
|
||||
bool changed = false;
|
||||
MOZ_ASSERT(aFromBlock.HasPropertyBit(aPropID), "oops");
|
||||
|
|
@ -737,6 +741,13 @@ nsCSSExpandedDataBlock::DoTransferFromBlock(nsCSSExpandedDataBlock& aFromBlock,
|
|||
aDeclaration->ValueAppended(aPropID);
|
||||
}
|
||||
|
||||
if (aSheetDocument) {
|
||||
UseCounter useCounter = nsCSSProps::UseCounterFor(aPropID);
|
||||
if (useCounter != eUseCounter_UNKNOWN) {
|
||||
aSheetDocument->SetDocumentAndPageUseCounter(useCounter);
|
||||
}
|
||||
}
|
||||
|
||||
SetPropertyBit(aPropID);
|
||||
aFromBlock.ClearPropertyBit(aPropID);
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
struct nsRuleData;
|
||||
class nsCSSExpandedDataBlock;
|
||||
class nsIDocument;
|
||||
|
||||
namespace mozilla {
|
||||
namespace css {
|
||||
|
|
@ -257,6 +258,8 @@ public:
|
|||
* Returns true if something changed, false otherwise. Calls
|
||||
* |ValueAppended| on |aDeclaration| if the property was not
|
||||
* previously set, or in any case if |aMustCallValueAppended| is true.
|
||||
* Calls |SetDocumentAndPageUseCounter| on |aSheetDocument| if it is
|
||||
* non-null and |aPropID| has a use counter.
|
||||
*/
|
||||
bool TransferFromBlock(nsCSSExpandedDataBlock& aFromBlock,
|
||||
nsCSSPropertyID aPropID,
|
||||
|
|
@ -264,7 +267,8 @@ public:
|
|||
bool aIsImportant,
|
||||
bool aOverrideImportant,
|
||||
bool aMustCallValueAppended,
|
||||
mozilla::css::Declaration* aDeclaration);
|
||||
mozilla::css::Declaration* aDeclaration,
|
||||
nsIDocument* aSheetDocument);
|
||||
|
||||
/**
|
||||
* Copies the values for aPropID into the specified aRuleData object.
|
||||
|
|
@ -298,7 +302,8 @@ private:
|
|||
bool aIsImportant,
|
||||
bool aOverrideImportant,
|
||||
bool aMustCallValueAppended,
|
||||
mozilla::css::Declaration* aDeclaration);
|
||||
mozilla::css::Declaration* aDeclaration,
|
||||
nsIDocument* aSheetDocument);
|
||||
|
||||
#ifdef DEBUG
|
||||
void DoAssertInitialState();
|
||||
|
|
|
|||
|
|
@ -143,6 +143,8 @@ public:
|
|||
|
||||
nsresult SetStyleSheet(CSSStyleSheet* aSheet);
|
||||
|
||||
nsIDocument* GetDocument();
|
||||
|
||||
nsresult SetQuirkMode(bool aQuirkMode);
|
||||
|
||||
nsresult SetChildLoader(mozilla::css::Loader* aChildLoader);
|
||||
|
|
@ -1657,6 +1659,15 @@ CSSParserImpl::SetStyleSheet(CSSStyleSheet* aSheet)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsIDocument*
|
||||
CSSParserImpl::GetDocument()
|
||||
{
|
||||
if (!mSheet) {
|
||||
return nullptr;
|
||||
}
|
||||
return mSheet->GetDocument();
|
||||
}
|
||||
|
||||
nsresult
|
||||
CSSParserImpl::SetQuirkMode(bool aQuirkMode)
|
||||
{
|
||||
|
|
@ -1978,7 +1989,8 @@ CSSParserImpl::ParseTransformProperty(const nsAString& aPropValue,
|
|||
declaration->ExpandTo(&mData);
|
||||
changed = mData.TransferFromBlock(mTempData, eCSSProperty_transform,
|
||||
EnabledState(), false,
|
||||
true, false, declaration);
|
||||
true, false, declaration,
|
||||
GetDocument());
|
||||
declaration->CompressFrom(&mData);
|
||||
}
|
||||
|
||||
|
|
@ -2059,7 +2071,8 @@ CSSParserImpl::ParseProperty(const nsCSSPropertyID aPropID,
|
|||
aDeclaration->ExpandTo(&mData);
|
||||
*aChanged = mData.TransferFromBlock(mTempData, aPropID,
|
||||
EnabledState(), aIsImportant,
|
||||
true, false, aDeclaration);
|
||||
true, false, aDeclaration,
|
||||
GetDocument());
|
||||
aDeclaration->CompressFrom(&mData);
|
||||
}
|
||||
CLEAR_ERROR();
|
||||
|
|
@ -7573,7 +7586,7 @@ CSSParserImpl::ParseDeclaration(css::Declaration* aDeclaration,
|
|||
*aChanged |= mData.TransferFromBlock(mTempData, propID, EnabledState(),
|
||||
status == ePriority_Important,
|
||||
false, aMustCallValueAppended,
|
||||
aDeclaration);
|
||||
aDeclaration, GetDocument());
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -15355,17 +15368,17 @@ CSSParserImpl::ParseFontFeatureSettings(nsCSSValue& aValue)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CSSParserImpl::ParseFontVariationSettings(nsCSSValue& aValue)
|
||||
{
|
||||
// TODO: Actually implement this.
|
||||
|
||||
// This stub is here because websites insist on considering this
|
||||
// very hardware-dependent and O.S.-variable low-level font-control
|
||||
// as a "critical feature" which it isn't as there is 0 guarantee
|
||||
// that font variation settings are supported or honored by any
|
||||
// operating system used by the client.
|
||||
return true;
|
||||
bool
|
||||
CSSParserImpl::ParseFontVariationSettings(nsCSSValue& aValue)
|
||||
{
|
||||
// TODO: Actually implement this.
|
||||
|
||||
// This stub is here because websites insist on considering this
|
||||
// very hardware-dependent and O.S.-variable low-level font-control
|
||||
// as a "critical feature" which it isn't as there is 0 guarantee
|
||||
// that font variation settings are supported or honored by any
|
||||
// operating system used by the client.
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
|||
|
|
@ -3423,6 +3423,21 @@ nsCSSProps::gPropertyEnabled[eCSSProperty_COUNT_with_aliases] = {
|
|||
#undef IS_ENABLED_BY_DEFAULT
|
||||
};
|
||||
|
||||
#include "../../dom/base/PropertyUseCounterMap.inc"
|
||||
|
||||
/* static */ const UseCounter
|
||||
nsCSSProps::gPropertyUseCounter[eCSSProperty_COUNT_no_shorthands] = {
|
||||
#define CSS_PROP_PUBLIC_OR_PRIVATE(publicname_, privatename_) privatename_
|
||||
#define CSS_PROP_LIST_INCLUDE_LOGICAL
|
||||
#define CSS_PROP(name_, id_, method_, flags_, pref_, parsevariant_, \
|
||||
kwtable_, stylestruct_, stylestructoffset_, animtype_) \
|
||||
static_cast<UseCounter>(USE_COUNTER_FOR_CSS_PROPERTY_##method_),
|
||||
#include "nsCSSPropList.h"
|
||||
#undef CSS_PROP
|
||||
#undef CSS_PROP_LIST_INCLUDE_LOGICAL
|
||||
#undef CSS_PROP_PUBLIC_OR_PRIVATE
|
||||
};
|
||||
|
||||
// Check that all logical property flags are used appropriately.
|
||||
#define CSS_PROP(name_, id_, method_, flags_, pref_, parsevariant_, \
|
||||
kwtable_, stylestruct_, stylestructoffset_, animtype_) \
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
#include "nsStyleStructFwd.h"
|
||||
#include "nsCSSKeywords.h"
|
||||
#include "mozilla/CSSEnabledState.h"
|
||||
#include "mozilla/UseCounter.h"
|
||||
#include "mozilla/EnumTypeTraits.h"
|
||||
|
||||
// Length of the "--" prefix on custom names (such as custom property names,
|
||||
|
|
@ -639,8 +640,19 @@ public:
|
|||
return gPropertyEnabled[aProperty];
|
||||
}
|
||||
|
||||
// A table for the use counter associated with each CSS property. If a
|
||||
// property does not have a use counter defined in UseCounters.conf, then
|
||||
// its associated entry is |eUseCounter_UNKNOWN|.
|
||||
static const mozilla::UseCounter gPropertyUseCounter[eCSSProperty_COUNT_no_shorthands];
|
||||
|
||||
public:
|
||||
|
||||
static mozilla::UseCounter UseCounterFor(nsCSSPropertyID aProperty) {
|
||||
MOZ_ASSERT(0 <= aProperty && aProperty < eCSSProperty_COUNT_no_shorthands,
|
||||
"out of range");
|
||||
return gPropertyUseCounter[aProperty];
|
||||
}
|
||||
|
||||
static bool IsEnabled(nsCSSPropertyID aProperty, EnabledState aEnabled)
|
||||
{
|
||||
if (IsEnabled(aProperty)) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue