Merge inbound to mozilla-central a=merge

This commit is contained in:
Coroiu Cristina 2018-09-30 12:46:16 +03:00
Родитель 44102e9f3d 01b7969db1
Коммит 8ed1d04be2
44 изменённых файлов: 576 добавлений и 592 удалений

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

@ -5439,13 +5439,7 @@ CanvasRenderingContext2D::GetImageData(JSContext* aCx, double aSx,
// Check only if we have a canvas element; if we were created with a docshell,
// then it's special internal use.
if (mCanvasElement && mCanvasElement->IsWriteOnly() &&
// We could ask bindings for the caller type, but they already hand us a
// JSContext, and we're at least _somewhat_ perf-sensitive (so may not
// want to compute the caller type in the common non-write-only case), so
// let's just use what we have.
!nsContentUtils::CallerHasPermission(aCx, nsGkAtoms::all_urlsPermission))
{
if (mCanvasElement && !mCanvasElement->CallerCanRead(aCx)) {
// XXX ERRMSG we need to report an error to developers here! (bug 329026)
aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
return nullptr;

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

@ -233,8 +233,9 @@ DoDrawImageSecurityCheck(dom::HTMLCanvasElement *aCanvasElement,
return;
}
if (aCanvasElement->IsWriteOnly())
if (aCanvasElement->IsWriteOnly() && !aCanvasElement->mExpandedReader) {
return;
}
// If we explicitly set WriteOnly just do it and get out
if (forceWriteOnly) {
@ -253,6 +254,25 @@ DoDrawImageSecurityCheck(dom::HTMLCanvasElement *aCanvasElement,
return;
}
if (BasePrincipal::Cast(aPrincipal)->AddonPolicy()) {
// This is a resource from an extension content script principal.
if (aCanvasElement->mExpandedReader &&
aCanvasElement->mExpandedReader->Subsumes(aPrincipal)) {
// This canvas already allows reading from this principal.
return;
}
if (!aCanvasElement->mExpandedReader) {
// Allow future reads from this same princial only.
aCanvasElement->SetWriteOnly(aPrincipal);
return;
}
// If we got here, this must be the *second* extension tainting
// the canvas. Fall through to mark it WriteOnly for everyone.
}
aCanvasElement->SetWriteOnly();
}

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

@ -670,9 +670,8 @@ HTMLCanvasElement::ToDataURL(JSContext* aCx, const nsAString& aType,
nsIPrincipal& aSubjectPrincipal,
ErrorResult& aRv)
{
// do a trust check if this is a write-only canvas
if (mWriteOnly &&
!nsContentUtils::CallerHasPermission(aCx, nsGkAtoms::all_urlsPermission)) {
// mWriteOnly check is redundant, but optimizes for the common case.
if (mWriteOnly && !CallerCanRead(aCx)) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return;
}
@ -881,9 +880,8 @@ HTMLCanvasElement::ToBlob(JSContext* aCx,
nsIPrincipal& aSubjectPrincipal,
ErrorResult& aRv)
{
// do a trust check if this is a write-only canvas
if (mWriteOnly &&
!nsContentUtils::CallerHasPermission(aCx, nsGkAtoms::all_urlsPermission)) {
// mWriteOnly check is redundant, but optimizes for the common case.
if (mWriteOnly && !CallerCanRead(aCx)) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return;
}
@ -1093,9 +1091,36 @@ HTMLCanvasElement::IsWriteOnly()
void
HTMLCanvasElement::SetWriteOnly()
{
mExpandedReader = nullptr;
mWriteOnly = true;
}
void
HTMLCanvasElement::SetWriteOnly(nsIPrincipal* aExpandedReader)
{
mExpandedReader = aExpandedReader;
mWriteOnly = true;
}
bool
HTMLCanvasElement::CallerCanRead(JSContext* aCx)
{
if (!mWriteOnly) {
return true;
}
nsIPrincipal* prin = nsContentUtils::SubjectPrincipal(aCx);
// If mExpandedReader is set, this canvas was tainted only by
// mExpandedReader's resources. So allow reading if the subject
// principal subsumes mExpandedReader.
if (mExpandedReader && prin->Subsumes(mExpandedReader)) {
return true;
}
return nsContentUtils::PrincipalHasPermission(prin, nsGkAtoms::all_urlsPermission);
}
void
HTMLCanvasElement::InvalidateCanvasContent(const gfx::Rect* damageRect)
{

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

@ -230,6 +230,12 @@ public:
*/
void SetWriteOnly();
/**
* Force the canvas to be write-only, except for readers from
* a specific extension's content script expanded principal.
*/
void SetWriteOnly(nsIPrincipal* aExpandedReader);
/**
* Notify that some canvas content has changed and the window may
* need to be updated. aDamageRect is in canvas coordinates.
@ -395,8 +401,15 @@ public:
// We set this when script paints an image from a different origin.
// We also transitively set it when script paints a canvas which
// is itself write-only.
bool mWriteOnly;
bool mWriteOnly;
// When this canvas is (only) tainted by an image from an extension
// content script, allow reads from the same extension afterwards.
RefPtr<nsIPrincipal> mExpandedReader;
// Determines if the caller should be able to read the content.
bool CallerCanRead(JSContext* aCx);
bool IsPrintCallbackDone();
void HandlePrintCallback(nsPresContext::nsPresContextType aType);

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

@ -23,12 +23,6 @@ worker.onmessage = function(event) {
} else if (event.data.type == 'status') {
ok(event.data.status, event.data.msg);
} else if (event.data.type == 'getOSCPU') {
worker.postMessage({
type: 'returnOSCPU',
result: navigator.oscpu
});
}
}

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

@ -7,39 +7,22 @@ function workerTestDone() {
postMessage({ type: 'finish' });
}
function workerTestGetOSCPU(cb) {
addEventListener('message', function workerTestGetOSCPUCB(e) {
if (e.data.type !== 'returnOSCPU') {
return;
}
removeEventListener('message', workerTestGetOSCPUCB);
cb(e.data.result);
});
postMessage({
type: 'getOSCPU'
});
}
ok(self.performance, "Performance object should exist.");
ok(typeof self.performance.now == 'function', "Performance object should have a 'now' method.");
var n = self.performance.now(), d = Date.now();
ok(n >= 0, "The value of now() should be equal to or greater than 0.");
ok(self.performance.now() >= n, "The value of now() should monotonically increase.");
// The spec says performance.now() should have micro-second resolution, but allows 1ms if the platform doesn't support it.
// Our implementation does provide micro-second resolution, except for windows XP combined with some HW properties
// where we can't use QueryPerformanceCounters (see comments at mozilla-central/xpcom/ds/TimeStamp_windows.cpp).
// This XP-low-res case results in about 15ms resolutions, and can be identified when perf.now() returns only integers.
//
// Since setTimeout might return too early/late, our goal is that perf.now() changed within 2ms
// (or 25ms for XP-low-res), rather than specific number of setTimeout(N) invocations.
// Spin on setTimeout() until performance.now() increases. Due to recent
// security developments, the hr-time working group has not yet reached
// consensus on what the recommend minimum clock resolution should be:
// https://w3c.github.io/hr-time/#clock-resolution
// Since setTimeout might return too early/late, our goal is for
// performance.now() to increase before a 2 ms deadline rather than specific
// number of setTimeout(N) invocations.
// See bug 749894 (intermittent failures of this test)
var platformPossiblyLowRes;
workerTestGetOSCPU(function(oscpu) {
platformPossiblyLowRes = oscpu.indexOf("Windows NT 5.1") == 0; // XP only
setTimeout(checkAfterTimeout, 1);
});
var allInts = (n % 1) == 0; // Indicator of limited HW resolution.
setTimeout(checkAfterTimeout, 1);
var checks = 0;
function checkAfterTimeout() {
@ -47,30 +30,28 @@ function checkAfterTimeout() {
var d2 = Date.now();
var n2 = self.performance.now();
allInts = allInts && (n2 % 1) == 0;
var lowResCounter = platformPossiblyLowRes && allInts;
if ( n2 == n && checks < 50 && // 50 is just a failsafe. Our real goals are 2ms or 25ms.
( (d2 - d) < 2 // The spec allows 1ms resolution. We allow up to measured 2ms to ellapse.
||
lowResCounter &&
(d2 - d) < 25
)
) {
// Spin on setTimeout() until performance.now() increases. Abort the test
// if it runs for more than 2 ms or 50 timeouts.
let elapsedTime = d2 - d;
let elapsedPerf = n2 - n;
if (elapsedPerf == 0 && elapsedTime < 2 && checks < 50) {
setTimeout(checkAfterTimeout, 1);
return;
}
// Loose spec: 1ms resolution, or 15ms resolution for the XP-low-res case.
// We shouldn't test that dt is actually within 2/25ms since the iterations break if it isn't, and timeout could be late.
ok(n2 > n, "Loose - the value of now() should increase within 2ms (or 25ms if low-res counter) (delta now(): " + (n2 - n) + " ms).");
// Our implementation provides 1 ms resolution (bug 1451790), but we
// can't assert that elapsedPerf >= 1 ms because this worker test runs with
// "privacy.reduceTimerPrecision" == false so performance.now() is not
// limited to 1 ms resolution.
ok(elapsedPerf > 0,
`Loose - the value of now() should increase after 2ms. ` +
`delta now(): ${elapsedPerf} ms`);
// If we need more than 1 iteration, then either performance.now() resolution
// is shorter than 1 ms or setTimeout() is returning too early.
ok(checks == 1,
`Strict - the value of now() should increase after one setTimeout. ` +
`iters: ${checks}, dt: ${elapsedTime}, now(): ${n2}`);
// Strict spec: if it's not the XP-low-res case, while the spec allows 1ms resolution, it prefers microseconds, which we provide.
// Since the fastest setTimeout return which I observed was ~500 microseconds, a microseconds counter should change in 1 iteretion.
ok(n2 > n && (lowResCounter || checks == 1),
"Strict - [if high-res counter] the value of now() should increase after one setTimeout (hi-res: " + (!lowResCounter) +
", iters: " + checks +
", dt: " + (d2 - d) +
", now(): " + n2 + ").");
workerTestDone();
};

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

@ -13,21 +13,18 @@
var n = window.performance.now(), d = Date.now();
ok(n >= 0, "The value of now() should be equal to or greater than 0.");
ok(window.performance.now() >= n, "The value of now() should monotonically increase.");
SimpleTest.waitForExplicitFinish();
var reduceTimePrecisionPrevPrefValue = SpecialPowers.getBoolPref("privacy.reduceTimerPrecision");
SpecialPowers.setBoolPref("privacy.reduceTimerPrecision", false);
SimpleTest.requestFlakyTimeout("untriaged");
// The spec says performance.now() should have micro-second resolution, but allows 1ms if the platform doesn't support it.
// Our implementation does provide micro-second resolution, except for windows XP combined with some HW properties
// where we can't use QueryPerformanceCounters (see comments at mozilla-central/xpcom/ds/TimeStamp_windows.cpp).
// This XP-low-res case results in about 15ms resolutions, and can be identified when perf.now() returns only integers.
//
// Since setTimeout might return too early/late, our goal is that perf.now() changed within 2ms
// (or 25ms for XP-low-res), rather than specific number of setTimeout(N) invocations.
SimpleTest.waitForExplicitFinish();
SimpleTest.requestFlakyTimeout("using setTimeout() to measure performance.now()");
// Spin on setTimeout() until performance.now() increases. Due to recent
// security developments, the hr-time working group has not yet reached
// consensus on what the recommend minimum clock resolution should be:
// https://w3c.github.io/hr-time/#clock-resolution
// Since setTimeout might return too early/late, our goal is for
// performance.now() to increase before a 2 ms deadline rather than specific
// number of setTimeout(N) invocations.
// See bug 749894 (intermittent failures of this test)
var platformPossiblyLowRes = navigator.oscpu.indexOf("Windows NT 5.1") == 0; // XP only
var allInts = (n % 1) == 0; // Indicator of limited HW resolution.
var checks = 0;
function checkAfterTimeout() {
@ -35,32 +32,26 @@
var d2 = Date.now();
var n2 = window.performance.now();
allInts = allInts && (n2 % 1) == 0;
var lowResCounter = platformPossiblyLowRes && allInts;
if ( n2 == n && checks < 50 && // 50 is just a failsafe. Our real goals are 2ms or 25ms.
( (d2 - d) < 2 // The spec allows 1ms resolution. We allow up to measured 2ms to ellapse.
||
lowResCounter &&
(d2 - d) < 25
)
) {
// Spin on setTimeout() until performance.now() increases. Abort the
// test if it runs for more than 2 ms or 50 timeouts.
let elapsedTime = d2 - d;
let elapsedPerf = n2 - n;
if (elapsedPerf == 0 && elapsedTime < 2 && checks < 50) {
setTimeout(checkAfterTimeout, 1);
return;
}
// Loose spec: 1ms resolution, or 15ms resolution for the XP-low-res case.
// We shouldn't test that dt is actually within 2/25ms since the iterations break if it isn't, and timeout could be late.
ok(n2 > n, "Loose - the value of now() should increase within 2ms (or 25ms if low-res counter) (delta now(): " + (n2 - n) + " ms).");
// Our implementation provides 1 ms resolution (bug 1451790).
ok(elapsedPerf >= 1,
`Loose - the value of now() should increase by no less than 1 ms ` +
`after 2 ms. delta now(): ${elapsedPerf} ms`);
// If we need more than 1 iteration, then either performance.now()
// resolution is shorter than 1 ms or setTimeout() is returning too early.
ok(checks == 1,
`Strict - the value of now() should increase after one setTimeout. ` +
`iters: ${checks}, dt: ${elapsedTime}, now(): ${n2}`);
// Strict spec: if it's not the XP-low-res case, while the spec allows 1ms resolution, it prefers microseconds, which we provide.
// Since the fastest setTimeout return which I observed was ~500 microseconds, a microseconds counter should change in 1 iteretion.
ok(n2 > n && (lowResCounter || checks == 1),
"Strict - [if high-res counter] the value of now() should increase after one setTimeout (hi-res: " + (!lowResCounter) +
", iters: " + checks +
", dt: " + (d2 - d) +
", now(): " + n2 + ").");
SpecialPowers.setBoolPref("privacy.reduceTimerPrecision", reduceTimePrecisionPrevPrefValue);
SimpleTest.finish();
};
setTimeout(checkAfterTimeout, 1);

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

@ -139,7 +139,7 @@ struct OpUpdateBlobImage {
};
struct OpSetImageVisibleArea {
Rect area;
ImageIntRect area;
ImageKey key;
};

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

@ -328,7 +328,8 @@ IpcResourceUpdateQueue::UpdateExternalImage(wr::ExternalImageId aExtId,
}
void
IpcResourceUpdateQueue::SetImageVisibleArea(ImageKey aKey, const gfx::Rect& aArea)
IpcResourceUpdateQueue::SetImageVisibleArea(ImageKey aKey,
const ImageIntRect& aArea)
{
mUpdates.AppendElement(layers::OpSetImageVisibleArea(aArea, aKey));
}

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

@ -103,7 +103,7 @@ public:
ImageKey aKey,
ImageIntRect aDirtyRect);
void SetImageVisibleArea(ImageKey aKey, const gfx::Rect& aArea);
void SetImageVisibleArea(ImageKey aKey, const ImageIntRect& aArea);
void DeleteImage(wr::ImageKey aKey);

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

@ -343,7 +343,7 @@ WebRenderBridgeParent::UpdateResources(const nsTArray<OpUpdateResource>& aResour
}
case OpUpdateResource::TOpSetImageVisibleArea: {
const auto& op = cmd.get_OpSetImageVisibleArea();
wr::NormalizedRect area;
wr::DeviceUintRect area;
area.origin.x = op.area().x;
area.origin.y = op.area().y;
area.size.width = op.area().width;

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

@ -9,6 +9,7 @@
#include "BasicLayers.h"
#include "mozilla/AutoRestore.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/Logging.h"
#include "mozilla/gfx/Types.h"
#include "mozilla/layers/ClipManager.h"
#include "mozilla/layers/ImageClient.h"
@ -63,23 +64,6 @@ NS_DECLARE_FRAME_PROPERTY_WITH_DTOR(BlobGroupDataProperty,
nsTArray<BlobItemData*>,
DestroyBlobGroupDataProperty);
static void
SetBlobImageVisibleArea(wr::IpcResourceUpdateQueue& aResources,
wr::ImageKey aImageKey,
const LayoutDeviceRect& aImageRect,
const LayoutDeviceRect& aPaintRect)
{
LayoutDeviceRect visibleRect = aImageRect.Intersect(aPaintRect);
// Send the visible rect in normalized coordinates.
Rect visibleArea = Rect((visibleRect.x - aImageRect.x) / aImageRect.width,
(visibleRect.y - aImageRect.y) / aImageRect.height,
visibleRect.width / aImageRect.width,
visibleRect.height / aImageRect.height);
aResources.SetImageVisibleArea(aImageKey, visibleArea);
}
// These are currently manually allocated and ownership is help by the mDisplayItems
// hash table in DIGroup
struct BlobItemData
@ -348,7 +332,7 @@ struct DIGroup
nsPoint mLastAnimatedGeometryRootOrigin;
IntRect mInvalidRect;
nsRect mGroupBounds;
LayoutDeviceRect mPaintRect;
LayerIntRect mPaintRect;
int32_t mAppUnitsPerDevPixel;
gfx::Size mScale;
FrameMetrics::ViewID mScrollId;
@ -631,7 +615,9 @@ struct DIGroup
GP("Not repainting group because it's empty\n");
GP("End EndGroup\n");
if (mKey) {
SetBlobImageVisibleArea(aResources, mKey.value(), bounds, mPaintRect);
aResources.SetImageVisibleArea(
mKey.value(),
ViewAs<ImagePixel>(mPaintRect, PixelCastJustification::LayerIsImage));
PushImage(aBuilder, bounds);
}
return;
@ -703,7 +689,9 @@ struct DIGroup
}
mFonts = std::move(fonts);
mInvalidRect.SetEmpty();
SetBlobImageVisibleArea(aResources, mKey.value(), mPaintRect, bounds);
aResources.SetImageVisibleArea(
mKey.value(),
ViewAs<ImagePixel>(mPaintRect, PixelCastJustification::LayerIsImage));
PushImage(aBuilder, bounds);
GP("End EndGroup\n\n");
}
@ -759,6 +747,8 @@ struct DIGroup
data->mInvalid = false;
} else {
BlobItemData* data = GetBlobItemData(item);
if (data->mInvalid)
gfxCriticalError() << "DisplayItem" << item->Name() << "should be invalid";
// if the item is invalid it needs to be fully contained
MOZ_RELEASE_ASSERT(!data->mInvalid);
}
@ -1232,16 +1222,23 @@ WebRenderCommandBuilder::DoGroupingForDisplayList(nsDisplayList* aList,
g.mAppUnitsPerDevPixel = appUnitsPerDevPixel;
group.mResidualOffset = residualOffset;
group.mGroupBounds = groupBounds;
group.mPaintRect = LayoutDeviceRect::FromAppUnits(
aWrappingItem->GetPaintRect(),
appUnitsPerDevPixel
);
group.mAppUnitsPerDevPixel = appUnitsPerDevPixel;
group.mLayerBounds = LayerIntRect::FromUnknownRect(ScaleToOutsidePixelsOffset(group.mGroupBounds,
scale.width,
scale.height,
group.mAppUnitsPerDevPixel,
residualOffset));
group.mPaintRect = LayerIntRect::FromUnknownRect(
ScaleToOutsidePixelsOffset(aWrappingItem->GetPaintRect(),
scale.width,
scale.height,
group.mAppUnitsPerDevPixel,
residualOffset))
.Intersect(group.mLayerBounds);
// XXX: Make the paint rect relative to the layer bounds. After we include
// mLayerBounds.TopLeft() in the blob image we want to stop doing this
// adjustment.
group.mPaintRect = group.mPaintRect - group.mLayerBounds.TopLeft();
g.mTransform = Matrix::Scaling(scale.width, scale.height)
.PostTranslate(residualOffset.x, residualOffset.y);
group.mScale = scale;

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

@ -422,20 +422,20 @@ impl ClipStore {
&self.clip_node_instances[(node_range.first + index) as usize]
}
// Notify the clip store that a new rasterization root has been created.
// Notify the clip store that a new surface has been created.
// This means any clips from an earlier root should be collected rather
// than applied on the primitive itself.
pub fn push_raster_root(
pub fn push_surface(
&mut self,
raster_spatial_node_index: SpatialNodeIndex,
spatial_node_index: SpatialNodeIndex,
) {
self.clip_node_collectors.push(
ClipNodeCollector::new(raster_spatial_node_index),
ClipNodeCollector::new(spatial_node_index),
);
}
// Mark the end of a rasterization root.
pub fn pop_raster_root(
// Mark the end of a rendering surface.
pub fn pop_surface(
&mut self,
) -> ClipNodeCollector {
self.clip_node_collectors.pop().unwrap()
@ -474,7 +474,7 @@ impl ClipStore {
// Check if any clip node index should actually be
// handled during compositing of a rasterization root.
match self.clip_node_collectors.iter_mut().find(|c| {
clip_chain_node.spatial_node_index < c.raster_root
clip_chain_node.spatial_node_index < c.spatial_node_index
}) {
Some(collector) => {
collector.insert(current_clip_chain_id);
@ -1186,16 +1186,16 @@ pub fn project_inner_rect(
// root at the end of primitive preparation.
#[derive(Debug)]
pub struct ClipNodeCollector {
raster_root: SpatialNodeIndex,
spatial_node_index: SpatialNodeIndex,
clips: FastHashSet<ClipChainId>,
}
impl ClipNodeCollector {
pub fn new(
raster_root: SpatialNodeIndex,
spatial_node_index: SpatialNodeIndex,
) -> Self {
ClipNodeCollector {
raster_root,
spatial_node_index,
clips: FastHashSet::default(),
}
}

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

@ -13,7 +13,7 @@ use api::{LineOrientation, LineStyle, LocalClip, NinePatchBorderSource, Pipeline
use api::{PropertyBinding, ReferenceFrame, RepeatMode, ScrollFrameDisplayItem, ScrollSensitivity};
use api::{Shadow, SpecificDisplayItem, StackingContext, StickyFrameDisplayItem, TexelRect};
use api::{ClipMode, TransformStyle, YuvColorSpace, YuvData};
use clip::{ClipDataInterner, ClipChainId, ClipRegion, ClipItemKey, ClipStore};
use clip::{ClipChainId, ClipRegion, ClipItemKey, ClipStore};
use clip_scroll_tree::{ClipScrollTree, SpatialNodeIndex};
use euclid::vec2;
use frame_builder::{ChasePrimitive, FrameBuilder, FrameBuilderConfig};
@ -31,18 +31,12 @@ use prim_store::{OpacityBinding, ScrollNodeAndClipChain, TextRunPrimitive};
use render_backend::{DocumentView};
use resource_cache::{FontInstanceMap, ImageRequest};
use scene::{Scene, ScenePipeline, StackingContextHelpers};
use scene_builder::DocumentResources;
use spatial_node::{SpatialNodeType, StickyFrameInfo};
use std::{f32, mem};
use tiling::{CompositeOps, ScrollbarPrimitive};
use tiling::{CompositeOps};
use util::{MaxRect, RectHelpers};
static DEFAULT_SCROLLBAR_COLOR: ColorF = ColorF {
r: 0.3,
g: 0.3,
b: 0.3,
a: 0.6,
};
#[derive(Debug, Copy, Clone)]
struct ClipNode {
id: ClipChainId,
@ -144,9 +138,6 @@ pub struct DisplayListFlattener<'a> {
/// The stack keeping track of the root clip chains associated with pipelines.
pipeline_clip_chain_stack: Vec<ClipChainId>,
/// A list of scrollbar primitives.
pub scrollbar_prims: Vec<ScrollbarPrimitive>,
/// The store of primitives.
pub prim_store: PrimitiveStore,
@ -160,8 +151,9 @@ pub struct DisplayListFlattener<'a> {
/// order to determine the default font.
pub config: FrameBuilderConfig,
/// Reference to the clip interner for this document.
clip_interner: &'a mut ClipDataInterner,
/// Reference to the document resources, which contains
/// shared (interned) data between display lists.
resources: &'a mut DocumentResources,
/// The estimated count of primtives we expect to encounter during flattening.
prim_count_estimate: usize,
@ -178,7 +170,7 @@ impl<'a> DisplayListFlattener<'a> {
new_scene: &mut Scene,
scene_id: u64,
picture_id_generator: &mut PictureIdGenerator,
clip_interner: &mut ClipDataInterner,
resources: &mut DocumentResources,
) -> FrameBuilder {
// We checked that the root pipeline is available on the render backend.
let root_pipeline_id = scene.root_pipeline_id.unwrap();
@ -196,14 +188,13 @@ impl<'a> DisplayListFlattener<'a> {
output_pipelines,
id_to_index_mapper: ClipIdToIndexMapper::default(),
hit_testing_runs: Vec::new(),
scrollbar_prims: Vec::new(),
shadow_stack: Vec::new(),
sc_stack: Vec::new(),
pipeline_clip_chain_stack: vec![ClipChainId::NONE],
prim_store: PrimitiveStore::new(),
clip_store: ClipStore::new(),
picture_id_generator,
clip_interner,
resources,
prim_count_estimate: 0,
};
@ -259,7 +250,6 @@ impl<'a> DisplayListFlattener<'a> {
);
let root_scroll_node = ClipId::root_scroll_node(pipeline_id);
let scroll_frame_info = self.simple_scroll_and_clip_chain(&root_scroll_node);
self.push_stacking_context(
pipeline_id,
@ -295,17 +285,6 @@ impl<'a> DisplayListFlattener<'a> {
self.flatten_items(&mut pipeline.display_list.iter(), pipeline_id, LayoutVector2D::zero());
if self.config.enable_scrollbars {
let scrollbar_rect = LayoutRect::new(LayoutPoint::zero(), LayoutSize::new(10.0, 70.0));
let container_rect = LayoutRect::new(LayoutPoint::zero(), *frame_size);
self.add_scroll_bar(
reference_frame_info.spatial_node_index,
&LayoutPrimitiveInfo::new(scrollbar_rect),
DEFAULT_SCROLLBAR_COLOR,
ScrollbarInfo(scroll_frame_info.spatial_node_index, container_rect),
);
}
self.pop_stacking_context();
}
@ -819,7 +798,7 @@ impl<'a> DisplayListFlattener<'a> {
for item in clip_items {
// Intern this clip item, and store the handle
// in the clip chain node.
let handle = self.clip_interner.intern(&item);
let handle = self.resources.clip_interner.intern(&item);
clip_chain_id = self.clip_store
.add_clip_chain_node(
@ -1337,6 +1316,7 @@ impl<'a> DisplayListFlattener<'a> {
// Build the clip sources from the supplied region.
let handle = self
.resources
.clip_interner
.intern(&ClipItemKey::rectangle(clip_region.main, ClipMode::Clip));
@ -1351,6 +1331,7 @@ impl<'a> DisplayListFlattener<'a> {
if let Some(ref image_mask) = clip_region.image_mask {
let handle = self
.resources
.clip_interner
.intern(&ClipItemKey::image_mask(image_mask));
@ -1366,6 +1347,7 @@ impl<'a> DisplayListFlattener<'a> {
for region in clip_region.complex_clips {
let handle = self
.resources
.clip_interner
.intern(&ClipItemKey::rounded_rect(region.rect, region.radii, region.mode));
@ -1447,9 +1429,10 @@ impl<'a> DisplayListFlattener<'a> {
// blur radius is 0, the code in Picture::prepare_for_render will
// detect this and mark the picture to be drawn directly into the
// parent picture, which avoids an intermediate surface and blur.
let blur_filter = FilterOp::Blur(std_deviation).sanitize();
let shadow_pic = PicturePrimitive::new_image(
self.picture_id_generator.next(),
Some(PictureCompositeMode::Filter(FilterOp::Blur(std_deviation))),
Some(PictureCompositeMode::Filter(blur_filter)),
false,
pipeline_id,
None,
@ -1528,40 +1511,6 @@ impl<'a> DisplayListFlattener<'a> {
);
}
pub fn add_scroll_bar(
&mut self,
spatial_node_index: SpatialNodeIndex,
info: &LayoutPrimitiveInfo,
color: ColorF,
scrollbar_info: ScrollbarInfo,
) {
if color.a == 0.0 {
return;
}
let prim = BrushPrimitive::new(
BrushKind::new_solid(color),
None,
);
let prim_index = self.create_primitive(
info,
ClipChainId::NONE,
spatial_node_index,
PrimitiveContainer::Brush(prim),
);
self.add_primitive_to_draw_list(
prim_index,
);
self.scrollbar_prims.push(ScrollbarPrimitive {
prim_index,
scroll_frame_index: scrollbar_info.0,
frame_rect: scrollbar_info.1,
});
}
pub fn add_line(
&mut self,
clip_and_scroll: ScrollNodeAndClipChain,
@ -2117,6 +2066,3 @@ struct FlattenedStackingContext {
participating_in_3d_context: bool,
has_mix_blend_mode: bool,
}
#[derive(Debug)]
pub struct ScrollbarInfo(pub SpatialNodeIndex, pub LayoutRect);

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

@ -15,7 +15,7 @@ use internal_types::{FastHashMap};
use picture::{PictureCompositeMode, PictureSurface, RasterConfig};
use prim_store::{PrimitiveIndex, PrimitiveStore, SpaceMapper};
use profiler::{FrameProfileCounters, GpuCacheProfileCounters, TextureCacheProfileCounters};
use render_backend::FrameId;
use render_backend::{FrameResources, FrameId};
use render_task::{RenderTask, RenderTaskId, RenderTaskLocation, RenderTaskTree};
use resource_cache::{ResourceCache};
use scene::{ScenePipeline, SceneProperties};
@ -24,8 +24,7 @@ use spatial_node::SpatialNode;
use std::f32;
use std::sync::Arc;
use tiling::{Frame, RenderPass, RenderPassKind, RenderTargetContext};
use tiling::{ScrollbarPrimitive, SpecialRenderPasses};
use util;
use tiling::{SpecialRenderPasses};
#[derive(Clone, Copy, Debug, PartialEq)]
@ -47,7 +46,6 @@ impl Default for ChasePrimitive {
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct FrameBuilderConfig {
pub enable_scrollbars: bool,
pub default_font_render_mode: FontRenderMode,
pub dual_source_blending_is_supported: bool,
pub dual_source_blending_is_enabled: bool,
@ -64,7 +62,6 @@ pub struct FrameBuilder {
pub clip_store: ClipStore,
pub hit_testing_runs: Vec<HitTestingRun>,
pub config: FrameBuilderConfig,
pub scrollbar_prims: Vec<ScrollbarPrimitive>,
}
pub struct FrameBuildingContext<'a> {
@ -85,7 +82,7 @@ pub struct FrameBuildingState<'a> {
pub gpu_cache: &'a mut GpuCache,
pub special_render_passes: &'a mut SpecialRenderPasses,
pub transforms: &'a mut TransformPalette,
pub clip_data_store: &'a mut ClipDataStore,
pub resources: &'a mut FrameResources,
pub segment_builder: SegmentBuilder,
}
@ -95,7 +92,6 @@ pub struct PictureContext {
pub inflation_factor: f32,
pub allow_subpixel_aa: bool,
pub is_passthrough: bool,
pub establishes_raster_root: bool,
pub raster_space: RasterSpace,
}
@ -135,7 +131,6 @@ impl FrameBuilder {
pub fn empty() -> Self {
FrameBuilder {
hit_testing_runs: Vec::new(),
scrollbar_prims: Vec::new(),
prim_store: PrimitiveStore::new(),
clip_store: ClipStore::new(),
screen_rect: DeviceUintRect::zero(),
@ -143,7 +138,6 @@ impl FrameBuilder {
background_color: None,
scene_id: 0,
config: FrameBuilderConfig {
enable_scrollbars: false,
default_font_render_mode: FontRenderMode::Mono,
dual_source_blending_is_enabled: true,
dual_source_blending_is_supported: false,
@ -161,7 +155,6 @@ impl FrameBuilder {
) -> Self {
FrameBuilder {
hit_testing_runs: flattener.hit_testing_runs,
scrollbar_prims: flattener.scrollbar_prims,
prim_store: flattener.prim_store,
clip_store: flattener.clip_store,
screen_rect,
@ -186,7 +179,7 @@ impl FrameBuilder {
device_pixel_scale: DevicePixelScale,
scene_properties: &SceneProperties,
transform_palette: &mut TransformPalette,
clip_data_store: &mut ClipDataStore,
resources: &mut FrameResources,
) -> Option<RenderTaskId> {
profile_scope!("cull");
@ -224,7 +217,7 @@ impl FrameBuilder {
gpu_cache,
special_render_passes,
transforms: transform_palette,
clip_data_store,
resources,
segment_builder: SegmentBuilder::new(),
};
@ -290,35 +283,6 @@ impl FrameBuilder {
Some(render_task_id)
}
fn update_scroll_bars(&mut self, clip_scroll_tree: &ClipScrollTree, gpu_cache: &mut GpuCache) {
static SCROLLBAR_PADDING: f32 = 8.0;
for scrollbar_prim in &self.scrollbar_prims {
let metadata = &mut self.prim_store.primitives[scrollbar_prim.prim_index.0].metadata;
let scroll_frame = &clip_scroll_tree.spatial_nodes[scrollbar_prim.scroll_frame_index.0];
// Invalidate what's in the cache so it will get rebuilt.
gpu_cache.invalidate(&metadata.gpu_location);
let scrollable_distance = scroll_frame.scrollable_size().height;
if scrollable_distance <= 0.0 {
metadata.local_clip_rect.size = LayoutSize::zero();
continue;
}
let amount_scrolled = -scroll_frame.scroll_offset().y / scrollable_distance;
let frame_rect = scrollbar_prim.frame_rect;
let min_y = frame_rect.origin.y + SCROLLBAR_PADDING;
let max_y = frame_rect.origin.y + frame_rect.size.height -
(SCROLLBAR_PADDING + metadata.local_rect.size.height);
metadata.local_rect.origin.x = frame_rect.origin.x + frame_rect.size.width -
(metadata.local_rect.size.width + SCROLLBAR_PADDING);
metadata.local_rect.origin.y = util::lerp(min_y, max_y, amount_scrolled);
metadata.local_clip_rect = metadata.local_rect;
}
}
pub fn build(
&mut self,
resource_cache: &mut ResourceCache,
@ -332,7 +296,7 @@ impl FrameBuilder {
texture_cache_profile: &mut TextureCacheProfileCounters,
gpu_cache_profile: &mut GpuCacheProfileCounters,
scene_properties: &SceneProperties,
clip_data_store: &mut ClipDataStore,
resources: &mut FrameResources,
) -> Frame {
profile_scope!("build");
debug_assert!(
@ -355,8 +319,6 @@ impl FrameBuilder {
Some(&mut transform_palette),
);
self.update_scroll_bars(clip_scroll_tree, gpu_cache);
let mut render_tasks = RenderTaskTree::new(frame_id);
let screen_size = self.screen_rect.size.to_i32();
@ -373,7 +335,7 @@ impl FrameBuilder {
device_pixel_scale,
scene_properties,
&mut transform_palette,
clip_data_store,
resources,
);
resource_cache.block_until_all_resources_added(gpu_cache,
@ -417,7 +379,7 @@ impl FrameBuilder {
resource_cache,
use_dual_source_blending,
clip_scroll_tree,
clip_data_store,
resources,
};
pass.build(

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

@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use api::{TileOffset, TileRange, LayoutRect, LayoutSize, LayoutPoint};
use api::{DeviceUintSize, NormalizedRect};
use api::{DeviceUintSize, DeviceUintRect};
use euclid::{vec2, point2};
use prim_store::EdgeAaSegmentMask;
@ -227,22 +227,21 @@ pub fn for_each_tile(
}
pub fn compute_tile_range(
visible_area: &NormalizedRect,
image_size: &DeviceUintSize,
visible_area: &DeviceUintRect,
tile_size: u16,
) -> TileRange {
// Tile dimensions in normalized coordinates.
let tw = (image_size.width as f32) / (tile_size as f32);
let th = (image_size.height as f32) / (tile_size as f32);
let tw = 1. / (tile_size as f32);
let th = 1. / (tile_size as f32);
let t0 = point2(
f32::floor(visible_area.origin.x * tw),
f32::floor(visible_area.origin.y * th),
f32::floor(visible_area.origin.x as f32 * tw),
f32::floor(visible_area.origin.y as f32 * th),
).cast::<u16>();
let t1 = point2(
f32::ceil(visible_area.max_x() * tw),
f32::ceil(visible_area.max_y() * th),
f32::ceil(visible_area.max_x() as f32 * tw),
f32::ceil(visible_area.max_y() as f32 * th),
).cast::<u16>();
TileRange {
@ -323,4 +322,4 @@ mod tests {
);
assert_eq!(count, 0);
}
}
}

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

@ -292,9 +292,9 @@ impl PicturePrimitive {
raster_spatial_node_index
};
if establishes_raster_root {
if has_surface {
frame_state.clip_store
.push_raster_root(raster_spatial_node_index);
.push_surface(surface_spatial_node_index);
}
let map_pic_to_world = SpaceMapper::new_with_target(
@ -361,7 +361,6 @@ impl PicturePrimitive {
inflation_factor,
allow_subpixel_aa,
is_passthrough: self.raster_config.is_none(),
establishes_raster_root,
raster_space,
};
@ -425,10 +424,10 @@ impl PicturePrimitive {
}
};
let clip_node_collector = if context.establishes_raster_root {
Some(frame_state.clip_store.pop_raster_root())
} else {
let clip_node_collector = if context.is_passthrough {
None
} else {
Some(frame_state.clip_store.pop_surface())
};
(local_rect, clip_node_collector)

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

@ -1733,7 +1733,7 @@ impl PrimitiveStore {
frame_context.device_pixel_scale,
&frame_context.world_rect,
&clip_node_collector,
frame_state.clip_data_store,
&mut frame_state.resources.clip_data_store,
);
let clip_chain = match clip_chain {
@ -2087,7 +2087,7 @@ fn write_brush_segment_description(
let clip_instance = frame_state
.clip_store
.get_instance_from_range(&clip_chain.clips_range, i);
let clip_node = &frame_state.clip_data_store[clip_instance.handle];
let clip_node = &frame_state.resources.clip_data_store[clip_instance.handle];
// If this clip item is positioned by another positioning node, its relative position
// could change during scrolling. This means that we would need to resegment. Instead
@ -2254,7 +2254,7 @@ impl Primitive {
frame_context.device_pixel_scale,
&frame_context.world_rect,
clip_node_collector,
frame_state.clip_data_store,
&mut frame_state.resources.clip_data_store,
);
match segment_clip_chain {
@ -2287,7 +2287,7 @@ impl Primitive {
frame_state.gpu_cache,
frame_state.resource_cache,
frame_state.render_tasks,
frame_state.clip_data_store,
&mut frame_state.resources.clip_data_store,
);
let clip_task_id = frame_state.render_tasks.add(clip_task);
@ -2828,7 +2828,7 @@ impl Primitive {
frame_state.gpu_cache,
frame_state.resource_cache,
frame_state.render_tasks,
frame_state.clip_data_store,
&mut frame_state.resources.clip_data_store,
);
let clip_task_id = frame_state.render_tasks.add(clip_task);

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

@ -16,9 +16,7 @@ use api::channel::{MsgReceiver, Payload};
use api::CaptureBits;
#[cfg(feature = "replay")]
use api::CapturedDocument;
#[cfg(feature = "replay")]
use clip::ClipDataInterner;
use clip::{ClipDataUpdateList, ClipDataStore};
use clip::ClipDataStore;
use clip_scroll_tree::{SpatialNodeIndex, ClipScrollTree};
#[cfg(feature = "debugger")]
use debug_server;
@ -80,6 +78,24 @@ impl DocumentView {
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct FrameId(pub u32);
// A collection of resources that are shared by clips, primitives
// between display lists.
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct FrameResources {
// The store of currently active / available clip nodes. This is kept
// in sync with the clip interner in the scene builder for each document.
pub clip_data_store: ClipDataStore,
}
impl FrameResources {
fn new() -> Self {
FrameResources {
clip_data_store: ClipDataStore::new(),
}
}
}
struct Document {
// The latest built scene, usable to build frames.
// received from the scene builder thread.
@ -118,9 +134,7 @@ struct Document {
frame_is_valid: bool,
hit_tester_is_valid: bool,
// The store of currently active / available clip nodes. This is kept
// in sync with the clip interner in the scene builder for each document.
clip_data_store: ClipDataStore,
resources: FrameResources,
}
impl Document {
@ -149,7 +163,7 @@ impl Document {
dynamic_properties: SceneProperties::new(),
frame_is_valid: false,
hit_tester_is_valid: false,
clip_data_store: ClipDataStore::new(),
resources: FrameResources::new(),
}
}
@ -278,11 +292,11 @@ impl Document {
&mut resource_profile.texture_cache,
&mut resource_profile.gpu_cache,
&self.dynamic_properties,
&mut self.clip_data_store,
&mut self.resources,
);
self.hit_tester = Some(frame_builder.create_hit_tester(
&self.clip_scroll_tree,
&self.clip_data_store,
&self.resources.clip_data_store,
));
frame
};
@ -309,7 +323,7 @@ impl Document {
self.hit_tester = Some(frame_builder.create_hit_tester(
&self.clip_scroll_tree,
&self.clip_data_store,
&self.resources.clip_data_store,
));
}
}
@ -419,6 +433,7 @@ pub struct RenderBackend {
recorder: Option<Box<ApiRecordingReceiver>>,
sampler: Option<Box<AsyncPropertySampler + Send>>,
size_of_op: Option<VoidPtrToSizeFn>,
namespace_alloc_by_client: bool,
last_scene_id: u64,
}
@ -438,6 +453,7 @@ impl RenderBackend {
recorder: Option<Box<ApiRecordingReceiver>>,
sampler: Option<Box<AsyncPropertySampler + Send>>,
size_of_op: Option<VoidPtrToSizeFn>,
namespace_alloc_by_client: bool,
) -> RenderBackend {
RenderBackend {
api_rx,
@ -457,6 +473,7 @@ impl RenderBackend {
sampler,
size_of_op,
last_scene_id: 0,
namespace_alloc_by_client,
}
}
@ -629,7 +646,7 @@ impl RenderBackend {
self.update_document(
txn.document_id,
replace(&mut txn.resource_updates, Vec::new()),
txn.clip_updates.take(),
txn.doc_resource_updates.take(),
replace(&mut txn.frame_ops, Vec::new()),
replace(&mut txn.notifications, Vec::new()),
txn.render_frame,
@ -729,8 +746,13 @@ impl RenderBackend {
tx.send(glyph_indices).unwrap();
}
ApiMsg::CloneApi(sender) => {
assert!(!self.namespace_alloc_by_client);
sender.send(self.next_namespace_id()).unwrap();
}
ApiMsg::CloneApiByClient(namespace_id) => {
assert!(self.namespace_alloc_by_client);
debug_assert!(!self.documents.iter().any(|(did, _doc)| did.0 == namespace_id));
}
ApiMsg::AddDocument(document_id, initial_size, layer) => {
let document = Document::new(
initial_size,
@ -973,7 +995,7 @@ impl RenderBackend {
&mut self,
document_id: DocumentId,
resource_updates: Vec<ResourceUpdate>,
clip_updates: Option<ClipDataUpdateList>,
doc_resource_updates: Option<DocumentResourceUpdates>,
mut frame_ops: Vec<FrameMsg>,
mut notifications: Vec<NotificationRequest>,
mut render_frame: bool,
@ -998,8 +1020,8 @@ impl RenderBackend {
// If there are any additions or removals of clip modes
// during the scene build, apply them to the data store now.
if let Some(clip_updates) = clip_updates {
doc.clip_data_store.apply_updates(clip_updates);
if let Some(updates) = doc_resource_updates {
doc.resources.clip_data_store.apply_updates(updates.clip_updates);
}
// TODO: this scroll variable doesn't necessarily mean we scrolled. It is only used
@ -1316,8 +1338,8 @@ impl RenderBackend {
config.serialize(&rendered_document.frame, file_name);
}
let clip_data_name = format!("clip-data-{}-{}", (id.0).0, id.1);
config.serialize(&doc.clip_data_store, clip_data_name);
let frame_resources_name = format!("frame-resources-{}-{}", (id.0).0, id.1);
config.serialize(&doc.resources, frame_resources_name);
}
debug!("\tscene builder");
@ -1403,13 +1425,13 @@ impl RenderBackend {
let scene = CaptureConfig::deserialize::<Scene, _>(root, &scene_name)
.expect(&format!("Unable to open {}.ron", scene_name));
let clip_interner_name = format!("clip-interner-{}-{}", (id.0).0, id.1);
let clip_interner = CaptureConfig::deserialize::<ClipDataInterner, _>(root, &clip_interner_name)
.expect(&format!("Unable to open {}.ron", clip_interner_name));
let doc_resources_name = format!("doc-resources-{}-{}", (id.0).0, id.1);
let doc_resources = CaptureConfig::deserialize::<DocumentResources, _>(root, &doc_resources_name)
.expect(&format!("Unable to open {}.ron", doc_resources_name));
let clip_data_name = format!("clip-data-{}-{}", (id.0).0, id.1);
let clip_data_store = CaptureConfig::deserialize::<ClipDataStore, _>(root, &clip_data_name)
.expect(&format!("Unable to open {}.ron", clip_data_name));
let frame_resources_name = format!("frame-resources-{}-{}", (id.0).0, id.1);
let frame_resources = CaptureConfig::deserialize::<FrameResources, _>(root, &frame_resources_name)
.expect(&format!("Unable to open {}.ron", frame_resources_name));
let mut doc = Document {
scene: scene.clone(),
@ -1423,7 +1445,7 @@ impl RenderBackend {
hit_tester: None,
frame_is_valid: false,
hit_tester_is_valid: false,
clip_data_store,
resources: frame_resources,
};
let frame_name = format!("frame-{}-{}", (id.0).0, id.1);
@ -1464,7 +1486,7 @@ impl RenderBackend {
font_instances: self.resource_cache.get_font_instances(),
scene_id: last_scene_id,
build_frame,
clip_interner,
doc_resources,
});
self.documents.insert(id, doc);

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

@ -1721,7 +1721,6 @@ impl Renderer {
};
let config = FrameBuilderConfig {
enable_scrollbars: options.enable_scrollbars,
default_font_render_mode,
dual_source_blending_is_enabled: true,
dual_source_blending_is_supported: ext_dual_source_blending,
@ -1759,6 +1758,7 @@ impl Renderer {
});
let sampler = options.sampler;
let size_of_op = options.size_of_op;
let namespace_alloc_by_client = options.namespace_alloc_by_client;
let blob_image_handler = options.blob_image_handler.take();
let thread_listener_for_render_backend = thread_listener.clone();
@ -1842,6 +1842,7 @@ impl Renderer {
recorder,
sampler,
size_of_op,
namespace_alloc_by_client,
);
backend.run(backend_profile_counters);
if let Some(ref thread_listener) = *thread_listener_for_render_backend {
@ -4400,7 +4401,6 @@ pub struct RendererOptions {
pub enable_aa: bool,
pub enable_dithering: bool,
pub max_recorded_profiles: usize,
pub enable_scrollbars: bool,
pub precache_shaders: bool,
pub renderer_kind: RendererKind,
pub enable_subpixel_aa: bool,
@ -4422,6 +4422,7 @@ pub struct RendererOptions {
pub sampler: Option<Box<AsyncPropertySampler + Send>>,
pub chase_primitive: ChasePrimitive,
pub support_low_priority_transactions: bool,
pub namespace_alloc_by_client: bool,
}
impl Default for RendererOptions {
@ -4433,7 +4434,6 @@ impl Default for RendererOptions {
enable_dithering: true,
debug_flags: DebugFlags::empty(),
max_recorded_profiles: 0,
enable_scrollbars: false,
precache_shaders: false,
renderer_kind: RendererKind::Native,
enable_subpixel_aa: false,
@ -4457,6 +4457,7 @@ impl Default for RendererOptions {
sampler: None,
chase_primitive: ChasePrimitive::Nothing,
support_low_priority_transactions: false,
namespace_alloc_by_client: false,
}
}
}

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

@ -11,7 +11,7 @@ use api::{FontInstanceData, FontInstanceOptions, FontInstancePlatformOptions, Fo
use api::{GlyphDimensions, IdNamespace};
use api::{ImageData, ImageDescriptor, ImageKey, ImageRendering};
use api::{MemoryReport, VoidPtrToSizeFn};
use api::{TileOffset, TileSize, TileRange, NormalizedRect, BlobImageData};
use api::{TileOffset, TileSize, TileRange, BlobImageData};
use app_units::Au;
#[cfg(feature = "capture")]
use capture::ExternalCaptureImage;
@ -555,7 +555,6 @@ impl ResourceCache {
if let Some(tile_size) = template.tiling {
template.viewport_tiles = Some(compute_tile_range(
&area,
&template.descriptor.size,
tile_size,
));
}
@ -1040,31 +1039,28 @@ impl ResourceCache {
let mut tiles = template.viewport_tiles.unwrap_or_else(|| {
// Default to requesting the full range of tiles.
compute_tile_range(
&NormalizedRect {
origin: point2(0.0, 0.0),
size: size2(1.0, 1.0),
&DeviceUintRect {
origin: point2(0, 0),
size: template.descriptor.size,
},
&template.descriptor.size,
tile_size,
)
});
// Don't request tiles that weren't invalidated.
if let Some(dirty_rect) = template.dirty_rect {
let f32_size = template.descriptor.size.to_f32();
let normalized_dirty_rect = NormalizedRect {
let dirty_rect = DeviceUintRect {
origin: point2(
dirty_rect.origin.x as f32 / f32_size.width,
dirty_rect.origin.y as f32 / f32_size.height,
dirty_rect.origin.x,
dirty_rect.origin.y,
),
size: size2(
dirty_rect.size.width as f32 / f32_size.width,
dirty_rect.size.height as f32 / f32_size.height,
dirty_rect.size.width,
dirty_rect.size.height,
),
};
let dirty_tiles = compute_tile_range(
&normalized_dirty_rect,
&template.descriptor.size,
&dirty_rect,
tile_size,
);
@ -1173,7 +1169,7 @@ impl ResourceCache {
fn discard_tiles_outside_visible_area(
&mut self,
key: ImageKey,
area: &NormalizedRect
area: &DeviceUintRect
) {
let template = match self.blob_image_templates.get(&key) {
Some(template) => template,
@ -1194,7 +1190,6 @@ impl ResourceCache {
let tile_range = compute_tile_range(
&area,
&template.descriptor.size,
tile_size,
);

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

@ -25,6 +25,10 @@ use util::drain_filter;
use std::thread;
use std::time::Duration;
pub struct DocumentResourceUpdates {
pub clip_updates: ClipDataUpdateList,
}
/// Represents the work associated to a transaction before scene building.
pub struct Transaction {
pub document_id: DocumentId,
@ -69,7 +73,7 @@ pub struct BuiltTransaction {
pub frame_ops: Vec<FrameMsg>,
pub removed_pipelines: Vec<PipelineId>,
pub notifications: Vec<NotificationRequest>,
pub clip_updates: Option<ClipDataUpdateList>,
pub doc_resource_updates: Option<DocumentResourceUpdates>,
pub scene_build_start_time: u64,
pub scene_build_end_time: u64,
pub render_frame: bool,
@ -102,7 +106,7 @@ pub struct LoadScene {
pub view: DocumentView,
pub config: FrameBuilderConfig,
pub build_frame: bool,
pub clip_interner: ClipDataInterner,
pub doc_resources: DocumentResources,
}
pub struct BuiltScene {
@ -144,20 +148,40 @@ pub enum SceneSwapResult {
Aborted,
}
// This struct contains all items that can be shared between
// display lists. We want to intern and share the same clips,
// primitives and other things between display lists so that:
// - GPU cache handles remain valid, reducing GPU cache updates.
// - Comparison of primitives and pictures between two
// display lists is (a) fast (b) done during scene building.
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct DocumentResources {
pub clip_interner: ClipDataInterner,
}
impl DocumentResources {
fn new() -> Self {
DocumentResources {
clip_interner: ClipDataInterner::new(),
}
}
}
// A document in the scene builder contains the current scene,
// as well as a persistent clip interner. This allows clips
// to be de-duplicated, and persisted in the GPU cache between
// display lists.
struct Document {
scene: Scene,
clip_interner: ClipDataInterner,
resources: DocumentResources,
}
impl Document {
fn new(scene: Scene) -> Self {
Document {
scene,
clip_interner: ClipDataInterner::new(),
resources: DocumentResources::new(),
}
}
}
@ -260,8 +284,8 @@ impl SceneBuilder {
#[cfg(feature = "capture")]
fn save_scene(&mut self, config: CaptureConfig) {
for (id, doc) in &self.documents {
let clip_interner_name = format!("clip-interner-{}-{}", (id.0).0, id.1);
config.serialize(&doc.clip_interner, clip_interner_name);
let doc_resources_name = format!("doc-resources-{}-{}", (id.0).0, id.1);
config.serialize(&doc.resources, doc_resources_name);
}
}
@ -273,7 +297,7 @@ impl SceneBuilder {
let scene_build_start_time = precise_time_ns();
let mut built_scene = None;
let mut clip_updates = None;
let mut doc_resource_updates = None;
if item.scene.has_root_pipeline() {
let mut clip_scroll_tree = ClipScrollTree::new();
@ -289,10 +313,19 @@ impl SceneBuilder {
&mut new_scene,
item.scene_id,
&mut self.picture_id_generator,
&mut item.clip_interner,
&mut item.doc_resources,
);
clip_updates = Some(item.clip_interner.end_frame_and_get_pending_updates());
let clip_updates = item
.doc_resources
.clip_interner
.end_frame_and_get_pending_updates();
doc_resource_updates = Some(
DocumentResourceUpdates {
clip_updates,
}
);
built_scene = Some(BuiltScene {
scene: new_scene,
@ -305,7 +338,7 @@ impl SceneBuilder {
item.document_id,
Document {
scene: item.scene,
clip_interner: item.clip_interner,
resources: item.doc_resources,
},
);
@ -321,7 +354,7 @@ impl SceneBuilder {
notifications: Vec::new(),
scene_build_start_time,
scene_build_end_time: precise_time_ns(),
clip_updates,
doc_resource_updates,
});
self.forward_built_transaction(txn);
@ -362,7 +395,7 @@ impl SceneBuilder {
}
let mut built_scene = None;
let mut clip_updates = None;
let mut doc_resource_updates = None;
if scene.has_root_pipeline() {
if let Some(request) = txn.request_scene_build.take() {
let mut clip_scroll_tree = ClipScrollTree::new();
@ -378,11 +411,20 @@ impl SceneBuilder {
&mut new_scene,
request.scene_id,
&mut self.picture_id_generator,
&mut doc.clip_interner,
&mut doc.resources,
);
// Retrieve the list of updates from the clip interner.
clip_updates = Some(doc.clip_interner.end_frame_and_get_pending_updates());
let clip_updates = doc
.resources
.clip_interner
.end_frame_and_get_pending_updates();
doc_resource_updates = Some(
DocumentResourceUpdates {
clip_updates,
}
);
built_scene = Some(BuiltScene {
scene: new_scene,
@ -419,7 +461,7 @@ impl SceneBuilder {
frame_ops: replace(&mut txn.frame_ops, Vec::new()),
removed_pipelines: replace(&mut txn.removed_pipelines, Vec::new()),
notifications: replace(&mut txn.notifications, Vec::new()),
clip_updates,
doc_resource_updates,
scene_build_start_time,
scene_build_end_time: precise_time_ns(),
})

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

@ -4,10 +4,10 @@
use api::{ColorF, BorderStyle, DeviceIntPoint, DeviceIntRect, DeviceIntSize, DevicePixelScale};
use api::{DeviceUintPoint, DeviceUintRect, DeviceUintSize, DocumentLayer, FilterOp, ImageFormat};
use api::{LayoutRect, MixBlendMode, PipelineId};
use api::{MixBlendMode, PipelineId};
use batch::{AlphaBatchBuilder, AlphaBatchContainer, ClipBatcher, resolve_image};
use clip::{ClipDataStore, ClipStore};
use clip_scroll_tree::{ClipScrollTree, SpatialNodeIndex};
use clip::ClipStore;
use clip_scroll_tree::{ClipScrollTree};
use device::{FrameId, Texture};
#[cfg(feature = "pathfinder")]
use euclid::{TypedPoint2D, TypedVector2D};
@ -17,8 +17,9 @@ use gpu_types::{TransformData, TransformPalette};
use internal_types::{FastHashMap, SavedTargetIndex, SourceTexture};
#[cfg(feature = "pathfinder")]
use pathfinder_partitioner::mesh::Mesh;
use prim_store::{PrimitiveIndex, PrimitiveStore, DeferredResolve};
use prim_store::{PrimitiveStore, DeferredResolve};
use profiler::FrameProfileCounters;
use render_backend::FrameResources;
use render_task::{BlitSource, RenderTaskAddress, RenderTaskId, RenderTaskKind};
use render_task::{BlurTask, ClearMode, GlyphTask, RenderTaskLocation, RenderTaskTree, ScalingTask};
use resource_cache::ResourceCache;
@ -31,13 +32,6 @@ const MIN_TARGET_SIZE: u32 = 2048;
const STYLE_SOLID: i32 = ((BorderStyle::Solid as i32) << 8) | ((BorderStyle::Solid as i32) << 16);
const STYLE_MASK: i32 = 0x00FF_FF00;
#[derive(Debug)]
pub struct ScrollbarPrimitive {
pub scroll_frame_index: SpatialNodeIndex,
pub prim_index: PrimitiveIndex,
pub frame_rect: LayoutRect,
}
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
@ -49,7 +43,7 @@ pub struct RenderTargetContext<'a, 'rc> {
pub resource_cache: &'rc mut ResourceCache,
pub use_dual_source_blending: bool,
pub clip_scroll_tree: &'a ClipScrollTree,
pub clip_data_store: &'a ClipDataStore,
pub resources: &'a FrameResources,
}
#[cfg_attr(feature = "capture", derive(Serialize))]
@ -594,7 +588,7 @@ impl RenderTarget for AlphaRenderTarget {
clip_store,
ctx.clip_scroll_tree,
transforms,
ctx.clip_data_store,
&ctx.resources.clip_data_store,
);
}
RenderTaskKind::ClipRegion(ref task) => {

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

@ -17,7 +17,7 @@ use {BuiltDisplayList, BuiltDisplayListDescriptor, ColorF, DeviceIntPoint, Devic
use {DeviceUintSize, ExternalScrollId, FontInstanceKey, FontInstanceOptions};
use {FontInstancePlatformOptions, FontKey, FontVariation, GlyphDimensions, GlyphIndex, ImageData};
use {ImageDescriptor, ImageKey, ItemTag, LayoutPoint, LayoutSize, LayoutTransform, LayoutVector2D};
use {NativeFontHandle, WorldPoint, NormalizedRect};
use {NativeFontHandle, WorldPoint};
pub type TileSize = u16;
/// Documents are rendered in the ascending order of their associated layer values.
@ -28,7 +28,7 @@ pub enum ResourceUpdate {
AddImage(AddImage),
UpdateImage(UpdateImage),
DeleteImage(ImageKey),
SetImageVisibleArea(ImageKey, NormalizedRect),
SetImageVisibleArea(ImageKey, DeviceUintRect),
AddFont(AddFont),
DeleteFont(FontKey),
AddFontInstance(AddFontInstance),
@ -321,7 +321,7 @@ impl Transaction {
self.resource_updates.push(ResourceUpdate::DeleteImage(key));
}
pub fn set_image_visible_area(&mut self, key: ImageKey, area: NormalizedRect) {
pub fn set_image_visible_area(&mut self, key: ImageKey, area: DeviceUintRect) {
self.resource_updates.push(ResourceUpdate::SetImageVisibleArea(key, area))
}
@ -662,6 +662,8 @@ pub enum ApiMsg {
GetGlyphIndices(FontKey, String, MsgSender<Vec<Option<u32>>>),
/// Adds a new document namespace.
CloneApi(MsgSender<IdNamespace>),
/// Adds a new document namespace.
CloneApiByClient(IdNamespace),
/// Adds a new document with given initial size.
AddDocument(DocumentId, DeviceUintSize, DocumentLayer),
/// A message targeted at a particular document.
@ -695,6 +697,7 @@ impl fmt::Debug for ApiMsg {
ApiMsg::GetGlyphDimensions(..) => "ApiMsg::GetGlyphDimensions",
ApiMsg::GetGlyphIndices(..) => "ApiMsg::GetGlyphIndices",
ApiMsg::CloneApi(..) => "ApiMsg::CloneApi",
ApiMsg::CloneApiByClient(..) => "ApiMsg::CloneApiByClient",
ApiMsg::AddDocument(..) => "ApiMsg::AddDocument",
ApiMsg::UpdateDocument(..) => "ApiMsg::UpdateDocument",
ApiMsg::DeleteDocument(..) => "ApiMsg::DeleteDocument",
@ -864,6 +867,23 @@ impl RenderApiSender {
next_id: Cell::new(ResourceId(0)),
}
}
/// Creates a new resource API object with a dedicated namespace.
/// Namespace id is allocated by client.
///
/// The function could be used only when RendererOptions::namespace_alloc_by_client is true.
/// When the option is true, create_api() could not be used to prevent namespace id conflict.
pub fn create_api_by_client(&self, namespace_id: IdNamespace) -> RenderApi {
let msg = ApiMsg::CloneApiByClient(namespace_id);
self.api_sender.send(msg).expect("Failed to send CloneApiByClient message");
RenderApi {
api_sender: self.api_sender.clone(),
payload_sender: self.payload_sender.clone(),
namespace_id,
next_id: Cell::new(ResourceId(0)),
}
}
}
pub struct RenderApi {

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

@ -123,12 +123,6 @@ pub type LayoutRectAu = TypedRect<Au, LayoutPixel>;
pub type LayoutSizeAu = TypedSize2D<Au, LayoutPixel>;
pub type LayoutVector2DAu = TypedVector2D<Au, LayoutPixel>;
/// Coordinates in normalized space (between zero and one).
#[derive(Hash, Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub struct NormalizedCoordinates;
pub type NormalizedRect = TypedRect<f32, NormalizedCoordinates>;
/// Stores two coordinates in texel space. The coordinates
/// are stored in texel coordinates because the texture atlas
/// may grow. Storing them as texel coords and normalizing

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

@ -702,7 +702,9 @@ TransactionBuilder::UpdateExternalImageWithDirtyRect(ImageKey aKey,
aDirtyRect);
}
void TransactionBuilder::SetImageVisibleArea(ImageKey aKey, const wr::NormalizedRect& aArea)
void
TransactionBuilder::SetImageVisibleArea(ImageKey aKey,
const wr::DeviceUintRect& aArea)
{
wr_resource_updates_set_image_visible_area(mTxn, aKey, &aArea);
}

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

@ -141,7 +141,7 @@ public:
const wr::DeviceUintRect& aDirtyRect,
uint8_t aChannelIndex = 0);
void SetImageVisibleArea(ImageKey aKey, const wr::NormalizedRect& aArea);
void SetImageVisibleArea(ImageKey aKey, const wr::DeviceUintRect& aArea);
void DeleteImage(wr::ImageKey aKey);

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

@ -1 +1 @@
0d2e9611c07e04ac830277f16a3b46bf125b9e7c
d7a6d081384ce0da9dd359b0cf4b9f758aab1b67

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

@ -1359,7 +1359,7 @@ pub extern "C" fn wr_resource_updates_update_image(
pub extern "C" fn wr_resource_updates_set_image_visible_area(
txn: &mut Transaction,
key: WrImageKey,
area: &NormalizedRect,
area: &DeviceUintRect,
) {
txn.set_image_visible_area(key, *area);
}

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

@ -277,9 +277,6 @@ struct DocumentHandle;
// Geometry in a stacking context's local coordinate space (logical pixels).
struct LayoutPixel;
// Coordinates in normalized space (between zero and one).
struct NormalizedCoordinates;
// The renderer is responsible for submitting to the GPU the work prepared by the
// RenderBackend.
struct Renderer;
@ -1052,8 +1049,6 @@ struct WrImageDescriptor {
}
};
using NormalizedRect = TypedRect<float, NormalizedCoordinates>;
struct WrTransformProperty {
uint64_t id;
LayoutTransform transform;
@ -1715,7 +1710,7 @@ WR_FUNC;
WR_INLINE
void wr_resource_updates_set_image_visible_area(Transaction *aTxn,
WrImageKey aKey,
const NormalizedRect *aArea)
const DeviceUintRect *aArea)
WR_FUNC;
WR_INLINE

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

@ -185,9 +185,9 @@ impl<'a> RawtestHarness<'a> {
);
txn.set_image_visible_area(
blob_img,
NormalizedRect {
origin: point2(0.0, 0.03),
size: size2(1.0, 0.03),
DeviceUintRect {
origin: point2(0, 111256 / 30),
size: size2(1510, 111256 / 30),
}
);
@ -310,9 +310,9 @@ impl<'a> RawtestHarness<'a> {
);
// Set a visible rectangle that is too small.
// This will force sync rasterization of the missing tiles during frame building.
txn.set_image_visible_area(blob_img2, NormalizedRect {
origin: point2(0.25, 0.25),
size: size2(0.1, 0.1),
txn.set_image_visible_area(blob_img2, DeviceUintRect {
origin: point2(200, 200),
size: size2(80, 80),
});
builder.push_image(

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

@ -1587,11 +1587,9 @@ RestyleManager::ProcessRestyledFrames(nsStyleChangeList& aChangeList)
hint &= ~nsChangeHint_UpdateTransformLayer;
}
if (hint & nsChangeHint_UpdateEffects) {
for (nsIFrame* cont = frame; cont;
cont = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(cont)) {
SVGObserverUtils::UpdateEffects(cont);
}
if ((hint & nsChangeHint_UpdateEffects) &&
frame == nsLayoutUtils::FirstContinuationOrIBSplitSibling(frame)) {
SVGObserverUtils::UpdateEffects(frame);
}
if ((hint & nsChangeHint_InvalidateRenderingObservers) ||
((hint & nsChangeHint_UpdateOpacityLayer) &&

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

@ -21,14 +21,16 @@ namespace mozilla {
// Feel free to add more justifications to PixelCastJustification, along with
// a comment that explains under what circumstances it is appropriate to use.
enum class PixelCastJustification : uint8_t {
enum class PixelCastJustification : uint8_t
{
// For the root layer, Screen Pixel = Parent Layer Pixel.
ScreenIsParentLayerForRoot,
// On the layout side, Screen Pixel = LayoutDevice at the outer-window level.
LayoutDeviceIsScreenForBounds,
// For the root layer, Render Target Pixel = Parent Layer Pixel.
RenderTargetIsParentLayerForRoot,
// For the root composition size we want to view it as layer pixels in any layer
// For the root composition size we want to view it as layer pixels in any
// layer
ParentLayerToLayerForRootComposition,
// The Layer coordinate space for one layer is the ParentLayer coordinate
// space for its children
@ -55,7 +57,9 @@ enum class PixelCastJustification : uint8_t {
MultipleAsyncTransforms,
// We have reason to believe a layer doesn't have a local transform.
// Should only be used if we've already checked or asserted this.
NoTransformOnLayer
NoTransformOnLayer,
// LayerPixels are ImagePixels
LayerIsImage,
};
template <class TargetUnits, class SourceUnits>

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

@ -2717,10 +2717,11 @@ ComputeClipForMaskItem(nsDisplayListBuilder* aBuilder, nsIFrame* aMaskedFrame,
// case, and we handle that specially.
nsRect dirtyRect(nscoord_MIN/2, nscoord_MIN/2, nscoord_MAX, nscoord_MAX);
nsIFrame* firstFrame = nsLayoutUtils::FirstContinuationOrIBSplitSibling(aMaskedFrame);
SVGObserverUtils::EffectProperties effectProperties =
SVGObserverUtils::GetEffectProperties(firstFrame);
nsTArray<nsSVGMaskFrame*> maskFrames = effectProperties.GetMaskFrames();
nsIFrame* firstFrame =
nsLayoutUtils::FirstContinuationOrIBSplitSibling(aMaskedFrame);
nsTArray<nsSVGMaskFrame*> maskFrames;
// XXX check return value?
SVGObserverUtils::GetAndObserveMasks(firstFrame, &maskFrames);
for (uint32_t i = 0; i < maskFrames.Length(); ++i) {
gfxRect clipArea;

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

@ -9572,9 +9572,9 @@ ComputeMaskGeometry(PaintFramesParams& aParams)
const nsStyleSVGReset* svgReset = firstFrame->StyleSVGReset();
SVGObserverUtils::EffectProperties effectProperties =
SVGObserverUtils::GetEffectProperties(firstFrame);
nsTArray<nsSVGMaskFrame*> maskFrames = effectProperties.GetMaskFrames();
nsTArray<nsSVGMaskFrame*> maskFrames;
// XXX check return value?
SVGObserverUtils::GetAndObserveMasks(firstFrame, &maskFrames);
if (maskFrames.Length() == 0) {
return;
@ -9715,12 +9715,11 @@ nsDisplayMasksAndClipPaths::IsValidMask() {
nsIFrame* firstFrame =
nsLayoutUtils::FirstContinuationOrIBSplitSibling(mFrame);
SVGObserverUtils::EffectProperties effectProperties =
SVGObserverUtils::GetEffectProperties(firstFrame);
if (SVGObserverUtils::GetAndObserveClipPath(firstFrame, nullptr) ==
SVGObserverUtils::eHasRefsSomeInvalid ||
effectProperties.HasInvalidMask()) {
SVGObserverUtils::GetAndObserveMasks(firstFrame, nullptr) ==
SVGObserverUtils::eHasRefsSomeInvalid) {
return false;
}
@ -10035,8 +10034,6 @@ nsDisplayMasksAndClipPaths::PrintEffects(nsACString& aTo)
{
nsIFrame* firstFrame =
nsLayoutUtils::FirstContinuationOrIBSplitSibling(mFrame);
SVGObserverUtils::EffectProperties effectProperties =
SVGObserverUtils::GetEffectProperties(firstFrame);
bool first = true;
aTo += " effects=(";
if (mFrame->StyleEffects()->mOpacity != 1.0f && mHandleOpacity) {
@ -10061,7 +10058,9 @@ nsDisplayMasksAndClipPaths::PrintEffects(nsACString& aTo)
first = false;
}
nsTArray<nsSVGMaskFrame*> masks = effectProperties.GetMaskFrames();
nsTArray<nsSVGMaskFrame*> masks;
// XXX check return value?
SVGObserverUtils::GetAndObserveMasks(firstFrame, &masks);
if (!masks.IsEmpty() && masks[0]) {
if (!first) {
aTo += ", ";

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

@ -566,20 +566,6 @@ nsSVGPaintingProperty::OnRenderingChange()
}
}
static SVGMaskObserverList*
GetOrCreateMaskProperty(nsIFrame* aFrame)
{
SVGMaskObserverList *prop =
aFrame->GetProperty(SVGObserverUtils::MaskProperty());
if (prop)
return prop;
prop = new SVGMaskObserverList(aFrame);
NS_ADDREF(prop);
aFrame->SetProperty(SVGObserverUtils::MaskProperty(), prop);
return prop;
}
static already_AddRefed<URLAndReferrerInfo>
ResolveURLUsingLocalRef(nsIFrame* aFrame, const css::URLValueData* aURL)
{
@ -673,6 +659,8 @@ SVGObserverUtils::GetMarkerFrames(nsIFrame* aMarkedFrame,
static SVGFilterObserverListForCSSProp*
GetOrCreateFilterObserverListForCSS(nsIFrame* aFrame)
{
MOZ_ASSERT(!aFrame->GetPrevContinuation(), "Require first continuation");
const nsStyleEffects* effects = aFrame->StyleEffects();
if (!effects->HasFilters()) {
return nullptr;
@ -757,6 +745,8 @@ SVGObserverUtils::DetachFromCanvasContext(nsISupports* aAutoObserver)
static nsSVGPaintingProperty*
GetOrCreateClipPathObserver(nsIFrame* aClippedFrame)
{
MOZ_ASSERT(!aClippedFrame->GetPrevContinuation(), "Require first continuation");
const nsStyleSVGReset* svgStyleReset = aClippedFrame->StyleSVGReset();
if (svgStyleReset->mClipPath.GetType() != StyleShapeSourceType::URL) {
return nullptr;
@ -793,6 +783,71 @@ SVGObserverUtils::GetAndObserveClipPath(nsIFrame* aClippedFrame,
return frame ? eHasRefsAllValid : eHasNoRefs;
}
static SVGMaskObserverList*
GetOrCreateMaskObserverList(nsIFrame* aMaskedFrame)
{
MOZ_ASSERT(!aMaskedFrame->GetPrevContinuation(), "Require first continuation");
const nsStyleSVGReset* style = aMaskedFrame->StyleSVGReset();
if (!style->HasMask()) {
return nullptr;
}
MOZ_ASSERT(style->mMask.mImageCount > 0);
SVGMaskObserverList* prop =
aMaskedFrame->GetProperty(SVGObserverUtils::MaskProperty());
if (prop) {
return prop;
}
prop = new SVGMaskObserverList(aMaskedFrame);
NS_ADDREF(prop);
aMaskedFrame->SetProperty(SVGObserverUtils::MaskProperty(), prop);
return prop;
}
SVGObserverUtils::ReferenceState
SVGObserverUtils::GetAndObserveMasks(nsIFrame* aMaskedFrame,
nsTArray<nsSVGMaskFrame*>* aMaskFrames)
{
SVGMaskObserverList* observerList = GetOrCreateMaskObserverList(aMaskedFrame);
if (!observerList) {
return eHasNoRefs;
}
const nsTArray<RefPtr<nsSVGPaintingProperty>>& observers =
observerList->GetObservers();
if (observers.IsEmpty()) {
return eHasNoRefs;
}
ReferenceState state = eHasRefsAllValid;
for (size_t i = 0; i < observers.Length(); i++) {
bool frameTypeOK = true;
nsSVGMaskFrame* maskFrame = static_cast<nsSVGMaskFrame*>(
observers[i]->GetAndObserveReferencedFrame(LayoutFrameType::SVGMask,
&frameTypeOK));
MOZ_ASSERT(!maskFrame || frameTypeOK);
// XXXjwatt: this looks fishy
if (!frameTypeOK) {
// We can not find the specific SVG mask resource in the downloaded SVG
// document. There are two possibilities:
// 1. The given resource id is invalid.
// 2. The given resource id refers to a viewbox.
//
// Hand it over to the style image.
observerList->ResolveImage(i);
state = eHasRefsSomeInvalid;
}
if (aMaskFrames) {
aMaskFrames->AppendElement(maskFrame);
}
}
return state;
}
SVGGeometryElement*
SVGObserverUtils::GetTextPathsReferencedPath(nsIFrame* aTextPathFrame)
{
@ -838,7 +893,7 @@ SVGObserverUtils::InitiateResourceDocLoads(nsIFrame* aFrame)
// make aFrame start observing the referenced frames.
Unused << GetOrCreateFilterObserverListForCSS(aFrame);
Unused << GetOrCreateClipPathObserver(aFrame);
Unused << GetEffectProperties(aFrame);
Unused << GetOrCreateMaskObserverList(aFrame);
}
void
@ -919,21 +974,6 @@ SVGObserverUtils::GetPaintingPropertyForURI(URLAndReferrerInfo* aURI,
return prop;
}
SVGObserverUtils::EffectProperties
SVGObserverUtils::GetEffectProperties(nsIFrame* aFrame)
{
NS_ASSERTION(!aFrame->GetPrevContinuation(), "aFrame should be first continuation");
EffectProperties result;
const nsStyleSVGReset *style = aFrame->StyleSVGReset();
MOZ_ASSERT(style->mMask.mImageCount > 0);
result.mMaskObservers = style->HasMask()
? GetOrCreateMaskProperty(aFrame) : nullptr;
return result;
}
nsSVGPaintServerFrame *
SVGObserverUtils::GetPaintServer(nsIFrame* aTargetFrame,
nsStyleSVGPaint nsStyleSVG::* aPaint)
@ -978,60 +1018,6 @@ SVGObserverUtils::GetPaintServer(nsIFrame* aTargetFrame,
return static_cast<nsSVGPaintServerFrame*>(result);
}
nsTArray<nsSVGMaskFrame *>
SVGObserverUtils::EffectProperties::GetMaskFrames()
{
nsTArray<nsSVGMaskFrame *> result;
if (!mMaskObservers) {
return result;
}
bool ok = true;
const nsTArray<RefPtr<nsSVGPaintingProperty>>& observers =
mMaskObservers->GetObservers();
for (size_t i = 0; i < observers.Length(); i++) {
nsSVGMaskFrame* maskFrame = static_cast<nsSVGMaskFrame*>(
observers[i]->GetAndObserveReferencedFrame(LayoutFrameType::SVGMask, &ok));
MOZ_ASSERT(!maskFrame || ok);
if (!ok) {
// We can not find the specific SVG mask resource in the downloaded SVG
// document. There are two possibilities:
// 1. The given resource id is invalid.
// 2. The given resource id refers to a viewbox.
//
// Hand it over to the style image.
mMaskObservers->ResolveImage(i);
}
result.AppendElement(maskFrame);
}
return result;
}
bool
SVGObserverUtils::EffectProperties::HasNoOrValidEffects()
{
return HasNoOrValidMask();
}
bool
SVGObserverUtils::EffectProperties::HasNoOrValidMask()
{
if (mMaskObservers) {
bool ok = true;
const nsTArray<RefPtr<nsSVGPaintingProperty>>& observers =
mMaskObservers->GetObservers();
for (size_t i = 0; i < observers.Length(); i++) {
observers[i]->GetAndObserveReferencedFrame(LayoutFrameType::SVGMask, &ok);
if (!ok) {
return false;
}
}
}
return true;
}
void
SVGObserverUtils::UpdateEffects(nsIFrame* aFrame)
{

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

@ -581,46 +581,6 @@ public:
NS_DECLARE_FRAME_PROPERTY_DELETABLE(BackgroundImageProperty,
URIObserverHashtable)
struct EffectProperties {
SVGMaskObserverList* mMaskObservers;
/**
* @return an array which contains all SVG mask frames.
*/
nsTArray<nsSVGMaskFrame*> GetMaskFrames();
/*
* @return true if all effects we have are valid or we have no effect
* at all.
*/
bool HasNoOrValidEffects();
/*
* @return true if we have any invalid effect.
*/
bool HasInvalidEffects() {
return !HasNoOrValidEffects();
}
/*
* @return true if we either do not have mask or all masks we have
* are valid.
*/
bool HasNoOrValidMask();
/*
* @return true if we have an invalid mask.
*/
bool HasInvalidMask() {
return !HasNoOrValidMask();
}
};
/**
* @param aFrame should be the first continuation
*/
static EffectProperties GetEffectProperties(nsIFrame* aFrame);
/**
* Ensures that that if the given frame requires any resources that are in
* SVG resource documents that the loading of those documents is initiated.
@ -795,6 +755,22 @@ public:
GetAndObserveClipPath(nsIFrame* aClippedFrame,
nsSVGClipPathFrame** aClipPathFrame);
/**
* If masking is applied to aMaskedFrame, gets an array of any SVG masks
* that are referenced, setting up aMaskFrames as a rendering observer of
* those masks (if any).
*
* NOTE! A return value of eHasNoRefs does NOT mean that there are no masks
* to be applied, only that there are no references to SVG mask elements.
*
* Note that, unlike for filters, a reference to an ID that doesn't exist
* is not invalid for clip-path or mask. We will return eHasNoRefs in that
* case.
*/
static ReferenceState
GetAndObserveMasks(nsIFrame* aMaskedFrame,
nsTArray<nsSVGMaskFrame*>* aMaskFrames);
/**
* Get the SVGGeometryElement that is referenced by aTextPathFrame, and make
* aTextPathFrame start observing rendering changes to that element.

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

@ -303,7 +303,7 @@ nsRect
// GetPostFilterBounds below! See bug 1494263.
// TODO: we should really return an empty rect for eHasRefsSomeInvalid since
// in that case we disable painting of the element.
if (SVGObserverUtils::GetAndObserveFilters(aFrame, nullptr) ==
if (SVGObserverUtils::GetAndObserveFilters(firstFrame, nullptr) ==
SVGObserverUtils::eHasRefsSomeInvalid) {
return aPreEffectsOverflowRect;
}
@ -747,9 +747,10 @@ nsSVGIntegrationUtils::IsMaskResourceReady(nsIFrame* aFrame)
{
nsIFrame* firstFrame =
nsLayoutUtils::FirstContinuationOrIBSplitSibling(aFrame);
SVGObserverUtils::EffectProperties effectProperties =
SVGObserverUtils::GetEffectProperties(firstFrame);
nsTArray<nsSVGMaskFrame*> maskFrames = effectProperties.GetMaskFrames();
nsTArray<nsSVGMaskFrame*> maskFrames;
// XXX check return value?
SVGObserverUtils::GetAndObserveMasks(firstFrame, &maskFrames);
const nsStyleSVGReset* svgReset = firstFrame->StyleSVGReset();
for (uint32_t i = 0; i < maskFrames.Length(); i++) {
@ -803,11 +804,6 @@ nsSVGIntegrationUtils::PaintMask(const PaintFramesParams& aParams)
}
gfxContext& ctx = aParams.ctx;
nsIFrame* firstFrame =
nsLayoutUtils::FirstContinuationOrIBSplitSibling(frame);
SVGObserverUtils::EffectProperties effectProperties =
SVGObserverUtils::GetEffectProperties(firstFrame);
RefPtr<DrawTarget> maskTarget = ctx.GetDrawTarget();
if (maskUsage.shouldGenerateMaskLayer &&
@ -823,7 +819,12 @@ nsSVGIntegrationUtils::PaintMask(const PaintFramesParams& aParams)
SurfaceFormat::A8);
}
nsTArray<nsSVGMaskFrame *> maskFrames = effectProperties.GetMaskFrames();
nsIFrame* firstFrame =
nsLayoutUtils::FirstContinuationOrIBSplitSibling(frame);
nsTArray<nsSVGMaskFrame*> maskFrames;
// XXX check return value?
SVGObserverUtils::GetAndObserveMasks(firstFrame, &maskFrames);
AutoPopGroup autoPop;
bool shouldPushOpacity = (maskUsage.opacity != 1.0) &&
(maskFrames.Length() != 1);
@ -924,19 +925,18 @@ void PaintMaskAndClipPathInternal(const PaintFramesParams& aParams, const T& aPa
gfxContext& context = aParams.ctx;
gfxContextMatrixAutoSaveRestore matrixAutoSaveRestore(&context);
/* Properties are added lazily and may have been removed by a restyle,
so make sure all applicable ones are set again. */
nsIFrame* firstFrame =
nsLayoutUtils::FirstContinuationOrIBSplitSibling(frame);
SVGObserverUtils::EffectProperties effectProperties =
SVGObserverUtils::GetEffectProperties(firstFrame);
nsSVGClipPathFrame* clipPathFrame;
// XXX check return value?
SVGObserverUtils::GetAndObserveClipPath(firstFrame, &clipPathFrame);
nsTArray<nsSVGMaskFrame*> maskFrames;
// XXX check return value?
SVGObserverUtils::GetAndObserveMasks(firstFrame, &maskFrames);
gfxMatrix cssPxToDevPxMatrix = nsSVGUtils::GetCSSPxToDevPxMatrix(frame);
nsTArray<nsSVGMaskFrame*> maskFrames = effectProperties.GetMaskFrames();
bool shouldGenerateMask = (maskUsage.opacity != 1.0f ||
maskUsage.shouldGenerateClipMaskLayer ||

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

@ -487,12 +487,11 @@ nsSVGUtils::DetermineMaskUsage(nsIFrame* aFrame, bool aHandleOpacity,
nsIFrame* firstFrame =
nsLayoutUtils::FirstContinuationOrIBSplitSibling(aFrame);
SVGObserverUtils::EffectProperties effectProperties =
SVGObserverUtils::GetEffectProperties(firstFrame);
const nsStyleSVGReset *svgReset = firstFrame->StyleSVGReset();
nsTArray<nsSVGMaskFrame*> maskFrames = effectProperties.GetMaskFrames();
nsTArray<nsSVGMaskFrame*> maskFrames;
// XXX check return value?
SVGObserverUtils::GetAndObserveMasks(firstFrame, &maskFrames);
aUsage.shouldGenerateMaskLayer = (maskFrames.Length() > 0);
nsSVGClipPathFrame* clipPathFrame;
@ -714,22 +713,21 @@ nsSVGUtils::PaintFrameWithEffects(nsIFrame *aFrame,
/* Properties are added lazily and may have been removed by a restyle,
so make sure all applicable ones are set again. */
nsSVGClipPathFrame* clipPathFrame;
SVGObserverUtils::EffectProperties effectProperties =
SVGObserverUtils::GetEffectProperties(aFrame);
nsTArray<nsSVGMaskFrame*> maskFrames;
// TODO: We currently pass nullptr instead of an nsTArray* here, but we
// actually should get the filter frames and then pass them into
// PaintFilteredFrame below! See bug 1494263.
if (effectProperties.HasInvalidEffects() ||
SVGObserverUtils::GetAndObserveFilters(aFrame, nullptr) ==
if (SVGObserverUtils::GetAndObserveFilters(aFrame, nullptr) ==
SVGObserverUtils::eHasRefsSomeInvalid ||
SVGObserverUtils::GetAndObserveClipPath(aFrame, &clipPathFrame) ==
SVGObserverUtils::eHasRefsSomeInvalid ||
SVGObserverUtils::GetAndObserveMasks(aFrame, &maskFrames) ==
SVGObserverUtils::eHasRefsSomeInvalid) {
// Some resource is invalid. We shouldn't paint anything.
return;
}
nsTArray<nsSVGMaskFrame*> masks = effectProperties.GetMaskFrames();
nsSVGMaskFrame *maskFrame = masks.IsEmpty() ? nullptr : masks[0];
nsSVGMaskFrame* maskFrame = maskFrames.IsEmpty() ? nullptr : maskFrames[0];
MixModeBlender blender(aFrame, &aContext);
gfxContext* target = blender.ShouldCreateDrawTargetForBlend()

Двоичные данные
toolkit/components/extensions/test/xpcshell/data/pixel_green.gif Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 35 B

Двоичные данные
toolkit/components/extensions/test/xpcshell/data/pixel_red.gif Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 35 B

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

@ -0,0 +1,86 @@
"use strict";
const server = createHttpServer({hosts: ["green.example.com", "red.example.com"]});
server.registerDirectory("/data/", do_get_file("data"));
server.registerPathHandler("/pixel.html", (request, response) => {
response.setStatusLine(request.httpVersion, 200, "OK");
response.setHeader("Content-Type", "text/html", false);
response.write(`<!DOCTYPE html>
<script>
function readByWeb() {
let ctx = document.querySelector("canvas").getContext("2d");
let {data} = ctx.getImageData(0, 0, 1, 1);
return data.slice(0, 3).join();
}
</script>
`);
});
add_task(async function test_contentscript_canvas_tainting() {
async function contentScript() {
let canvas = document.createElement("canvas");
let ctx = canvas.getContext("2d");
document.body.appendChild(canvas);
function draw(url) {
return new Promise(resolve => {
let img = document.createElement("img");
img.onload = () => {
ctx.drawImage(img, 0, 0, 1, 1);
resolve();
};
img.src = url;
});
}
function readByExt() {
let {data} = ctx.getImageData(0, 0, 1, 1);
return data.slice(0, 3).join();
}
let readByWeb = window.wrappedJSObject.readByWeb;
// Test reading after drawing an image from the same origin as the web page.
await draw("http://green.example.com/data/pixel_green.gif");
browser.test.assertEq(readByWeb(), "0,255,0", "Content can read same-origin image");
browser.test.assertEq(readByExt(), "0,255,0", "Extension can read same-origin image");
// Test reading after drawing a blue pixel data URI from extension content script.
await draw("data:image/gif;base64,R0lGODlhAQABAIABAAAA/wAAACwAAAAAAQABAAACAkQBADs=");
browser.test.assertThrows(readByWeb, /operation is insecure/, "Content can't read extension's image");
browser.test.assertEq(readByExt(), "0,0,255", "Extension can read its own image");
// Test after tainting the canvas with an image from a third party domain.
await draw("http://red.example.com/data/pixel_red.gif");
browser.test.assertThrows(readByWeb, /operation is insecure/, "Content can't read third party image");
browser.test.assertThrows(readByExt, /operation is insecure/, "Extension can't read fully tainted");
// Test canvas is still fully tainted after drawing extension's data: image again.
await draw("data:image/gif;base64,R0lGODlhAQABAIABAAAA/wAAACwAAAAAAQABAAACAkQBADs=");
browser.test.assertThrows(readByWeb, /operation is insecure/, "Canvas still fully tainted for content");
browser.test.assertThrows(readByExt, /operation is insecure/, "Canvas still fully tainted for extension");
browser.test.sendMessage("done");
}
let extension = ExtensionTestUtils.loadExtension({
manifest: {
content_scripts: [{
"matches": ["http://green.example.com/pixel.html"],
"js": ["cs.js"],
}],
},
files: {
"cs.js": contentScript,
},
});
await extension.startup();
let contentPage = await ExtensionTestUtils.loadContentPage("http://green.example.com/pixel.html");
await extension.awaitMessage("done");
await contentPage.close();
await extension.unload();
});

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

@ -3,6 +3,7 @@ skip-if = os == "android" || (os == "win" && debug) || (os == "linux")
[test_ext_i18n_css.js]
[test_ext_contentscript.js]
[test_ext_contentscript_about_blank_start.js]
[test_ext_contentscript_canvas_tainting.js]
[test_ext_contentscript_scriptCreated.js]
[test_ext_contentscript_triggeringPrincipal.js]
skip-if = (os == "android" && debug) || (os == "win" && debug) # Windows: Bug 1438796

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

@ -446,13 +446,6 @@ nsChildView::Create(nsIWidget* aParent,
if (!gChildViewMethodsSwizzled) {
nsToolkit::SwizzleMethods([NSView class], @selector(mouseDownCanMoveWindow),
@selector(nsChildView_NSView_mouseDownCanMoveWindow));
#ifdef __LP64__
nsToolkit::SwizzleMethods([NSEvent class], @selector(addLocalMonitorForEventsMatchingMask:handler:),
@selector(nsChildView_NSEvent_addLocalMonitorForEventsMatchingMask:handler:),
true);
nsToolkit::SwizzleMethods([NSEvent class], @selector(removeMonitor:),
@selector(nsChildView_NSEvent_removeMonitor:), true);
#endif
gChildViewMethodsSwizzled = true;
}
@ -7274,48 +7267,3 @@ static const CGEventField kCGWindowNumberField = (const CGEventField) 51;
}
@end
#ifdef __LP64__
// When using blocks, at least on OS X 10.7, the OS sometimes calls
// +[NSEvent removeMonitor:] more than once on a single event monitor, which
// causes crashes. See bug 678607. We hook these methods to work around
// the problem.
@interface NSEvent (MethodSwizzling)
+ (id)nsChildView_NSEvent_addLocalMonitorForEventsMatchingMask:(unsigned long long)mask handler:(id)block;
+ (void)nsChildView_NSEvent_removeMonitor:(id)eventMonitor;
@end
// This is a local copy of the AppKit frameworks sEventObservers hashtable.
// It only stores "local monitors". We use it to ensure that +[NSEvent
// removeMonitor:] is never called more than once on the same local monitor.
static NSHashTable *sLocalEventObservers = nil;
@implementation NSEvent (MethodSwizzling)
+ (id)nsChildView_NSEvent_addLocalMonitorForEventsMatchingMask:(unsigned long long)mask handler:(id)block
{
if (!sLocalEventObservers) {
sLocalEventObservers = [[NSHashTable hashTableWithOptions:
NSHashTableStrongMemory | NSHashTableObjectPointerPersonality] retain];
}
id retval =
[self nsChildView_NSEvent_addLocalMonitorForEventsMatchingMask:mask handler:block];
if (sLocalEventObservers && retval && ![sLocalEventObservers containsObject:retval]) {
[sLocalEventObservers addObject:retval];
}
return retval;
}
+ (void)nsChildView_NSEvent_removeMonitor:(id)eventMonitor
{
if (sLocalEventObservers && [eventMonitor isKindOfClass: ::NSClassFromString(@"_NSLocalEventObserver")]) {
if (![sLocalEventObservers containsObject:eventMonitor]) {
return;
}
[sLocalEventObservers removeObject:eventMonitor];
}
[self nsChildView_NSEvent_removeMonitor:eventMonitor];
}
@end
#endif // #ifdef __LP64__