Merge mozilla-central to mozilla-inbound

This commit is contained in:
Iris Hsiao 2017-05-22 11:53:00 +08:00
Родитель 04f4fcb13c 961e38ad87
Коммит 65ea740eda
82 изменённых файлов: 3044 добавлений и 3411 удалений

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

@ -48,6 +48,7 @@ toolkit/library
profile
services
startupcache
devtools/platform
devtools/server
devtools/shared
browser/app

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

@ -4,7 +4,7 @@
# 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/.
if CONFIG['MOZ_DEVTOOLS'] and CONFIG['MOZ_DEVTOOLS'] not in ('all', 'server'):
if CONFIG['MOZ_DEVTOOLS'] and CONFIG['MOZ_DEVTOOLS'] not in ('all', 'server', 'addon'):
error('Unsupported MOZ_DEVTOOLS value: %s' % (CONFIG['MOZ_DEVTOOLS']))
if CONFIG['MOZ_DEVTOOLS'] == 'all':
@ -12,11 +12,20 @@ if CONFIG['MOZ_DEVTOOLS'] == 'all':
'client',
]
# `addon` is a special build mode to strip everything except binary components
# and shim modules that are going to stay in Firefox once DevTools ship as an
# add-on.
# `platform` contains all native components
DIRS += [
'shim',
'platform',
]
if CONFIG['MOZ_DEVTOOLS'] != 'addon':
DIRS += [
'server',
'shared',
'shim',
]
]
# /browser uses DIST_SUBDIR. We opt-in to this treatment when building
# DevTools for the browser to keep the root omni.ja slim for use by external XUL

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

@ -0,0 +1,19 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=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/.
XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini']
XPIDL_SOURCES += [
'nsIJSInspector.idl',
]
XPIDL_MODULE = 'jsinspector'
SOURCES += [
'nsJSInspector.cpp',
]
FINAL_LIBRARY = 'xul'

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

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

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

@ -0,0 +1,19 @@
// Parent config file for all devtools xpcshell files.
module.exports = {
"extends": [
"plugin:mozilla/xpcshell-test"
],
"rules": {
// Allow non-camelcase so that run_test doesn't produce a warning.
"camelcase": "off",
// Allow using undefined variables so that tests can refer to functions
// and variables defined in head.js files, without having to maintain a
// list of globals in each .eslintrc file.
// Note that bug 1168340 will eventually help auto-registering globals
// from head.js files.
"no-undef": "off",
"block-scoped-var": "off",
// Tests can always import anything.
"mozilla/reject-some-requires": "off",
}
}

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

@ -3,9 +3,13 @@
"use strict";
const Cc = Components.classes;
const Ci = Components.interfaces;
// Test the basic functionality of the nsIJSInspector component.
var gCount = 0;
const MAX = 10;
var inspector = Cc["@mozilla.org/jsinspector;1"].getService(Ci.nsIJSInspector);
var tm = Cc["@mozilla.org/thread-manager;1"].getService(Ci.nsIThreadManager);

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

@ -0,0 +1,6 @@
[DEFAULT]
tags = devtools
firefox-appdir = browser
skip-if = toolkit == 'android'
[test_nsjsinspector.js]

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

@ -16,18 +16,6 @@ BROWSER_CHROME_MANIFESTS += ['tests/browser/browser.ini']
MOCHITEST_CHROME_MANIFESTS += ['tests/mochitest/chrome.ini']
XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini']
XPIDL_SOURCES += [
'nsIJSInspector.idl',
]
XPIDL_MODULE = 'jsinspector'
SOURCES += [
'nsJSInspector.cpp',
]
FINAL_LIBRARY = 'xul'
DevToolsModules(
'child.js',
'content-server.jsm',

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

@ -43,7 +43,6 @@ support-files =
[test_nesting-03.js]
[test_forwardingprefix.js]
[test_getyoungestframe.js]
[test_nsjsinspector.js]
[test_dbgactor.js]
[test_dbgglobal.js]
[test_dbgclient_debuggerstatement.js]

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

@ -329,15 +329,15 @@ public:
* Get the SMIL override style declaration for this element. If the
* rule hasn't been created, this method simply returns null.
*/
virtual DeclarationBlock* GetSMILOverrideStyleDeclaration();
DeclarationBlock* GetSMILOverrideStyleDeclaration();
/**
* Set the SMIL override style declaration for this element. If
* aNotify is true, this method will notify the document's pres
* context, so that the style changes will be noticed.
*/
virtual nsresult SetSMILOverrideStyleDeclaration(
DeclarationBlock* aDeclaration, bool aNotify);
nsresult SetSMILOverrideStyleDeclaration(DeclarationBlock* aDeclaration,
bool aNotify);
/**
* Returns a new nsISMILAttr that allows the caller to animate the given
@ -357,7 +357,7 @@ public:
* Note: This method is analogous to the 'GetStyle' method in
* nsGenericHTMLElement and nsStyledElement.
*/
virtual nsICSSDeclaration* GetSMILOverrideStyle();
nsICSSDeclaration* GetSMILOverrideStyle();
/**
* Returns if the element is labelable as per HTML specification.

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

@ -275,7 +275,7 @@ public:
/**
* SMIL Overridde style rules (for SMIL animation of CSS properties)
* @see nsIContent::GetSMILOverrideStyle
* @see Element::GetSMILOverrideStyle
*/
nsCOMPtr<nsICSSDeclaration> mSMILOverrideStyle;

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

@ -113,7 +113,6 @@ const char* mozilla::dom::ContentPrefs::gInitPrefs[] = {
"javascript.options.wasm_baselinejit",
"javascript.options.werror",
"javascript.use_us_english_locale",
"jsloader.reuseGlobal",
"layout.idle_period.required_quiescent_frames",
"layout.idle_period.time_limit",
"layout.interruptible-reflow.enabled",

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

@ -6,6 +6,7 @@
#include "MediaDecoder.h"
#include "nsIPrincipal.h"
#include "nsMimeTypes.h"
#include "TimeUnits.h"
#include "mozilla/Logging.h"
#include "mozilla/Preferences.h"
#include "mozilla/StaticPtr.h"
@ -33,7 +34,36 @@ void
MediaStreamVideoRecorderSink::SetCurrentFrames(const VideoSegment& aSegment)
{
MOZ_ASSERT(mVideoEncoder);
// If we're suspended (paused) we don't forward frames
if (!mSuspended) {
mVideoEncoder->SetCurrentFrames(aSegment);
}
}
void
MediaEncoder::Suspend()
{
MOZ_ASSERT(NS_IsMainThread());
mLastPauseStartTime = TimeStamp::Now();
mSuspended = true;
mVideoSink->Suspend();
}
void
MediaEncoder::Resume()
{
MOZ_ASSERT(NS_IsMainThread());
if (!mSuspended) {
return;
}
media::TimeUnit timeSpentPaused =
media::TimeUnit::FromTimeDuration(
TimeStamp::Now() - mLastPauseStartTime);
MOZ_ASSERT(timeSpentPaused.ToMicroseconds() >= 0);
MOZ_RELEASE_ASSERT(timeSpentPaused.IsValid());
mMicrosecondsSpentPaused += timeSpentPaused.ToMicroseconds();;
mSuspended = false;
mVideoSink->Resume();
}
void
@ -49,7 +79,9 @@ MediaEncoder::NotifyRealtimeData(MediaStreamGraph* aGraph,
uint32_t aTrackEvents,
const MediaSegment& aRealtimeMedia)
{
if (mSuspended == RECORD_NOT_SUSPENDED) {
if (mSuspended) {
return;
}
// Process the incoming raw track data from MediaStreamGraph, called on the
// thread of MediaStreamGraph.
if (mAudioEncoder && aRealtimeMedia.GetType() == MediaSegment::AUDIO) {
@ -63,7 +95,6 @@ MediaEncoder::NotifyRealtimeData(MediaStreamGraph* aGraph,
aTrackOffset, aTrackEvents,
aRealtimeMedia);
}
}
}
void
@ -88,24 +119,6 @@ MediaEncoder::NotifyQueuedTrackChanges(MediaStreamGraph* aGraph,
NotifyRealtimeData(aGraph, aID, aTrackOffset, aTrackEvents, segment);
}
}
if (mSuspended == RECORD_RESUMED) {
if (mVideoEncoder) {
if (aQueuedMedia.GetType() == MediaSegment::VIDEO) {
// insert a null frame of duration equal to the first segment passed
// after Resume(), so it'll get added to one of the DirectListener frames
VideoSegment segment;
gfx::IntSize size(0,0);
segment.AppendFrame(nullptr, aQueuedMedia.GetDuration(), size,
PRINCIPAL_HANDLE_NONE);
mVideoEncoder->NotifyQueuedTrackChanges(aGraph, aID,
aTrackOffset, aTrackEvents,
segment);
mSuspended = RECORD_NOT_SUSPENDED;
}
} else {
mSuspended = RECORD_NOT_SUSPENDED; // no video
}
}
}
}
@ -118,12 +131,6 @@ MediaEncoder::NotifyQueuedAudioData(MediaStreamGraph* aGraph, TrackID aID,
{
if (!mDirectConnected) {
NotifyRealtimeData(aGraph, aID, aTrackOffset, 0, aQueuedMedia);
} else {
if (mSuspended == RECORD_RESUMED) {
if (!mVideoEncoder) {
mSuspended = RECORD_NOT_SUSPENDED; // no video
}
}
}
}
@ -341,6 +348,29 @@ MediaEncoder::WriteEncodedDataToMuxer(TrackEncoder *aTrackEncoder)
mState = ENCODE_ERROR;
return rv;
}
// Update timestamps to accommodate pauses
const nsTArray<RefPtr<EncodedFrame> >& encodedFrames =
encodedVideoData.GetEncodedFrames();
// Take a copy of the atomic so we don't continually access it
uint64_t microsecondsSpentPaused = mMicrosecondsSpentPaused;
for (size_t i = 0; i < encodedFrames.Length(); ++i) {
RefPtr<EncodedFrame> frame = encodedFrames[i];
if (frame->GetTimeStamp() > microsecondsSpentPaused &&
frame->GetTimeStamp() - microsecondsSpentPaused > mLastMuxedTimestamp) {
// Use the adjusted timestamp if it's after the last timestamp
frame->SetTimeStamp(frame->GetTimeStamp() - microsecondsSpentPaused);
} else {
// If not, we force the last time stamp. We do this so the frames are
// still around and in order in case the codec needs to reference them.
// Dropping them here may result in artifacts in playback.
frame->SetTimeStamp(mLastMuxedTimestamp);
}
MOZ_ASSERT(mLastMuxedTimestamp <= frame->GetTimeStamp(),
"Our frames should be ordered by this point!");
mLastMuxedTimestamp = frame->GetTimeStamp();
}
rv = mWriter->WriteEncodedTrack(encodedVideoData,
aTrackEncoder->IsEncodingComplete() ?
ContainerWriter::END_OF_STREAM : 0);

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

@ -24,15 +24,20 @@ class MediaStreamVideoRecorderSink : public MediaStreamVideoSink
{
public:
explicit MediaStreamVideoRecorderSink(VideoTrackEncoder* aEncoder)
: mVideoEncoder(aEncoder) {}
: mVideoEncoder(aEncoder)
, mSuspended(false) {}
// MediaStreamVideoSink methods
virtual void SetCurrentFrames(const VideoSegment& aSegment) override;
virtual void ClearFrames() override {}
void Resume() { mSuspended = false; }
void Suspend() { mSuspended = true; }
private:
virtual ~MediaStreamVideoRecorderSink() {}
VideoTrackEncoder* mVideoEncoder;
Atomic<bool> mSuspended;
};
/**
@ -98,32 +103,19 @@ public :
, mShutdown(false)
, mDirectConnected(false)
, mSuspended(false)
, mMicrosecondsSpentPaused(0)
, mLastMuxedTimestamp(0)
{}
~MediaEncoder() {};
enum SuspendState {
RECORD_NOT_SUSPENDED,
RECORD_SUSPENDED,
RECORD_RESUMED
};
/* Note - called from control code, not on MSG threads. */
void Suspend()
{
mSuspended = RECORD_SUSPENDED;
}
void Suspend();
/**
* Note - called from control code, not on MSG threads.
* Arm to collect the Duration of the next video frame and give it
* to the next frame, in order to avoid any possible loss of sync. */
void Resume()
{
if (mSuspended == RECORD_SUSPENDED) {
mSuspended = RECORD_RESUMED;
}
}
* Calculates time spent paused in order to offset frames. */
void Resume();
/**
* Tells us which Notify to pay attention to for media
@ -243,7 +235,18 @@ private:
int mState;
bool mShutdown;
bool mDirectConnected;
Atomic<int> mSuspended;
// Tracks if the encoder is suspended (paused). Used on the main thread and
// MediaRecorder's read thread.
Atomic<bool> mSuspended;
// Timestamp of when the last pause happened. Should only be accessed on the
// main thread.
TimeStamp mLastPauseStartTime;
// Exposes the time spend paused in microseconds. Read by the main thread
// and MediaRecorder's read thread. Should only be written by main thread.
Atomic<uint64_t> mMicrosecondsSpentPaused;
// The timestamp of the last muxed sample. Should only be used on
// MediaRecorder's read thread.
uint64_t mLastMuxedTimestamp;
// Get duration from create encoder, for logging purpose
double GetEncodeTimeStamp()
{

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

@ -802,6 +802,9 @@ tags=msg
[test_mediarecorder_getencodeddata.html]
skip-if = android_version == '17' # android(bug 1232305)
tags=msg
[test_mediarecorder_pause_resume_video.html]
skip-if = toolkit == 'android' # android(bug 1232305)
tags=msg
[test_mediarecorder_principals.html]
skip-if = (os == 'linux' && bits == 64) || toolkit == 'android' # See bug 1266345, android(bug 1232305)
tags=msg

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

@ -0,0 +1,130 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test MediaRecorder Recording doesn't record during pause</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<script src="/tests/dom/canvas/test/captureStream_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<pre id="test">
<div id="content">
<canvas id="video-src-canvas"></canvas>
<video id="recorded-video"></video>>
</div>
<script class="testbody" type="text/javascript">
function startTest() {
// Setup canvas and take a stream from it
let canvas = document.getElementById("video-src-canvas");
let canvas_size = 100;
let new_canvas_size = 50;
canvas.width = canvas.height = canvas_size;
let helper = new CaptureStreamTestHelper2D(100, 100);
helper.drawColor(canvas, helper.red);
let canvasStream = canvas.captureStream();
// Canvas set up
// Check values for events
let numDataAvailabledRaised = 0;
// Recorded data that will be playback.
let blob;
mediaRecorder = new MediaRecorder(canvasStream);
is(mediaRecorder.stream, canvasStream,
"Media recorder stream = canvas stream at the start of recording");
mediaRecorder.onwarning = () => ok(false, "warning unexpectedly fired");
mediaRecorder.onerror = () => ok(false, "Recording failed");
mediaRecorder.ondataavailable = ev => {
info("Got 'dataavailable' event");
++numDataAvailabledRaised;
// Save recorded data for playback
blob = ev.data;
};
mediaRecorder.onstart = () => {
info("Got 'start' event");
// We just want one frame encoded before we pause
mediaRecorder.pause();
// We may rewrite this once we settle Bug 1363915, could listen for pause event instead
is(mediaRecorder.state, 'paused', 'Media recorder should be paused');
// Change our canvas color and size, these changes should not be recorded due to pause
canvas.width = canvas.height = new_canvas_size;
helper.drawColor(canvas, helper.blue);
// Wait awhile with the canvas as blue. Then change color to green, resume, and record green
let numberOfPaintsSincePause = 0;
let draw = () => {
numberOfPaintsSincePause++;
if(numberOfPaintsSincePause == 60) {
canvas.width = canvas.height = canvas_size;
helper.drawColor(canvas, helper.green);
} else if (numberOfPaintsSincePause == 62) {
// Waited 2 draws since changing canvas to green, should be safe to resume
mediaRecorder.resume();
} else if (numberOfPaintsSincePause > 120) {
mediaRecorder.stop();
return; // Early return, we don't want to request any more animation frames
}
window.requestAnimationFrame(draw);
};
window.requestAnimationFrame(draw);
};
mediaRecorder.onstop = () => {
info("Got 'stop' event");
is(mediaRecorder.state, 'inactive', 'Media recorder should be incative after stop');
is(numDataAvailabledRaised, 1, "Expected 1 dataavailable event");
ok(blob, "Should have gotten a data blob");
let video = document.getElementById("recorded-video");
video.id = "recorded-video";
video.src = URL.createObjectURL(blob);
// Setup a check to make sure we don't play back any blue
let checkVideoHasNoBlue = () => {
if(helper.isPixel(helper.getPixel(video), helper.blue, 128)) {
ok(false, "Video should have no blue frames");
// Remove handler so we don't spam the log
video.ontimeupdate = null;
}
};
video.ontimeupdate = checkVideoHasNoBlue;
video.onerror = () => {
ok(false, "Should be able to play the recording. Got error. code=" + video.error.code);
SimpleTest.finish();
};
video.onended = () => {
ok(helper.isPixel(helper.getPixel(video), helper.green, 128), "Last frame should be green");
SimpleTest.finish();
};
// The video will resize once it loads its metadata, only listen for resizes after that
video.onloadedmetadata = () => {
ok(video.videoWidth === canvas_size && video.videoHeight === canvas_size,
"video element should be same size as canvas once metadata is loaded");
// We shouldn't have any resize events once the video is loaded
video.onresize = () => {
ok(false, "Should not have any resize events!");
};
};
video.play();
};
mediaRecorder.start();
is(mediaRecorder.state, "recording", "Media recorder should be recording");
}
SimpleTest.waitForExplicitFinish();
startTest();
</script>
</pre>
</body>
</html>

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

@ -27,7 +27,6 @@ UNIFIED_SOURCES += [
'testDefinePropertyIgnoredAttributes.cpp',
'testDeflateStringToUTF8Buffer.cpp',
'testDifferentNewTargetInvokeConstructor.cpp',
'testEnclosingFunction.cpp',
'testErrorCopying.cpp',
'testException.cpp',
'testExternalArrayBuffer.cpp',

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

@ -1,68 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
*
* Test script cloning.
*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "jsfriendapi.h"
#include "jsapi-tests/tests.h"
using namespace js;
static JSFunction* foundFun = nullptr;
static bool
CheckEnclosing(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
foundFun = js::GetOutermostEnclosingFunctionOfScriptedCaller(cx);
args.rval().set(UndefinedValue());
return true;
}
BEGIN_TEST(test_enclosingFunction)
{
CHECK(JS_DefineFunction(cx, global, "checkEnclosing", CheckEnclosing, 0, 0));
EXEC("checkEnclosing()");
CHECK(foundFun == nullptr);
RootedFunction fun(cx);
JS::CompileOptions options(cx);
options.setFileAndLine(__FILE__, __LINE__);
const char s1chars[] = "checkEnclosing()";
JS::AutoObjectVector emptyScopeChain(cx);
CHECK(JS::CompileFunction(cx, emptyScopeChain, options, "s1", 0, nullptr, s1chars,
strlen(s1chars), &fun));
CHECK(fun);
CHECK(JS_DefineProperty(cx, global, "s1", fun, JSPROP_ENUMERATE));
EXEC("s1()");
CHECK(foundFun == fun);
const char s2chars[] = "return function() { checkEnclosing() }";
CHECK(JS::CompileFunction(cx, emptyScopeChain, options, "s2", 0, nullptr, s2chars,
strlen(s2chars), &fun));
CHECK(fun);
CHECK(JS_DefineProperty(cx, global, "s2", fun, JSPROP_ENUMERATE));
EXEC("s2()()");
CHECK(foundFun == fun);
const char s3chars[] = "return function() { { let x; function g() { checkEnclosing() } return g() } }";
CHECK(JS::CompileFunction(cx, emptyScopeChain, options, "s3", 0, nullptr, s3chars,
strlen(s3chars), &fun));
CHECK(fun);
CHECK(JS_DefineProperty(cx, global, "s3", fun, JSPROP_ENUMERATE));
EXEC("s3()()");
CHECK(foundFun == fun);
return true;
}
END_TEST(test_enclosingFunction)

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

@ -418,34 +418,6 @@ js::RunningWithTrustedPrincipals(JSContext* cx)
return cx->runningWithTrustedPrincipals();
}
JS_FRIEND_API(JSFunction*)
js::GetOutermostEnclosingFunctionOfScriptedCaller(JSContext* cx)
{
ScriptFrameIter iter(cx);
// Skip eval frames.
while (!iter.done() && iter.isEvalFrame())
++iter;
if (iter.done())
return nullptr;
if (!iter.isFunctionFrame())
return nullptr;
if (iter.compartment() != cx->compartment())
return nullptr;
RootedFunction curr(cx, iter.callee(cx));
for (ScopeIter si(curr->nonLazyScript()); si; si++) {
if (si.kind() == ScopeKind::Function)
curr = si.scope()->as<FunctionScope>().canonicalFunction();
}
assertSameCompartment(cx, curr);
return curr;
}
JS_FRIEND_API(JSFunction*)
js::DefineFunctionWithReserved(JSContext* cx, JSObject* objArg, const char* name, JSNative call,
unsigned nargs, unsigned attrs)

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

@ -677,18 +677,6 @@ inline void AssertSameCompartment(JSObject* objA, JSObject* objB) {}
JS_FRIEND_API(void)
NotifyAnimationActivity(JSObject* obj);
/**
* Return the outermost enclosing function (script) of the scripted caller.
* This function returns nullptr in several cases:
* - no script is running on the context
* - the caller is in global or eval code
* In particular, this function will "stop" its outermost search at eval() and
* thus it will really return the outermost enclosing function *since the
* innermost eval*.
*/
JS_FRIEND_API(JSFunction*)
GetOutermostEnclosingFunctionOfScriptedCaller(JSContext* cx);
JS_FRIEND_API(JSFunction*)
DefineFunctionWithReserved(JSContext* cx, JSObject* obj, const char* name, JSNative call,
unsigned nargs, unsigned attrs);
@ -2850,14 +2838,6 @@ extern JS_FRIEND_API(void)
SetJitExceptionHandler(JitExceptionHandler handler);
#endif
/**
* Get the nearest enclosing with environment object for a given function. If
* the function is not scripted or is not enclosed by a with scope, returns
* the global.
*/
extern JS_FRIEND_API(JSObject*)
GetNearestEnclosingWithEnvironmentObjectForFunction(JSFunction* fun);
/**
* Get the first SavedFrame object in this SavedFrame stack whose principals are
* subsumed by the cx's principals. If there is no such frame, return nullptr.

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

@ -3095,23 +3095,6 @@ js::GetDebugEnvironmentForGlobalLexicalEnvironment(JSContext* cx)
return GetDebugEnvironment(cx, ei);
}
// See declaration and documentation in jsfriendapi.h
JS_FRIEND_API(JSObject*)
js::GetNearestEnclosingWithEnvironmentObjectForFunction(JSFunction* fun)
{
if (!fun->isInterpreted())
return &fun->global();
JSObject* env = fun->environment();
while (env && !env->is<WithEnvironmentObject>())
env = env->enclosingEnvironment();
if (!env)
return &fun->global();
return &env->as<WithEnvironmentObject>().object();
}
bool
js::CreateObjectsForEnvironmentChain(JSContext* cx, AutoObjectVector& chain,
HandleObject terminatingEnv, MutableHandleObject envObj)

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

@ -54,11 +54,6 @@ using namespace mozilla::scache;
using namespace xpc;
using namespace JS;
// This JSClass exists to trick silly code that expects toString()ing the
// global in a component scope to return something with "BackstagePass" in it
// to continue working.
static const JSClass kFakeBackstagePassJSClass = { "FakeBackstagePass" };
static const char kObserverServiceContractID[] = "@mozilla.org/observer-service;1";
static const char kJSCachePrefix[] = "jsloader";
@ -196,8 +191,7 @@ mozJSComponentLoader::mozJSComponentLoader()
: mModules(16),
mImports(16),
mInProgressImports(16),
mInitialized(false),
mReuseLoaderGlobal(false)
mInitialized(false)
{
MOZ_ASSERT(!sSelf, "mozJSComponentLoader should be a singleton");
@ -300,8 +294,6 @@ mozJSComponentLoader::ReallyInit()
{
nsresult rv;
mReuseLoaderGlobal = Preferences::GetBool("jsloader.reuseGlobal");
nsCOMPtr<nsIScriptSecurityManager> secman =
do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
if (!secman)
@ -430,9 +422,7 @@ mozJSComponentLoader::LoadModule(FileLocation& aFile)
// Set the location information for the new global, so that tools like
// about:memory may use that information
if (!mReuseLoaderGlobal) {
xpc::SetLocationForGlobal(entryObj, spec);
}
// The hash owns the ModuleEntry now, forget about it
return entry.forget();
@ -442,27 +432,7 @@ void
mozJSComponentLoader::FindTargetObject(JSContext* aCx,
MutableHandleObject aTargetObject)
{
aTargetObject.set(nullptr);
RootedObject targetObject(aCx);
if (mReuseLoaderGlobal) {
JSFunction* fun = js::GetOutermostEnclosingFunctionOfScriptedCaller(aCx);
if (fun) {
JSObject* funParent = js::GetNearestEnclosingWithEnvironmentObjectForFunction(fun);
if (JS_GetClass(funParent) == &kFakeBackstagePassJSClass)
targetObject = funParent;
}
}
// The above could fail, even if mReuseLoaderGlobal, if the scripted
// caller is not a component/JSM (it could be a DOM scope, for
// instance).
if (!targetObject) {
// Our targetObject is the caller's global object. Let's get it.
targetObject = CurrentGlobalOrNull(aCx);
}
aTargetObject.set(targetObject);
aTargetObject.set(CurrentGlobalOrNull(aCx));
}
// This requires that the keys be strings and the values be pointers.
@ -489,6 +459,53 @@ mozJSComponentLoader::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf)
return n;
}
void
mozJSComponentLoader::CreateLoaderGlobal(JSContext* aCx,
JSAddonId* aAddonID,
MutableHandleObject aGlobal)
{
RefPtr<BackstagePass> backstagePass;
nsresult rv = NS_NewBackstagePass(getter_AddRefs(backstagePass));
NS_ENSURE_SUCCESS_VOID(rv);
CompartmentOptions options;
options.creationOptions()
.setSystemZone()
.setAddonId(aAddonID);
options.behaviors().setVersion(JSVERSION_LATEST);
if (xpc::SharedMemoryEnabled())
options.creationOptions().setSharedMemoryAndAtomicsEnabled(true);
// Defer firing OnNewGlobalObject until after the __URI__ property has
// been defined so the JS debugger can tell what module the global is
// for
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
rv = nsXPConnect::XPConnect()->
InitClassesWithNewWrappedGlobal(aCx,
static_cast<nsIGlobalObject*>(backstagePass),
mSystemPrincipal,
nsIXPConnect::DONT_FIRE_ONNEWGLOBALHOOK,
options,
getter_AddRefs(holder));
NS_ENSURE_SUCCESS_VOID(rv);
RootedObject global(aCx, holder->GetJSObject());
NS_ENSURE_TRUE_VOID(global);
backstagePass->SetGlobalObject(global);
JSAutoCompartment ac(aCx, global);
if (!JS_DefineFunctions(aCx, global, gGlobalFun) ||
!JS_DefineProfilingFunctions(aCx, global)) {
return;
}
aGlobal.set(global);
}
// Some stack based classes for cleaning up on early return
class FileAutoCloser
{
@ -512,79 +529,27 @@ JSObject*
mozJSComponentLoader::PrepareObjectForLocation(JSContext* aCx,
nsIFile* aComponentFile,
nsIURI* aURI,
bool aReuseLoaderGlobal,
bool* aRealFile)
{
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
if (aReuseLoaderGlobal) {
holder = mLoaderGlobal;
}
RootedObject globalObj(aCx);
nsresult rv = NS_OK;
bool createdNewGlobal = false;
CreateLoaderGlobal(aCx, MapURIToAddonID(aURI), &globalObj);
if (!mLoaderGlobal) {
RefPtr<BackstagePass> backstagePass;
rv = NS_NewBackstagePass(getter_AddRefs(backstagePass));
NS_ENSURE_SUCCESS(rv, nullptr);
// |thisObj| is the object we set properties on for a particular .jsm.
// XXX Right now, thisObj is always globalObj, but if we start
// sharing globals between jsms, they won't be the same.
// See bug 1186409.
RootedObject thisObj(aCx, globalObj);
NS_ENSURE_TRUE(thisObj, nullptr);
CompartmentOptions options;
options.creationOptions()
.setSystemZone()
.setAddonId(aReuseLoaderGlobal ? nullptr : MapURIToAddonID(aURI));
options.behaviors().setVersion(JSVERSION_LATEST);
if (xpc::SharedMemoryEnabled())
options.creationOptions().setSharedMemoryAndAtomicsEnabled(true);
// Defer firing OnNewGlobalObject until after the __URI__ property has
// been defined so the JS debugger can tell what module the global is
// for
rv = nsXPConnect::XPConnect()->
InitClassesWithNewWrappedGlobal(aCx,
static_cast<nsIGlobalObject*>(backstagePass),
mSystemPrincipal,
nsIXPConnect::DONT_FIRE_ONNEWGLOBALHOOK,
options,
getter_AddRefs(holder));
NS_ENSURE_SUCCESS(rv, nullptr);
createdNewGlobal = true;
RootedObject global(aCx, holder->GetJSObject());
NS_ENSURE_TRUE(global, nullptr);
backstagePass->SetGlobalObject(global);
JSAutoCompartment ac(aCx, global);
if (!JS_DefineFunctions(aCx, global, gGlobalFun) ||
!JS_DefineProfilingFunctions(aCx, global)) {
return nullptr;
}
if (aReuseLoaderGlobal) {
mLoaderGlobal = holder;
}
}
RootedObject obj(aCx, holder->GetJSObject());
NS_ENSURE_TRUE(obj, nullptr);
JSAutoCompartment ac(aCx, obj);
if (aReuseLoaderGlobal) {
// If we're reusing the loader global, we don't actually use the
// global, but rather we use a different object as the 'this' object.
obj = JS_NewObject(aCx, &kFakeBackstagePassJSClass);
NS_ENSURE_TRUE(obj, nullptr);
}
JSAutoCompartment ac(aCx, thisObj);
*aRealFile = false;
// need to be extra careful checking for URIs pointing to files
// EnsureFile may not always get called, especially on resource URIs
// so we need to call GetFile to make sure this is a valid file
nsresult rv = NS_OK;
nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(aURI, &rv);
nsCOMPtr<nsIFile> testFile;
if (NS_SUCCEEDED(rv)) {
@ -597,13 +562,13 @@ mozJSComponentLoader::PrepareObjectForLocation(JSContext* aCx,
if (XRE_IsParentProcess()) {
RootedObject locationObj(aCx);
rv = nsXPConnect::XPConnect()->WrapNative(aCx, obj, aComponentFile,
rv = nsXPConnect::XPConnect()->WrapNative(aCx, thisObj, aComponentFile,
NS_GET_IID(nsIFile),
locationObj.address());
NS_ENSURE_SUCCESS(rv, nullptr);
NS_ENSURE_TRUE(locationObj, nullptr);
if (!JS_DefineProperty(aCx, obj, "__LOCATION__", locationObj, 0))
if (!JS_DefineProperty(aCx, thisObj, "__LOCATION__", locationObj, 0))
return nullptr;
}
}
@ -617,19 +582,18 @@ mozJSComponentLoader::PrepareObjectForLocation(JSContext* aCx,
RootedString exposedUri(aCx, JS_NewStringCopyN(aCx, nativePath.get(), nativePath.Length()));
NS_ENSURE_TRUE(exposedUri, nullptr);
if (!JS_DefineProperty(aCx, obj, "__URI__", exposedUri, 0))
if (!JS_DefineProperty(aCx, thisObj, "__URI__", exposedUri, 0))
return nullptr;
if (createdNewGlobal) {
{
// AutoEntryScript required to invoke debugger hook, which is a
// Gecko-specific concept at present.
dom::AutoEntryScript aes(holder->GetJSObject(),
dom::AutoEntryScript aes(globalObj,
"component loader report global");
RootedObject global(aes.cx(), holder->GetJSObject());
JS_FireOnNewGlobalObject(aes.cx(), global);
JS_FireOnNewGlobalObject(aes.cx(), globalObj);
}
return obj;
return thisObj;
}
nsresult
@ -651,14 +615,13 @@ mozJSComponentLoader::ObjectForLocation(ComponentLoaderInfo& aInfo,
nsresult rv = aInfo.EnsureURI();
NS_ENSURE_SUCCESS(rv, rv);
RootedObject obj(cx, PrepareObjectForLocation(cx, aComponentFile, aInfo.URI(),
mReuseLoaderGlobal, &realFile));
&realFile));
NS_ENSURE_TRUE(obj, NS_ERROR_FAILURE);
MOZ_ASSERT(JS_IsGlobalObject(obj) == !mReuseLoaderGlobal);
MOZ_ASSERT(JS_IsGlobalObject(obj));
JSAutoCompartment ac(cx, obj);
RootedScript script(cx);
RootedFunction function(cx);
nsAutoCString nativePath;
rv = aInfo.URI()->GetSpec(nativePath);
@ -675,52 +638,37 @@ mozJSComponentLoader::ObjectForLocation(ComponentLoaderInfo& aInfo,
rv = PathifyURI(aInfo.URI(), cachePath);
NS_ENSURE_SUCCESS(rv, rv);
if (!mReuseLoaderGlobal) {
script = ScriptPreloader::GetSingleton().GetCachedScript(cx, cachePath);
if (!script && cache) {
ReadCachedScript(cache, cachePath, cx, mSystemPrincipal, &script);
}
} else if (cache) {
ReadCachedFunction(cache, cachePath, cx, mSystemPrincipal,
function.address());
}
if (script || function) {
if (script) {
LOG(("Successfully loaded %s from startupcache\n", nativePath.get()));
} else if (cache) {
// This is ok, it just means the script is not yet in the
// cache. Could mean that the cache was corrupted and got removed,
// but either way we're going to write this out.
writeToCache = true;
// ReadCachedScript and ReadCachedFunction may have set a pending
// exception.
// ReadCachedScript may have set a pending exception.
JS_ClearPendingException(cx);
}
if (!script && !function) {
if (!script) {
// The script wasn't in the cache , so compile it now.
LOG(("Slow loading %s\n", nativePath.get()));
// Use lazy source if both of these conditions hold:
//
// (1) mReuseLoaderGlobal is false. If mReuseLoaderGlobal is true, we
// can't do lazy source because we compile things as functions
// (rather than script), and lazy source isn't supported in that
// configuration. That's ok though, because we only do
// mReuseLoaderGlobal on b2g, where we invoke setDiscardSource(true)
// on the entire global.
//
// (2) We're using the startup cache. Non-lazy source + startup cache
// regresses installer size (due to source code stored in XDR
// encoded modules in omni.ja). Also, XDR decoding is relatively
// fast. Content processes don't use the startup cache, so we want
// them to use non-lazy source code to enable lazy parsing.
// Use lazy source if we're using the startup cache. Non-lazy source +
// startup cache regresses installer size (due to source code stored in
// XDR encoded modules in omni.ja). Also, XDR decoding is relatively
// fast. When we're not using the startup cache, we want to use non-lazy
// source code so that we can use lazy parsing.
// See bug 1303754.
CompileOptions options(cx);
options.setNoScriptRval(mReuseLoaderGlobal ? false : true)
options.setNoScriptRval(true)
.setVersion(JSVERSION_LATEST)
.setFileAndLine(nativePath.get(), 1)
.setSourceIsLazy(!mReuseLoaderGlobal && !!cache);
.setSourceIsLazy(!!cache);
if (realFile) {
int64_t fileSize;
@ -766,18 +714,9 @@ mozJSComponentLoader::ObjectForLocation(ComponentLoaderInfo& aInfo,
return NS_ERROR_FAILURE;
}
if (!mReuseLoaderGlobal) {
Compile(cx, options, buf, fileSize32, &script);
} else {
// Note: exceptions will get handled further down;
// don't early return for them here.
AutoObjectVector envChain(cx);
if (envChain.append(obj)) {
CompileFunction(cx, envChain,
options, nullptr, 0, nullptr,
buf, fileSize32, &function);
}
}
Compile(cx, options, buf, fileSize32, &script);
PR_MemUnmap(buf, fileSize32);
} else {
@ -810,51 +749,26 @@ mozJSComponentLoader::ObjectForLocation(ComponentLoaderInfo& aInfo,
buf[len] = '\0';
if (!mReuseLoaderGlobal) {
Compile(cx, options, buf.get(), bytesRead, &script);
} else {
// Note: exceptions will get handled further down;
// don't early return for them here.
AutoObjectVector envChain(cx);
if (envChain.append(obj)) {
CompileFunction(cx, envChain,
options, nullptr, 0, nullptr,
buf.get(), bytesRead, &function);
}
}
}
// Propagate the exception, if one exists. Also, don't leave the stale
// exception on this context.
if (!script && !function && aPropagateExceptions &&
jsapi.HasException()) {
if (!script && aPropagateExceptions && jsapi.HasException()) {
if (!jsapi.StealException(aException))
return NS_ERROR_OUT_OF_MEMORY;
}
}
if (!script && !function) {
if (!script) {
return NS_ERROR_FAILURE;
}
// We must have a script or a function (but not both!) here. We have a
// script when we're not reusing the loader global, and a function
// otherwise.
MOZ_ASSERT(!!script != !!function);
MOZ_ASSERT(!!script == JS_IsGlobalObject(obj));
if (script) {
ScriptPreloader::GetSingleton().NoteScript(nativePath, cachePath, script);
}
if (writeToCache) {
// We successfully compiled the script, so cache it.
if (script) {
rv = WriteCachedScript(cache, cachePath, cx, mSystemPrincipal,
script);
} else {
rv = WriteCachedFunction(cache, cachePath, cx, mSystemPrincipal,
function);
}
// Don't treat failure to write as fatal, since we might be working
// with a read-only cache.
@ -869,34 +783,18 @@ mozJSComponentLoader::ObjectForLocation(ComponentLoaderInfo& aInfo,
// See bug 384168.
aObject.set(obj);
RootedScript tableScript(cx, script);
if (!tableScript) {
tableScript = JS_GetFunctionScript(cx, function);
MOZ_ASSERT(tableScript);
}
aTableScript.set(tableScript);
aTableScript.set(script);
{ // Scope for AutoEntryScript
// We're going to run script via JS_ExecuteScript or
// JS_CallFunction, so we need an AutoEntryScript.
// This is Gecko-specific and not in any spec.
// We're going to run script via JS_ExecuteScript, so we need an
// AutoEntryScript. This is Gecko-specific and not in any spec.
dom::AutoEntryScript aes(CurrentGlobalOrNull(cx),
"component loader load module");
JSContext* aescx = aes.cx();
bool ok;
if (script) {
JS::RootedValue rval(cx);
ok = JS::CloneAndExecuteScript(aescx, script, &rval);
} else {
RootedValue rval(cx);
ok = JS_CallFunction(aescx, obj, function,
JS::HandleValueArray::empty(), &rval);
}
if (!ok) {
if (!JS::CloneAndExecuteScript(aescx, script, &rval)) {
if (aPropagateExceptions && aes.HasException()) {
// Ignore return value because we're returning an error code
// anyway.
@ -924,26 +822,6 @@ mozJSComponentLoader::UnloadModules()
{
mInitialized = false;
if (mLoaderGlobal) {
MOZ_ASSERT(mReuseLoaderGlobal, "How did this happen?");
dom::AutoJSAPI jsapi;
jsapi.Init();
JSContext* cx = jsapi.cx();
RootedObject global(cx, mLoaderGlobal->GetJSObject());
if (global) {
JSAutoCompartment ac(cx, global);
if (JS_HasExtensibleLexicalEnvironment(global)) {
JS_SetAllNonReservedSlotsToUndefined(cx, JS_ExtensibleLexicalEnvironment(global));
}
JS_SetAllNonReservedSlotsToUndefined(cx, global);
} else {
NS_WARNING("Going to leak!");
}
mLoaderGlobal = nullptr;
}
mInProgressImports.Clear();
mImports.Clear();
@ -1141,9 +1019,7 @@ mozJSComponentLoader::ImportInto(const nsACString& aLocation,
// Set the location information for the new global, so that tools like
// about:memory may use that information
if (!mReuseLoaderGlobal) {
xpc::SetLocationForGlobal(newEntry->obj, aLocation);
}
mod = newEntry;
}
@ -1286,9 +1162,6 @@ mozJSComponentLoader::Unload(const nsACString & aLocation)
return NS_OK;
}
MOZ_RELEASE_ASSERT(!mReuseLoaderGlobal, "Module unloading not supported when "
"compartment sharing is enabled");
ComponentLoaderInfo info(aLocation);
rv = info.EnsureKey();
NS_ENSURE_SUCCESS(rv, rv);

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

@ -62,10 +62,13 @@ class mozJSComponentLoader : public mozilla::ModuleLoader,
nsresult ReallyInit();
void UnloadModules();
void CreateLoaderGlobal(JSContext* aCx,
JSAddonId* aAddonID,
JS::MutableHandleObject aGlobal);
JSObject* PrepareObjectForLocation(JSContext* aCx,
nsIFile* aComponentFile,
nsIURI* aComponent,
bool aReuseLoaderGlobal,
bool* aRealFile);
nsresult ObjectForLocation(ComponentLoaderInfo& aInfo,
@ -83,7 +86,6 @@ class mozJSComponentLoader : public mozilla::ModuleLoader,
nsCOMPtr<nsIComponentManager> mCompMgr;
nsCOMPtr<nsIPrincipal> mSystemPrincipal;
nsCOMPtr<nsIXPConnectJSObjectHolder> mLoaderGlobal;
class ModuleEntry : public mozilla::Module
{
@ -155,7 +157,6 @@ class mozJSComponentLoader : public mozilla::ModuleLoader,
nsDataHashtable<nsCStringHashKey, ModuleEntry*> mInProgressImports;
bool mInitialized;
bool mReuseLoaderGlobal;
};
#endif

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

@ -43,14 +43,6 @@ ReadCachedScript(StartupCache* cache, nsACString& uri, JSContext* cx,
return NS_ERROR_OUT_OF_MEMORY;
}
nsresult
ReadCachedFunction(StartupCache* cache, nsACString& uri, JSContext* cx,
nsIPrincipal* systemPrincipal, JSFunction** functionp)
{
// This doesn't actually work ...
return NS_ERROR_NOT_IMPLEMENTED;
}
nsresult
WriteCachedScript(StartupCache* cache, nsACString& uri, JSContext* cx,
nsIPrincipal* systemPrincipal, HandleScript script)
@ -75,11 +67,3 @@ WriteCachedScript(StartupCache* cache, nsACString& uri, JSContext* cx,
size);
return rv;
}
nsresult
WriteCachedFunction(StartupCache* cache, nsACString& uri, JSContext* cx,
nsIPrincipal* systemPrincipal, JSFunction* function)
{
// This doesn't actually work ...
return NS_ERROR_NOT_IMPLEMENTED;
}

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

@ -20,18 +20,9 @@ ReadCachedScript(mozilla::scache::StartupCache* cache, nsACString& uri,
JSContext* cx, nsIPrincipal* systemPrincipal,
JS::MutableHandleScript scriptp);
nsresult
ReadCachedFunction(mozilla::scache::StartupCache* cache, nsACString& uri,
JSContext* cx, nsIPrincipal* systemPrincipal,
JSFunction** function);
nsresult
WriteCachedScript(mozilla::scache::StartupCache* cache, nsACString& uri,
JSContext* cx, nsIPrincipal* systemPrincipal,
JS::HandleScript script);
nsresult
WriteCachedFunction(mozilla::scache::StartupCache* cache, nsACString& uri,
JSContext* cx, nsIPrincipal* systemPrincipal,
JSFunction* function);
#endif /* mozJSLoaderUtils_h */

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

@ -132,15 +132,11 @@ PrepareScript(nsIURI* uri,
const nsAString& charset,
const char* buf,
int64_t len,
bool reuseGlobal,
bool wantReturnValue,
MutableHandleScript script,
MutableHandleFunction function)
MutableHandleScript script)
{
JS::CompileOptions options(cx);
// Use line 0 to make the function body starts from line 1 when
// |reuseGlobal == true|.
options.setFileAndLine(uriStr, reuseGlobal ? 0 : 1)
options.setFileAndLine(uriStr, 1)
.setVersion(JSVERSION_LATEST)
.setNoScriptRval(!wantReturnValue);
if (!charset.IsVoid()) {
@ -159,34 +155,18 @@ PrepareScript(nsIURI* uri,
return false;
}
if (!reuseGlobal) {
if (JS_IsGlobalObject(targetObj)) {
return JS::Compile(cx, options, srcBuf, script);
}
return JS::CompileForNonSyntacticScope(cx, options, srcBuf, script);
}
AutoObjectVector envChain(cx);
if (!JS_IsGlobalObject(targetObj) && !envChain.append(targetObj)) {
return false;
}
return JS::CompileFunction(cx, envChain, options, nullptr, 0, nullptr,
srcBuf, function);
}
// We only use lazy source when no special encoding is specified because
// the lazy source loader doesn't know the encoding.
if (!reuseGlobal) {
options.setSourceIsLazy(true);
if (JS_IsGlobalObject(targetObj)) {
return JS::Compile(cx, options, buf, len, script);
}
return JS::CompileForNonSyntacticScope(cx, options, buf, len, script);
}
AutoObjectVector envChain(cx);
if (!JS_IsGlobalObject(targetObj) && !envChain.append(targetObj)) {
return false;
}
return JS::CompileFunction(cx, envChain, options, nullptr, 0, nullptr,
buf, len, function);
}
static bool
@ -196,18 +176,8 @@ EvalScript(JSContext* cx,
nsIURI* uri,
bool startupCache,
bool preloadCache,
MutableHandleScript script,
HandleFunction function)
MutableHandleScript script)
{
if (function) {
script.set(JS_GetFunctionScript(cx, function));
}
if (function) {
if (!JS_CallFunction(cx, targetObj, function, JS::HandleValueArray::empty(), retval)) {
return false;
}
} else {
if (JS_IsGlobalObject(targetObj)) {
if (!JS::CloneAndExecuteScript(cx, script, retval)) {
return false;
@ -221,7 +191,6 @@ EvalScript(JSContext* cx,
return false;
}
}
}
JSAutoCompartment rac(cx, targetObj);
if (!JS_WrapValue(cx, retval)) {
@ -270,14 +239,13 @@ public:
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(AsyncScriptLoader)
AsyncScriptLoader(nsIChannel* aChannel, bool aReuseGlobal, bool aWantReturnValue,
AsyncScriptLoader(nsIChannel* aChannel, bool aWantReturnValue,
JSObject* aTargetObj, const nsAString& aCharset,
bool aCache, Promise* aPromise)
: mChannel(aChannel)
, mTargetObj(aTargetObj)
, mPromise(aPromise)
, mCharset(aCharset)
, mReuseGlobal(aReuseGlobal)
, mWantReturnValue(aWantReturnValue)
, mCache(aCache)
{
@ -294,7 +262,6 @@ private:
Heap<JSObject*> mTargetObj;
RefPtr<Promise> mPromise;
nsString mCharset;
bool mReuseGlobal;
bool mWantReturnValue;
bool mCache;
};
@ -394,7 +361,6 @@ AsyncScriptLoader::OnStreamComplete(nsIIncrementalStreamLoader* aLoader,
return NS_OK;
}
RootedFunction function(cx);
RootedScript script(cx);
nsAutoCString spec;
nsresult rv = uri->GetSpec(spec);
@ -404,7 +370,7 @@ AsyncScriptLoader::OnStreamComplete(nsIIncrementalStreamLoader* aLoader,
if (!PrepareScript(uri, cx, targetObj, spec.get(), mCharset,
reinterpret_cast<const char*>(aBuf), aLength,
mReuseGlobal, mWantReturnValue, &script, &function))
mWantReturnValue, &script))
{
return NS_OK;
}
@ -412,7 +378,7 @@ AsyncScriptLoader::OnStreamComplete(nsIIncrementalStreamLoader* aLoader,
JS::Rooted<JS::Value> retval(cx);
if (EvalScript(cx, targetObj, &retval, uri, mCache,
mCache && !mWantReturnValue,
&script, function)) {
&script)) {
autoPromise.ResolvePromise(retval);
}
@ -424,7 +390,6 @@ mozJSSubScriptLoader::ReadScriptAsync(nsIURI* uri,
HandleObject targetObj,
const nsAString& charset,
nsIIOService* serv,
bool reuseGlobal,
bool wantReturnValue,
bool cache,
MutableHandleValue retval)
@ -467,7 +432,6 @@ mozJSSubScriptLoader::ReadScriptAsync(nsIURI* uri,
RefPtr<AsyncScriptLoader> loadObserver =
new AsyncScriptLoader(channel,
reuseGlobal,
wantReturnValue,
targetObj,
charset,
@ -489,13 +453,10 @@ mozJSSubScriptLoader::ReadScript(nsIURI* uri,
const nsAString& charset,
const char* uriStr,
nsIIOService* serv,
bool reuseGlobal,
bool wantReturnValue,
MutableHandleScript script,
MutableHandleFunction function)
MutableHandleScript script)
{
script.set(nullptr);
function.set(nullptr);
// We create a channel and call SetContentType, to avoid expensive MIME type
// lookups (bug 632490).
@ -540,9 +501,8 @@ mozJSSubScriptLoader::ReadScript(nsIURI* uri,
NS_ENSURE_SUCCESS(rv, false);
return PrepareScript(uri, cx, targetObj, uriStr, charset,
buf.get(), len,
reuseGlobal, wantReturnValue,
script, function);
buf.get(), len, wantReturnValue,
script);
}
NS_IMETHODIMP
@ -605,15 +565,13 @@ mozJSSubScriptLoader::DoLoadSubScriptWithOptions(const nsAString& url,
}
RootedObject targetObj(cx);
if (options.target) {
targetObj = options.target;
} else {
mozJSComponentLoader* loader = mozJSComponentLoader::Get();
loader->FindTargetObject(cx, &targetObj);
// We base reusingGlobal off of what the loader told us, but we may not
// actually be using that object.
bool reusingGlobal = !JS_IsGlobalObject(targetObj);
if (options.target)
targetObj = options.target;
MOZ_ASSERT(JS_IsGlobalObject(targetObj));
}
// Remember an object out of the calling compartment so that we
// can properly wrap the result later.
@ -694,7 +652,6 @@ mozJSSubScriptLoader::DoLoadSubScriptWithOptions(const nsAString& url,
cachePath.AppendPrintf("jssubloader/%d", version);
PathifyURI(uri, cachePath);
RootedFunction function(cx);
RootedScript script(cx);
if (!options.ignoreCache) {
if (!options.wantReturnValue)
@ -710,25 +667,22 @@ mozJSSubScriptLoader::DoLoadSubScriptWithOptions(const nsAString& url,
// If we are doing an async load, trigger it and bail out.
if (!script && options.async) {
return ReadScriptAsync(uri, targetObj, options.charset, serv,
reusingGlobal, options.wantReturnValue,
!!cache, retval);
options.wantReturnValue, !!cache, retval);
}
if (!script) {
if (!ReadScript(uri, cx, targetObj, options.charset,
static_cast<const char*>(uriStr.get()), serv,
reusingGlobal, options.wantReturnValue, &script,
&function))
{
return NS_OK;
}
} else {
if (script) {
// |script| came from the cache, so don't bother writing it
// |back there.
cache = nullptr;
} else if (!ReadScript(uri, cx, targetObj, options.charset,
static_cast<const char*>(uriStr.get()), serv,
options.wantReturnValue, &script)) {
return NS_OK;
}
Unused << EvalScript(cx, targetObj, retval, uri, !!cache,
!ignoreCache && !options.wantReturnValue,
&script, function);
&script);
return NS_OK;
}

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

@ -36,14 +36,15 @@ private:
bool ReadScript(nsIURI* uri, JSContext* cx, JS::HandleObject targetObj,
const nsAString& charset, const char* uriStr,
nsIIOService* serv,
bool reuseGlobal, bool wantReturnValue,
JS::MutableHandleScript script,
JS::MutableHandleFunction function);
bool wantReturnValue,
JS::MutableHandleScript script);
nsresult ReadScriptAsync(nsIURI* uri, JS::HandleObject targetObj,
nsresult ReadScriptAsync(nsIURI* uri,
JS::HandleObject targetObj,
const nsAString& charset,
nsIIOService* serv, bool reuseGlobal,
bool wantReturnValue, bool cache,
nsIIOService* serv,
bool wantReturnValue,
bool cache,
JS::MutableHandleValue retval);
nsresult DoLoadSubScriptWithOptions(const nsAString& url,

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

@ -273,6 +273,12 @@ public:
nsChangeHint aMinChangeHint,
const RestyleHintData* aRestyleHintData = nullptr);
void PostRestyleEventForCSSRuleChanges(Element* aElement,
nsRestyleHint aRestyleHint,
nsChangeHint aMinChangeHint) {
PostRestyleEvent(aElement, aRestyleHint, aMinChangeHint);
}
public:
/**
* Asynchronously clear style data from the root frame downwards and ensure

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

@ -4584,11 +4584,13 @@ nsIPresShell::RestyleForCSSRuleChanges()
// If scopeRoots is empty, we know that mStylesHaveChanged was true at
// the beginning of this function, and that we need to restyle the whole
// document.
restyleManager->PostRestyleEvent(root, eRestyle_Subtree,
restyleManager->PostRestyleEventForCSSRuleChanges(root,
eRestyle_Subtree,
nsChangeHint(0));
} else {
for (Element* scopeRoot : scopeRoots) {
restyleManager->PostRestyleEvent(scopeRoot, eRestyle_Subtree,
restyleManager->PostRestyleEventForCSSRuleChanges(scopeRoot,
eRestyle_Subtree,
nsChangeHint(0));
}
}

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

@ -161,6 +161,9 @@ public:
inline void PostRestyleEvent(dom::Element* aElement,
nsRestyleHint aRestyleHint,
nsChangeHint aMinChangeHint);
inline void PostRestyleEventForCSSRuleChanges(dom::Element* aElement,
nsRestyleHint aRestyleHint,
nsChangeHint aMinChangeHint);
inline void RebuildAllStyleData(nsChangeHint aExtraHint,
nsRestyleHint aRestyleHint);
inline void PostRebuildAllStyleDataEvent(nsChangeHint aExtraHint,

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

@ -24,6 +24,15 @@ RestyleManager::PostRestyleEvent(dom::Element* aElement,
MOZ_STYLO_FORWARD(PostRestyleEvent, (aElement, aRestyleHint, aMinChangeHint));
}
void
RestyleManager::PostRestyleEventForCSSRuleChanges(dom::Element* aElement,
nsRestyleHint aRestyleHint,
nsChangeHint aMinChangeHint)
{
MOZ_STYLO_FORWARD(PostRestyleEventForCSSRuleChanges,
(aElement, aRestyleHint, aMinChangeHint));
}
void
RestyleManager::RebuildAllStyleData(nsChangeHint aExtraHint,
nsRestyleHint aRestyleHint)

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

@ -66,6 +66,17 @@ ServoRestyleManager::PostRestyleEvent(Element* aElement,
Servo_NoteExplicitHints(aElement, aRestyleHint, aMinChangeHint);
}
void
ServoRestyleManager::PostRestyleEventForCSSRuleChanges(
Element* aElement,
nsRestyleHint aRestyleHint,
nsChangeHint aMinChangeHint)
{
mRestyleForCSSRuleChanges = true;
PostRestyleEvent(aElement, aRestyleHint, aMinChangeHint);
}
/* static */ void
ServoRestyleManager::PostRestyleEventForAnimations(Element* aElement,
nsRestyleHint aRestyleHint)
@ -553,8 +564,11 @@ ServoRestyleManager::DoProcessPendingRestyles(TraversalRestyleBehavior
++mAnimationGeneration;
}
TraversalRestyleBehavior restyleBehavior = mRestyleForCSSRuleChanges
? TraversalRestyleBehavior::ForCSSRuleChanges
: TraversalRestyleBehavior::Normal;
while (animationOnly ? styleSet->StyleDocumentForAnimationOnly()
: styleSet->StyleDocument()) {
: styleSet->StyleDocument(restyleBehavior)) {
if (!animationOnly) {
ClearSnapshots();
}
@ -603,6 +617,7 @@ ServoRestyleManager::DoProcessPendingRestyles(TraversalRestyleBehavior
styleSet->AssertTreeIsClean();
mHaveNonAnimationRestyles = false;
}
mRestyleForCSSRuleChanges = false;
mInStyleRefresh = false;
// Note: We are in the scope of |animationsWithDestroyedFrame|, so

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

@ -44,6 +44,9 @@ public:
nsRestyleHint aRestyleHint,
nsChangeHint aMinChangeHint);
void PostRestyleEventForLazyConstruction();
void PostRestyleEventForCSSRuleChanges(dom::Element* aElement,
nsRestyleHint aRestyleHint,
nsChangeHint aMinChangeHint);
void RebuildAllStyleData(nsChangeHint aExtraHint,
nsRestyleHint aRestyleHint);
void PostRebuildAllStyleDataEvent(nsChangeHint aExtraHint,
@ -162,6 +165,14 @@ private:
// creation sequence will be correct.
bool mHaveNonAnimationRestyles = false;
// Set to true when posting restyle events triggered by CSS rule changes.
// This flag is cleared once ProcessPendingRestyles has completed.
// When we process a traversal all descendants elements of the document
// triggered by CSS rule changes, we will need to update all elements with
// CSS animations. We propagate TraversalRestyleBehavior::ForCSSRuleChanges
// to traversal function if this flag is set.
bool mRestyleForCSSRuleChanges = false;
// A hashtable with the elements that have changed state or attributes, in
// order to calculate restyle hints during the traversal.
SnapshotTable mSnapshots;

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

@ -2537,7 +2537,7 @@ nsCSSFrameConstructor::ConstructDocElementFrame(Element* aDocEle
// We delay traversing the entire document until here, since we per above we
// may invalidate the root style when we load doc stylesheets.
if (ServoStyleSet* set = mPresShell->StyleSet()->GetAsServo()) {
set->StyleDocument();
set->StyleDocument(TraversalRestyleBehavior::Normal);
}
// --------- IF SCROLLABLE WRAP IN SCROLLFRAME --------

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

@ -157,16 +157,16 @@ fuzzy-if(d2d&&layersGPUAccelerated,3,1200) == dynamic-rect-02.svg dynamic-rect-0
== dynamic-stroke-opacity-01.svg pass.svg
== dynamic-stroke-width-01.svg pass.svg
== dynamic-switch-01.svg pass.svg
fails-if(stylo) == dynamic-text-01.svg dynamic-text-01-ref.svg
fuzzy-if(d2d&&layersGPUAccelerated,3,12739) fails-if(stylo) == dynamic-text-02.svg dynamic-text-02-ref.svg # bug 776038 for Win7, Win8
fuzzy-if(d2d&&layersGPUAccelerated,2,10539) fails-if(stylo) == dynamic-text-03.svg dynamic-text-03-ref.svg # bug 776038 for Win7
fuzzy-if(/^Windows\x20NT\x206\.1/.test(http.oscpu),47,89) fails-if(stylo) == dynamic-text-04.svg dynamic-text-04-ref.svg # bug 776038 for Win7
== dynamic-text-01.svg dynamic-text-01-ref.svg
fuzzy-if(d2d&&layersGPUAccelerated,3,12739) == dynamic-text-02.svg dynamic-text-02-ref.svg # bug 776038 for Win7, Win8
fuzzy-if(d2d&&layersGPUAccelerated,2,10539) == dynamic-text-03.svg dynamic-text-03-ref.svg # bug 776038 for Win7
fuzzy-if(/^Windows\x20NT\x206\.1/.test(http.oscpu),47,89) == dynamic-text-04.svg dynamic-text-04-ref.svg # bug 776038 for Win7
== dynamic-text-05.svg pass.svg
== dynamic-text-06.svg pass.svg
fails-if(stylo) == dynamic-text-07.svg dynamic-text-07-ref.svg
fails-if(stylo) == dynamic-text-08.svg dynamic-text-08-ref.svg
== dynamic-text-07.svg dynamic-text-07-ref.svg
== dynamic-text-08.svg dynamic-text-08-ref.svg
== dynamic-text-attr-01.svg dynamic-text-attr-01-ref.svg
fails-if(stylo) == dynamic-textPath-01.svg dynamic-textPath-01-ref.svg
== dynamic-textPath-01.svg dynamic-textPath-01-ref.svg
== dynamic-textPath-02.svg dynamic-textPath-02-ref.svg
== dynamic-textPath-03.svg dynamic-textPath-03-ref.svg
== dynamic-use-01.svg pass.svg
@ -188,7 +188,7 @@ random == dynamic-use-nested-01b.svg dynamic-use-nested-01-ref.svg
== fallback-color-02a.svg fallback-color-02-ref.svg
== fallback-color-02b.svg fallback-color-02-ref.svg
== fallback-color-03.svg pass.svg
fuzzy-if(skiaContent,1,2) fails-if(stylo) == fallback-color-04.svg pass.svg
fuzzy-if(skiaContent,1,2) == fallback-color-04.svg pass.svg
== fallback-color-05.svg fallback-color-05-ref.svg
== filter-basic-01.svg pass.svg
@ -236,10 +236,10 @@ fuzzy-if(Android,18,600) == foreignObject-fixedpos-01.html foreignObject-dynamic
== getElementById-a-element-01.svg pass.svg
fuzzy-if(Android,9,980) fuzzy-if(skiaContent,3,32000) fails-if(stylo) == gradient-live-01a.svg gradient-live-01-ref.svg
fuzzy-if(Android,9,980) fuzzy-if(skiaContent,3,32000) fails-if(stylo) == gradient-live-01b.svg gradient-live-01-ref.svg
fuzzy-if(Android,9,980) fuzzy-if(skiaContent,3,32000) fails-if(stylo) == gradient-live-01c.svg gradient-live-01-ref.svg
fuzzy-if(Android,9,980) fuzzy-if(skiaContent,3,32000) fails-if(stylo) == gradient-live-01d.svg gradient-live-01-ref.svg
fuzzy-if(Android,9,980) fuzzy-if(skiaContent,3,32000) == gradient-live-01a.svg gradient-live-01-ref.svg
fuzzy-if(Android,9,980) fuzzy-if(skiaContent,3,32000) == gradient-live-01b.svg gradient-live-01-ref.svg
fuzzy-if(Android,9,980) fuzzy-if(skiaContent,3,32000) == gradient-live-01c.svg gradient-live-01-ref.svg
fuzzy-if(Android,9,980) fuzzy-if(skiaContent,3,32000) == gradient-live-01d.svg gradient-live-01-ref.svg
== gradient-transform-01.svg pass.svg
== href-attr-change-restyles.svg href-attr-change-restyles-ref.svg
fuzzy-if(skiaContent,1,550) == import-svg-01.html pass.svg
@ -319,7 +319,7 @@ fuzzy-if(skiaContent,1,10000) == opacity-and-transform-01.svg opacity-and-transf
fuzzy-if(Android,8,200) == outer-svg-border-and-padding-01.svg outer-svg-border-and-padding-01-ref.svg
fuzzy-if(skiaContent,7,175) fuzzy-if(skiaContent&&webrender,1,225) fails-if(stylo) == outline.html outline-ref.html
fuzzy-if(skiaContent,7,175) fuzzy-if(skiaContent&&webrender,1,225) == outline.html outline-ref.html
== overflow-on-outer-svg-01.svg overflow-on-outer-svg-01-ref.svg
== overflow-on-outer-svg-02a.xhtml overflow-on-outer-svg-02-ref.xhtml
@ -333,7 +333,7 @@ fuzzy-if(skiaContent,7,175) fuzzy-if(skiaContent&&webrender,1,225) fails-if(styl
== paint-on-maskLayer-1b.html paint-on-maskLayer-1-ref.html
pref(layout.css.clip-path-shapes.enabled,true) == paint-on-maskLayer-1c.html paint-on-maskLayer-1-ref.html
pref(svg.paint-order.enabled,true) == paint-order-01.svg paint-order-01-ref.svg
pref(svg.paint-order.enabled,true) fails-if(stylo) == paint-order-02.svg paint-order-02-ref.svg
pref(svg.paint-order.enabled,true) == paint-order-02.svg paint-order-02-ref.svg
pref(svg.paint-order.enabled,true) == paint-order-03.svg paint-order-03-ref.svg
#fuzzy(23,60) fails-if(d2d) == path-01.svg path-01-ref.svg
@ -393,7 +393,7 @@ fuzzy-if(skiaContent,1,3600) == rect-01.svg pass.svg
fuzzy-if(skiaContent,1,340) fails-if(stylo) == stroke-dasharray-02.svg pass.svg
fuzzy-if(skiaContent,1,340) == stroke-dasharray-03.svg pass.svg
== stroke-dasharray-and-pathLength-01.svg pass.svg
fails-if(stylo) == stroke-dasharray-and-text-01.svg stroke-dasharray-and-text-01-ref.svg
== stroke-dasharray-and-text-01.svg stroke-dasharray-and-text-01-ref.svg
== stroke-dashoffset-01.svg pass.svg
== stroke-dashoffset-and-pathLength-01.svg pass.svg
== stroke-linecap-circle-ellipse-01.svg stroke-linecap-circle-ellipse-01-ref.svg
@ -434,24 +434,24 @@ fuzzy-if(skiaContent,1,2600) == svg-in-foreignObject-02.xhtml svg-in-foreignObje
== text-font-size-01.svg pass.svg
random-if(gtkWidget) == text-font-weight-01.svg text-font-weight-01-ref.svg # bug 386713
== text-gradient-01.svg text-gradient-01-ref.svg
random-if(winWidget) fails-if(stylo) == text-gradient-02.svg text-gradient-02-ref.svg # see bug 590101
random-if(winWidget) == text-gradient-02.svg text-gradient-02-ref.svg # see bug 590101
fuzzy-if(skiaContent,1,5500) == text-gradient-03.svg pass.svg
HTTP(..) == text-gradient-04.svg text-gradient-04-ref.svg
== text-in-link-01.svg text-in-link-01-ref.svg
== text-in-link-02.svg text-in-link-02-ref.svg
fails-if(stylo) == text-in-link-03.svg text-in-link-03-ref.svg
== text-in-link-03.svg text-in-link-03-ref.svg
# Tests for bug 546813: sanity-check using HTML text, then test SVG behavior.
!= text-language-00.xhtml text-language-00-ref.xhtml
random-if(gtkWidget) != text-language-01.xhtml text-language-01-ref.xhtml # Fails on Linux tryserver due to lack of CJK fonts.
random-if(stylo) == text-layout-01.svg text-layout-01-ref.svg
fails-if(stylo) == text-layout-02.svg text-layout-02-ref.svg
fails-if(stylo) == text-layout-03.svg text-layout-03-ref.svg
fails-if(stylo) == text-layout-04.svg text-layout-04-ref.svg
== text-layout-01.svg text-layout-01-ref.svg
== text-layout-02.svg text-layout-02-ref.svg
== text-layout-03.svg text-layout-03-ref.svg
== text-layout-04.svg text-layout-04-ref.svg
== text-layout-05.svg text-layout-05-ref.svg
fuzzy-if(cocoaWidget&&layersGPUAccelerated,1,3) fails-if(stylo) == text-layout-06.svg text-layout-06-ref.svg
fails-if(stylo) == text-layout-07.svg text-layout-07-ref.svg
fuzzy-if(cocoaWidget&&layersGPUAccelerated,1,3) == text-layout-06.svg text-layout-06-ref.svg
== text-layout-07.svg text-layout-07-ref.svg
== text-layout-08.svg text-layout-08-ref.svg
fails-if(stylo) == text-scale-01.svg text-scale-01-ref.svg
== text-scale-01.svg text-scale-01-ref.svg
fuzzy-if(skiaContent,2,1000) HTTP(..) == text-scale-02.svg text-scale-02-ref.svg
HTTP(..) == text-scale-03.svg text-scale-03-ref.svg
@ -465,7 +465,7 @@ HTTP(..) == text-scale-03.svg text-scale-03-ref.svg
fuzzy(16,3) == text-stroke-scaling-02a.html text-stroke-scaling-02-ref.html # antialiasing
fuzzy(16,3) == text-stroke-scaling-02b.html text-stroke-scaling-02-ref.html # antialiasing
== text-stroke-scaling-02a.html text-stroke-scaling-02b.html
fails-if(stylo) == textPath-01.svg textPath-01-ref.svg
== textPath-01.svg textPath-01-ref.svg
== textPath-02.svg pass.svg
fuzzy-if(skiaContent,1,610) == textPath-03.svg pass.svg
== textPath-04.svg pass.svg

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

@ -71,14 +71,14 @@ fails-if(stylo) == anim-css-fontsize-1-from-by-px-px.svg anim-css-fontsize-1-
== anim-css-fontsize-1-from-to-px-px.svg anim-css-fontsize-1-ref.svg
# 'font-size' property (accepts unitless values)
fails-if(stylo) == anim-css-fontsize-1-from-to-no-no.svg anim-css-fontsize-1-ref.svg
fails-if(stylo) == anim-css-fontsize-1-from-to-no-px.svg anim-css-fontsize-1-ref.svg
fails-if(stylo) == anim-css-fontsize-1-from-to-px-no.svg anim-css-fontsize-1-ref.svg
== anim-css-fontsize-1-from-to-no-no.svg anim-css-fontsize-1-ref.svg
== anim-css-fontsize-1-from-to-no-px.svg anim-css-fontsize-1-ref.svg
== anim-css-fontsize-1-from-to-px-no.svg anim-css-fontsize-1-ref.svg
# 'font-size' mapped attribute (accepts unitless values)
fails-if(stylo) == anim-mapped-fontsize-1-from-to-no-no.svg anim-css-fontsize-1-ref.svg
fails-if(stylo) == anim-mapped-fontsize-1-from-to-no-px.svg anim-css-fontsize-1-ref.svg
fails-if(stylo) == anim-mapped-fontsize-1-from-to-px-no.svg anim-css-fontsize-1-ref.svg
== anim-mapped-fontsize-1-from-to-no-no.svg anim-css-fontsize-1-ref.svg
== anim-mapped-fontsize-1-from-to-no-px.svg anim-css-fontsize-1-ref.svg
== anim-mapped-fontsize-1-from-to-px-no.svg anim-css-fontsize-1-ref.svg
# 'font-size' property, from/by/to with percent values
fails-if(stylo) == anim-css-fontsize-1-from-by-pct-pct.svg anim-css-fontsize-1-ref.svg

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

@ -825,8 +825,14 @@ ServoStyleSet::HasStateDependentStyle(dom::Element* aElement,
}
bool
ServoStyleSet::StyleDocument()
ServoStyleSet::StyleDocument(TraversalRestyleBehavior aRestyleBehavior)
{
MOZ_ASSERT(
aRestyleBehavior == TraversalRestyleBehavior::Normal ||
aRestyleBehavior == TraversalRestyleBehavior::ForCSSRuleChanges,
"StyleDocument() should be only called for normal traversal or CSS rule "
"changes");
PreTraverse();
// Restyle the document from the root element and each of the document level
@ -836,7 +842,7 @@ ServoStyleSet::StyleDocument()
while (Element* root = iter.GetNextStyleRoot()) {
if (PrepareAndTraverseSubtree(root,
TraversalRootBehavior::Normal,
TraversalRestyleBehavior::Normal)) {
aRestyleBehavior)) {
postTraversalRequired = true;
}
}

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

@ -230,9 +230,14 @@ public:
* This will traverse all of the document's style roots (that is, its document
* element, and the roots of the document-level native anonymous content).
*
* |aRestyleBehavior| should be `Normal` or `ForCSSRuleChanges`.
* We need to specify |ForCSSRuleChanges| to try to update all CSS animations
* when we call this function due to CSS rule changes since @keyframes rules
* may have changed.
*
* Returns true if a post-traversal is required.
*/
bool StyleDocument();
bool StyleDocument(TraversalRestyleBehavior aRestyleBehavior);
/**
* Performs a Servo animation-only traversal to compute style for all nodes

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

@ -59,10 +59,18 @@ enum class TraversalRootBehavior {
// hints, which is what's required when handling frame reconstruction.
// The change hints in this case are unneeded, since the old frames have
// already been destroyed.
// Indicates how the Servo style system should perform.
enum class TraversalRestyleBehavior {
// Normal processing.
Normal,
// Traverses in a mode that doesn't generate any change hints, which is what's
// required when handling frame reconstruction. The change hints in this case
// are unneeded, since the old frames have already been destroyed.
ForReconstruct,
// Processes animation-only restyle.
ForAnimationOnly,
// Traverses as normal mode but tries to update all CSS animations.
ForCSSRuleChanges,
};
// Represents which tasks are performed in a SequentialTask of UpdateAnimations.

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

@ -176,9 +176,10 @@ nsDOMCSSAttributeDeclaration::GetCSSParsingEnvironment(CSSParsingEnvironment& aC
nsDOMCSSDeclaration::ServoCSSParsingEnvironment
nsDOMCSSAttributeDeclaration::GetServoCSSParsingEnvironment() const
{
ServoCSSParsingEnvironment parsingEnv(mElement->GetURLDataForStyleAttr(),
mElement->OwnerDoc()->GetCompatibilityMode());
return parsingEnv;
return {
mElement->GetURLDataForStyleAttr(),
mElement->OwnerDoc()->GetCompatibilityMode(),
};
}
NS_IMETHODIMP

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

@ -285,16 +285,20 @@ nsDOMCSSDeclaration::GetServoCSSParsingEnvironmentForRule(const css::Rule* aRule
{
StyleSheet* sheet = aRule ? aRule->GetStyleSheet() : nullptr;
if (!sheet) {
return ServoCSSParsingEnvironment(nullptr, eCompatibility_FullStandards);
return { nullptr, eCompatibility_FullStandards };
}
if (nsIDocument* document = aRule->GetDocument()) {
return ServoCSSParsingEnvironment(sheet->AsServo()->URLData(),
document->GetCompatibilityMode());
} else {
return ServoCSSParsingEnvironment(sheet->AsServo()->URLData(),
eCompatibility_FullStandards);
return {
sheet->AsServo()->URLData(),
document->GetCompatibilityMode(),
};
}
return {
sheet->AsServo()->URLData(),
eCompatibility_FullStandards,
};
}
template<typename GeckoFunc, typename ServoFunc>

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

@ -149,12 +149,16 @@ protected:
};
// Information neded to parse a declaration for Servo side.
struct MOZ_STACK_CLASS ServoCSSParsingEnvironment {
struct MOZ_STACK_CLASS ServoCSSParsingEnvironment
{
mozilla::URLExtraData* mUrlExtraData;
nsCompatibility mCompatMode;
ServoCSSParsingEnvironment(mozilla::URLExtraData* aUrlData, nsCompatibility aCompatMode)
: mUrlExtraData(aUrlData), mCompatMode(aCompatMode) {}
ServoCSSParsingEnvironment(mozilla::URLExtraData* aUrlData,
nsCompatibility aCompatMode)
: mUrlExtraData(aUrlData)
, mCompatMode(aCompatMode)
{}
};
// On failure, mPrincipal should be set to null in aCSSParseEnv.

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

@ -36,13 +36,11 @@ to mochitest command.
* test_webkit_device_pixel_ratio.html: -webkit-device-pixel-ratio [3]
* browser_bug453896.js [8]
* Animation support:
* test_animations.html [3]
* test_animations.html [1]
* test_animations_dynamic_changes.html [1]
* test_bug716226.html [3]
* inserting keyframes rule doesn't trigger restyle bug 1364799:
* test_rule_insertion.html `@keyframes` [36]
* OMTA
* test_animations_omta.html: bug 1361938, bug 1361663 [88]
* test_animations_omta.html: bug 1361938, bug 1361663 [85]
* SMIL Animation
* test_restyles_in_smil_animation.html [2]
* CSSOM support:

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

@ -86,6 +86,22 @@ public class ActionBarPresenter {
initIndicator();
}
/**
* Called when ActionBar is to start interacting with user. Usually this method is called from
* Activity.onResume.
*/
public void onResume() {
mIdentityPopup.registerListeners();
}
/**
* Called when ActionBar is going to background, but has not yet been killed. Usually this method
* is called from Activity.onPause.
*/
public void onPause() {
mIdentityPopup.unregisterListeners();
}
/**
* To display Url in CustomView only and immediately.
*

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

@ -231,12 +231,14 @@ public class CustomTabsActivity extends SingleTabActivity implements Tabs.OnTabs
public void onResume() {
super.onResume();
mLayerView.getDynamicToolbarAnimator().setPinned(true, PinReason.CUSTOM_TAB);
actionBarPresenter.onResume();
}
@Override
public void onPause() {
super.onPause();
mLayerView.getDynamicToolbarAnimator().setPinned(false, PinReason.CUSTOM_TAB);
actionBarPresenter.onPause();
}
// Usually should use onCreateOptionsMenu() to initialize menu items. But GeckoApp overwrite

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

@ -97,7 +97,7 @@ public class SiteIdentityPopup extends AnchoredPopup implements BundleEventListe
mContentButtonClickListener = new ContentNotificationButtonListener();
}
void registerListeners() {
public void registerListeners() {
EventDispatcher.getInstance().registerUiThreadListener(this,
"Doorhanger:Logins",
"Permissions:CheckResult");
@ -540,7 +540,7 @@ public class SiteIdentityPopup extends AnchoredPopup implements BundleEventListe
void destroy() {
}
void unregisterListeners() {
public void unregisterListeners() {
EventDispatcher.getInstance().unregisterUiThreadListener(this,
"Doorhanger:Logins",
"Permissions:CheckResult");

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

@ -5072,12 +5072,6 @@ pref("dom.idle-observers-api.fuzz_time.disabled", true);
// a restart is required to enable a new value.
pref("network.activity.blipIntervalMilliseconds", 0);
// If true, reuse the same global for everything loaded by the component loader
// (JS components, JSMs, etc). This saves memory, but makes it possible for
// the scripts to interfere with each other. A restart is required for this
// to take effect.
pref("jsloader.reuseGlobal", false);
// When we're asked to take a screenshot, don't wait more than 2000ms for the
// event loop to become idle before actually taking the screenshot.
pref("dom.browserElement.maxScreenshotDelayMS", 2000);

17
servo/Cargo.lock сгенерированный
Просмотреть файл

@ -998,7 +998,7 @@ dependencies = [
"fontsan 0.3.2 (git+https://github.com/servo/fontsan)",
"freetype 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gfx_traits 0.0.1",
"harfbuzz-sys 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"harfbuzz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"heapsize 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"heapsize_derive 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"ipc-channel 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1124,10 +1124,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "harfbuzz-sys"
version = "0.1.7"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cmake 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)",
"freetype 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -2554,12 +2555,12 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
"servo-fontconfig-sys 4.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"servo-fontconfig-sys 4.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "servo-fontconfig-sys"
version = "4.0.2"
version = "4.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"expat-sys 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2616,7 +2617,7 @@ dependencies = [
"io-surface 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
"servo-egl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"servo-fontconfig-sys 4.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"servo-fontconfig-sys 4.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"servo-freetype-sys 4.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"servo-glutin 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
"x11 2.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -3160,7 +3161,7 @@ name = "unicode-script"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"harfbuzz-sys 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"harfbuzz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -3538,7 +3539,7 @@ dependencies = [
"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
"checksum glx 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b280007fa9c7442cfd1e0b1addb8d1a59240267110e8705f8f7e2c7bfb7e2f72"
"checksum half 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "63d68db75012a85555434ee079e7e6337931f87a087ab2988becbadf64673a7f"
"checksum harfbuzz-sys 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6b76113246f5c089dcf272cf89c3f61168a4d77b50ec5b2c1fab8c628c9ea762"
"checksum harfbuzz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "3072efe30deebdda55fcbe7c74c6d42f546fd8533488e43a692ea940ecface11"
"checksum heapsize 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "556cd479866cf85c3f671209c85e8a6990211c916d1002c2fcb2e9b7cf60bc36"
"checksum heapsize_derive 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "46f96d52fb1564059fc97b85ef6165728cc30198ab60073bf114c66c4c89bb5d"
"checksum heartbeats-simple 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9ad003ce233955e9d95f2c69cde84e68302ba9ba4a673d351c9bff93c738aadc"
@ -3646,7 +3647,7 @@ dependencies = [
"checksum serde_json 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ad8bcf487be7d2e15d3d543f04312de991d631cfe1b43ea0ade69e6a8a5b16a1"
"checksum servo-egl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "21069a884c33fe6ee596975e1f3849ed88c4ec857fbaf11d33672d8ebe051217"
"checksum servo-fontconfig 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "93f799b649b4a2bf362398910eca35240704c7e765e780349b2bb1070d892262"
"checksum servo-fontconfig-sys 4.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a0af4a4d7746467921486e5c5420f815cc016a6bf5574210d8e9c00f4afae224"
"checksum servo-fontconfig-sys 4.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6be80777ee6edecbbbf8774c76e19dddfe336256c57a4ded06d6ad3df7be358e"
"checksum servo-freetype-sys 4.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9232032c2e85118c0282c6562c84cab12316e655491ba0a5d1905b2320060d1b"
"checksum servo-glutin 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8398095f9b3dc3c6d706d395e192624be1f1bcc6f366b009fe17a20cb5dd3d72"
"checksum servo-skia 0.30000004.1 (registry+https://github.com/rust-lang/crates.io-index)" = "22ba980da523e91b9d2f7da9fb35f721138a1e604b8d8191e56f403e4760a9e4"

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

@ -10,7 +10,6 @@ use app_units::{Au, MAX_AU, MIN_AU};
use euclid::point::Point2D;
use euclid::rect::Rect;
use euclid::size::Size2D;
use std::i32;
// Units for use with euclid::length and euclid::scale_factor.

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

@ -17,12 +17,17 @@ use servo_config::opts;
use std::mem;
use std::sync::atomic::{AtomicIsize, Ordering};
use style::dom::UnsafeNode;
use style::parallel::CHUNK_SIZE;
use traversal::{AssignISizes, BubbleISizes};
use traversal::AssignBSizes;
pub use style::parallel::traverse_dom;
/// Traversal chunk size.
///
/// FIXME(bholley): This is all likely very inefficient and should probably be
/// reworked to mirror the style system's parallel.rs.
pub const CHUNK_SIZE: usize = 64;
#[allow(dead_code)]
fn static_assertion(node: UnsafeNode) {
unsafe {

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

@ -8,7 +8,7 @@
use dom::TNode;
use properties::{DeclaredValue, PropertyDeclaration};
use values::HasViewportPercentage;
use style_traits::HasViewportPercentage;
/// A structure to collect information about the cascade.
///

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

@ -14,7 +14,7 @@ use std::ascii::AsciiExt;
use std::borrow::Cow;
use std::collections::{HashMap, HashSet};
use std::fmt;
use style_traits::ToCss;
use style_traits::{HasViewportPercentage, ToCss};
use stylearc::Arc;
/// A custom property name is just an `Atom`.
@ -49,7 +49,7 @@ pub struct SpecifiedValue {
references: HashSet<Name>,
}
impl ::values::HasViewportPercentage for SpecifiedValue {
impl HasViewportPercentage for SpecifiedValue {
fn has_viewport_percentage(&self) -> bool {
panic!("has_viewport_percentage called before resolving!");
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -366,6 +366,7 @@ trait PrivateMatchMethods: TElement {
#[cfg(feature = "gecko")]
fn needs_animations_update(&self,
context: &mut StyleContext<Self>,
old_values: Option<&Arc<ComputedValues>>,
new_values: &ComputedValues)
-> bool {
@ -378,7 +379,10 @@ trait PrivateMatchMethods: TElement {
let old_box_style = old.get_box();
let old_display_style = old_box_style.clone_display();
let new_display_style = new_box_style.clone_display();
// FIXME: Bug 1344581: We still need to compare keyframe rules.
// If the traverse is triggered by CSS rule changes,
// we need to try to update all CSS animations.
context.shared.traversal_flags.for_css_rule_changes() ||
!old_box_style.animations_equals(&new_box_style) ||
(old_display_style == display::T::none &&
new_display_style != display::T::none &&
@ -400,7 +404,7 @@ trait PrivateMatchMethods: TElement {
use context::UpdateAnimationsTasks;
let mut tasks = UpdateAnimationsTasks::empty();
if self.needs_animations_update(old_values.as_ref(), new_values) {
if self.needs_animations_update(context, old_values.as_ref(), new_values) {
tasks.insert(CSS_ANIMATIONS);
}

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

@ -26,16 +26,38 @@ use context::TraversalStatistics;
use dom::{OpaqueNode, SendNode, TElement, TNode};
use rayon;
use scoped_tls::ScopedTLS;
use sharing::STYLE_SHARING_CANDIDATE_CACHE_SIZE;
use smallvec::SmallVec;
use std::borrow::Borrow;
use std::mem;
use time;
use traversal::{DomTraversal, PerLevelTraversalData, PreTraverseToken};
/// The chunk size used to split the parallel traversal nodes.
/// The maximum number of child nodes that we will process as a single unit.
///
/// We send each `CHUNK_SIZE` nodes as a different work unit to the work queue.
pub const CHUNK_SIZE: usize = 64;
/// Larger values will increase style sharing cache hits and general DOM locality
/// at the expense of decreased opportunities for parallelism. The style sharing
/// cache can hold 8 entries, but not all styles are shareable, so we set this
/// value to 16. These values have not been measured and could potentially be
/// tuned.
pub const WORK_UNIT_MAX: usize = 16;
/// A parallel top down traversal, generic over `D`.
/// Verify that the style sharing cache size doesn't change. If it does, we should
/// reconsider the above. We do this, rather than defining WORK_UNIT_MAX in terms
/// of STYLE_SHARING_CANDIDATE_CACHE_SIZE, so that altering the latter doesn't
/// have surprising effects on the parallelism characteristics of the style system.
#[allow(dead_code)]
fn static_assert() {
unsafe { mem::transmute::<_, [u32; STYLE_SHARING_CANDIDATE_CACHE_SIZE]>([1; 8]); }
}
/// A list of node pointers.
///
/// Note that the inline storage doesn't need to be sized to WORK_UNIT_MAX, but
/// it generally seems sensible to do so.
type NodeList<N> = SmallVec<[SendNode<N>; WORK_UNIT_MAX]>;
/// Entry point for the parallel traversal.
#[allow(unsafe_code)]
pub fn traverse_dom<E, D>(traversal: &D,
root: E,
@ -46,24 +68,29 @@ pub fn traverse_dom<E, D>(traversal: &D,
{
let dump_stats = traversal.shared_context().options.dump_style_statistics;
let start_time = if dump_stats { Some(time::precise_time_s()) } else { None };
let mut nodes = NodeList::<E::ConcreteNode>::new();
debug_assert!(traversal.is_parallel());
// Handle Gecko's eager initial styling. We don't currently support it
// in conjunction with bottom-up traversal. If we did, we'd need to put
// it on the context to make it available to the bottom-up phase.
let (nodes, depth) = if token.traverse_unstyled_children_only() {
let depth = if token.traverse_unstyled_children_only() {
debug_assert!(!D::needs_postorder_traversal());
let mut children = vec![];
for kid in root.as_node().children() {
if kid.as_element().map_or(false, |el| el.get_data().is_none()) {
children.push(unsafe { SendNode::new(kid) });
nodes.push(unsafe { SendNode::new(kid) });
}
}
(children, root.depth() + 1)
root.depth() + 1
} else {
(vec![unsafe { SendNode::new(root.as_node()) }], root.depth())
nodes.push(unsafe { SendNode::new(root.as_node()) });
root.depth()
};
if nodes.is_empty() {
return;
}
let traversal_data = PerLevelTraversalData {
current_dom_depth: depth,
};
@ -72,7 +99,13 @@ pub fn traverse_dom<E, D>(traversal: &D,
queue.install(|| {
rayon::scope(|scope| {
traverse_nodes(nodes, root, traversal_data, scope, traversal, &tls);
traverse_nodes(nodes,
DispatchMode::TailCall,
root,
traversal_data,
scope,
traversal,
&tls);
});
});
@ -93,6 +126,17 @@ pub fn traverse_dom<E, D>(traversal: &D,
}
/// A parallel top-down DOM traversal.
///
/// This algorithm traverses the DOM in a breadth-first, top-down manner. The
/// goals are:
/// * Never process a child before its parent (since child style depends on
/// parent style). If this were to happen, the styling algorithm would panic.
/// * Prioritize discovering nodes as quickly as possible to maximize
/// opportunities for parallelism.
/// * Style all the children of a given node (i.e. all sibling nodes) on
/// a single thread (with an upper bound to handle nodes with an
/// abnormally large number of children). This is important because we use
/// a thread-local cache to share styles between siblings.
#[inline(always)]
#[allow(unsafe_code)]
fn top_down_dom<'a, 'scope, E, D>(nodes: &'a [SendNode<E::ConcreteNode>],
@ -104,17 +148,42 @@ fn top_down_dom<'a, 'scope, E, D>(nodes: &'a [SendNode<E::ConcreteNode>],
where E: TElement + 'scope,
D: DomTraversal<E>,
{
let mut discovered_child_nodes = vec![];
debug_assert!(nodes.len() <= WORK_UNIT_MAX);
let mut discovered_child_nodes = NodeList::<E::ConcreteNode>::new();
{
// Scope the borrow of the TLS so that the borrow is dropped before
// potentially traversing a child on this thread.
// a potential recursive call when we pass TailCall.
let mut tlc = tls.ensure(|| traversal.create_thread_local_context());
for n in nodes {
// Perform the appropriate traversal.
// If the last node we processed produced children, spawn them off
// into a work item. We do this at the beginning of the loop (rather
// than at the end) so that we can traverse the children of the last
// sibling directly on this thread without a spawn call.
//
// This has the important effect of removing the allocation and
// context-switching overhead of the parallel traversal for perfectly
// linear regions of the DOM, i.e.:
//
// <russian><doll><tag><nesting></nesting></tag></doll></russian>
//
// Which are not at all uncommon.
if !discovered_child_nodes.is_empty() {
let children = mem::replace(&mut discovered_child_nodes, Default::default());
let mut traversal_data_copy = traversal_data.clone();
traversal_data_copy.current_dom_depth += 1;
traverse_nodes(children,
DispatchMode::NotTailCall,
root,
traversal_data_copy,
scope,
traversal,
tls);
}
let node = **n;
let mut children_to_process = 0isize;
traversal.process_preorder(&mut traversal_data, &mut *tlc, node);
traversal.process_preorder(&traversal_data, &mut *tlc, node);
if let Some(el) = node.as_element() {
traversal.traverse_children(&mut *tlc, el, |_tlc, kid| {
children_to_process += 1;
@ -127,11 +196,37 @@ fn top_down_dom<'a, 'scope, E, D>(nodes: &'a [SendNode<E::ConcreteNode>],
}
}
// Handle the children of the last element in this work unit. If any exist,
// we can process them (or at least one work unit's worth of them) directly
// on this thread by passing TailCall.
if !discovered_child_nodes.is_empty() {
traversal_data.current_dom_depth += 1;
traverse_nodes(discovered_child_nodes, root, traversal_data, scope, traversal, tls);
traverse_nodes(discovered_child_nodes,
DispatchMode::TailCall,
root,
traversal_data,
scope,
traversal,
tls);
}
}
fn traverse_nodes<'a, 'scope, E, D>(nodes: Vec<SendNode<E::ConcreteNode>>, root: OpaqueNode,
/// Controls whether traverse_nodes may make a recursive call to continue
/// doing work, or whether it should always dispatch work asynchronously.
#[derive(Clone, Copy, PartialEq)]
enum DispatchMode {
TailCall,
NotTailCall,
}
impl DispatchMode {
fn is_tail_call(&self) -> bool { matches!(*self, DispatchMode::TailCall) }
}
#[inline]
fn traverse_nodes<'a, 'scope, E, D>(nodes: NodeList<E::ConcreteNode>,
mode: DispatchMode,
root: OpaqueNode,
traversal_data: PerLevelTraversalData,
scope: &'a rayon::Scope<'scope>,
traversal: &'scope D,
@ -139,25 +234,44 @@ fn traverse_nodes<'a, 'scope, E, D>(nodes: Vec<SendNode<E::ConcreteNode>>, root:
where E: TElement + 'scope,
D: DomTraversal<E>,
{
if nodes.is_empty() {
return;
}
debug_assert!(!nodes.is_empty());
// Optimization: traverse directly and avoid a heap-allocating spawn() call if
// we're only pushing one work unit.
if nodes.len() <= CHUNK_SIZE {
let nodes = nodes.into_boxed_slice();
// In the common case, our children fit within a single work unit, in which
// case we can pass the SmallVec directly and avoid extra allocation.
if nodes.len() <= WORK_UNIT_MAX {
if mode.is_tail_call() {
// If this is a tail call, bypass rayon and invoke top_down_dom directly.
top_down_dom(&nodes, root, traversal_data, scope, traversal, tls);
return;
}
// General case.
for chunk in nodes.chunks(CHUNK_SIZE) {
let nodes = chunk.iter().cloned().collect::<Vec<_>>().into_boxed_slice();
let traversal_data = traversal_data.clone();
} else {
// The caller isn't done yet. Append to the queue and return synchronously.
scope.spawn(move |scope| {
let nodes = nodes;
top_down_dom(&nodes, root, traversal_data, scope, traversal, tls)
})
top_down_dom(&nodes, root, traversal_data, scope, traversal, tls);
});
}
} else {
// FIXME(bholley): This should be an ArrayVec.
let mut first_chunk: Option<NodeList<E::ConcreteNode>> = None;
for chunk in nodes.chunks(WORK_UNIT_MAX) {
if mode.is_tail_call() && first_chunk.is_none() {
first_chunk = Some(chunk.iter().cloned().collect::<NodeList<E::ConcreteNode>>());
} else {
let boxed = chunk.iter().cloned().collect::<Vec<_>>().into_boxed_slice();
let traversal_data_copy = traversal_data.clone();
scope.spawn(move |scope| {
let b = boxed;
top_down_dom(&*b, root, traversal_data_copy, scope, traversal, tls)
});
}
}
// If this is a tail call, bypass rayon for the first chunk and invoke top_down_dom
// directly.
debug_assert_eq!(first_chunk.is_some(), mode.is_tail_call());
if let Some(c) = first_chunk {
debug_assert_eq!(c.len(), WORK_UNIT_MAX);
top_down_dom(&*c, root, traversal_data, scope, traversal, tls);
}
}
}

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

@ -2769,19 +2769,18 @@ fn static_assert() {
pub fn copy_${shorthand}_${name}_from(&mut self, other: &Self) {
use gecko_bindings::structs::nsStyleImageLayers_LayerType as LayerType;
let count = other.gecko.${image_layers_field}.${field_name}Count;
unsafe {
Gecko_EnsureImageLayersLength(&mut self.gecko.${image_layers_field},
other.gecko.${image_layers_field}.mLayers.len(),
count as usize,
LayerType::${shorthand.title()});
}
for (layer, other) in self.gecko.${image_layers_field}.mLayers.iter_mut()
.zip(other.gecko.${image_layers_field}.mLayers.iter())
.take(other.gecko.${image_layers_field}
.${field_name}Count as usize) {
.take(count as usize) {
layer.${field_name} = other.${field_name};
}
self.gecko.${image_layers_field}.${field_name}Count =
other.gecko.${image_layers_field}.${field_name}Count;
self.gecko.${image_layers_field}.${field_name}Count = count;
}
@ -2874,23 +2873,21 @@ fn static_assert() {
pub fn copy_${shorthand}_position_${orientation}_from(&mut self, other: &Self) {
use gecko_bindings::structs::nsStyleImageLayers_LayerType as LayerType;
self.gecko.${image_layers_field}.mPosition${orientation.upper()}Count
= cmp::min(1, other.gecko.${image_layers_field}.mPosition${orientation.upper()}Count);
self.gecko.${image_layers_field}.mLayers.mFirstElement.mPosition =
other.gecko.${image_layers_field}.mLayers.mFirstElement.mPosition;
let count = other.gecko.${image_layers_field}.mPosition${orientation.upper()}Count;
unsafe {
Gecko_EnsureImageLayersLength(&mut self.gecko.${image_layers_field},
other.gecko.${image_layers_field}.mLayers.len(),
count as usize,
LayerType::${shorthand.capitalize()});
}
for (layer, other) in self.gecko.${image_layers_field}.mLayers.iter_mut()
.zip(other.gecko.${image_layers_field}.mLayers.iter()) {
.zip(other.gecko.${image_layers_field}.mLayers.iter())
.take(count as usize) {
layer.mPosition.m${orientation.upper()}Position
= other.mPosition.m${orientation.upper()}Position;
}
self.gecko.${image_layers_field}.mPosition${orientation.upper()}Count
= other.gecko.${image_layers_field}.mPosition${orientation.upper()}Count;
self.gecko.${image_layers_field}.mPosition${orientation.upper()}Count = count;
}
pub fn clone_${shorthand}_position_${orientation}(&self)

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

@ -82,7 +82,7 @@
use smallvec::SmallVec;
use std::fmt;
#[allow(unused_imports)]
use values::HasViewportPercentage;
use style_traits::HasViewportPercentage;
use style_traits::ToCss;
pub mod single_value {

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

@ -87,8 +87,8 @@ ${helpers.predefined_type("clip",
spec="https://drafts.fxtf.org/filters/#propdef-filter">
//pub use self::computed_value::T as SpecifiedValue;
use std::fmt;
use style_traits::ToCss;
use values::{CSSFloat, HasViewportPercentage};
use style_traits::{HasViewportPercentage, ToCss};
use values::CSSFloat;
use values::specified::{Angle, Length};
#[cfg(feature = "gecko")]
use values::specified::Shadow;

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

@ -550,8 +550,8 @@ ${helpers.single_keyword_system("font-variant-caps",
use properties::longhands::system_font::SystemFont;
use properties::style_structs::Font;
use std::fmt;
use style_traits::ToCss;
use values::{FONT_MEDIUM_PX, HasViewportPercentage};
use style_traits::{HasViewportPercentage, ToCss};
use values::FONT_MEDIUM_PX;
use values::specified::{AllowQuirks, FontRelativeLength, LengthOrPercentage};
use values::specified::{NoCalcLength, Percentage};
use values::specified::length::FontBaseSize;

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

@ -34,10 +34,10 @@ use parser::{PARSING_MODE_DEFAULT, Parse, ParserContext};
use properties::animated_properties::TransitionProperty;
#[cfg(feature = "servo")] use servo_config::prefs::PREFS;
use shared_lock::StylesheetGuards;
use style_traits::ToCss;
use style_traits::{HasViewportPercentage, ToCss};
use stylesheets::{CssRuleType, Origin, UrlExtraData};
#[cfg(feature = "servo")] use values::Either;
use values::{HasViewportPercentage, computed};
use values::computed;
use cascade_info::CascadeInfo;
use rule_tree::StrongRuleNode;
use style_adjuster::StyleAdjuster;

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

@ -37,6 +37,10 @@ bitflags! {
const ANIMATION_ONLY = 0x02,
/// Traverse without generating any change hints.
const FOR_RECONSTRUCT = 0x04,
/// Traverse triggered by CSS rule changes.
/// Traverse and update all elements with CSS animations since
/// @keyframes rules may have changed
const FOR_CSS_RULE_CHANGES = 0x08,
}
}
@ -55,6 +59,11 @@ impl TraversalFlags {
pub fn for_reconstruct(&self) -> bool {
self.contains(FOR_RECONSTRUCT)
}
/// Returns true if the traversal is triggered by CSS rule changes.
pub fn for_css_rule_changes(&self) -> bool {
self.contains(FOR_CSS_RULE_CHANGES)
}
}
/// This structure exists to enforce that callers invoke pre_traverse, and also

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

@ -4,6 +4,7 @@
//! Computed values.
use Atom;
use context::QuirksMode;
use euclid::size::Size2D;
use font_metrics::FontMetricsProvider;
@ -154,6 +155,79 @@ pub trait ToComputedValue {
fn from_computed_value(computed: &Self::ComputedValue) -> Self;
}
impl<A, B> ToComputedValue for (A, B)
where A: ToComputedValue, B: ToComputedValue,
{
type ComputedValue = (
<A as ToComputedValue>::ComputedValue,
<B as ToComputedValue>::ComputedValue,
);
#[inline]
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
(self.0.to_computed_value(context), self.1.to_computed_value(context))
}
#[inline]
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
(A::from_computed_value(&computed.0), B::from_computed_value(&computed.1))
}
}
impl<T> ToComputedValue for Option<T>
where T: ToComputedValue
{
type ComputedValue = Option<<T as ToComputedValue>::ComputedValue>;
#[inline]
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
self.as_ref().map(|item| item.to_computed_value(context))
}
#[inline]
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
computed.as_ref().map(T::from_computed_value)
}
}
impl<T> ToComputedValue for Size2D<T>
where T: ToComputedValue
{
type ComputedValue = Size2D<<T as ToComputedValue>::ComputedValue>;
#[inline]
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
Size2D::new(
self.width.to_computed_value(context),
self.height.to_computed_value(context),
)
}
#[inline]
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
Size2D::new(
T::from_computed_value(&computed.width),
T::from_computed_value(&computed.height),
)
}
}
impl<T> ToComputedValue for Vec<T>
where T: ToComputedValue
{
type ComputedValue = Vec<<T as ToComputedValue>::ComputedValue>;
#[inline]
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
self.iter().map(|item| item.to_computed_value(context)).collect()
}
#[inline]
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
computed.iter().map(T::from_computed_value).collect()
}
}
/// A marker trait to represent that the specified value is also the computed
/// value.
pub trait ComputedValueAsSpecified {}
@ -174,6 +248,9 @@ impl<T> ToComputedValue for T
}
}
impl ComputedValueAsSpecified for Atom {}
impl ComputedValueAsSpecified for bool {}
/// A computed `<angle>` value.
#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, PartialOrd)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))]

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

@ -11,16 +11,15 @@ use parser::{Parse, ParserContext};
use properties::shorthands::serialize_four_sides;
use std::ascii::AsciiExt;
use std::fmt;
use style_traits::ToCss;
use values::HasViewportPercentage;
use values::computed::{ComputedValueAsSpecified, Context, ToComputedValue};
use style_traits::{HasViewportPercentage, ToCss};
use values::computed::ComputedValueAsSpecified;
use values::generics::BorderRadiusSize;
use values::specified::url::SpecifiedUrl;
/// A generic type used for `border-radius`, `outline-radius` and `inset()` values.
///
/// https://drafts.csswg.org/css-backgrounds-3/#border-radius
#[derive(Clone, PartialEq, Debug)]
#[derive(Clone, Debug, PartialEq, ToComputedValue)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct BorderRadius<L> {
/// The top left radius.
@ -60,32 +59,8 @@ impl<L: ToCss + PartialEq> ToCss for BorderRadius<L> {
}
}
impl<L: ToComputedValue> ToComputedValue for BorderRadius<L> {
type ComputedValue = BorderRadius<L::ComputedValue>;
#[inline]
fn to_computed_value(&self, cx: &Context) -> Self::ComputedValue {
BorderRadius {
top_left: self.top_left.to_computed_value(cx),
top_right: self.top_right.to_computed_value(cx),
bottom_right: self.bottom_right.to_computed_value(cx),
bottom_left: self.bottom_left.to_computed_value(cx),
}
}
#[inline]
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
BorderRadius {
top_left: ToComputedValue::from_computed_value(&computed.top_left),
top_right: ToComputedValue::from_computed_value(&computed.top_right),
bottom_right: ToComputedValue::from_computed_value(&computed.bottom_right),
bottom_left: ToComputedValue::from_computed_value(&computed.bottom_left),
}
}
}
/// https://drafts.csswg.org/css-shapes/#typedef-shape-radius
#[derive(Clone, PartialEq, Debug)]
#[derive(Clone, Debug, PartialEq, ToComputedValue)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub enum ShapeRadius<L> {
@ -110,28 +85,6 @@ impl<L: ToCss> ToCss for ShapeRadius<L> {
}
}
impl<L: ToComputedValue> ToComputedValue for ShapeRadius<L> {
type ComputedValue = ShapeRadius<L::ComputedValue>;
#[inline]
fn to_computed_value(&self, cx: &Context) -> Self::ComputedValue {
match *self {
ShapeRadius::Length(ref lop) => ShapeRadius::Length(lop.to_computed_value(cx)),
ShapeRadius::ClosestSide => ShapeRadius::ClosestSide,
ShapeRadius::FarthestSide => ShapeRadius::FarthestSide,
}
}
#[inline]
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
match *computed {
ShapeRadius::Length(ref lop) => ShapeRadius::Length(ToComputedValue::from_computed_value(lop)),
ShapeRadius::ClosestSide => ShapeRadius::ClosestSide,
ShapeRadius::FarthestSide => ShapeRadius::FarthestSide,
}
}
}
// https://drafts.csswg.org/css-shapes/#typedef-fill-rule
// NOTE: Basic shapes spec says that these are the only two values, however
// https://www.w3.org/TR/SVG/painting.html#FillRuleProperty
@ -148,7 +101,7 @@ impl Default for FillRule {
fn default() -> Self { FillRule::NonZero }
}
#[derive(Clone, PartialEq, Debug)]
#[derive(Clone, Debug, PartialEq, ToComputedValue)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
/// A generic type for representing the `polygon()` function
///
@ -212,32 +165,7 @@ impl<L: ToCss> ToCss for Polygon<L> {
}
}
impl<L: ToComputedValue> ToComputedValue for Polygon<L> {
type ComputedValue = Polygon<L::ComputedValue>;
#[inline]
fn to_computed_value(&self, cx: &Context) -> Self::ComputedValue {
Polygon {
fill: self.fill.to_computed_value(cx),
coordinates: self.coordinates.iter().map(|c| {
(c.0.to_computed_value(cx), c.1.to_computed_value(cx))
}).collect(),
}
}
#[inline]
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
Polygon {
fill: ToComputedValue::from_computed_value(&computed.fill),
coordinates: computed.coordinates.iter().map(|c| {
(ToComputedValue::from_computed_value(&c.0),
ToComputedValue::from_computed_value(&c.1))
}).collect(),
}
}
}
#[derive(Clone, PartialEq, Debug)]
#[derive(Clone, Debug, PartialEq, ToComputedValue)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
/// https://drafts.csswg.org/css-shapes/#funcdef-inset
#[allow(missing_docs)]
@ -269,37 +197,11 @@ impl<L: ToCss + PartialEq> ToCss for InsetRect<L> {
}
}
impl<L: ToComputedValue> ToComputedValue for InsetRect<L> {
type ComputedValue = InsetRect<L::ComputedValue>;
#[inline]
fn to_computed_value(&self, cx: &Context) -> Self::ComputedValue {
InsetRect {
top: self.top.to_computed_value(cx),
right: self.right.to_computed_value(cx),
bottom: self.bottom.to_computed_value(cx),
left: self.left.to_computed_value(cx),
round: self.round.as_ref().map(|r| r.to_computed_value(cx)),
}
}
#[inline]
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
InsetRect {
top: ToComputedValue::from_computed_value(&computed.top),
right: ToComputedValue::from_computed_value(&computed.right),
bottom: ToComputedValue::from_computed_value(&computed.bottom),
left: ToComputedValue::from_computed_value(&computed.left),
round: computed.round.as_ref().map(|r| ToComputedValue::from_computed_value(r)),
}
}
}
/// A shape source, for some reference box
///
/// `clip-path` uses ShapeSource<BasicShape, GeometryBox>,
/// `shape-outside` uses ShapeSource<BasicShape, ShapeBox>
#[derive(Clone, PartialEq, Debug)]
#[derive(Clone, Debug, PartialEq, ToComputedValue)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub enum ShapeSource<B, T> {
@ -365,33 +267,3 @@ impl<B: Parse, T: Parse> Parse for ShapeSource<B, T> {
ref_box.map(|v| ShapeSource::Box(v)).ok_or(())
}
}
impl<B: ToComputedValue, T: ToComputedValue> ToComputedValue for ShapeSource<B, T> {
type ComputedValue = ShapeSource<B::ComputedValue, T::ComputedValue>;
#[inline]
fn to_computed_value(&self, cx: &Context) -> Self::ComputedValue {
match *self {
ShapeSource::Url(ref url) => ShapeSource::Url(url.to_computed_value(cx)),
ShapeSource::Shape(ref shape, ref ref_box) => {
ShapeSource::Shape(shape.to_computed_value(cx),
ref_box.as_ref().map(|ref val| val.to_computed_value(cx)))
},
ShapeSource::Box(ref ref_box) => ShapeSource::Box(ref_box.to_computed_value(cx)),
ShapeSource::None => ShapeSource::None,
}
}
#[inline]
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
match *computed {
ShapeSource::Url(ref url) => ShapeSource::Url(SpecifiedUrl::from_computed_value(url)),
ShapeSource::Shape(ref shape, ref ref_box) => {
ShapeSource::Shape(ToComputedValue::from_computed_value(shape),
ref_box.as_ref().map(|val| ToComputedValue::from_computed_value(val)))
},
ShapeSource::Box(ref ref_box) => ShapeSource::Box(ToComputedValue::from_computed_value(ref_box)),
ShapeSource::None => ShapeSource::None,
}
}
}

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

@ -9,15 +9,14 @@
use Atom;
use cssparser::serialize_identifier;
use std::fmt;
use style_traits::ToCss;
use values::HasViewportPercentage;
use values::computed::{Context, ToComputedValue};
use style_traits::{HasViewportPercentage, ToCss};
use values::computed::ComputedValueAsSpecified;
use values::specified::url::SpecifiedUrl;
/// An [image].
///
/// [image]: https://drafts.csswg.org/css-images/#image-values
#[derive(Clone, PartialEq)]
#[derive(Clone, PartialEq, ToComputedValue)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum Image<Gradient, ImageRect> {
/// A `<url()>` image.
@ -32,7 +31,7 @@ pub enum Image<Gradient, ImageRect> {
/// A CSS gradient.
/// https://drafts.csswg.org/css-images/#gradients
#[derive(Clone, Debug, HasViewportPercentage, PartialEq)]
#[derive(Clone, Debug, HasViewportPercentage, PartialEq, ToComputedValue)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct Gradient<LineDirection, Length, LengthOrPercentage, Position, Color> {
/// Gradients can be linear or radial.
@ -45,7 +44,7 @@ pub struct Gradient<LineDirection, Length, LengthOrPercentage, Position, Color>
pub compat_mode: CompatMode,
}
#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq)]
#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
/// Whether we used the modern notation or the compatibility `-webkit` prefix.
pub enum CompatMode {
@ -56,7 +55,7 @@ pub enum CompatMode {
}
/// A gradient kind.
#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq)]
#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum GradientKind<LineDirection, Length, LengthOrPercentage, Position> {
/// A linear gradient.
@ -66,7 +65,7 @@ pub enum GradientKind<LineDirection, Length, LengthOrPercentage, Position> {
}
/// A radial gradient's ending shape.
#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq)]
#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum EndingShape<Length, LengthOrPercentage> {
/// A circular gradient.
@ -76,7 +75,7 @@ pub enum EndingShape<Length, LengthOrPercentage> {
}
/// A circle shape.
#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq)]
#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum Circle<Length> {
/// A circle radius.
@ -86,7 +85,7 @@ pub enum Circle<Length> {
}
/// An ellipse shape.
#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq)]
#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum Ellipse<LengthOrPercentage> {
/// An ellipse pair of radii.
@ -105,10 +104,11 @@ define_css_keyword_enum!(ShapeExtent:
"cover" => Cover
);
no_viewport_percentage!(ShapeExtent);
impl ComputedValueAsSpecified for ShapeExtent {}
/// A gradient item.
/// https://drafts.csswg.org/css-images-4/#color-stop-syntax
#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq)]
#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub enum GradientItem<Color, LengthOrPercentage> {
/// A color stop.
@ -119,7 +119,7 @@ pub enum GradientItem<Color, LengthOrPercentage> {
/// A color stop.
/// https://drafts.csswg.org/css-images/#typedef-color-stop-list
#[derive(Clone, Copy, HasViewportPercentage, PartialEq)]
#[derive(Clone, Copy, HasViewportPercentage, PartialEq, ToComputedValue)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct ColorStop<Color, LengthOrPercentage> {
/// The color of this stop.
@ -131,7 +131,7 @@ pub struct ColorStop<Color, LengthOrPercentage> {
/// Values for `moz-image-rect`.
///
/// `-moz-image-rect(<uri>, top, right, bottom, left);`
#[derive(Clone, PartialEq, Debug)]
#[derive(Clone, Debug, PartialEq, ToComputedValue)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub struct ImageRect<NumberOrPercentage> {
@ -187,47 +187,6 @@ impl<G, R> HasViewportPercentage for Image<G, R>
}
}
impl<G, R> ToComputedValue for Image<G, R>
where G: ToComputedValue, R: ToComputedValue,
{
type ComputedValue = Image<<G as ToComputedValue>::ComputedValue,
<R as ToComputedValue>::ComputedValue>;
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
match *self {
Image::Url(ref url) => {
Image::Url(url.clone())
},
Image::Gradient(ref gradient) => {
Image::Gradient(gradient.to_computed_value(context))
},
Image::Rect(ref rect) => {
Image::Rect(rect.to_computed_value(context))
},
Image::Element(ref selector) => {
Image::Element(selector.clone())
}
}
}
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
match *computed {
Image::Url(ref url) => {
Image::Url(url.clone())
},
Image::Gradient(ref gradient) => {
Image::Gradient(ToComputedValue::from_computed_value(gradient))
},
Image::Rect(ref rect) => {
Image::Rect(ToComputedValue::from_computed_value(rect))
},
Image::Element(ref selector) => {
Image::Element(selector.clone())
},
}
}
}
impl<D, L, LoP, P, C> ToCss for Gradient<D, L, LoP, P, C>
where D: LineDirection, L: ToCss, LoP: ToCss, P: ToCss, C: ToCss,
{
@ -282,38 +241,6 @@ impl<D, L, LoP, P, C> ToCss for Gradient<D, L, LoP, P, C>
}
}
impl<D, L, LoP, P, C> ToComputedValue for Gradient<D, L, LoP, P, C>
where D: ToComputedValue,
L: ToComputedValue,
LoP: ToComputedValue,
P: ToComputedValue,
C: ToComputedValue,
{
type ComputedValue = Gradient<<D as ToComputedValue>::ComputedValue,
<L as ToComputedValue>::ComputedValue,
<LoP as ToComputedValue>::ComputedValue,
<P as ToComputedValue>::ComputedValue,
<C as ToComputedValue>::ComputedValue>;
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
Gradient {
kind: self.kind.to_computed_value(context),
items: self.items.iter().map(|s| s.to_computed_value(context)).collect(),
repeating: self.repeating,
compat_mode: self.compat_mode,
}
}
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
Gradient {
kind: ToComputedValue::from_computed_value(&computed.kind),
items: computed.items.iter().map(ToComputedValue::from_computed_value).collect(),
repeating: computed.repeating,
compat_mode: computed.compat_mode,
}
}
}
impl<D, L, LoP, P> GradientKind<D, L, LoP, P> {
fn label(&self) -> &str {
match *self {
@ -323,43 +250,6 @@ impl<D, L, LoP, P> GradientKind<D, L, LoP, P> {
}
}
impl<D, L, LoP, P> ToComputedValue for GradientKind<D, L, LoP, P>
where D: ToComputedValue,
L: ToComputedValue,
LoP: ToComputedValue,
P: ToComputedValue,
{
type ComputedValue = GradientKind<<D as ToComputedValue>::ComputedValue,
<L as ToComputedValue>::ComputedValue,
<LoP as ToComputedValue>::ComputedValue,
<P as ToComputedValue>::ComputedValue>;
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
match *self {
GradientKind::Linear(ref direction) => {
GradientKind::Linear(direction.to_computed_value(context))
},
GradientKind::Radial(ref shape, ref position) => {
GradientKind::Radial(shape.to_computed_value(context), position.to_computed_value(context))
},
}
}
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
match *computed {
GradientKind::Linear(ref direction) => {
GradientKind::Linear(ToComputedValue::from_computed_value(direction))
},
GradientKind::Radial(ref shape, ref position) => {
GradientKind::Radial(
ToComputedValue::from_computed_value(shape),
ToComputedValue::from_computed_value(position),
)
}
}
}
}
/// The direction of a linear gradient.
pub trait LineDirection {
/// Whether this direction points towards, and thus can be omitted.
@ -398,53 +288,6 @@ impl<L, LoP> ToCss for EndingShape<L, LoP>
}
}
impl<L, LoP> ToComputedValue for EndingShape<L, LoP>
where L: ToComputedValue, LoP: ToComputedValue,
{
type ComputedValue = EndingShape<<L as ToComputedValue>::ComputedValue,
<LoP as ToComputedValue>::ComputedValue>;
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
match *self {
EndingShape::Circle(Circle::Radius(ref length)) => {
EndingShape::Circle(Circle::Radius(length.to_computed_value(context)))
},
EndingShape::Circle(Circle::Extent(extent)) => {
EndingShape::Circle(Circle::Extent(extent))
},
EndingShape::Ellipse(Ellipse::Radii(ref x, ref y)) => {
EndingShape::Ellipse(Ellipse::Radii(
x.to_computed_value(context),
y.to_computed_value(context),
))
},
EndingShape::Ellipse(Ellipse::Extent(extent)) => {
EndingShape::Ellipse(Ellipse::Extent(extent))
},
}
}
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
match *computed {
EndingShape::Circle(Circle::Radius(ref length)) => {
EndingShape::Circle(Circle::Radius(ToComputedValue::from_computed_value(length)))
},
EndingShape::Circle(Circle::Extent(extent)) => {
EndingShape::Circle(Circle::Extent(extent))
},
EndingShape::Ellipse(Ellipse::Radii(ref x, ref y)) => {
EndingShape::Ellipse(Ellipse::Radii(
ToComputedValue::from_computed_value(x),
ToComputedValue::from_computed_value(y),
))
},
EndingShape::Ellipse(Ellipse::Extent(extent)) => {
EndingShape::Ellipse(Ellipse::Extent(extent))
},
}
}
}
impl<C, L> ToCss for GradientItem<C, L>
where C: ToCss, L: ToCss,
{
@ -456,35 +299,6 @@ impl<C, L> ToCss for GradientItem<C, L>
}
}
impl<C, L> ToComputedValue for GradientItem<C, L>
where C: ToComputedValue, L: ToComputedValue,
{
type ComputedValue = GradientItem<<C as ToComputedValue>::ComputedValue,
<L as ToComputedValue>::ComputedValue>;
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
match *self {
GradientItem::ColorStop(ref stop) => {
GradientItem::ColorStop(stop.to_computed_value(context))
},
GradientItem::InterpolationHint(ref hint) => {
GradientItem::InterpolationHint(hint.to_computed_value(context))
},
}
}
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
match *computed {
GradientItem::ColorStop(ref stop) => {
GradientItem::ColorStop(ToComputedValue::from_computed_value(stop))
},
GradientItem::InterpolationHint(ref hint) => {
GradientItem::InterpolationHint(ToComputedValue::from_computed_value(hint))
},
}
}
}
impl<C, L> fmt::Debug for ColorStop<C, L>
where C: fmt::Debug, L: fmt::Debug,
{
@ -510,27 +324,6 @@ impl<C, L> ToCss for ColorStop<C, L>
}
}
impl<C, L> ToComputedValue for ColorStop<C, L>
where C: ToComputedValue, L: ToComputedValue,
{
type ComputedValue = ColorStop<<C as ToComputedValue>::ComputedValue,
<L as ToComputedValue>::ComputedValue>;
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
ColorStop {
color: self.color.to_computed_value(context),
position: self.position.as_ref().map(|p| p.to_computed_value(context)),
}
}
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
ColorStop {
color: ToComputedValue::from_computed_value(&computed.color),
position: computed.position.as_ref().map(ToComputedValue::from_computed_value),
}
}
}
impl<C> ToCss for ImageRect<C>
where C: ToCss,
{
@ -548,29 +341,3 @@ impl<C> ToCss for ImageRect<C>
dest.write_str(")")
}
}
impl<C> ToComputedValue for ImageRect<C>
where C: ToComputedValue,
{
type ComputedValue = ImageRect<<C as ToComputedValue>::ComputedValue>;
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
ImageRect {
url: self.url.to_computed_value(context),
top: self.top.to_computed_value(context),
right: self.right.to_computed_value(context),
bottom: self.bottom.to_computed_value(context),
left: self.left.to_computed_value(context),
}
}
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
ImageRect {
url: ToComputedValue::from_computed_value(&computed.url),
top: ToComputedValue::from_computed_value(&computed.top),
right: ToComputedValue::from_computed_value(&computed.right),
bottom: ToComputedValue::from_computed_value(&computed.bottom),
left: ToComputedValue::from_computed_value(&computed.left),
}
}
}

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

@ -10,10 +10,8 @@ use cssparser::Parser;
use euclid::size::Size2D;
use parser::{Parse, ParserContext};
use std::fmt;
use style_traits::ToCss;
use style_traits::{HasViewportPercentage, ToCss};
use super::CustomIdent;
use super::HasViewportPercentage;
use super::computed::{Context, ToComputedValue};
pub use self::basic_shape::serialize_radius_values;
@ -21,9 +19,9 @@ pub mod basic_shape;
pub mod image;
pub mod position;
#[derive(Clone, PartialEq, Debug)]
#[derive(Clone, Debug, PartialEq, ToComputedValue)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
/// A type for representing CSS `widthh` and `height` values.
/// A type for representing CSS `width` and `height` values.
pub struct BorderRadiusSize<L>(pub Size2D<L>);
impl<L> HasViewportPercentage for BorderRadiusSize<L> {
@ -62,24 +60,6 @@ impl<L: ToCss> ToCss for BorderRadiusSize<L> {
}
}
impl<L: ToComputedValue> ToComputedValue for BorderRadiusSize<L> {
type ComputedValue = BorderRadiusSize<L::ComputedValue>;
#[inline]
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
let w = self.0.width.to_computed_value(context);
let h = self.0.height.to_computed_value(context);
BorderRadiusSize(Size2D::new(w, h))
}
#[inline]
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
let w = ToComputedValue::from_computed_value(&computed.0.width);
let h = ToComputedValue::from_computed_value(&computed.0.height);
BorderRadiusSize(Size2D::new(w, h))
}
}
/// https://drafts.csswg.org/css-counter-styles/#typedef-counter-style
///
/// Since wherever <counter-style> is used, 'none' is a valid value as

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

@ -5,9 +5,7 @@
//! Generic types for CSS handling of specified and computed values of
//! [`position`](https://drafts.csswg.org/css-backgrounds-3/#position)
use values::computed::{Context, ToComputedValue};
#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq)]
#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
/// A generic type for representing a CSS [position](https://drafts.csswg.org/css-values/#position).
pub struct Position<H, V> {
@ -26,24 +24,3 @@ impl<H, V> Position<H, V> {
}
}
}
impl<H: ToComputedValue, V: ToComputedValue> ToComputedValue for Position<H, V> {
type ComputedValue = Position<<H as ToComputedValue>::ComputedValue,
<V as ToComputedValue>::ComputedValue>;
#[inline]
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
Position {
horizontal: self.horizontal.to_computed_value(context),
vertical: self.vertical.to_computed_value(context),
}
}
#[inline]
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
Self {
horizontal: ToComputedValue::from_computed_value(&computed.horizontal),
vertical: ToComputedValue::from_computed_value(&computed.vertical),
}
}
}

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

@ -16,7 +16,6 @@ use std::borrow::Cow;
use std::fmt::{self, Debug};
use std::hash;
use style_traits::ToCss;
pub use style_traits::HasViewportPercentage;
pub mod computed;
pub mod generics;

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

@ -11,9 +11,9 @@ use cssparser::{Parser, Token};
use parser::ParserContext;
use std::ascii::AsciiExt;
use std::fmt;
use style_traits::ToCss;
use style_traits::{HasViewportPercentage, ToCss};
use style_traits::values::specified::AllowedLengthType;
use values::{CSSInteger, CSSFloat, HasViewportPercentage};
use values::{CSSInteger, CSSFloat};
use values::specified::{Angle, Time};
use values::specified::length::{FontRelativeLength, NoCalcLength, ViewportPercentageLength};

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

@ -8,8 +8,8 @@ use cssparser::{Parser, Token, serialize_identifier};
use parser::{Parse, ParserContext};
use std::{fmt, mem, usize};
use std::ascii::AsciiExt;
use style_traits::ToCss;
use values::{CSSFloat, CustomIdent, Either, HasViewportPercentage};
use style_traits::{HasViewportPercentage, ToCss};
use values::{CSSFloat, CustomIdent, Either};
use values::computed::{self, ComputedValueAsSpecified, Context, ToComputedValue};
use values::specified::{Integer, LengthOrPercentage};

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

@ -14,11 +14,11 @@ use parser::{Parse, ParserContext};
use std::{cmp, fmt, mem};
use std::ascii::AsciiExt;
use std::ops::Mul;
use style_traits::ToCss;
use style_traits::{HasViewportPercentage, ToCss};
use style_traits::values::specified::{AllowedLengthType, AllowedNumericType};
use stylesheets::CssRuleType;
use super::{AllowQuirks, Number, ToComputedValue};
use values::{Auto, CSSFloat, Either, FONT_MEDIUM_PX, HasViewportPercentage, None_, Normal};
use values::{Auto, CSSFloat, Either, FONT_MEDIUM_PX, None_, Normal};
use values::ExtremumLength;
use values::computed::{ComputedValueAsSpecified, Context};
use values::specified::calc::CalcNode;
@ -620,7 +620,8 @@ impl Length {
Token::Dimension(ref value, ref unit) if num_context.is_ok(value.value) =>
Length::parse_dimension(context, value.value, unit),
Token::Number(ref value) if num_context.is_ok(value.value) => {
if value.value != 0. && !context.parsing_mode.allows_unitless_lengths() &&
if value.value != 0. &&
!context.parsing_mode.allows_unitless_lengths() &&
!allow_quirks.allowed(context.quirks_mode) {
return Err(())
}
@ -805,9 +806,14 @@ impl LengthOrPercentage {
NoCalcLength::parse_dimension(context, value.value, unit).map(LengthOrPercentage::Length),
Token::Percentage(ref value) if num_context.is_ok(value.unit_value) =>
Ok(LengthOrPercentage::Percentage(Percentage(value.unit_value))),
Token::Number(value) if value.value == 0. ||
(num_context.is_ok(value.value) && allow_quirks.allowed(context.quirks_mode)) =>
Ok(LengthOrPercentage::Length(NoCalcLength::from_px(value.value))),
Token::Number(value) if num_context.is_ok(value.value) => {
if value.value != 0. &&
!context.parsing_mode.allows_unitless_lengths() &&
!allow_quirks.allowed(context.quirks_mode) {
return Err(())
}
Ok(LengthOrPercentage::Length(NoCalcLength::from_px(value.value)))
}
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
let calc = try!(input.parse_nested_block(|i| {
CalcNode::parse_length_or_percentage(context, i, num_context)
@ -942,7 +948,8 @@ impl LengthOrPercentageOrAuto {
Token::Percentage(ref value) if num_context.is_ok(value.unit_value) =>
Ok(LengthOrPercentageOrAuto::Percentage(Percentage(value.unit_value))),
Token::Number(ref value) if num_context.is_ok(value.value) => {
if value.value != 0. && !context.parsing_mode.allows_unitless_lengths() &&
if value.value != 0. &&
!context.parsing_mode.allows_unitless_lengths() &&
!allow_quirks.allowed(context.quirks_mode) {
return Err(())
}

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

@ -10,8 +10,7 @@
use cssparser::Parser;
use parser::{Parse, ParserContext};
use std::fmt;
use style_traits::ToCss;
use values::HasViewportPercentage;
use style_traits::{HasViewportPercentage, ToCss};
use values::computed::{CalcLengthOrPercentage, LengthOrPercentage as ComputedLengthOrPercentage};
use values::computed::{Context, ToComputedValue};
use values::generics::position::Position as GenericPosition;

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

@ -10,9 +10,16 @@ extern crate synstructure;
use proc_macro::TokenStream;
mod has_viewport_percentage;
mod to_computed_value;
#[proc_macro_derive(HasViewportPercentage)]
pub fn derive_has_viewport_percentage(stream: TokenStream) -> TokenStream {
let input = syn::parse_derive_input(&stream.to_string()).unwrap();
has_viewport_percentage::derive(input).to_string().parse().unwrap()
}
#[proc_macro_derive(ToComputedValue)]
pub fn derive_to_computed_value(stream: TokenStream) -> TokenStream {
let input = syn::parse_derive_input(&stream.to_string()).unwrap();
to_computed_value::derive(input).to_string().parse().unwrap()
}

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

@ -0,0 +1,142 @@
/* 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/. */
use quote;
use syn;
use synstructure;
pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
let name = &input.ident;
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
let mut where_clause = where_clause.clone();
for param in &input.generics.ty_params {
where_clause.predicates.push(where_predicate(syn::Ty::Path(None, param.ident.clone().into()), None));
}
let computed_value_type = syn::Path::from(syn::PathSegment {
ident: name.clone(),
parameters: syn::PathParameters::AngleBracketed(syn::AngleBracketedParameterData {
lifetimes: input.generics.lifetimes.iter().map(|l| {
l.lifetime.clone()
}).collect(),
types: input.generics.ty_params.iter().map(|ty| {
syn::Ty::Path(
Some(syn::QSelf {
ty: Box::new(syn::Ty::Path(None, ty.ident.clone().into())),
position: 3,
}),
syn::Path {
global: true,
segments: vec![
"values".into(),
"computed".into(),
"ToComputedValue".into(),
"ComputedValue".into(),
],
},
)
}).collect(),
.. Default::default()
}),
});
let to_body = match_body(&input, |field| {
quote!(::values::computed::ToComputedValue::to_computed_value(#field, context))
});
let from_body = match_body(&input, |field| {
quote!(::values::computed::ToComputedValue::from_computed_value(#field))
});
quote! {
impl #impl_generics ::values::computed::ToComputedValue for #name #ty_generics #where_clause {
type ComputedValue = #computed_value_type;
#[allow(unused_variables)]
#[inline]
fn to_computed_value(&self, context: &::values::computed::Context) -> Self::ComputedValue {
match *self {
#to_body
}
}
#[inline]
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
match *computed {
#from_body
}
}
}
}
}
fn match_body<F>(input: &syn::DeriveInput, f: F) -> quote::Tokens
where F: Fn(&synstructure::BindingInfo) -> quote::Tokens,
{
let by_ref = synstructure::BindStyle::Ref.into();
let by_value = synstructure::BindStyle::Move.into();
synstructure::each_variant(&input, &by_ref, |fields, variant| {
let name = if let syn::Body::Enum(_) = input.body {
format!("{}::{}", input.ident, variant.ident).into()
} else {
variant.ident.clone()
};
let (computed_value, computed_fields) = synstructure::match_pattern(&name, &variant.data, &by_value);
let fields_pairs = fields.iter().zip(computed_fields.iter());
let mut computations = quote!();
computations.append_all(fields_pairs.map(|(field, computed_field)| {
let expr = f(field);
quote!(let #computed_field = #expr;)
}));
Some(quote!(
#computations
#computed_value
))
})
}
/// `#ty: ::values::computed::ToComputedValue<ComputedValue = #computed_value,>`
fn where_predicate(ty: syn::Ty, computed_value: Option<syn::Ty>) -> syn::WherePredicate {
syn::WherePredicate::BoundPredicate(syn::WhereBoundPredicate {
bound_lifetimes: vec![],
bounded_ty: ty,
bounds: vec![syn::TyParamBound::Trait(
syn::PolyTraitRef {
bound_lifetimes: vec![],
trait_ref: trait_ref(computed_value),
},
syn::TraitBoundModifier::None
)],
})
}
/// `::values::computed::ToComputedValue<ComputedValue = #computed_value,>`
fn trait_ref(computed_value: Option<syn::Ty>) -> syn::Path {
syn::Path {
global: true,
segments: vec![
"values".into(),
"computed".into(),
syn::PathSegment {
ident: "ToComputedValue".into(),
parameters: syn::PathParameters::AngleBracketed(
syn::AngleBracketedParameterData {
bindings: trait_bindings(computed_value),
.. Default::default()
}
),
}
],
}
}
/// `ComputedValue = #computed_value,`
fn trait_bindings(computed_value: Option<syn::Ty>) -> Vec<syn::TypeBinding> {
computed_value.into_iter().map(|ty| {
syn::TypeBinding {
ident: "ComputedValue".into(),
ty: ty,
}
}).collect()
}

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

@ -103,7 +103,7 @@ use style::stylesheets::StylesheetLoader as StyleStylesheetLoader;
use style::supports::parse_condition_or_declaration;
use style::thread_state;
use style::timer::Timer;
use style::traversal::{ANIMATION_ONLY, FOR_RECONSTRUCT, UNSTYLED_CHILDREN_ONLY};
use style::traversal::{ANIMATION_ONLY, FOR_CSS_RULE_CHANGES, FOR_RECONSTRUCT, UNSTYLED_CHILDREN_ONLY};
use style::traversal::{resolve_style, DomTraversal, TraversalDriver, TraversalFlags};
use style::values::{CustomIdent, KeyframesName};
use style_traits::ToCss;
@ -256,6 +256,7 @@ pub extern "C" fn Servo_TraverseSubtree(root: RawGeckoElementBorrowed,
(Root::UnstyledChildrenOnly, Restyle::Normal) |
(Root::UnstyledChildrenOnly, Restyle::ForAnimationOnly)
=> UNSTYLED_CHILDREN_ONLY,
(Root::Normal, Restyle::ForCSSRuleChanges) => FOR_CSS_RULE_CHANGES,
(Root::Normal, Restyle::ForReconstruct) => FOR_RECONSTRUCT,
_ => panic!("invalid combination of TraversalRootBehavior and TraversalRestyleBehavior"),
};

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

@ -8,8 +8,8 @@ use media_queries::CSSErrorReporterTest;
use style::context::QuirksMode;
use style::parser::{PARSING_MODE_ALLOW_ALL_NUMERIC_VALUES, ParserContext};
use style::stylesheets::{CssRuleType, Origin};
use style::values::HasViewportPercentage;
use style::values::specified::{AbsoluteLength, NoCalcLength, Number, ViewportPercentageLength};
use style_traits::HasViewportPercentage;
#[test]
fn length_has_viewport_percentage() {

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

@ -5,8 +5,8 @@
use app_units::Au;
use style::properties::PropertyDeclaration;
use style::properties::longhands::border_top_width;
use style::values::HasViewportPercentage;
use style::values::specified::{AbsoluteLength, Length, NoCalcLength, ViewportPercentageLength};
use style_traits::HasViewportPercentage;
#[test]
fn has_viewport_percentage_for_specified_value() {

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

@ -5,6 +5,8 @@ server.registerDirectory("/data/", do_get_file("data"));
const BASE_URL = `http://localhost:${server.identity.primaryPort}/data`;
// ExtensionContent.jsm needs to know when it's running from xpcshell,
// to use the right timeout for content scripts executed at document_idle.
ExtensionTestUtils.mockAppInfo();
add_task(async function test_contentscript_runAt() {

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

@ -2,6 +2,8 @@
Cu.import("resource://gre/modules/Preferences.jsm");
// ExtensionContent.jsm needs to know when it's running from xpcshell,
// to use the right timeout for content scripts executed at document_idle.
ExtensionTestUtils.mockAppInfo();
const server = createHttpServer();

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

@ -2,6 +2,8 @@
Cu.import("resource://gre/modules/Preferences.jsm");
// ExtensionContent.jsm needs to know when it's running from xpcshell,
// to use the right timeout for content scripts executed at document_idle.
ExtensionTestUtils.mockAppInfo();
const server = createHttpServer();