зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to mozilla-inbound
This commit is contained in:
Коммит
65ea740eda
|
@ -48,6 +48,7 @@ toolkit/library
|
||||||
profile
|
profile
|
||||||
services
|
services
|
||||||
startupcache
|
startupcache
|
||||||
|
devtools/platform
|
||||||
devtools/server
|
devtools/server
|
||||||
devtools/shared
|
devtools/shared
|
||||||
browser/app
|
browser/app
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
# 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/.
|
# 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']))
|
error('Unsupported MOZ_DEVTOOLS value: %s' % (CONFIG['MOZ_DEVTOOLS']))
|
||||||
|
|
||||||
if CONFIG['MOZ_DEVTOOLS'] == 'all':
|
if CONFIG['MOZ_DEVTOOLS'] == 'all':
|
||||||
|
@ -12,12 +12,21 @@ if CONFIG['MOZ_DEVTOOLS'] == 'all':
|
||||||
'client',
|
'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 += [
|
DIRS += [
|
||||||
'server',
|
|
||||||
'shared',
|
|
||||||
'shim',
|
'shim',
|
||||||
|
'platform',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
if CONFIG['MOZ_DEVTOOLS'] != 'addon':
|
||||||
|
DIRS += [
|
||||||
|
'server',
|
||||||
|
'shared',
|
||||||
|
]
|
||||||
|
|
||||||
# /browser uses DIST_SUBDIR. We opt-in to this treatment when building
|
# /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
|
# DevTools for the browser to keep the root omni.ja slim for use by external XUL
|
||||||
# apps. Mulet also uses this since it includes /browser.
|
# apps. Mulet also uses this since it includes /browser.
|
||||||
|
|
|
@ -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";
|
"use strict";
|
||||||
|
|
||||||
|
const Cc = Components.classes;
|
||||||
|
const Ci = Components.interfaces;
|
||||||
|
|
||||||
// Test the basic functionality of the nsIJSInspector component.
|
// Test the basic functionality of the nsIJSInspector component.
|
||||||
var gCount = 0;
|
var gCount = 0;
|
||||||
const MAX = 10;
|
const MAX = 10;
|
||||||
|
|
||||||
var inspector = Cc["@mozilla.org/jsinspector;1"].getService(Ci.nsIJSInspector);
|
var inspector = Cc["@mozilla.org/jsinspector;1"].getService(Ci.nsIJSInspector);
|
||||||
var tm = Cc["@mozilla.org/thread-manager;1"].getService(Ci.nsIThreadManager);
|
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']
|
MOCHITEST_CHROME_MANIFESTS += ['tests/mochitest/chrome.ini']
|
||||||
XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini']
|
XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini']
|
||||||
|
|
||||||
XPIDL_SOURCES += [
|
|
||||||
'nsIJSInspector.idl',
|
|
||||||
]
|
|
||||||
|
|
||||||
XPIDL_MODULE = 'jsinspector'
|
|
||||||
|
|
||||||
SOURCES += [
|
|
||||||
'nsJSInspector.cpp',
|
|
||||||
]
|
|
||||||
|
|
||||||
FINAL_LIBRARY = 'xul'
|
|
||||||
|
|
||||||
DevToolsModules(
|
DevToolsModules(
|
||||||
'child.js',
|
'child.js',
|
||||||
'content-server.jsm',
|
'content-server.jsm',
|
||||||
|
|
|
@ -43,7 +43,6 @@ support-files =
|
||||||
[test_nesting-03.js]
|
[test_nesting-03.js]
|
||||||
[test_forwardingprefix.js]
|
[test_forwardingprefix.js]
|
||||||
[test_getyoungestframe.js]
|
[test_getyoungestframe.js]
|
||||||
[test_nsjsinspector.js]
|
|
||||||
[test_dbgactor.js]
|
[test_dbgactor.js]
|
||||||
[test_dbgglobal.js]
|
[test_dbgglobal.js]
|
||||||
[test_dbgclient_debuggerstatement.js]
|
[test_dbgclient_debuggerstatement.js]
|
||||||
|
|
|
@ -329,15 +329,15 @@ public:
|
||||||
* Get the SMIL override style declaration for this element. If the
|
* Get the SMIL override style declaration for this element. If the
|
||||||
* rule hasn't been created, this method simply returns null.
|
* 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
|
* Set the SMIL override style declaration for this element. If
|
||||||
* aNotify is true, this method will notify the document's pres
|
* aNotify is true, this method will notify the document's pres
|
||||||
* context, so that the style changes will be noticed.
|
* context, so that the style changes will be noticed.
|
||||||
*/
|
*/
|
||||||
virtual nsresult SetSMILOverrideStyleDeclaration(
|
nsresult SetSMILOverrideStyleDeclaration(DeclarationBlock* aDeclaration,
|
||||||
DeclarationBlock* aDeclaration, bool aNotify);
|
bool aNotify);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a new nsISMILAttr that allows the caller to animate the given
|
* 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
|
* Note: This method is analogous to the 'GetStyle' method in
|
||||||
* nsGenericHTMLElement and nsStyledElement.
|
* nsGenericHTMLElement and nsStyledElement.
|
||||||
*/
|
*/
|
||||||
virtual nsICSSDeclaration* GetSMILOverrideStyle();
|
nsICSSDeclaration* GetSMILOverrideStyle();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns if the element is labelable as per HTML specification.
|
* 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)
|
* SMIL Overridde style rules (for SMIL animation of CSS properties)
|
||||||
* @see nsIContent::GetSMILOverrideStyle
|
* @see Element::GetSMILOverrideStyle
|
||||||
*/
|
*/
|
||||||
nsCOMPtr<nsICSSDeclaration> mSMILOverrideStyle;
|
nsCOMPtr<nsICSSDeclaration> mSMILOverrideStyle;
|
||||||
|
|
||||||
|
|
|
@ -113,7 +113,6 @@ const char* mozilla::dom::ContentPrefs::gInitPrefs[] = {
|
||||||
"javascript.options.wasm_baselinejit",
|
"javascript.options.wasm_baselinejit",
|
||||||
"javascript.options.werror",
|
"javascript.options.werror",
|
||||||
"javascript.use_us_english_locale",
|
"javascript.use_us_english_locale",
|
||||||
"jsloader.reuseGlobal",
|
|
||||||
"layout.idle_period.required_quiescent_frames",
|
"layout.idle_period.required_quiescent_frames",
|
||||||
"layout.idle_period.time_limit",
|
"layout.idle_period.time_limit",
|
||||||
"layout.interruptible-reflow.enabled",
|
"layout.interruptible-reflow.enabled",
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "MediaDecoder.h"
|
#include "MediaDecoder.h"
|
||||||
#include "nsIPrincipal.h"
|
#include "nsIPrincipal.h"
|
||||||
#include "nsMimeTypes.h"
|
#include "nsMimeTypes.h"
|
||||||
|
#include "TimeUnits.h"
|
||||||
#include "mozilla/Logging.h"
|
#include "mozilla/Logging.h"
|
||||||
#include "mozilla/Preferences.h"
|
#include "mozilla/Preferences.h"
|
||||||
#include "mozilla/StaticPtr.h"
|
#include "mozilla/StaticPtr.h"
|
||||||
|
@ -33,7 +34,36 @@ void
|
||||||
MediaStreamVideoRecorderSink::SetCurrentFrames(const VideoSegment& aSegment)
|
MediaStreamVideoRecorderSink::SetCurrentFrames(const VideoSegment& aSegment)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mVideoEncoder);
|
MOZ_ASSERT(mVideoEncoder);
|
||||||
mVideoEncoder->SetCurrentFrames(aSegment);
|
// 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
|
void
|
||||||
|
@ -49,20 +79,21 @@ MediaEncoder::NotifyRealtimeData(MediaStreamGraph* aGraph,
|
||||||
uint32_t aTrackEvents,
|
uint32_t aTrackEvents,
|
||||||
const MediaSegment& aRealtimeMedia)
|
const MediaSegment& aRealtimeMedia)
|
||||||
{
|
{
|
||||||
if (mSuspended == RECORD_NOT_SUSPENDED) {
|
if (mSuspended) {
|
||||||
// Process the incoming raw track data from MediaStreamGraph, called on the
|
return;
|
||||||
// thread of MediaStreamGraph.
|
}
|
||||||
if (mAudioEncoder && aRealtimeMedia.GetType() == MediaSegment::AUDIO) {
|
// Process the incoming raw track data from MediaStreamGraph, called on the
|
||||||
mAudioEncoder->NotifyQueuedTrackChanges(aGraph, aID,
|
// thread of MediaStreamGraph.
|
||||||
aTrackOffset, aTrackEvents,
|
if (mAudioEncoder && aRealtimeMedia.GetType() == MediaSegment::AUDIO) {
|
||||||
aRealtimeMedia);
|
mAudioEncoder->NotifyQueuedTrackChanges(aGraph, aID,
|
||||||
} else if (mVideoEncoder &&
|
aTrackOffset, aTrackEvents,
|
||||||
aRealtimeMedia.GetType() == MediaSegment::VIDEO &&
|
aRealtimeMedia);
|
||||||
aTrackEvents != TrackEventCommand::TRACK_EVENT_NONE) {
|
} else if (mVideoEncoder &&
|
||||||
mVideoEncoder->NotifyQueuedTrackChanges(aGraph, aID,
|
aRealtimeMedia.GetType() == MediaSegment::VIDEO &&
|
||||||
aTrackOffset, aTrackEvents,
|
aTrackEvents != TrackEventCommand::TRACK_EVENT_NONE) {
|
||||||
aRealtimeMedia);
|
mVideoEncoder->NotifyQueuedTrackChanges(aGraph, aID,
|
||||||
}
|
aTrackOffset, aTrackEvents,
|
||||||
|
aRealtimeMedia);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,24 +119,6 @@ MediaEncoder::NotifyQueuedTrackChanges(MediaStreamGraph* aGraph,
|
||||||
NotifyRealtimeData(aGraph, aID, aTrackOffset, aTrackEvents, segment);
|
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) {
|
if (!mDirectConnected) {
|
||||||
NotifyRealtimeData(aGraph, aID, aTrackOffset, 0, aQueuedMedia);
|
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;
|
mState = ENCODE_ERROR;
|
||||||
return rv;
|
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,
|
rv = mWriter->WriteEncodedTrack(encodedVideoData,
|
||||||
aTrackEncoder->IsEncodingComplete() ?
|
aTrackEncoder->IsEncodingComplete() ?
|
||||||
ContainerWriter::END_OF_STREAM : 0);
|
ContainerWriter::END_OF_STREAM : 0);
|
||||||
|
|
|
@ -24,15 +24,20 @@ class MediaStreamVideoRecorderSink : public MediaStreamVideoSink
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit MediaStreamVideoRecorderSink(VideoTrackEncoder* aEncoder)
|
explicit MediaStreamVideoRecorderSink(VideoTrackEncoder* aEncoder)
|
||||||
: mVideoEncoder(aEncoder) {}
|
: mVideoEncoder(aEncoder)
|
||||||
|
, mSuspended(false) {}
|
||||||
|
|
||||||
// MediaStreamVideoSink methods
|
// MediaStreamVideoSink methods
|
||||||
virtual void SetCurrentFrames(const VideoSegment& aSegment) override;
|
virtual void SetCurrentFrames(const VideoSegment& aSegment) override;
|
||||||
virtual void ClearFrames() override {}
|
virtual void ClearFrames() override {}
|
||||||
|
|
||||||
|
void Resume() { mSuspended = false; }
|
||||||
|
void Suspend() { mSuspended = true; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual ~MediaStreamVideoRecorderSink() {}
|
virtual ~MediaStreamVideoRecorderSink() {}
|
||||||
VideoTrackEncoder* mVideoEncoder;
|
VideoTrackEncoder* mVideoEncoder;
|
||||||
|
Atomic<bool> mSuspended;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -98,32 +103,19 @@ public :
|
||||||
, mShutdown(false)
|
, mShutdown(false)
|
||||||
, mDirectConnected(false)
|
, mDirectConnected(false)
|
||||||
, mSuspended(false)
|
, mSuspended(false)
|
||||||
|
, mMicrosecondsSpentPaused(0)
|
||||||
|
, mLastMuxedTimestamp(0)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
~MediaEncoder() {};
|
~MediaEncoder() {};
|
||||||
|
|
||||||
enum SuspendState {
|
|
||||||
RECORD_NOT_SUSPENDED,
|
|
||||||
RECORD_SUSPENDED,
|
|
||||||
RECORD_RESUMED
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Note - called from control code, not on MSG threads. */
|
/* Note - called from control code, not on MSG threads. */
|
||||||
void Suspend()
|
void Suspend();
|
||||||
{
|
|
||||||
mSuspended = RECORD_SUSPENDED;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Note - called from control code, not on MSG threads.
|
* Note - called from control code, not on MSG threads.
|
||||||
* Arm to collect the Duration of the next video frame and give it
|
* Calculates time spent paused in order to offset frames. */
|
||||||
* to the next frame, in order to avoid any possible loss of sync. */
|
void Resume();
|
||||||
void Resume()
|
|
||||||
{
|
|
||||||
if (mSuspended == RECORD_SUSPENDED) {
|
|
||||||
mSuspended = RECORD_RESUMED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tells us which Notify to pay attention to for media
|
* Tells us which Notify to pay attention to for media
|
||||||
|
@ -243,7 +235,18 @@ private:
|
||||||
int mState;
|
int mState;
|
||||||
bool mShutdown;
|
bool mShutdown;
|
||||||
bool mDirectConnected;
|
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
|
// Get duration from create encoder, for logging purpose
|
||||||
double GetEncodeTimeStamp()
|
double GetEncodeTimeStamp()
|
||||||
{
|
{
|
||||||
|
|
|
@ -802,6 +802,9 @@ tags=msg
|
||||||
[test_mediarecorder_getencodeddata.html]
|
[test_mediarecorder_getencodeddata.html]
|
||||||
skip-if = android_version == '17' # android(bug 1232305)
|
skip-if = android_version == '17' # android(bug 1232305)
|
||||||
tags=msg
|
tags=msg
|
||||||
|
[test_mediarecorder_pause_resume_video.html]
|
||||||
|
skip-if = toolkit == 'android' # android(bug 1232305)
|
||||||
|
tags=msg
|
||||||
[test_mediarecorder_principals.html]
|
[test_mediarecorder_principals.html]
|
||||||
skip-if = (os == 'linux' && bits == 64) || toolkit == 'android' # See bug 1266345, android(bug 1232305)
|
skip-if = (os == 'linux' && bits == 64) || toolkit == 'android' # See bug 1266345, android(bug 1232305)
|
||||||
tags=msg
|
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',
|
'testDefinePropertyIgnoredAttributes.cpp',
|
||||||
'testDeflateStringToUTF8Buffer.cpp',
|
'testDeflateStringToUTF8Buffer.cpp',
|
||||||
'testDifferentNewTargetInvokeConstructor.cpp',
|
'testDifferentNewTargetInvokeConstructor.cpp',
|
||||||
'testEnclosingFunction.cpp',
|
|
||||||
'testErrorCopying.cpp',
|
'testErrorCopying.cpp',
|
||||||
'testException.cpp',
|
'testException.cpp',
|
||||||
'testExternalArrayBuffer.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();
|
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_FRIEND_API(JSFunction*)
|
||||||
js::DefineFunctionWithReserved(JSContext* cx, JSObject* objArg, const char* name, JSNative call,
|
js::DefineFunctionWithReserved(JSContext* cx, JSObject* objArg, const char* name, JSNative call,
|
||||||
unsigned nargs, unsigned attrs)
|
unsigned nargs, unsigned attrs)
|
||||||
|
|
|
@ -677,18 +677,6 @@ inline void AssertSameCompartment(JSObject* objA, JSObject* objB) {}
|
||||||
JS_FRIEND_API(void)
|
JS_FRIEND_API(void)
|
||||||
NotifyAnimationActivity(JSObject* obj);
|
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*)
|
JS_FRIEND_API(JSFunction*)
|
||||||
DefineFunctionWithReserved(JSContext* cx, JSObject* obj, const char* name, JSNative call,
|
DefineFunctionWithReserved(JSContext* cx, JSObject* obj, const char* name, JSNative call,
|
||||||
unsigned nargs, unsigned attrs);
|
unsigned nargs, unsigned attrs);
|
||||||
|
@ -2850,14 +2838,6 @@ extern JS_FRIEND_API(void)
|
||||||
SetJitExceptionHandler(JitExceptionHandler handler);
|
SetJitExceptionHandler(JitExceptionHandler handler);
|
||||||
#endif
|
#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
|
* 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.
|
* 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);
|
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
|
bool
|
||||||
js::CreateObjectsForEnvironmentChain(JSContext* cx, AutoObjectVector& chain,
|
js::CreateObjectsForEnvironmentChain(JSContext* cx, AutoObjectVector& chain,
|
||||||
HandleObject terminatingEnv, MutableHandleObject envObj)
|
HandleObject terminatingEnv, MutableHandleObject envObj)
|
||||||
|
|
|
@ -54,11 +54,6 @@ using namespace mozilla::scache;
|
||||||
using namespace xpc;
|
using namespace xpc;
|
||||||
using namespace JS;
|
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 kObserverServiceContractID[] = "@mozilla.org/observer-service;1";
|
||||||
static const char kJSCachePrefix[] = "jsloader";
|
static const char kJSCachePrefix[] = "jsloader";
|
||||||
|
|
||||||
|
@ -196,8 +191,7 @@ mozJSComponentLoader::mozJSComponentLoader()
|
||||||
: mModules(16),
|
: mModules(16),
|
||||||
mImports(16),
|
mImports(16),
|
||||||
mInProgressImports(16),
|
mInProgressImports(16),
|
||||||
mInitialized(false),
|
mInitialized(false)
|
||||||
mReuseLoaderGlobal(false)
|
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(!sSelf, "mozJSComponentLoader should be a singleton");
|
MOZ_ASSERT(!sSelf, "mozJSComponentLoader should be a singleton");
|
||||||
|
|
||||||
|
@ -300,8 +294,6 @@ mozJSComponentLoader::ReallyInit()
|
||||||
{
|
{
|
||||||
nsresult rv;
|
nsresult rv;
|
||||||
|
|
||||||
mReuseLoaderGlobal = Preferences::GetBool("jsloader.reuseGlobal");
|
|
||||||
|
|
||||||
nsCOMPtr<nsIScriptSecurityManager> secman =
|
nsCOMPtr<nsIScriptSecurityManager> secman =
|
||||||
do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
|
do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
|
||||||
if (!secman)
|
if (!secman)
|
||||||
|
@ -430,9 +422,7 @@ mozJSComponentLoader::LoadModule(FileLocation& aFile)
|
||||||
|
|
||||||
// Set the location information for the new global, so that tools like
|
// Set the location information for the new global, so that tools like
|
||||||
// about:memory may use that information
|
// about:memory may use that information
|
||||||
if (!mReuseLoaderGlobal) {
|
xpc::SetLocationForGlobal(entryObj, spec);
|
||||||
xpc::SetLocationForGlobal(entryObj, spec);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The hash owns the ModuleEntry now, forget about it
|
// The hash owns the ModuleEntry now, forget about it
|
||||||
return entry.forget();
|
return entry.forget();
|
||||||
|
@ -442,27 +432,7 @@ void
|
||||||
mozJSComponentLoader::FindTargetObject(JSContext* aCx,
|
mozJSComponentLoader::FindTargetObject(JSContext* aCx,
|
||||||
MutableHandleObject aTargetObject)
|
MutableHandleObject aTargetObject)
|
||||||
{
|
{
|
||||||
aTargetObject.set(nullptr);
|
aTargetObject.set(CurrentGlobalOrNull(aCx));
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This requires that the keys be strings and the values be pointers.
|
// This requires that the keys be strings and the values be pointers.
|
||||||
|
@ -489,6 +459,53 @@ mozJSComponentLoader::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf)
|
||||||
return n;
|
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
|
// Some stack based classes for cleaning up on early return
|
||||||
class FileAutoCloser
|
class FileAutoCloser
|
||||||
{
|
{
|
||||||
|
@ -512,79 +529,27 @@ JSObject*
|
||||||
mozJSComponentLoader::PrepareObjectForLocation(JSContext* aCx,
|
mozJSComponentLoader::PrepareObjectForLocation(JSContext* aCx,
|
||||||
nsIFile* aComponentFile,
|
nsIFile* aComponentFile,
|
||||||
nsIURI* aURI,
|
nsIURI* aURI,
|
||||||
bool aReuseLoaderGlobal,
|
|
||||||
bool* aRealFile)
|
bool* aRealFile)
|
||||||
{
|
{
|
||||||
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
|
RootedObject globalObj(aCx);
|
||||||
if (aReuseLoaderGlobal) {
|
|
||||||
holder = mLoaderGlobal;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult rv = NS_OK;
|
CreateLoaderGlobal(aCx, MapURIToAddonID(aURI), &globalObj);
|
||||||
bool createdNewGlobal = false;
|
|
||||||
|
|
||||||
if (!mLoaderGlobal) {
|
// |thisObj| is the object we set properties on for a particular .jsm.
|
||||||
RefPtr<BackstagePass> backstagePass;
|
// XXX Right now, thisObj is always globalObj, but if we start
|
||||||
rv = NS_NewBackstagePass(getter_AddRefs(backstagePass));
|
// sharing globals between jsms, they won't be the same.
|
||||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
// See bug 1186409.
|
||||||
|
RootedObject thisObj(aCx, globalObj);
|
||||||
|
NS_ENSURE_TRUE(thisObj, nullptr);
|
||||||
|
|
||||||
CompartmentOptions options;
|
JSAutoCompartment ac(aCx, thisObj);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
*aRealFile = false;
|
*aRealFile = false;
|
||||||
|
|
||||||
// need to be extra careful checking for URIs pointing to files
|
// need to be extra careful checking for URIs pointing to files
|
||||||
// EnsureFile may not always get called, especially on resource URIs
|
// EnsureFile may not always get called, especially on resource URIs
|
||||||
// so we need to call GetFile to make sure this is a valid file
|
// 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<nsIFileURL> fileURL = do_QueryInterface(aURI, &rv);
|
||||||
nsCOMPtr<nsIFile> testFile;
|
nsCOMPtr<nsIFile> testFile;
|
||||||
if (NS_SUCCEEDED(rv)) {
|
if (NS_SUCCEEDED(rv)) {
|
||||||
|
@ -597,13 +562,13 @@ mozJSComponentLoader::PrepareObjectForLocation(JSContext* aCx,
|
||||||
if (XRE_IsParentProcess()) {
|
if (XRE_IsParentProcess()) {
|
||||||
RootedObject locationObj(aCx);
|
RootedObject locationObj(aCx);
|
||||||
|
|
||||||
rv = nsXPConnect::XPConnect()->WrapNative(aCx, obj, aComponentFile,
|
rv = nsXPConnect::XPConnect()->WrapNative(aCx, thisObj, aComponentFile,
|
||||||
NS_GET_IID(nsIFile),
|
NS_GET_IID(nsIFile),
|
||||||
locationObj.address());
|
locationObj.address());
|
||||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||||
NS_ENSURE_TRUE(locationObj, nullptr);
|
NS_ENSURE_TRUE(locationObj, nullptr);
|
||||||
|
|
||||||
if (!JS_DefineProperty(aCx, obj, "__LOCATION__", locationObj, 0))
|
if (!JS_DefineProperty(aCx, thisObj, "__LOCATION__", locationObj, 0))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -617,19 +582,18 @@ mozJSComponentLoader::PrepareObjectForLocation(JSContext* aCx,
|
||||||
RootedString exposedUri(aCx, JS_NewStringCopyN(aCx, nativePath.get(), nativePath.Length()));
|
RootedString exposedUri(aCx, JS_NewStringCopyN(aCx, nativePath.get(), nativePath.Length()));
|
||||||
NS_ENSURE_TRUE(exposedUri, nullptr);
|
NS_ENSURE_TRUE(exposedUri, nullptr);
|
||||||
|
|
||||||
if (!JS_DefineProperty(aCx, obj, "__URI__", exposedUri, 0))
|
if (!JS_DefineProperty(aCx, thisObj, "__URI__", exposedUri, 0))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
if (createdNewGlobal) {
|
{
|
||||||
// AutoEntryScript required to invoke debugger hook, which is a
|
// AutoEntryScript required to invoke debugger hook, which is a
|
||||||
// Gecko-specific concept at present.
|
// Gecko-specific concept at present.
|
||||||
dom::AutoEntryScript aes(holder->GetJSObject(),
|
dom::AutoEntryScript aes(globalObj,
|
||||||
"component loader report global");
|
"component loader report global");
|
||||||
RootedObject global(aes.cx(), holder->GetJSObject());
|
JS_FireOnNewGlobalObject(aes.cx(), globalObj);
|
||||||
JS_FireOnNewGlobalObject(aes.cx(), global);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return obj;
|
return thisObj;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
|
@ -651,14 +615,13 @@ mozJSComponentLoader::ObjectForLocation(ComponentLoaderInfo& aInfo,
|
||||||
nsresult rv = aInfo.EnsureURI();
|
nsresult rv = aInfo.EnsureURI();
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
RootedObject obj(cx, PrepareObjectForLocation(cx, aComponentFile, aInfo.URI(),
|
RootedObject obj(cx, PrepareObjectForLocation(cx, aComponentFile, aInfo.URI(),
|
||||||
mReuseLoaderGlobal, &realFile));
|
&realFile));
|
||||||
NS_ENSURE_TRUE(obj, NS_ERROR_FAILURE);
|
NS_ENSURE_TRUE(obj, NS_ERROR_FAILURE);
|
||||||
MOZ_ASSERT(JS_IsGlobalObject(obj) == !mReuseLoaderGlobal);
|
MOZ_ASSERT(JS_IsGlobalObject(obj));
|
||||||
|
|
||||||
JSAutoCompartment ac(cx, obj);
|
JSAutoCompartment ac(cx, obj);
|
||||||
|
|
||||||
RootedScript script(cx);
|
RootedScript script(cx);
|
||||||
RootedFunction function(cx);
|
|
||||||
|
|
||||||
nsAutoCString nativePath;
|
nsAutoCString nativePath;
|
||||||
rv = aInfo.URI()->GetSpec(nativePath);
|
rv = aInfo.URI()->GetSpec(nativePath);
|
||||||
|
@ -675,52 +638,37 @@ mozJSComponentLoader::ObjectForLocation(ComponentLoaderInfo& aInfo,
|
||||||
rv = PathifyURI(aInfo.URI(), cachePath);
|
rv = PathifyURI(aInfo.URI(), cachePath);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
if (!mReuseLoaderGlobal) {
|
script = ScriptPreloader::GetSingleton().GetCachedScript(cx, cachePath);
|
||||||
script = ScriptPreloader::GetSingleton().GetCachedScript(cx, cachePath);
|
if (!script && cache) {
|
||||||
if (!script && cache) {
|
ReadCachedScript(cache, cachePath, cx, mSystemPrincipal, &script);
|
||||||
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()));
|
LOG(("Successfully loaded %s from startupcache\n", nativePath.get()));
|
||||||
} else if (cache) {
|
} else if (cache) {
|
||||||
// This is ok, it just means the script is not yet in the
|
// This is ok, it just means the script is not yet in the
|
||||||
// cache. Could mean that the cache was corrupted and got removed,
|
// cache. Could mean that the cache was corrupted and got removed,
|
||||||
// but either way we're going to write this out.
|
// but either way we're going to write this out.
|
||||||
writeToCache = true;
|
writeToCache = true;
|
||||||
// ReadCachedScript and ReadCachedFunction may have set a pending
|
// ReadCachedScript may have set a pending exception.
|
||||||
// exception.
|
|
||||||
JS_ClearPendingException(cx);
|
JS_ClearPendingException(cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!script && !function) {
|
if (!script) {
|
||||||
// The script wasn't in the cache , so compile it now.
|
// The script wasn't in the cache , so compile it now.
|
||||||
LOG(("Slow loading %s\n", nativePath.get()));
|
LOG(("Slow loading %s\n", nativePath.get()));
|
||||||
|
|
||||||
// Use lazy source if both of these conditions hold:
|
// Use lazy source if we're using the startup cache. Non-lazy source +
|
||||||
//
|
// startup cache regresses installer size (due to source code stored in
|
||||||
// (1) mReuseLoaderGlobal is false. If mReuseLoaderGlobal is true, we
|
// XDR encoded modules in omni.ja). Also, XDR decoding is relatively
|
||||||
// can't do lazy source because we compile things as functions
|
// fast. When we're not using the startup cache, we want to use non-lazy
|
||||||
// (rather than script), and lazy source isn't supported in that
|
// source code so that we can use lazy parsing.
|
||||||
// configuration. That's ok though, because we only do
|
// See bug 1303754.
|
||||||
// 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.
|
|
||||||
// See bug 1303754.
|
|
||||||
CompileOptions options(cx);
|
CompileOptions options(cx);
|
||||||
options.setNoScriptRval(mReuseLoaderGlobal ? false : true)
|
options.setNoScriptRval(true)
|
||||||
.setVersion(JSVERSION_LATEST)
|
.setVersion(JSVERSION_LATEST)
|
||||||
.setFileAndLine(nativePath.get(), 1)
|
.setFileAndLine(nativePath.get(), 1)
|
||||||
.setSourceIsLazy(!mReuseLoaderGlobal && !!cache);
|
.setSourceIsLazy(!!cache);
|
||||||
|
|
||||||
if (realFile) {
|
if (realFile) {
|
||||||
int64_t fileSize;
|
int64_t fileSize;
|
||||||
|
@ -766,18 +714,9 @@ mozJSComponentLoader::ObjectForLocation(ComponentLoaderInfo& aInfo,
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mReuseLoaderGlobal) {
|
// Note: exceptions will get handled further down;
|
||||||
Compile(cx, options, buf, fileSize32, &script);
|
// don't early return for them here.
|
||||||
} else {
|
Compile(cx, options, buf, fileSize32, &script);
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PR_MemUnmap(buf, fileSize32);
|
PR_MemUnmap(buf, fileSize32);
|
||||||
} else {
|
} else {
|
||||||
|
@ -810,51 +749,26 @@ mozJSComponentLoader::ObjectForLocation(ComponentLoaderInfo& aInfo,
|
||||||
|
|
||||||
buf[len] = '\0';
|
buf[len] = '\0';
|
||||||
|
|
||||||
if (!mReuseLoaderGlobal) {
|
Compile(cx, options, buf.get(), bytesRead, &script);
|
||||||
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
|
// Propagate the exception, if one exists. Also, don't leave the stale
|
||||||
// exception on this context.
|
// exception on this context.
|
||||||
if (!script && !function && aPropagateExceptions &&
|
if (!script && aPropagateExceptions && jsapi.HasException()) {
|
||||||
jsapi.HasException()) {
|
|
||||||
if (!jsapi.StealException(aException))
|
if (!jsapi.StealException(aException))
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!script && !function) {
|
if (!script) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We must have a script or a function (but not both!) here. We have a
|
ScriptPreloader::GetSingleton().NoteScript(nativePath, cachePath, script);
|
||||||
// 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) {
|
if (writeToCache) {
|
||||||
// We successfully compiled the script, so cache it.
|
// We successfully compiled the script, so cache it.
|
||||||
if (script) {
|
rv = WriteCachedScript(cache, cachePath, cx, mSystemPrincipal,
|
||||||
rv = WriteCachedScript(cache, cachePath, cx, mSystemPrincipal,
|
script);
|
||||||
script);
|
|
||||||
} else {
|
|
||||||
rv = WriteCachedFunction(cache, cachePath, cx, mSystemPrincipal,
|
|
||||||
function);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't treat failure to write as fatal, since we might be working
|
// Don't treat failure to write as fatal, since we might be working
|
||||||
// with a read-only cache.
|
// with a read-only cache.
|
||||||
|
@ -869,34 +783,18 @@ mozJSComponentLoader::ObjectForLocation(ComponentLoaderInfo& aInfo,
|
||||||
// See bug 384168.
|
// See bug 384168.
|
||||||
aObject.set(obj);
|
aObject.set(obj);
|
||||||
|
|
||||||
RootedScript tableScript(cx, script);
|
aTableScript.set(script);
|
||||||
if (!tableScript) {
|
|
||||||
tableScript = JS_GetFunctionScript(cx, function);
|
|
||||||
MOZ_ASSERT(tableScript);
|
|
||||||
}
|
|
||||||
|
|
||||||
aTableScript.set(tableScript);
|
|
||||||
|
|
||||||
|
|
||||||
{ // Scope for AutoEntryScript
|
{ // Scope for AutoEntryScript
|
||||||
|
|
||||||
// We're going to run script via JS_ExecuteScript or
|
// We're going to run script via JS_ExecuteScript, so we need an
|
||||||
// JS_CallFunction, so we need an AutoEntryScript.
|
// AutoEntryScript. This is Gecko-specific and not in any spec.
|
||||||
// This is Gecko-specific and not in any spec.
|
|
||||||
dom::AutoEntryScript aes(CurrentGlobalOrNull(cx),
|
dom::AutoEntryScript aes(CurrentGlobalOrNull(cx),
|
||||||
"component loader load module");
|
"component loader load module");
|
||||||
JSContext* aescx = aes.cx();
|
JSContext* aescx = aes.cx();
|
||||||
bool ok;
|
JS::RootedValue rval(cx);
|
||||||
if (script) {
|
if (!JS::CloneAndExecuteScript(aescx, script, &rval)) {
|
||||||
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 (aPropagateExceptions && aes.HasException()) {
|
if (aPropagateExceptions && aes.HasException()) {
|
||||||
// Ignore return value because we're returning an error code
|
// Ignore return value because we're returning an error code
|
||||||
// anyway.
|
// anyway.
|
||||||
|
@ -924,26 +822,6 @@ mozJSComponentLoader::UnloadModules()
|
||||||
{
|
{
|
||||||
mInitialized = false;
|
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();
|
mInProgressImports.Clear();
|
||||||
mImports.Clear();
|
mImports.Clear();
|
||||||
|
|
||||||
|
@ -1141,9 +1019,7 @@ mozJSComponentLoader::ImportInto(const nsACString& aLocation,
|
||||||
|
|
||||||
// Set the location information for the new global, so that tools like
|
// Set the location information for the new global, so that tools like
|
||||||
// about:memory may use that information
|
// about:memory may use that information
|
||||||
if (!mReuseLoaderGlobal) {
|
xpc::SetLocationForGlobal(newEntry->obj, aLocation);
|
||||||
xpc::SetLocationForGlobal(newEntry->obj, aLocation);
|
|
||||||
}
|
|
||||||
|
|
||||||
mod = newEntry;
|
mod = newEntry;
|
||||||
}
|
}
|
||||||
|
@ -1286,9 +1162,6 @@ mozJSComponentLoader::Unload(const nsACString & aLocation)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
MOZ_RELEASE_ASSERT(!mReuseLoaderGlobal, "Module unloading not supported when "
|
|
||||||
"compartment sharing is enabled");
|
|
||||||
|
|
||||||
ComponentLoaderInfo info(aLocation);
|
ComponentLoaderInfo info(aLocation);
|
||||||
rv = info.EnsureKey();
|
rv = info.EnsureKey();
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
|
@ -62,10 +62,13 @@ class mozJSComponentLoader : public mozilla::ModuleLoader,
|
||||||
nsresult ReallyInit();
|
nsresult ReallyInit();
|
||||||
void UnloadModules();
|
void UnloadModules();
|
||||||
|
|
||||||
|
void CreateLoaderGlobal(JSContext* aCx,
|
||||||
|
JSAddonId* aAddonID,
|
||||||
|
JS::MutableHandleObject aGlobal);
|
||||||
|
|
||||||
JSObject* PrepareObjectForLocation(JSContext* aCx,
|
JSObject* PrepareObjectForLocation(JSContext* aCx,
|
||||||
nsIFile* aComponentFile,
|
nsIFile* aComponentFile,
|
||||||
nsIURI* aComponent,
|
nsIURI* aComponent,
|
||||||
bool aReuseLoaderGlobal,
|
|
||||||
bool* aRealFile);
|
bool* aRealFile);
|
||||||
|
|
||||||
nsresult ObjectForLocation(ComponentLoaderInfo& aInfo,
|
nsresult ObjectForLocation(ComponentLoaderInfo& aInfo,
|
||||||
|
@ -83,7 +86,6 @@ class mozJSComponentLoader : public mozilla::ModuleLoader,
|
||||||
|
|
||||||
nsCOMPtr<nsIComponentManager> mCompMgr;
|
nsCOMPtr<nsIComponentManager> mCompMgr;
|
||||||
nsCOMPtr<nsIPrincipal> mSystemPrincipal;
|
nsCOMPtr<nsIPrincipal> mSystemPrincipal;
|
||||||
nsCOMPtr<nsIXPConnectJSObjectHolder> mLoaderGlobal;
|
|
||||||
|
|
||||||
class ModuleEntry : public mozilla::Module
|
class ModuleEntry : public mozilla::Module
|
||||||
{
|
{
|
||||||
|
@ -155,7 +157,6 @@ class mozJSComponentLoader : public mozilla::ModuleLoader,
|
||||||
nsDataHashtable<nsCStringHashKey, ModuleEntry*> mInProgressImports;
|
nsDataHashtable<nsCStringHashKey, ModuleEntry*> mInProgressImports;
|
||||||
|
|
||||||
bool mInitialized;
|
bool mInitialized;
|
||||||
bool mReuseLoaderGlobal;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -43,14 +43,6 @@ ReadCachedScript(StartupCache* cache, nsACString& uri, JSContext* cx,
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
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
|
nsresult
|
||||||
WriteCachedScript(StartupCache* cache, nsACString& uri, JSContext* cx,
|
WriteCachedScript(StartupCache* cache, nsACString& uri, JSContext* cx,
|
||||||
nsIPrincipal* systemPrincipal, HandleScript script)
|
nsIPrincipal* systemPrincipal, HandleScript script)
|
||||||
|
@ -75,11 +67,3 @@ WriteCachedScript(StartupCache* cache, nsACString& uri, JSContext* cx,
|
||||||
size);
|
size);
|
||||||
return rv;
|
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,
|
JSContext* cx, nsIPrincipal* systemPrincipal,
|
||||||
JS::MutableHandleScript scriptp);
|
JS::MutableHandleScript scriptp);
|
||||||
|
|
||||||
nsresult
|
|
||||||
ReadCachedFunction(mozilla::scache::StartupCache* cache, nsACString& uri,
|
|
||||||
JSContext* cx, nsIPrincipal* systemPrincipal,
|
|
||||||
JSFunction** function);
|
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
WriteCachedScript(mozilla::scache::StartupCache* cache, nsACString& uri,
|
WriteCachedScript(mozilla::scache::StartupCache* cache, nsACString& uri,
|
||||||
JSContext* cx, nsIPrincipal* systemPrincipal,
|
JSContext* cx, nsIPrincipal* systemPrincipal,
|
||||||
JS::HandleScript script);
|
JS::HandleScript script);
|
||||||
nsresult
|
|
||||||
WriteCachedFunction(mozilla::scache::StartupCache* cache, nsACString& uri,
|
|
||||||
JSContext* cx, nsIPrincipal* systemPrincipal,
|
|
||||||
JSFunction* function);
|
|
||||||
|
|
||||||
#endif /* mozJSLoaderUtils_h */
|
#endif /* mozJSLoaderUtils_h */
|
||||||
|
|
|
@ -132,15 +132,11 @@ PrepareScript(nsIURI* uri,
|
||||||
const nsAString& charset,
|
const nsAString& charset,
|
||||||
const char* buf,
|
const char* buf,
|
||||||
int64_t len,
|
int64_t len,
|
||||||
bool reuseGlobal,
|
|
||||||
bool wantReturnValue,
|
bool wantReturnValue,
|
||||||
MutableHandleScript script,
|
MutableHandleScript script)
|
||||||
MutableHandleFunction function)
|
|
||||||
{
|
{
|
||||||
JS::CompileOptions options(cx);
|
JS::CompileOptions options(cx);
|
||||||
// Use line 0 to make the function body starts from line 1 when
|
options.setFileAndLine(uriStr, 1)
|
||||||
// |reuseGlobal == true|.
|
|
||||||
options.setFileAndLine(uriStr, reuseGlobal ? 0 : 1)
|
|
||||||
.setVersion(JSVERSION_LATEST)
|
.setVersion(JSVERSION_LATEST)
|
||||||
.setNoScriptRval(!wantReturnValue);
|
.setNoScriptRval(!wantReturnValue);
|
||||||
if (!charset.IsVoid()) {
|
if (!charset.IsVoid()) {
|
||||||
|
@ -159,34 +155,18 @@ PrepareScript(nsIURI* uri,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!reuseGlobal) {
|
if (JS_IsGlobalObject(targetObj)) {
|
||||||
if (JS_IsGlobalObject(targetObj)) {
|
return JS::Compile(cx, options, srcBuf, script);
|
||||||
return JS::Compile(cx, options, srcBuf, script);
|
|
||||||
}
|
|
||||||
return JS::CompileForNonSyntacticScope(cx, options, srcBuf, script);
|
|
||||||
}
|
}
|
||||||
AutoObjectVector envChain(cx);
|
return JS::CompileForNonSyntacticScope(cx, options, srcBuf, script);
|
||||||
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
|
// We only use lazy source when no special encoding is specified because
|
||||||
// the lazy source loader doesn't know the encoding.
|
// the lazy source loader doesn't know the encoding.
|
||||||
if (!reuseGlobal) {
|
options.setSourceIsLazy(true);
|
||||||
options.setSourceIsLazy(true);
|
if (JS_IsGlobalObject(targetObj)) {
|
||||||
if (JS_IsGlobalObject(targetObj)) {
|
return JS::Compile(cx, options, buf, len, script);
|
||||||
return JS::Compile(cx, options, buf, len, script);
|
|
||||||
}
|
|
||||||
return JS::CompileForNonSyntacticScope(cx, options, buf, len, script);
|
|
||||||
}
|
}
|
||||||
AutoObjectVector envChain(cx);
|
return JS::CompileForNonSyntacticScope(cx, options, buf, len, script);
|
||||||
if (!JS_IsGlobalObject(targetObj) && !envChain.append(targetObj)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return JS::CompileFunction(cx, envChain, options, nullptr, 0, nullptr,
|
|
||||||
buf, len, function);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
@ -196,30 +176,19 @@ EvalScript(JSContext* cx,
|
||||||
nsIURI* uri,
|
nsIURI* uri,
|
||||||
bool startupCache,
|
bool startupCache,
|
||||||
bool preloadCache,
|
bool preloadCache,
|
||||||
MutableHandleScript script,
|
MutableHandleScript script)
|
||||||
HandleFunction function)
|
|
||||||
{
|
{
|
||||||
if (function) {
|
if (JS_IsGlobalObject(targetObj)) {
|
||||||
script.set(JS_GetFunctionScript(cx, function));
|
if (!JS::CloneAndExecuteScript(cx, script, retval)) {
|
||||||
}
|
|
||||||
|
|
||||||
if (function) {
|
|
||||||
if (!JS_CallFunction(cx, targetObj, function, JS::HandleValueArray::empty(), retval)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (JS_IsGlobalObject(targetObj)) {
|
JS::AutoObjectVector envChain(cx);
|
||||||
if (!JS::CloneAndExecuteScript(cx, script, retval)) {
|
if (!envChain.append(targetObj)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
if (!JS::CloneAndExecuteScript(cx, envChain, script, retval)) {
|
||||||
JS::AutoObjectVector envChain(cx);
|
return false;
|
||||||
if (!envChain.append(targetObj)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!JS::CloneAndExecuteScript(cx, envChain, script, retval)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,14 +239,13 @@ public:
|
||||||
|
|
||||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(AsyncScriptLoader)
|
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,
|
JSObject* aTargetObj, const nsAString& aCharset,
|
||||||
bool aCache, Promise* aPromise)
|
bool aCache, Promise* aPromise)
|
||||||
: mChannel(aChannel)
|
: mChannel(aChannel)
|
||||||
, mTargetObj(aTargetObj)
|
, mTargetObj(aTargetObj)
|
||||||
, mPromise(aPromise)
|
, mPromise(aPromise)
|
||||||
, mCharset(aCharset)
|
, mCharset(aCharset)
|
||||||
, mReuseGlobal(aReuseGlobal)
|
|
||||||
, mWantReturnValue(aWantReturnValue)
|
, mWantReturnValue(aWantReturnValue)
|
||||||
, mCache(aCache)
|
, mCache(aCache)
|
||||||
{
|
{
|
||||||
|
@ -294,7 +262,6 @@ private:
|
||||||
Heap<JSObject*> mTargetObj;
|
Heap<JSObject*> mTargetObj;
|
||||||
RefPtr<Promise> mPromise;
|
RefPtr<Promise> mPromise;
|
||||||
nsString mCharset;
|
nsString mCharset;
|
||||||
bool mReuseGlobal;
|
|
||||||
bool mWantReturnValue;
|
bool mWantReturnValue;
|
||||||
bool mCache;
|
bool mCache;
|
||||||
};
|
};
|
||||||
|
@ -394,7 +361,6 @@ AsyncScriptLoader::OnStreamComplete(nsIIncrementalStreamLoader* aLoader,
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
RootedFunction function(cx);
|
|
||||||
RootedScript script(cx);
|
RootedScript script(cx);
|
||||||
nsAutoCString spec;
|
nsAutoCString spec;
|
||||||
nsresult rv = uri->GetSpec(spec);
|
nsresult rv = uri->GetSpec(spec);
|
||||||
|
@ -404,7 +370,7 @@ AsyncScriptLoader::OnStreamComplete(nsIIncrementalStreamLoader* aLoader,
|
||||||
|
|
||||||
if (!PrepareScript(uri, cx, targetObj, spec.get(), mCharset,
|
if (!PrepareScript(uri, cx, targetObj, spec.get(), mCharset,
|
||||||
reinterpret_cast<const char*>(aBuf), aLength,
|
reinterpret_cast<const char*>(aBuf), aLength,
|
||||||
mReuseGlobal, mWantReturnValue, &script, &function))
|
mWantReturnValue, &script))
|
||||||
{
|
{
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
@ -412,7 +378,7 @@ AsyncScriptLoader::OnStreamComplete(nsIIncrementalStreamLoader* aLoader,
|
||||||
JS::Rooted<JS::Value> retval(cx);
|
JS::Rooted<JS::Value> retval(cx);
|
||||||
if (EvalScript(cx, targetObj, &retval, uri, mCache,
|
if (EvalScript(cx, targetObj, &retval, uri, mCache,
|
||||||
mCache && !mWantReturnValue,
|
mCache && !mWantReturnValue,
|
||||||
&script, function)) {
|
&script)) {
|
||||||
autoPromise.ResolvePromise(retval);
|
autoPromise.ResolvePromise(retval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -424,7 +390,6 @@ mozJSSubScriptLoader::ReadScriptAsync(nsIURI* uri,
|
||||||
HandleObject targetObj,
|
HandleObject targetObj,
|
||||||
const nsAString& charset,
|
const nsAString& charset,
|
||||||
nsIIOService* serv,
|
nsIIOService* serv,
|
||||||
bool reuseGlobal,
|
|
||||||
bool wantReturnValue,
|
bool wantReturnValue,
|
||||||
bool cache,
|
bool cache,
|
||||||
MutableHandleValue retval)
|
MutableHandleValue retval)
|
||||||
|
@ -467,7 +432,6 @@ mozJSSubScriptLoader::ReadScriptAsync(nsIURI* uri,
|
||||||
|
|
||||||
RefPtr<AsyncScriptLoader> loadObserver =
|
RefPtr<AsyncScriptLoader> loadObserver =
|
||||||
new AsyncScriptLoader(channel,
|
new AsyncScriptLoader(channel,
|
||||||
reuseGlobal,
|
|
||||||
wantReturnValue,
|
wantReturnValue,
|
||||||
targetObj,
|
targetObj,
|
||||||
charset,
|
charset,
|
||||||
|
@ -489,13 +453,10 @@ mozJSSubScriptLoader::ReadScript(nsIURI* uri,
|
||||||
const nsAString& charset,
|
const nsAString& charset,
|
||||||
const char* uriStr,
|
const char* uriStr,
|
||||||
nsIIOService* serv,
|
nsIIOService* serv,
|
||||||
bool reuseGlobal,
|
|
||||||
bool wantReturnValue,
|
bool wantReturnValue,
|
||||||
MutableHandleScript script,
|
MutableHandleScript script)
|
||||||
MutableHandleFunction function)
|
|
||||||
{
|
{
|
||||||
script.set(nullptr);
|
script.set(nullptr);
|
||||||
function.set(nullptr);
|
|
||||||
|
|
||||||
// We create a channel and call SetContentType, to avoid expensive MIME type
|
// We create a channel and call SetContentType, to avoid expensive MIME type
|
||||||
// lookups (bug 632490).
|
// lookups (bug 632490).
|
||||||
|
@ -540,9 +501,8 @@ mozJSSubScriptLoader::ReadScript(nsIURI* uri,
|
||||||
NS_ENSURE_SUCCESS(rv, false);
|
NS_ENSURE_SUCCESS(rv, false);
|
||||||
|
|
||||||
return PrepareScript(uri, cx, targetObj, uriStr, charset,
|
return PrepareScript(uri, cx, targetObj, uriStr, charset,
|
||||||
buf.get(), len,
|
buf.get(), len, wantReturnValue,
|
||||||
reuseGlobal, wantReturnValue,
|
script);
|
||||||
script, function);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
|
@ -605,15 +565,13 @@ mozJSSubScriptLoader::DoLoadSubScriptWithOptions(const nsAString& url,
|
||||||
}
|
}
|
||||||
|
|
||||||
RootedObject targetObj(cx);
|
RootedObject targetObj(cx);
|
||||||
mozJSComponentLoader* loader = mozJSComponentLoader::Get();
|
if (options.target) {
|
||||||
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;
|
targetObj = options.target;
|
||||||
|
} else {
|
||||||
|
mozJSComponentLoader* loader = mozJSComponentLoader::Get();
|
||||||
|
loader->FindTargetObject(cx, &targetObj);
|
||||||
|
MOZ_ASSERT(JS_IsGlobalObject(targetObj));
|
||||||
|
}
|
||||||
|
|
||||||
// Remember an object out of the calling compartment so that we
|
// Remember an object out of the calling compartment so that we
|
||||||
// can properly wrap the result later.
|
// can properly wrap the result later.
|
||||||
|
@ -694,7 +652,6 @@ mozJSSubScriptLoader::DoLoadSubScriptWithOptions(const nsAString& url,
|
||||||
cachePath.AppendPrintf("jssubloader/%d", version);
|
cachePath.AppendPrintf("jssubloader/%d", version);
|
||||||
PathifyURI(uri, cachePath);
|
PathifyURI(uri, cachePath);
|
||||||
|
|
||||||
RootedFunction function(cx);
|
|
||||||
RootedScript script(cx);
|
RootedScript script(cx);
|
||||||
if (!options.ignoreCache) {
|
if (!options.ignoreCache) {
|
||||||
if (!options.wantReturnValue)
|
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 we are doing an async load, trigger it and bail out.
|
||||||
if (!script && options.async) {
|
if (!script && options.async) {
|
||||||
return ReadScriptAsync(uri, targetObj, options.charset, serv,
|
return ReadScriptAsync(uri, targetObj, options.charset, serv,
|
||||||
reusingGlobal, options.wantReturnValue,
|
options.wantReturnValue, !!cache, retval);
|
||||||
!!cache, retval);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!script) {
|
if (script) {
|
||||||
if (!ReadScript(uri, cx, targetObj, options.charset,
|
// |script| came from the cache, so don't bother writing it
|
||||||
static_cast<const char*>(uriStr.get()), serv,
|
// |back there.
|
||||||
reusingGlobal, options.wantReturnValue, &script,
|
|
||||||
&function))
|
|
||||||
{
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
cache = nullptr;
|
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,
|
Unused << EvalScript(cx, targetObj, retval, uri, !!cache,
|
||||||
!ignoreCache && !options.wantReturnValue,
|
!ignoreCache && !options.wantReturnValue,
|
||||||
&script, function);
|
&script);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,14 +36,15 @@ private:
|
||||||
bool ReadScript(nsIURI* uri, JSContext* cx, JS::HandleObject targetObj,
|
bool ReadScript(nsIURI* uri, JSContext* cx, JS::HandleObject targetObj,
|
||||||
const nsAString& charset, const char* uriStr,
|
const nsAString& charset, const char* uriStr,
|
||||||
nsIIOService* serv,
|
nsIIOService* serv,
|
||||||
bool reuseGlobal, bool wantReturnValue,
|
bool wantReturnValue,
|
||||||
JS::MutableHandleScript script,
|
JS::MutableHandleScript script);
|
||||||
JS::MutableHandleFunction function);
|
|
||||||
|
|
||||||
nsresult ReadScriptAsync(nsIURI* uri, JS::HandleObject targetObj,
|
nsresult ReadScriptAsync(nsIURI* uri,
|
||||||
|
JS::HandleObject targetObj,
|
||||||
const nsAString& charset,
|
const nsAString& charset,
|
||||||
nsIIOService* serv, bool reuseGlobal,
|
nsIIOService* serv,
|
||||||
bool wantReturnValue, bool cache,
|
bool wantReturnValue,
|
||||||
|
bool cache,
|
||||||
JS::MutableHandleValue retval);
|
JS::MutableHandleValue retval);
|
||||||
|
|
||||||
nsresult DoLoadSubScriptWithOptions(const nsAString& url,
|
nsresult DoLoadSubScriptWithOptions(const nsAString& url,
|
||||||
|
|
|
@ -273,6 +273,12 @@ public:
|
||||||
nsChangeHint aMinChangeHint,
|
nsChangeHint aMinChangeHint,
|
||||||
const RestyleHintData* aRestyleHintData = nullptr);
|
const RestyleHintData* aRestyleHintData = nullptr);
|
||||||
|
|
||||||
|
void PostRestyleEventForCSSRuleChanges(Element* aElement,
|
||||||
|
nsRestyleHint aRestyleHint,
|
||||||
|
nsChangeHint aMinChangeHint) {
|
||||||
|
PostRestyleEvent(aElement, aRestyleHint, aMinChangeHint);
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Asynchronously clear style data from the root frame downwards and ensure
|
* Asynchronously clear style data from the root frame downwards and ensure
|
||||||
|
|
|
@ -4584,12 +4584,14 @@ nsIPresShell::RestyleForCSSRuleChanges()
|
||||||
// If scopeRoots is empty, we know that mStylesHaveChanged was true at
|
// If scopeRoots is empty, we know that mStylesHaveChanged was true at
|
||||||
// the beginning of this function, and that we need to restyle the whole
|
// the beginning of this function, and that we need to restyle the whole
|
||||||
// document.
|
// document.
|
||||||
restyleManager->PostRestyleEvent(root, eRestyle_Subtree,
|
restyleManager->PostRestyleEventForCSSRuleChanges(root,
|
||||||
nsChangeHint(0));
|
eRestyle_Subtree,
|
||||||
|
nsChangeHint(0));
|
||||||
} else {
|
} else {
|
||||||
for (Element* scopeRoot : scopeRoots) {
|
for (Element* scopeRoot : scopeRoots) {
|
||||||
restyleManager->PostRestyleEvent(scopeRoot, eRestyle_Subtree,
|
restyleManager->PostRestyleEventForCSSRuleChanges(scopeRoot,
|
||||||
nsChangeHint(0));
|
eRestyle_Subtree,
|
||||||
|
nsChangeHint(0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -161,6 +161,9 @@ public:
|
||||||
inline void PostRestyleEvent(dom::Element* aElement,
|
inline void PostRestyleEvent(dom::Element* aElement,
|
||||||
nsRestyleHint aRestyleHint,
|
nsRestyleHint aRestyleHint,
|
||||||
nsChangeHint aMinChangeHint);
|
nsChangeHint aMinChangeHint);
|
||||||
|
inline void PostRestyleEventForCSSRuleChanges(dom::Element* aElement,
|
||||||
|
nsRestyleHint aRestyleHint,
|
||||||
|
nsChangeHint aMinChangeHint);
|
||||||
inline void RebuildAllStyleData(nsChangeHint aExtraHint,
|
inline void RebuildAllStyleData(nsChangeHint aExtraHint,
|
||||||
nsRestyleHint aRestyleHint);
|
nsRestyleHint aRestyleHint);
|
||||||
inline void PostRebuildAllStyleDataEvent(nsChangeHint aExtraHint,
|
inline void PostRebuildAllStyleDataEvent(nsChangeHint aExtraHint,
|
||||||
|
|
|
@ -24,6 +24,15 @@ RestyleManager::PostRestyleEvent(dom::Element* aElement,
|
||||||
MOZ_STYLO_FORWARD(PostRestyleEvent, (aElement, aRestyleHint, aMinChangeHint));
|
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
|
void
|
||||||
RestyleManager::RebuildAllStyleData(nsChangeHint aExtraHint,
|
RestyleManager::RebuildAllStyleData(nsChangeHint aExtraHint,
|
||||||
nsRestyleHint aRestyleHint)
|
nsRestyleHint aRestyleHint)
|
||||||
|
|
|
@ -66,6 +66,17 @@ ServoRestyleManager::PostRestyleEvent(Element* aElement,
|
||||||
Servo_NoteExplicitHints(aElement, aRestyleHint, aMinChangeHint);
|
Servo_NoteExplicitHints(aElement, aRestyleHint, aMinChangeHint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ServoRestyleManager::PostRestyleEventForCSSRuleChanges(
|
||||||
|
Element* aElement,
|
||||||
|
nsRestyleHint aRestyleHint,
|
||||||
|
nsChangeHint aMinChangeHint)
|
||||||
|
{
|
||||||
|
mRestyleForCSSRuleChanges = true;
|
||||||
|
|
||||||
|
PostRestyleEvent(aElement, aRestyleHint, aMinChangeHint);
|
||||||
|
}
|
||||||
|
|
||||||
/* static */ void
|
/* static */ void
|
||||||
ServoRestyleManager::PostRestyleEventForAnimations(Element* aElement,
|
ServoRestyleManager::PostRestyleEventForAnimations(Element* aElement,
|
||||||
nsRestyleHint aRestyleHint)
|
nsRestyleHint aRestyleHint)
|
||||||
|
@ -553,8 +564,11 @@ ServoRestyleManager::DoProcessPendingRestyles(TraversalRestyleBehavior
|
||||||
++mAnimationGeneration;
|
++mAnimationGeneration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TraversalRestyleBehavior restyleBehavior = mRestyleForCSSRuleChanges
|
||||||
|
? TraversalRestyleBehavior::ForCSSRuleChanges
|
||||||
|
: TraversalRestyleBehavior::Normal;
|
||||||
while (animationOnly ? styleSet->StyleDocumentForAnimationOnly()
|
while (animationOnly ? styleSet->StyleDocumentForAnimationOnly()
|
||||||
: styleSet->StyleDocument()) {
|
: styleSet->StyleDocument(restyleBehavior)) {
|
||||||
if (!animationOnly) {
|
if (!animationOnly) {
|
||||||
ClearSnapshots();
|
ClearSnapshots();
|
||||||
}
|
}
|
||||||
|
@ -603,6 +617,7 @@ ServoRestyleManager::DoProcessPendingRestyles(TraversalRestyleBehavior
|
||||||
styleSet->AssertTreeIsClean();
|
styleSet->AssertTreeIsClean();
|
||||||
mHaveNonAnimationRestyles = false;
|
mHaveNonAnimationRestyles = false;
|
||||||
}
|
}
|
||||||
|
mRestyleForCSSRuleChanges = false;
|
||||||
mInStyleRefresh = false;
|
mInStyleRefresh = false;
|
||||||
|
|
||||||
// Note: We are in the scope of |animationsWithDestroyedFrame|, so
|
// Note: We are in the scope of |animationsWithDestroyedFrame|, so
|
||||||
|
|
|
@ -44,6 +44,9 @@ public:
|
||||||
nsRestyleHint aRestyleHint,
|
nsRestyleHint aRestyleHint,
|
||||||
nsChangeHint aMinChangeHint);
|
nsChangeHint aMinChangeHint);
|
||||||
void PostRestyleEventForLazyConstruction();
|
void PostRestyleEventForLazyConstruction();
|
||||||
|
void PostRestyleEventForCSSRuleChanges(dom::Element* aElement,
|
||||||
|
nsRestyleHint aRestyleHint,
|
||||||
|
nsChangeHint aMinChangeHint);
|
||||||
void RebuildAllStyleData(nsChangeHint aExtraHint,
|
void RebuildAllStyleData(nsChangeHint aExtraHint,
|
||||||
nsRestyleHint aRestyleHint);
|
nsRestyleHint aRestyleHint);
|
||||||
void PostRebuildAllStyleDataEvent(nsChangeHint aExtraHint,
|
void PostRebuildAllStyleDataEvent(nsChangeHint aExtraHint,
|
||||||
|
@ -162,6 +165,14 @@ private:
|
||||||
// creation sequence will be correct.
|
// creation sequence will be correct.
|
||||||
bool mHaveNonAnimationRestyles = false;
|
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
|
// A hashtable with the elements that have changed state or attributes, in
|
||||||
// order to calculate restyle hints during the traversal.
|
// order to calculate restyle hints during the traversal.
|
||||||
SnapshotTable mSnapshots;
|
SnapshotTable mSnapshots;
|
||||||
|
|
|
@ -2537,7 +2537,7 @@ nsCSSFrameConstructor::ConstructDocElementFrame(Element* aDocEle
|
||||||
// We delay traversing the entire document until here, since we per above we
|
// We delay traversing the entire document until here, since we per above we
|
||||||
// may invalidate the root style when we load doc stylesheets.
|
// may invalidate the root style when we load doc stylesheets.
|
||||||
if (ServoStyleSet* set = mPresShell->StyleSet()->GetAsServo()) {
|
if (ServoStyleSet* set = mPresShell->StyleSet()->GetAsServo()) {
|
||||||
set->StyleDocument();
|
set->StyleDocument(TraversalRestyleBehavior::Normal);
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------- IF SCROLLABLE WRAP IN SCROLLFRAME --------
|
// --------- 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-opacity-01.svg pass.svg
|
||||||
== dynamic-stroke-width-01.svg pass.svg
|
== dynamic-stroke-width-01.svg pass.svg
|
||||||
== dynamic-switch-01.svg pass.svg
|
== dynamic-switch-01.svg pass.svg
|
||||||
fails-if(stylo) == dynamic-text-01.svg dynamic-text-01-ref.svg
|
== 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,3,12739) == 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(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) fails-if(stylo) == dynamic-text-04.svg dynamic-text-04-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-05.svg pass.svg
|
||||||
== dynamic-text-06.svg pass.svg
|
== dynamic-text-06.svg pass.svg
|
||||||
fails-if(stylo) == dynamic-text-07.svg dynamic-text-07-ref.svg
|
== dynamic-text-07.svg dynamic-text-07-ref.svg
|
||||||
fails-if(stylo) == dynamic-text-08.svg dynamic-text-08-ref.svg
|
== dynamic-text-08.svg dynamic-text-08-ref.svg
|
||||||
== dynamic-text-attr-01.svg dynamic-text-attr-01-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-02.svg dynamic-textPath-02-ref.svg
|
||||||
== dynamic-textPath-03.svg dynamic-textPath-03-ref.svg
|
== dynamic-textPath-03.svg dynamic-textPath-03-ref.svg
|
||||||
== dynamic-use-01.svg pass.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-02a.svg fallback-color-02-ref.svg
|
||||||
== fallback-color-02b.svg fallback-color-02-ref.svg
|
== fallback-color-02b.svg fallback-color-02-ref.svg
|
||||||
== fallback-color-03.svg pass.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
|
== fallback-color-05.svg fallback-color-05-ref.svg
|
||||||
|
|
||||||
== filter-basic-01.svg pass.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
|
== 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) == 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) == 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) == 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-01d.svg gradient-live-01-ref.svg
|
||||||
== gradient-transform-01.svg pass.svg
|
== gradient-transform-01.svg pass.svg
|
||||||
== href-attr-change-restyles.svg href-attr-change-restyles-ref.svg
|
== href-attr-change-restyles.svg href-attr-change-restyles-ref.svg
|
||||||
fuzzy-if(skiaContent,1,550) == import-svg-01.html pass.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(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-01.svg overflow-on-outer-svg-01-ref.svg
|
||||||
== overflow-on-outer-svg-02a.xhtml overflow-on-outer-svg-02-ref.xhtml
|
== 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
|
== 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(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) == 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
|
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
|
#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) fails-if(stylo) == stroke-dasharray-02.svg pass.svg
|
||||||
fuzzy-if(skiaContent,1,340) == stroke-dasharray-03.svg pass.svg
|
fuzzy-if(skiaContent,1,340) == stroke-dasharray-03.svg pass.svg
|
||||||
== stroke-dasharray-and-pathLength-01.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-01.svg pass.svg
|
||||||
== stroke-dashoffset-and-pathLength-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
|
== 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
|
== text-font-size-01.svg pass.svg
|
||||||
random-if(gtkWidget) == text-font-weight-01.svg text-font-weight-01-ref.svg # bug 386713
|
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
|
== 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
|
fuzzy-if(skiaContent,1,5500) == text-gradient-03.svg pass.svg
|
||||||
HTTP(..) == text-gradient-04.svg text-gradient-04-ref.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-01.svg text-in-link-01-ref.svg
|
||||||
== text-in-link-02.svg text-in-link-02-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.
|
# Tests for bug 546813: sanity-check using HTML text, then test SVG behavior.
|
||||||
!= text-language-00.xhtml text-language-00-ref.xhtml
|
!= 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(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
|
== text-layout-01.svg text-layout-01-ref.svg
|
||||||
fails-if(stylo) == text-layout-02.svg text-layout-02-ref.svg
|
== text-layout-02.svg text-layout-02-ref.svg
|
||||||
fails-if(stylo) == text-layout-03.svg text-layout-03-ref.svg
|
== text-layout-03.svg text-layout-03-ref.svg
|
||||||
fails-if(stylo) == text-layout-04.svg text-layout-04-ref.svg
|
== text-layout-04.svg text-layout-04-ref.svg
|
||||||
== text-layout-05.svg text-layout-05-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
|
fuzzy-if(cocoaWidget&&layersGPUAccelerated,1,3) == text-layout-06.svg text-layout-06-ref.svg
|
||||||
fails-if(stylo) == text-layout-07.svg text-layout-07-ref.svg
|
== text-layout-07.svg text-layout-07-ref.svg
|
||||||
== text-layout-08.svg text-layout-08-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
|
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
|
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-02a.html text-stroke-scaling-02-ref.html # antialiasing
|
||||||
fuzzy(16,3) == text-stroke-scaling-02b.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
|
== 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
|
== textPath-02.svg pass.svg
|
||||||
fuzzy-if(skiaContent,1,610) == textPath-03.svg pass.svg
|
fuzzy-if(skiaContent,1,610) == textPath-03.svg pass.svg
|
||||||
== textPath-04.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
|
== anim-css-fontsize-1-from-to-px-px.svg anim-css-fontsize-1-ref.svg
|
||||||
|
|
||||||
# 'font-size' property (accepts unitless values)
|
# 'font-size' property (accepts unitless values)
|
||||||
fails-if(stylo) == anim-css-fontsize-1-from-to-no-no.svg anim-css-fontsize-1-ref.svg
|
== 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
|
== 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-px-no.svg anim-css-fontsize-1-ref.svg
|
||||||
|
|
||||||
# 'font-size' mapped attribute (accepts unitless values)
|
# '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
|
== 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
|
== 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-px-no.svg anim-css-fontsize-1-ref.svg
|
||||||
|
|
||||||
# 'font-size' property, from/by/to with percent values
|
# '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
|
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
|
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();
|
PreTraverse();
|
||||||
|
|
||||||
// Restyle the document from the root element and each of the document level
|
// Restyle the document from the root element and each of the document level
|
||||||
|
@ -836,7 +842,7 @@ ServoStyleSet::StyleDocument()
|
||||||
while (Element* root = iter.GetNextStyleRoot()) {
|
while (Element* root = iter.GetNextStyleRoot()) {
|
||||||
if (PrepareAndTraverseSubtree(root,
|
if (PrepareAndTraverseSubtree(root,
|
||||||
TraversalRootBehavior::Normal,
|
TraversalRootBehavior::Normal,
|
||||||
TraversalRestyleBehavior::Normal)) {
|
aRestyleBehavior)) {
|
||||||
postTraversalRequired = true;
|
postTraversalRequired = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -230,9 +230,14 @@ public:
|
||||||
* This will traverse all of the document's style roots (that is, its document
|
* 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).
|
* 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.
|
* 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
|
* 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.
|
// hints, which is what's required when handling frame reconstruction.
|
||||||
// The change hints in this case are unneeded, since the old frames have
|
// The change hints in this case are unneeded, since the old frames have
|
||||||
// already been destroyed.
|
// already been destroyed.
|
||||||
|
// Indicates how the Servo style system should perform.
|
||||||
enum class TraversalRestyleBehavior {
|
enum class TraversalRestyleBehavior {
|
||||||
|
// Normal processing.
|
||||||
Normal,
|
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,
|
ForReconstruct,
|
||||||
|
// Processes animation-only restyle.
|
||||||
ForAnimationOnly,
|
ForAnimationOnly,
|
||||||
|
// Traverses as normal mode but tries to update all CSS animations.
|
||||||
|
ForCSSRuleChanges,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Represents which tasks are performed in a SequentialTask of UpdateAnimations.
|
// Represents which tasks are performed in a SequentialTask of UpdateAnimations.
|
||||||
|
|
|
@ -176,9 +176,10 @@ nsDOMCSSAttributeDeclaration::GetCSSParsingEnvironment(CSSParsingEnvironment& aC
|
||||||
nsDOMCSSDeclaration::ServoCSSParsingEnvironment
|
nsDOMCSSDeclaration::ServoCSSParsingEnvironment
|
||||||
nsDOMCSSAttributeDeclaration::GetServoCSSParsingEnvironment() const
|
nsDOMCSSAttributeDeclaration::GetServoCSSParsingEnvironment() const
|
||||||
{
|
{
|
||||||
ServoCSSParsingEnvironment parsingEnv(mElement->GetURLDataForStyleAttr(),
|
return {
|
||||||
mElement->OwnerDoc()->GetCompatibilityMode());
|
mElement->GetURLDataForStyleAttr(),
|
||||||
return parsingEnv;
|
mElement->OwnerDoc()->GetCompatibilityMode(),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
|
|
|
@ -285,16 +285,20 @@ nsDOMCSSDeclaration::GetServoCSSParsingEnvironmentForRule(const css::Rule* aRule
|
||||||
{
|
{
|
||||||
StyleSheet* sheet = aRule ? aRule->GetStyleSheet() : nullptr;
|
StyleSheet* sheet = aRule ? aRule->GetStyleSheet() : nullptr;
|
||||||
if (!sheet) {
|
if (!sheet) {
|
||||||
return ServoCSSParsingEnvironment(nullptr, eCompatibility_FullStandards);
|
return { nullptr, eCompatibility_FullStandards };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nsIDocument* document = aRule->GetDocument()) {
|
if (nsIDocument* document = aRule->GetDocument()) {
|
||||||
return ServoCSSParsingEnvironment(sheet->AsServo()->URLData(),
|
return {
|
||||||
document->GetCompatibilityMode());
|
sheet->AsServo()->URLData(),
|
||||||
} else {
|
document->GetCompatibilityMode(),
|
||||||
return ServoCSSParsingEnvironment(sheet->AsServo()->URLData(),
|
};
|
||||||
eCompatibility_FullStandards);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
sheet->AsServo()->URLData(),
|
||||||
|
eCompatibility_FullStandards,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename GeckoFunc, typename ServoFunc>
|
template<typename GeckoFunc, typename ServoFunc>
|
||||||
|
|
|
@ -149,12 +149,16 @@ protected:
|
||||||
};
|
};
|
||||||
|
|
||||||
// Information neded to parse a declaration for Servo side.
|
// Information neded to parse a declaration for Servo side.
|
||||||
struct MOZ_STACK_CLASS ServoCSSParsingEnvironment {
|
struct MOZ_STACK_CLASS ServoCSSParsingEnvironment
|
||||||
|
{
|
||||||
mozilla::URLExtraData* mUrlExtraData;
|
mozilla::URLExtraData* mUrlExtraData;
|
||||||
nsCompatibility mCompatMode;
|
nsCompatibility mCompatMode;
|
||||||
|
|
||||||
ServoCSSParsingEnvironment(mozilla::URLExtraData* aUrlData, nsCompatibility aCompatMode)
|
ServoCSSParsingEnvironment(mozilla::URLExtraData* aUrlData,
|
||||||
: mUrlExtraData(aUrlData), mCompatMode(aCompatMode) {}
|
nsCompatibility aCompatMode)
|
||||||
|
: mUrlExtraData(aUrlData)
|
||||||
|
, mCompatMode(aCompatMode)
|
||||||
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
// On failure, mPrincipal should be set to null in aCSSParseEnv.
|
// 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]
|
* test_webkit_device_pixel_ratio.html: -webkit-device-pixel-ratio [3]
|
||||||
* browser_bug453896.js [8]
|
* browser_bug453896.js [8]
|
||||||
* Animation support:
|
* Animation support:
|
||||||
* test_animations.html [3]
|
* test_animations.html [1]
|
||||||
* test_animations_dynamic_changes.html [1]
|
* test_animations_dynamic_changes.html [1]
|
||||||
* test_bug716226.html [3]
|
* test_bug716226.html [3]
|
||||||
* inserting keyframes rule doesn't trigger restyle bug 1364799:
|
|
||||||
* test_rule_insertion.html `@keyframes` [36]
|
|
||||||
* OMTA
|
* OMTA
|
||||||
* test_animations_omta.html: bug 1361938, bug 1361663 [88]
|
* test_animations_omta.html: bug 1361938, bug 1361663 [85]
|
||||||
* SMIL Animation
|
* SMIL Animation
|
||||||
* test_restyles_in_smil_animation.html [2]
|
* test_restyles_in_smil_animation.html [2]
|
||||||
* CSSOM support:
|
* CSSOM support:
|
||||||
|
|
|
@ -86,6 +86,22 @@ public class ActionBarPresenter {
|
||||||
initIndicator();
|
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.
|
* To display Url in CustomView only and immediately.
|
||||||
*
|
*
|
||||||
|
|
|
@ -231,12 +231,14 @@ public class CustomTabsActivity extends SingleTabActivity implements Tabs.OnTabs
|
||||||
public void onResume() {
|
public void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
mLayerView.getDynamicToolbarAnimator().setPinned(true, PinReason.CUSTOM_TAB);
|
mLayerView.getDynamicToolbarAnimator().setPinned(true, PinReason.CUSTOM_TAB);
|
||||||
|
actionBarPresenter.onResume();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPause() {
|
public void onPause() {
|
||||||
super.onPause();
|
super.onPause();
|
||||||
mLayerView.getDynamicToolbarAnimator().setPinned(false, PinReason.CUSTOM_TAB);
|
mLayerView.getDynamicToolbarAnimator().setPinned(false, PinReason.CUSTOM_TAB);
|
||||||
|
actionBarPresenter.onPause();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Usually should use onCreateOptionsMenu() to initialize menu items. But GeckoApp overwrite
|
// 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();
|
mContentButtonClickListener = new ContentNotificationButtonListener();
|
||||||
}
|
}
|
||||||
|
|
||||||
void registerListeners() {
|
public void registerListeners() {
|
||||||
EventDispatcher.getInstance().registerUiThreadListener(this,
|
EventDispatcher.getInstance().registerUiThreadListener(this,
|
||||||
"Doorhanger:Logins",
|
"Doorhanger:Logins",
|
||||||
"Permissions:CheckResult");
|
"Permissions:CheckResult");
|
||||||
|
@ -540,7 +540,7 @@ public class SiteIdentityPopup extends AnchoredPopup implements BundleEventListe
|
||||||
void destroy() {
|
void destroy() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void unregisterListeners() {
|
public void unregisterListeners() {
|
||||||
EventDispatcher.getInstance().unregisterUiThreadListener(this,
|
EventDispatcher.getInstance().unregisterUiThreadListener(this,
|
||||||
"Doorhanger:Logins",
|
"Doorhanger:Logins",
|
||||||
"Permissions:CheckResult");
|
"Permissions:CheckResult");
|
||||||
|
|
|
@ -5072,12 +5072,6 @@ pref("dom.idle-observers-api.fuzz_time.disabled", true);
|
||||||
// a restart is required to enable a new value.
|
// a restart is required to enable a new value.
|
||||||
pref("network.activity.blipIntervalMilliseconds", 0);
|
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
|
// 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.
|
// event loop to become idle before actually taking the screenshot.
|
||||||
pref("dom.browserElement.maxScreenshotDelayMS", 2000);
|
pref("dom.browserElement.maxScreenshotDelayMS", 2000);
|
||||||
|
|
|
@ -998,7 +998,7 @@ dependencies = [
|
||||||
"fontsan 0.3.2 (git+https://github.com/servo/fontsan)",
|
"fontsan 0.3.2 (git+https://github.com/servo/fontsan)",
|
||||||
"freetype 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"freetype 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"gfx_traits 0.0.1",
|
"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 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)",
|
"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)",
|
"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]]
|
[[package]]
|
||||||
name = "harfbuzz-sys"
|
name = "harfbuzz-sys"
|
||||||
version = "0.1.7"
|
version = "0.1.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cmake 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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)",
|
"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"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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]]
|
[[package]]
|
||||||
name = "servo-fontconfig-sys"
|
name = "servo-fontconfig-sys"
|
||||||
version = "4.0.2"
|
version = "4.0.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"expat-sys 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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)",
|
"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-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-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)",
|
"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)",
|
"x11 2.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -3160,7 +3161,7 @@ name = "unicode-script"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
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]]
|
[[package]]
|
||||||
|
@ -3538,7 +3539,7 @@ dependencies = [
|
||||||
"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
|
"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 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 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 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 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"
|
"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 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-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 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-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-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"
|
"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::point::Point2D;
|
||||||
use euclid::rect::Rect;
|
use euclid::rect::Rect;
|
||||||
use euclid::size::Size2D;
|
use euclid::size::Size2D;
|
||||||
use std::i32;
|
|
||||||
|
|
||||||
// Units for use with euclid::length and euclid::scale_factor.
|
// Units for use with euclid::length and euclid::scale_factor.
|
||||||
|
|
||||||
|
|
|
@ -17,12 +17,17 @@ use servo_config::opts;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::sync::atomic::{AtomicIsize, Ordering};
|
use std::sync::atomic::{AtomicIsize, Ordering};
|
||||||
use style::dom::UnsafeNode;
|
use style::dom::UnsafeNode;
|
||||||
use style::parallel::CHUNK_SIZE;
|
|
||||||
use traversal::{AssignISizes, BubbleISizes};
|
use traversal::{AssignISizes, BubbleISizes};
|
||||||
use traversal::AssignBSizes;
|
use traversal::AssignBSizes;
|
||||||
|
|
||||||
pub use style::parallel::traverse_dom;
|
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)]
|
#[allow(dead_code)]
|
||||||
fn static_assertion(node: UnsafeNode) {
|
fn static_assertion(node: UnsafeNode) {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
use dom::TNode;
|
use dom::TNode;
|
||||||
use properties::{DeclaredValue, PropertyDeclaration};
|
use properties::{DeclaredValue, PropertyDeclaration};
|
||||||
use values::HasViewportPercentage;
|
use style_traits::HasViewportPercentage;
|
||||||
|
|
||||||
/// A structure to collect information about the cascade.
|
/// A structure to collect information about the cascade.
|
||||||
///
|
///
|
||||||
|
|
|
@ -14,7 +14,7 @@ use std::ascii::AsciiExt;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use style_traits::ToCss;
|
use style_traits::{HasViewportPercentage, ToCss};
|
||||||
use stylearc::Arc;
|
use stylearc::Arc;
|
||||||
|
|
||||||
/// A custom property name is just an `Atom`.
|
/// A custom property name is just an `Atom`.
|
||||||
|
@ -49,7 +49,7 @@ pub struct SpecifiedValue {
|
||||||
references: HashSet<Name>,
|
references: HashSet<Name>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::values::HasViewportPercentage for SpecifiedValue {
|
impl HasViewportPercentage for SpecifiedValue {
|
||||||
fn has_viewport_percentage(&self) -> bool {
|
fn has_viewport_percentage(&self) -> bool {
|
||||||
panic!("has_viewport_percentage called before resolving!");
|
panic!("has_viewport_percentage called before resolving!");
|
||||||
}
|
}
|
||||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -366,6 +366,7 @@ trait PrivateMatchMethods: TElement {
|
||||||
|
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
fn needs_animations_update(&self,
|
fn needs_animations_update(&self,
|
||||||
|
context: &mut StyleContext<Self>,
|
||||||
old_values: Option<&Arc<ComputedValues>>,
|
old_values: Option<&Arc<ComputedValues>>,
|
||||||
new_values: &ComputedValues)
|
new_values: &ComputedValues)
|
||||||
-> bool {
|
-> bool {
|
||||||
|
@ -378,7 +379,10 @@ trait PrivateMatchMethods: TElement {
|
||||||
let old_box_style = old.get_box();
|
let old_box_style = old.get_box();
|
||||||
let old_display_style = old_box_style.clone_display();
|
let old_display_style = old_box_style.clone_display();
|
||||||
let new_display_style = new_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_box_style.animations_equals(&new_box_style) ||
|
||||||
(old_display_style == display::T::none &&
|
(old_display_style == display::T::none &&
|
||||||
new_display_style != display::T::none &&
|
new_display_style != display::T::none &&
|
||||||
|
@ -400,7 +404,7 @@ trait PrivateMatchMethods: TElement {
|
||||||
use context::UpdateAnimationsTasks;
|
use context::UpdateAnimationsTasks;
|
||||||
|
|
||||||
let mut tasks = UpdateAnimationsTasks::empty();
|
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);
|
tasks.insert(CSS_ANIMATIONS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,16 +26,38 @@ use context::TraversalStatistics;
|
||||||
use dom::{OpaqueNode, SendNode, TElement, TNode};
|
use dom::{OpaqueNode, SendNode, TElement, TNode};
|
||||||
use rayon;
|
use rayon;
|
||||||
use scoped_tls::ScopedTLS;
|
use scoped_tls::ScopedTLS;
|
||||||
|
use sharing::STYLE_SHARING_CANDIDATE_CACHE_SIZE;
|
||||||
|
use smallvec::SmallVec;
|
||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
|
use std::mem;
|
||||||
use time;
|
use time;
|
||||||
use traversal::{DomTraversal, PerLevelTraversalData, PreTraverseToken};
|
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.
|
/// Larger values will increase style sharing cache hits and general DOM locality
|
||||||
pub const CHUNK_SIZE: usize = 64;
|
/// 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)]
|
#[allow(unsafe_code)]
|
||||||
pub fn traverse_dom<E, D>(traversal: &D,
|
pub fn traverse_dom<E, D>(traversal: &D,
|
||||||
root: E,
|
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 dump_stats = traversal.shared_context().options.dump_style_statistics;
|
||||||
let start_time = if dump_stats { Some(time::precise_time_s()) } else { None };
|
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());
|
debug_assert!(traversal.is_parallel());
|
||||||
// Handle Gecko's eager initial styling. We don't currently support it
|
// 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
|
// 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.
|
// 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());
|
debug_assert!(!D::needs_postorder_traversal());
|
||||||
let mut children = vec![];
|
|
||||||
for kid in root.as_node().children() {
|
for kid in root.as_node().children() {
|
||||||
if kid.as_element().map_or(false, |el| el.get_data().is_none()) {
|
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 {
|
} 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 {
|
let traversal_data = PerLevelTraversalData {
|
||||||
current_dom_depth: depth,
|
current_dom_depth: depth,
|
||||||
};
|
};
|
||||||
|
@ -72,7 +99,13 @@ pub fn traverse_dom<E, D>(traversal: &D,
|
||||||
|
|
||||||
queue.install(|| {
|
queue.install(|| {
|
||||||
rayon::scope(|scope| {
|
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.
|
/// 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)]
|
#[inline(always)]
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
fn top_down_dom<'a, 'scope, E, D>(nodes: &'a [SendNode<E::ConcreteNode>],
|
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,
|
where E: TElement + 'scope,
|
||||||
D: DomTraversal<E>,
|
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
|
// 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());
|
let mut tlc = tls.ensure(|| traversal.create_thread_local_context());
|
||||||
|
|
||||||
for n in nodes {
|
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 node = **n;
|
||||||
let mut children_to_process = 0isize;
|
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() {
|
if let Some(el) = node.as_element() {
|
||||||
traversal.traverse_children(&mut *tlc, el, |_tlc, kid| {
|
traversal.traverse_children(&mut *tlc, el, |_tlc, kid| {
|
||||||
children_to_process += 1;
|
children_to_process += 1;
|
||||||
|
@ -127,11 +196,37 @@ fn top_down_dom<'a, 'scope, E, D>(nodes: &'a [SendNode<E::ConcreteNode>],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
traversal_data.current_dom_depth += 1;
|
// Handle the children of the last element in this work unit. If any exist,
|
||||||
traverse_nodes(discovered_child_nodes, root, traversal_data, scope, traversal, tls);
|
// 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,
|
||||||
|
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,
|
traversal_data: PerLevelTraversalData,
|
||||||
scope: &'a rayon::Scope<'scope>,
|
scope: &'a rayon::Scope<'scope>,
|
||||||
traversal: &'scope D,
|
traversal: &'scope D,
|
||||||
|
@ -139,25 +234,44 @@ fn traverse_nodes<'a, 'scope, E, D>(nodes: Vec<SendNode<E::ConcreteNode>>, root:
|
||||||
where E: TElement + 'scope,
|
where E: TElement + 'scope,
|
||||||
D: DomTraversal<E>,
|
D: DomTraversal<E>,
|
||||||
{
|
{
|
||||||
if nodes.is_empty() {
|
debug_assert!(!nodes.is_empty());
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Optimization: traverse directly and avoid a heap-allocating spawn() call if
|
// In the common case, our children fit within a single work unit, in which
|
||||||
// we're only pushing one work unit.
|
// case we can pass the SmallVec directly and avoid extra allocation.
|
||||||
if nodes.len() <= CHUNK_SIZE {
|
if nodes.len() <= WORK_UNIT_MAX {
|
||||||
let nodes = nodes.into_boxed_slice();
|
if mode.is_tail_call() {
|
||||||
top_down_dom(&nodes, root, traversal_data, scope, traversal, tls);
|
// If this is a tail call, bypass rayon and invoke top_down_dom directly.
|
||||||
return;
|
top_down_dom(&nodes, root, traversal_data, scope, traversal, tls);
|
||||||
}
|
} 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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} 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)
|
||||||
|
});
|
||||||
|
|
||||||
// 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();
|
// If this is a tail call, bypass rayon for the first chunk and invoke top_down_dom
|
||||||
scope.spawn(move |scope| {
|
// directly.
|
||||||
let nodes = nodes;
|
debug_assert_eq!(first_chunk.is_some(), mode.is_tail_call());
|
||||||
top_down_dom(&nodes, root, traversal_data, scope, traversal, tls)
|
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) {
|
pub fn copy_${shorthand}_${name}_from(&mut self, other: &Self) {
|
||||||
use gecko_bindings::structs::nsStyleImageLayers_LayerType as LayerType;
|
use gecko_bindings::structs::nsStyleImageLayers_LayerType as LayerType;
|
||||||
|
|
||||||
|
let count = other.gecko.${image_layers_field}.${field_name}Count;
|
||||||
unsafe {
|
unsafe {
|
||||||
Gecko_EnsureImageLayersLength(&mut self.gecko.${image_layers_field},
|
Gecko_EnsureImageLayersLength(&mut self.gecko.${image_layers_field},
|
||||||
other.gecko.${image_layers_field}.mLayers.len(),
|
count as usize,
|
||||||
LayerType::${shorthand.title()});
|
LayerType::${shorthand.title()});
|
||||||
}
|
}
|
||||||
for (layer, other) in self.gecko.${image_layers_field}.mLayers.iter_mut()
|
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(other.gecko.${image_layers_field}
|
.take(count as usize) {
|
||||||
.${field_name}Count as usize) {
|
|
||||||
layer.${field_name} = other.${field_name};
|
layer.${field_name} = other.${field_name};
|
||||||
}
|
}
|
||||||
self.gecko.${image_layers_field}.${field_name}Count =
|
self.gecko.${image_layers_field}.${field_name}Count = count;
|
||||||
other.gecko.${image_layers_field}.${field_name}Count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2874,23 +2873,21 @@ fn static_assert() {
|
||||||
pub fn copy_${shorthand}_position_${orientation}_from(&mut self, other: &Self) {
|
pub fn copy_${shorthand}_position_${orientation}_from(&mut self, other: &Self) {
|
||||||
use gecko_bindings::structs::nsStyleImageLayers_LayerType as LayerType;
|
use gecko_bindings::structs::nsStyleImageLayers_LayerType as LayerType;
|
||||||
|
|
||||||
self.gecko.${image_layers_field}.mPosition${orientation.upper()}Count
|
let count = other.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;
|
|
||||||
unsafe {
|
unsafe {
|
||||||
Gecko_EnsureImageLayersLength(&mut self.gecko.${image_layers_field},
|
Gecko_EnsureImageLayersLength(&mut self.gecko.${image_layers_field},
|
||||||
other.gecko.${image_layers_field}.mLayers.len(),
|
count as usize,
|
||||||
LayerType::${shorthand.capitalize()});
|
LayerType::${shorthand.capitalize()});
|
||||||
}
|
}
|
||||||
|
|
||||||
for (layer, other) in self.gecko.${image_layers_field}.mLayers.iter_mut()
|
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
|
layer.mPosition.m${orientation.upper()}Position
|
||||||
= other.mPosition.m${orientation.upper()}Position;
|
= other.mPosition.m${orientation.upper()}Position;
|
||||||
}
|
}
|
||||||
self.gecko.${image_layers_field}.mPosition${orientation.upper()}Count
|
self.gecko.${image_layers_field}.mPosition${orientation.upper()}Count = count;
|
||||||
= other.gecko.${image_layers_field}.mPosition${orientation.upper()}Count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clone_${shorthand}_position_${orientation}(&self)
|
pub fn clone_${shorthand}_position_${orientation}(&self)
|
||||||
|
|
|
@ -82,7 +82,7 @@
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use values::HasViewportPercentage;
|
use style_traits::HasViewportPercentage;
|
||||||
use style_traits::ToCss;
|
use style_traits::ToCss;
|
||||||
|
|
||||||
pub mod single_value {
|
pub mod single_value {
|
||||||
|
|
|
@ -87,8 +87,8 @@ ${helpers.predefined_type("clip",
|
||||||
spec="https://drafts.fxtf.org/filters/#propdef-filter">
|
spec="https://drafts.fxtf.org/filters/#propdef-filter">
|
||||||
//pub use self::computed_value::T as SpecifiedValue;
|
//pub use self::computed_value::T as SpecifiedValue;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use style_traits::ToCss;
|
use style_traits::{HasViewportPercentage, ToCss};
|
||||||
use values::{CSSFloat, HasViewportPercentage};
|
use values::CSSFloat;
|
||||||
use values::specified::{Angle, Length};
|
use values::specified::{Angle, Length};
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
use values::specified::Shadow;
|
use values::specified::Shadow;
|
||||||
|
|
|
@ -550,8 +550,8 @@ ${helpers.single_keyword_system("font-variant-caps",
|
||||||
use properties::longhands::system_font::SystemFont;
|
use properties::longhands::system_font::SystemFont;
|
||||||
use properties::style_structs::Font;
|
use properties::style_structs::Font;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use style_traits::ToCss;
|
use style_traits::{HasViewportPercentage, ToCss};
|
||||||
use values::{FONT_MEDIUM_PX, HasViewportPercentage};
|
use values::FONT_MEDIUM_PX;
|
||||||
use values::specified::{AllowQuirks, FontRelativeLength, LengthOrPercentage};
|
use values::specified::{AllowQuirks, FontRelativeLength, LengthOrPercentage};
|
||||||
use values::specified::{NoCalcLength, Percentage};
|
use values::specified::{NoCalcLength, Percentage};
|
||||||
use values::specified::length::FontBaseSize;
|
use values::specified::length::FontBaseSize;
|
||||||
|
|
|
@ -34,10 +34,10 @@ use parser::{PARSING_MODE_DEFAULT, Parse, ParserContext};
|
||||||
use properties::animated_properties::TransitionProperty;
|
use properties::animated_properties::TransitionProperty;
|
||||||
#[cfg(feature = "servo")] use servo_config::prefs::PREFS;
|
#[cfg(feature = "servo")] use servo_config::prefs::PREFS;
|
||||||
use shared_lock::StylesheetGuards;
|
use shared_lock::StylesheetGuards;
|
||||||
use style_traits::ToCss;
|
use style_traits::{HasViewportPercentage, ToCss};
|
||||||
use stylesheets::{CssRuleType, Origin, UrlExtraData};
|
use stylesheets::{CssRuleType, Origin, UrlExtraData};
|
||||||
#[cfg(feature = "servo")] use values::Either;
|
#[cfg(feature = "servo")] use values::Either;
|
||||||
use values::{HasViewportPercentage, computed};
|
use values::computed;
|
||||||
use cascade_info::CascadeInfo;
|
use cascade_info::CascadeInfo;
|
||||||
use rule_tree::StrongRuleNode;
|
use rule_tree::StrongRuleNode;
|
||||||
use style_adjuster::StyleAdjuster;
|
use style_adjuster::StyleAdjuster;
|
||||||
|
|
|
@ -37,6 +37,10 @@ bitflags! {
|
||||||
const ANIMATION_ONLY = 0x02,
|
const ANIMATION_ONLY = 0x02,
|
||||||
/// Traverse without generating any change hints.
|
/// Traverse without generating any change hints.
|
||||||
const FOR_RECONSTRUCT = 0x04,
|
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 {
|
pub fn for_reconstruct(&self) -> bool {
|
||||||
self.contains(FOR_RECONSTRUCT)
|
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
|
/// This structure exists to enforce that callers invoke pre_traverse, and also
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
//! Computed values.
|
//! Computed values.
|
||||||
|
|
||||||
|
use Atom;
|
||||||
use context::QuirksMode;
|
use context::QuirksMode;
|
||||||
use euclid::size::Size2D;
|
use euclid::size::Size2D;
|
||||||
use font_metrics::FontMetricsProvider;
|
use font_metrics::FontMetricsProvider;
|
||||||
|
@ -154,6 +155,79 @@ pub trait ToComputedValue {
|
||||||
fn from_computed_value(computed: &Self::ComputedValue) -> Self;
|
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
|
/// A marker trait to represent that the specified value is also the computed
|
||||||
/// value.
|
/// value.
|
||||||
pub trait ComputedValueAsSpecified {}
|
pub trait ComputedValueAsSpecified {}
|
||||||
|
@ -174,6 +248,9 @@ impl<T> ToComputedValue for T
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ComputedValueAsSpecified for Atom {}
|
||||||
|
impl ComputedValueAsSpecified for bool {}
|
||||||
|
|
||||||
/// A computed `<angle>` value.
|
/// A computed `<angle>` value.
|
||||||
#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, PartialOrd)]
|
#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, PartialOrd)]
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))]
|
||||||
|
|
|
@ -11,16 +11,15 @@ use parser::{Parse, ParserContext};
|
||||||
use properties::shorthands::serialize_four_sides;
|
use properties::shorthands::serialize_four_sides;
|
||||||
use std::ascii::AsciiExt;
|
use std::ascii::AsciiExt;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use style_traits::ToCss;
|
use style_traits::{HasViewportPercentage, ToCss};
|
||||||
use values::HasViewportPercentage;
|
use values::computed::ComputedValueAsSpecified;
|
||||||
use values::computed::{ComputedValueAsSpecified, Context, ToComputedValue};
|
|
||||||
use values::generics::BorderRadiusSize;
|
use values::generics::BorderRadiusSize;
|
||||||
use values::specified::url::SpecifiedUrl;
|
use values::specified::url::SpecifiedUrl;
|
||||||
|
|
||||||
/// A generic type used for `border-radius`, `outline-radius` and `inset()` values.
|
/// A generic type used for `border-radius`, `outline-radius` and `inset()` values.
|
||||||
///
|
///
|
||||||
/// https://drafts.csswg.org/css-backgrounds-3/#border-radius
|
/// https://drafts.csswg.org/css-backgrounds-3/#border-radius
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
#[derive(Clone, Debug, PartialEq, ToComputedValue)]
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
pub struct BorderRadius<L> {
|
pub struct BorderRadius<L> {
|
||||||
/// The top left radius.
|
/// 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
|
/// https://drafts.csswg.org/css-shapes/#typedef-shape-radius
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
#[derive(Clone, Debug, PartialEq, ToComputedValue)]
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
pub enum ShapeRadius<L> {
|
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
|
// https://drafts.csswg.org/css-shapes/#typedef-fill-rule
|
||||||
// NOTE: Basic shapes spec says that these are the only two values, however
|
// NOTE: Basic shapes spec says that these are the only two values, however
|
||||||
// https://www.w3.org/TR/SVG/painting.html#FillRuleProperty
|
// https://www.w3.org/TR/SVG/painting.html#FillRuleProperty
|
||||||
|
@ -148,7 +101,7 @@ impl Default for FillRule {
|
||||||
fn default() -> Self { FillRule::NonZero }
|
fn default() -> Self { FillRule::NonZero }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
#[derive(Clone, Debug, PartialEq, ToComputedValue)]
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
/// A generic type for representing the `polygon()` function
|
/// 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> {
|
#[derive(Clone, Debug, PartialEq, ToComputedValue)]
|
||||||
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)]
|
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
/// https://drafts.csswg.org/css-shapes/#funcdef-inset
|
/// https://drafts.csswg.org/css-shapes/#funcdef-inset
|
||||||
#[allow(missing_docs)]
|
#[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
|
/// A shape source, for some reference box
|
||||||
///
|
///
|
||||||
/// `clip-path` uses ShapeSource<BasicShape, GeometryBox>,
|
/// `clip-path` uses ShapeSource<BasicShape, GeometryBox>,
|
||||||
/// `shape-outside` uses ShapeSource<BasicShape, ShapeBox>
|
/// `shape-outside` uses ShapeSource<BasicShape, ShapeBox>
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
#[derive(Clone, Debug, PartialEq, ToComputedValue)]
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
pub enum ShapeSource<B, T> {
|
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(())
|
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 Atom;
|
||||||
use cssparser::serialize_identifier;
|
use cssparser::serialize_identifier;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use style_traits::ToCss;
|
use style_traits::{HasViewportPercentage, ToCss};
|
||||||
use values::HasViewportPercentage;
|
use values::computed::ComputedValueAsSpecified;
|
||||||
use values::computed::{Context, ToComputedValue};
|
|
||||||
use values::specified::url::SpecifiedUrl;
|
use values::specified::url::SpecifiedUrl;
|
||||||
|
|
||||||
/// An [image].
|
/// An [image].
|
||||||
///
|
///
|
||||||
/// [image]: https://drafts.csswg.org/css-images/#image-values
|
/// [image]: https://drafts.csswg.org/css-images/#image-values
|
||||||
#[derive(Clone, PartialEq)]
|
#[derive(Clone, PartialEq, ToComputedValue)]
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
pub enum Image<Gradient, ImageRect> {
|
pub enum Image<Gradient, ImageRect> {
|
||||||
/// A `<url()>` image.
|
/// A `<url()>` image.
|
||||||
|
@ -32,7 +31,7 @@ pub enum Image<Gradient, ImageRect> {
|
||||||
|
|
||||||
/// A CSS gradient.
|
/// A CSS gradient.
|
||||||
/// https://drafts.csswg.org/css-images/#gradients
|
/// https://drafts.csswg.org/css-images/#gradients
|
||||||
#[derive(Clone, Debug, HasViewportPercentage, PartialEq)]
|
#[derive(Clone, Debug, HasViewportPercentage, PartialEq, ToComputedValue)]
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
pub struct Gradient<LineDirection, Length, LengthOrPercentage, Position, Color> {
|
pub struct Gradient<LineDirection, Length, LengthOrPercentage, Position, Color> {
|
||||||
/// Gradients can be linear or radial.
|
/// Gradients can be linear or radial.
|
||||||
|
@ -45,7 +44,7 @@ pub struct Gradient<LineDirection, Length, LengthOrPercentage, Position, Color>
|
||||||
pub compat_mode: CompatMode,
|
pub compat_mode: CompatMode,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq)]
|
#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue)]
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
/// Whether we used the modern notation or the compatibility `-webkit` prefix.
|
/// Whether we used the modern notation or the compatibility `-webkit` prefix.
|
||||||
pub enum CompatMode {
|
pub enum CompatMode {
|
||||||
|
@ -56,7 +55,7 @@ pub enum CompatMode {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A gradient kind.
|
/// A gradient kind.
|
||||||
#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq)]
|
#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue)]
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
pub enum GradientKind<LineDirection, Length, LengthOrPercentage, Position> {
|
pub enum GradientKind<LineDirection, Length, LengthOrPercentage, Position> {
|
||||||
/// A linear gradient.
|
/// A linear gradient.
|
||||||
|
@ -66,7 +65,7 @@ pub enum GradientKind<LineDirection, Length, LengthOrPercentage, Position> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A radial gradient's ending shape.
|
/// 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))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
pub enum EndingShape<Length, LengthOrPercentage> {
|
pub enum EndingShape<Length, LengthOrPercentage> {
|
||||||
/// A circular gradient.
|
/// A circular gradient.
|
||||||
|
@ -76,7 +75,7 @@ pub enum EndingShape<Length, LengthOrPercentage> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A circle shape.
|
/// A circle shape.
|
||||||
#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq)]
|
#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue)]
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
pub enum Circle<Length> {
|
pub enum Circle<Length> {
|
||||||
/// A circle radius.
|
/// A circle radius.
|
||||||
|
@ -86,7 +85,7 @@ pub enum Circle<Length> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An ellipse shape.
|
/// An ellipse shape.
|
||||||
#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq)]
|
#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue)]
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
pub enum Ellipse<LengthOrPercentage> {
|
pub enum Ellipse<LengthOrPercentage> {
|
||||||
/// An ellipse pair of radii.
|
/// An ellipse pair of radii.
|
||||||
|
@ -105,10 +104,11 @@ define_css_keyword_enum!(ShapeExtent:
|
||||||
"cover" => Cover
|
"cover" => Cover
|
||||||
);
|
);
|
||||||
no_viewport_percentage!(ShapeExtent);
|
no_viewport_percentage!(ShapeExtent);
|
||||||
|
impl ComputedValueAsSpecified for ShapeExtent {}
|
||||||
|
|
||||||
/// A gradient item.
|
/// A gradient item.
|
||||||
/// https://drafts.csswg.org/css-images-4/#color-stop-syntax
|
/// 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))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
pub enum GradientItem<Color, LengthOrPercentage> {
|
pub enum GradientItem<Color, LengthOrPercentage> {
|
||||||
/// A color stop.
|
/// A color stop.
|
||||||
|
@ -119,7 +119,7 @@ pub enum GradientItem<Color, LengthOrPercentage> {
|
||||||
|
|
||||||
/// A color stop.
|
/// A color stop.
|
||||||
/// https://drafts.csswg.org/css-images/#typedef-color-stop-list
|
/// 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))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
pub struct ColorStop<Color, LengthOrPercentage> {
|
pub struct ColorStop<Color, LengthOrPercentage> {
|
||||||
/// The color of this stop.
|
/// The color of this stop.
|
||||||
|
@ -131,7 +131,7 @@ pub struct ColorStop<Color, LengthOrPercentage> {
|
||||||
/// Values for `moz-image-rect`.
|
/// Values for `moz-image-rect`.
|
||||||
///
|
///
|
||||||
/// `-moz-image-rect(<uri>, top, right, bottom, left);`
|
/// `-moz-image-rect(<uri>, top, right, bottom, left);`
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
#[derive(Clone, Debug, PartialEq, ToComputedValue)]
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
pub struct ImageRect<NumberOrPercentage> {
|
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>
|
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,
|
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> {
|
impl<D, L, LoP, P> GradientKind<D, L, LoP, P> {
|
||||||
fn label(&self) -> &str {
|
fn label(&self) -> &str {
|
||||||
match *self {
|
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.
|
/// The direction of a linear gradient.
|
||||||
pub trait LineDirection {
|
pub trait LineDirection {
|
||||||
/// Whether this direction points towards, and thus can be omitted.
|
/// 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>
|
impl<C, L> ToCss for GradientItem<C, L>
|
||||||
where C: ToCss, L: ToCss,
|
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>
|
impl<C, L> fmt::Debug for ColorStop<C, L>
|
||||||
where C: fmt::Debug, L: fmt::Debug,
|
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>
|
impl<C> ToCss for ImageRect<C>
|
||||||
where C: ToCss,
|
where C: ToCss,
|
||||||
{
|
{
|
||||||
|
@ -548,29 +341,3 @@ impl<C> ToCss for ImageRect<C>
|
||||||
dest.write_str(")")
|
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 euclid::size::Size2D;
|
||||||
use parser::{Parse, ParserContext};
|
use parser::{Parse, ParserContext};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use style_traits::ToCss;
|
use style_traits::{HasViewportPercentage, ToCss};
|
||||||
use super::CustomIdent;
|
use super::CustomIdent;
|
||||||
use super::HasViewportPercentage;
|
|
||||||
use super::computed::{Context, ToComputedValue};
|
|
||||||
|
|
||||||
pub use self::basic_shape::serialize_radius_values;
|
pub use self::basic_shape::serialize_radius_values;
|
||||||
|
|
||||||
|
@ -21,9 +19,9 @@ pub mod basic_shape;
|
||||||
pub mod image;
|
pub mod image;
|
||||||
pub mod position;
|
pub mod position;
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
#[derive(Clone, Debug, PartialEq, ToComputedValue)]
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[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>);
|
pub struct BorderRadiusSize<L>(pub Size2D<L>);
|
||||||
|
|
||||||
impl<L> HasViewportPercentage for BorderRadiusSize<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
|
/// https://drafts.csswg.org/css-counter-styles/#typedef-counter-style
|
||||||
///
|
///
|
||||||
/// Since wherever <counter-style> is used, 'none' is a valid value as
|
/// 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
|
//! Generic types for CSS handling of specified and computed values of
|
||||||
//! [`position`](https://drafts.csswg.org/css-backgrounds-3/#position)
|
//! [`position`](https://drafts.csswg.org/css-backgrounds-3/#position)
|
||||||
|
|
||||||
use values::computed::{Context, ToComputedValue};
|
#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue)]
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq)]
|
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
/// A generic type for representing a CSS [position](https://drafts.csswg.org/css-values/#position).
|
/// A generic type for representing a CSS [position](https://drafts.csswg.org/css-values/#position).
|
||||||
pub struct Position<H, V> {
|
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::fmt::{self, Debug};
|
||||||
use std::hash;
|
use std::hash;
|
||||||
use style_traits::ToCss;
|
use style_traits::ToCss;
|
||||||
pub use style_traits::HasViewportPercentage;
|
|
||||||
|
|
||||||
pub mod computed;
|
pub mod computed;
|
||||||
pub mod generics;
|
pub mod generics;
|
||||||
|
|
|
@ -11,9 +11,9 @@ use cssparser::{Parser, Token};
|
||||||
use parser::ParserContext;
|
use parser::ParserContext;
|
||||||
use std::ascii::AsciiExt;
|
use std::ascii::AsciiExt;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use style_traits::ToCss;
|
use style_traits::{HasViewportPercentage, ToCss};
|
||||||
use style_traits::values::specified::AllowedLengthType;
|
use style_traits::values::specified::AllowedLengthType;
|
||||||
use values::{CSSInteger, CSSFloat, HasViewportPercentage};
|
use values::{CSSInteger, CSSFloat};
|
||||||
use values::specified::{Angle, Time};
|
use values::specified::{Angle, Time};
|
||||||
use values::specified::length::{FontRelativeLength, NoCalcLength, ViewportPercentageLength};
|
use values::specified::length::{FontRelativeLength, NoCalcLength, ViewportPercentageLength};
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,8 @@ use cssparser::{Parser, Token, serialize_identifier};
|
||||||
use parser::{Parse, ParserContext};
|
use parser::{Parse, ParserContext};
|
||||||
use std::{fmt, mem, usize};
|
use std::{fmt, mem, usize};
|
||||||
use std::ascii::AsciiExt;
|
use std::ascii::AsciiExt;
|
||||||
use style_traits::ToCss;
|
use style_traits::{HasViewportPercentage, ToCss};
|
||||||
use values::{CSSFloat, CustomIdent, Either, HasViewportPercentage};
|
use values::{CSSFloat, CustomIdent, Either};
|
||||||
use values::computed::{self, ComputedValueAsSpecified, Context, ToComputedValue};
|
use values::computed::{self, ComputedValueAsSpecified, Context, ToComputedValue};
|
||||||
use values::specified::{Integer, LengthOrPercentage};
|
use values::specified::{Integer, LengthOrPercentage};
|
||||||
|
|
||||||
|
|
|
@ -14,11 +14,11 @@ use parser::{Parse, ParserContext};
|
||||||
use std::{cmp, fmt, mem};
|
use std::{cmp, fmt, mem};
|
||||||
use std::ascii::AsciiExt;
|
use std::ascii::AsciiExt;
|
||||||
use std::ops::Mul;
|
use std::ops::Mul;
|
||||||
use style_traits::ToCss;
|
use style_traits::{HasViewportPercentage, ToCss};
|
||||||
use style_traits::values::specified::{AllowedLengthType, AllowedNumericType};
|
use style_traits::values::specified::{AllowedLengthType, AllowedNumericType};
|
||||||
use stylesheets::CssRuleType;
|
use stylesheets::CssRuleType;
|
||||||
use super::{AllowQuirks, Number, ToComputedValue};
|
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::ExtremumLength;
|
||||||
use values::computed::{ComputedValueAsSpecified, Context};
|
use values::computed::{ComputedValueAsSpecified, Context};
|
||||||
use values::specified::calc::CalcNode;
|
use values::specified::calc::CalcNode;
|
||||||
|
@ -620,7 +620,8 @@ impl Length {
|
||||||
Token::Dimension(ref value, ref unit) if num_context.is_ok(value.value) =>
|
Token::Dimension(ref value, ref unit) if num_context.is_ok(value.value) =>
|
||||||
Length::parse_dimension(context, value.value, unit),
|
Length::parse_dimension(context, value.value, unit),
|
||||||
Token::Number(ref value) if num_context.is_ok(value.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) {
|
!allow_quirks.allowed(context.quirks_mode) {
|
||||||
return Err(())
|
return Err(())
|
||||||
}
|
}
|
||||||
|
@ -805,9 +806,14 @@ impl LengthOrPercentage {
|
||||||
NoCalcLength::parse_dimension(context, value.value, unit).map(LengthOrPercentage::Length),
|
NoCalcLength::parse_dimension(context, value.value, unit).map(LengthOrPercentage::Length),
|
||||||
Token::Percentage(ref value) if num_context.is_ok(value.unit_value) =>
|
Token::Percentage(ref value) if num_context.is_ok(value.unit_value) =>
|
||||||
Ok(LengthOrPercentage::Percentage(Percentage(value.unit_value))),
|
Ok(LengthOrPercentage::Percentage(Percentage(value.unit_value))),
|
||||||
Token::Number(value) if value.value == 0. ||
|
Token::Number(value) if num_context.is_ok(value.value) => {
|
||||||
(num_context.is_ok(value.value) && allow_quirks.allowed(context.quirks_mode)) =>
|
if value.value != 0. &&
|
||||||
Ok(LengthOrPercentage::Length(NoCalcLength::from_px(value.value))),
|
!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") => {
|
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
|
||||||
let calc = try!(input.parse_nested_block(|i| {
|
let calc = try!(input.parse_nested_block(|i| {
|
||||||
CalcNode::parse_length_or_percentage(context, i, num_context)
|
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) =>
|
Token::Percentage(ref value) if num_context.is_ok(value.unit_value) =>
|
||||||
Ok(LengthOrPercentageOrAuto::Percentage(Percentage(value.unit_value))),
|
Ok(LengthOrPercentageOrAuto::Percentage(Percentage(value.unit_value))),
|
||||||
Token::Number(ref value) if num_context.is_ok(value.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) {
|
!allow_quirks.allowed(context.quirks_mode) {
|
||||||
return Err(())
|
return Err(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,7 @@
|
||||||
use cssparser::Parser;
|
use cssparser::Parser;
|
||||||
use parser::{Parse, ParserContext};
|
use parser::{Parse, ParserContext};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use style_traits::ToCss;
|
use style_traits::{HasViewportPercentage, ToCss};
|
||||||
use values::HasViewportPercentage;
|
|
||||||
use values::computed::{CalcLengthOrPercentage, LengthOrPercentage as ComputedLengthOrPercentage};
|
use values::computed::{CalcLengthOrPercentage, LengthOrPercentage as ComputedLengthOrPercentage};
|
||||||
use values::computed::{Context, ToComputedValue};
|
use values::computed::{Context, ToComputedValue};
|
||||||
use values::generics::position::Position as GenericPosition;
|
use values::generics::position::Position as GenericPosition;
|
||||||
|
|
|
@ -10,9 +10,16 @@ extern crate synstructure;
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
|
|
||||||
mod has_viewport_percentage;
|
mod has_viewport_percentage;
|
||||||
|
mod to_computed_value;
|
||||||
|
|
||||||
#[proc_macro_derive(HasViewportPercentage)]
|
#[proc_macro_derive(HasViewportPercentage)]
|
||||||
pub fn derive_has_viewport_percentage(stream: TokenStream) -> TokenStream {
|
pub fn derive_has_viewport_percentage(stream: TokenStream) -> TokenStream {
|
||||||
let input = syn::parse_derive_input(&stream.to_string()).unwrap();
|
let input = syn::parse_derive_input(&stream.to_string()).unwrap();
|
||||||
has_viewport_percentage::derive(input).to_string().parse().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::supports::parse_condition_or_declaration;
|
||||||
use style::thread_state;
|
use style::thread_state;
|
||||||
use style::timer::Timer;
|
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::traversal::{resolve_style, DomTraversal, TraversalDriver, TraversalFlags};
|
||||||
use style::values::{CustomIdent, KeyframesName};
|
use style::values::{CustomIdent, KeyframesName};
|
||||||
use style_traits::ToCss;
|
use style_traits::ToCss;
|
||||||
|
@ -252,10 +252,11 @@ pub extern "C" fn Servo_TraverseSubtree(root: RawGeckoElementBorrowed,
|
||||||
let traversal_flags = match (root_behavior, restyle_behavior) {
|
let traversal_flags = match (root_behavior, restyle_behavior) {
|
||||||
(Root::Normal, Restyle::Normal) |
|
(Root::Normal, Restyle::Normal) |
|
||||||
(Root::Normal, Restyle::ForAnimationOnly)
|
(Root::Normal, Restyle::ForAnimationOnly)
|
||||||
=> TraversalFlags::empty(),
|
=> TraversalFlags::empty(),
|
||||||
(Root::UnstyledChildrenOnly, Restyle::Normal) |
|
(Root::UnstyledChildrenOnly, Restyle::Normal) |
|
||||||
(Root::UnstyledChildrenOnly, Restyle::ForAnimationOnly)
|
(Root::UnstyledChildrenOnly, Restyle::ForAnimationOnly)
|
||||||
=> UNSTYLED_CHILDREN_ONLY,
|
=> UNSTYLED_CHILDREN_ONLY,
|
||||||
|
(Root::Normal, Restyle::ForCSSRuleChanges) => FOR_CSS_RULE_CHANGES,
|
||||||
(Root::Normal, Restyle::ForReconstruct) => FOR_RECONSTRUCT,
|
(Root::Normal, Restyle::ForReconstruct) => FOR_RECONSTRUCT,
|
||||||
_ => panic!("invalid combination of TraversalRootBehavior and TraversalRestyleBehavior"),
|
_ => panic!("invalid combination of TraversalRootBehavior and TraversalRestyleBehavior"),
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,8 +8,8 @@ use media_queries::CSSErrorReporterTest;
|
||||||
use style::context::QuirksMode;
|
use style::context::QuirksMode;
|
||||||
use style::parser::{PARSING_MODE_ALLOW_ALL_NUMERIC_VALUES, ParserContext};
|
use style::parser::{PARSING_MODE_ALLOW_ALL_NUMERIC_VALUES, ParserContext};
|
||||||
use style::stylesheets::{CssRuleType, Origin};
|
use style::stylesheets::{CssRuleType, Origin};
|
||||||
use style::values::HasViewportPercentage;
|
|
||||||
use style::values::specified::{AbsoluteLength, NoCalcLength, Number, ViewportPercentageLength};
|
use style::values::specified::{AbsoluteLength, NoCalcLength, Number, ViewportPercentageLength};
|
||||||
|
use style_traits::HasViewportPercentage;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn length_has_viewport_percentage() {
|
fn length_has_viewport_percentage() {
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
use style::properties::PropertyDeclaration;
|
use style::properties::PropertyDeclaration;
|
||||||
use style::properties::longhands::border_top_width;
|
use style::properties::longhands::border_top_width;
|
||||||
use style::values::HasViewportPercentage;
|
|
||||||
use style::values::specified::{AbsoluteLength, Length, NoCalcLength, ViewportPercentageLength};
|
use style::values::specified::{AbsoluteLength, Length, NoCalcLength, ViewportPercentageLength};
|
||||||
|
use style_traits::HasViewportPercentage;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn has_viewport_percentage_for_specified_value() {
|
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`;
|
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();
|
ExtensionTestUtils.mockAppInfo();
|
||||||
|
|
||||||
add_task(async function test_contentscript_runAt() {
|
add_task(async function test_contentscript_runAt() {
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
Cu.import("resource://gre/modules/Preferences.jsm");
|
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();
|
ExtensionTestUtils.mockAppInfo();
|
||||||
|
|
||||||
const server = createHttpServer();
|
const server = createHttpServer();
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
Cu.import("resource://gre/modules/Preferences.jsm");
|
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();
|
ExtensionTestUtils.mockAppInfo();
|
||||||
|
|
||||||
const server = createHttpServer();
|
const server = createHttpServer();
|
||||||
|
|
Загрузка…
Ссылка в новой задаче