Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "BasicCompositor.h"
7 #include "BasicLayersImpl.h" // for FillRectWithMask
8 #include "TextureHostBasic.h"
9 #include "mozilla/layers/Effects.h"
10 #include "mozilla/layers/YCbCrImageDataSerializer.h"
11 #include "nsIWidget.h"
12 #include "gfx2DGlue.h"
13 #include "mozilla/gfx/2D.h"
14 #include "mozilla/gfx/Helpers.h"
15 #include "gfxUtils.h"
16 #include "YCbCrUtils.h"
17 #include <algorithm>
18 #include "ImageContainer.h"
19 #include "gfxPrefs.h"
20 #define PIXMAN_DONT_DEFINE_STDINT
21 #include "pixman.h" // for pixman_f_transform, etc
23 namespace mozilla {
24 using namespace mozilla::gfx;
26 namespace layers {
28 class DataTextureSourceBasic : public DataTextureSource
29 , public TextureSourceBasic
30 {
31 public:
33 virtual TextureSourceBasic* AsSourceBasic() MOZ_OVERRIDE { return this; }
35 virtual gfx::SourceSurface* GetSurface(DrawTarget* aTarget) MOZ_OVERRIDE { return mSurface; }
37 SurfaceFormat GetFormat() const MOZ_OVERRIDE
38 {
39 return mSurface->GetFormat();
40 }
42 virtual IntSize GetSize() const MOZ_OVERRIDE
43 {
44 return mSurface->GetSize();
45 }
47 virtual bool Update(gfx::DataSourceSurface* aSurface,
48 nsIntRegion* aDestRegion = nullptr,
49 gfx::IntPoint* aSrcOffset = nullptr) MOZ_OVERRIDE
50 {
51 // XXX - For this to work with IncrementalContentHost we will need to support
52 // the aDestRegion and aSrcOffset parameters properly;
53 mSurface = aSurface;
54 return true;
55 }
57 virtual void DeallocateDeviceData() MOZ_OVERRIDE
58 {
59 mSurface = nullptr;
60 SetUpdateSerial(0);
61 }
63 public:
64 RefPtr<gfx::DataSourceSurface> mSurface;
65 };
67 BasicCompositor::BasicCompositor(nsIWidget *aWidget)
68 : mWidget(aWidget)
69 {
70 MOZ_COUNT_CTOR(BasicCompositor);
71 SetBackend(LayersBackend::LAYERS_BASIC);
72 }
74 BasicCompositor::~BasicCompositor()
75 {
76 MOZ_COUNT_DTOR(BasicCompositor);
77 }
79 void BasicCompositor::Destroy()
80 {
81 mWidget->CleanupRemoteDrawing();
82 mWidget = nullptr;
83 }
85 TemporaryRef<CompositingRenderTarget>
86 BasicCompositor::CreateRenderTarget(const IntRect& aRect, SurfaceInitMode aInit)
87 {
88 RefPtr<DrawTarget> target = mDrawTarget->CreateSimilarDrawTarget(aRect.Size(), SurfaceFormat::B8G8R8A8);
90 RefPtr<BasicCompositingRenderTarget> rt = new BasicCompositingRenderTarget(target, aRect);
92 return rt.forget();
93 }
95 TemporaryRef<CompositingRenderTarget>
96 BasicCompositor::CreateRenderTargetFromSource(const IntRect &aRect,
97 const CompositingRenderTarget *aSource,
98 const IntPoint &aSourcePoint)
99 {
100 RefPtr<DrawTarget> target = mDrawTarget->CreateSimilarDrawTarget(aRect.Size(), SurfaceFormat::B8G8R8A8);
101 RefPtr<BasicCompositingRenderTarget> rt = new BasicCompositingRenderTarget(target, aRect);
103 DrawTarget *source;
104 if (aSource) {
105 const BasicCompositingRenderTarget* sourceSurface =
106 static_cast<const BasicCompositingRenderTarget*>(aSource);
107 source = sourceSurface->mDrawTarget;
108 } else {
109 source = mDrawTarget;
110 }
112 RefPtr<SourceSurface> snapshot = source->Snapshot();
114 IntRect sourceRect(aSourcePoint, aRect.Size());
115 rt->mDrawTarget->CopySurface(snapshot, sourceRect, IntPoint(0, 0));
116 return rt.forget();
117 }
119 TemporaryRef<DataTextureSource>
120 BasicCompositor::CreateDataTextureSource(TextureFlags aFlags)
121 {
122 RefPtr<DataTextureSource> result = new DataTextureSourceBasic();
123 return result.forget();
124 }
126 bool
127 BasicCompositor::SupportsEffect(EffectTypes aEffect)
128 {
129 return static_cast<EffectTypes>(aEffect) != EFFECT_YCBCR;
130 }
132 static void
133 DrawSurfaceWithTextureCoords(DrawTarget *aDest,
134 const gfx::Rect& aDestRect,
135 SourceSurface *aSource,
136 const gfx::Rect& aTextureCoords,
137 gfx::Filter aFilter,
138 float aOpacity,
139 SourceSurface *aMask,
140 const Matrix* aMaskTransform)
141 {
142 // Convert aTextureCoords into aSource's coordinate space
143 gfxRect sourceRect(aTextureCoords.x * aSource->GetSize().width,
144 aTextureCoords.y * aSource->GetSize().height,
145 aTextureCoords.width * aSource->GetSize().width,
146 aTextureCoords.height * aSource->GetSize().height);
147 // Compute a transform that maps sourceRect to aDestRect.
148 gfxMatrix transform =
149 gfxUtils::TransformRectToRect(sourceRect,
150 gfxPoint(aDestRect.x, aDestRect.y),
151 gfxPoint(aDestRect.XMost(), aDestRect.y),
152 gfxPoint(aDestRect.XMost(), aDestRect.YMost()));
153 Matrix matrix = ToMatrix(transform);
155 // Only use REPEAT if aTextureCoords is outside (0, 0, 1, 1).
156 gfx::Rect unitRect(0, 0, 1, 1);
157 ExtendMode mode = unitRect.Contains(aTextureCoords) ? ExtendMode::CLAMP : ExtendMode::REPEAT;
159 FillRectWithMask(aDest, aDestRect, aSource, aFilter, DrawOptions(aOpacity),
160 mode, aMask, aMaskTransform, &matrix);
161 }
163 static pixman_transform
164 Matrix3DToPixman(const gfx3DMatrix& aMatrix)
165 {
166 pixman_f_transform transform;
168 transform.m[0][0] = aMatrix._11;
169 transform.m[0][1] = aMatrix._21;
170 transform.m[0][2] = aMatrix._41;
171 transform.m[1][0] = aMatrix._12;
172 transform.m[1][1] = aMatrix._22;
173 transform.m[1][2] = aMatrix._42;
174 transform.m[2][0] = aMatrix._14;
175 transform.m[2][1] = aMatrix._24;
176 transform.m[2][2] = aMatrix._44;
178 pixman_transform result;
179 pixman_transform_from_pixman_f_transform(&result, &transform);
181 return result;
182 }
184 static void
185 PixmanTransform(DataSourceSurface* aDest,
186 DataSourceSurface* aSource,
187 const gfx3DMatrix& aTransform,
188 gfxPoint aDestOffset)
189 {
190 IntSize destSize = aDest->GetSize();
191 pixman_image_t* dest = pixman_image_create_bits(PIXMAN_a8r8g8b8,
192 destSize.width,
193 destSize.height,
194 (uint32_t*)aDest->GetData(),
195 aDest->Stride());
197 IntSize srcSize = aSource->GetSize();
198 pixman_image_t* src = pixman_image_create_bits(PIXMAN_a8r8g8b8,
199 srcSize.width,
200 srcSize.height,
201 (uint32_t*)aSource->GetData(),
202 aSource->Stride());
204 NS_ABORT_IF_FALSE(src && dest, "Failed to create pixman images?");
206 pixman_transform pixTransform = Matrix3DToPixman(aTransform);
207 pixman_transform pixTransformInverted;
209 // If the transform is singular then nothing would be drawn anyway, return here
210 if (!pixman_transform_invert(&pixTransformInverted, &pixTransform)) {
211 pixman_image_unref(dest);
212 pixman_image_unref(src);
213 return;
214 }
215 pixman_image_set_transform(src, &pixTransformInverted);
217 pixman_image_composite32(PIXMAN_OP_SRC,
218 src,
219 nullptr,
220 dest,
221 aDestOffset.x,
222 aDestOffset.y,
223 0,
224 0,
225 0,
226 0,
227 destSize.width,
228 destSize.height);
230 pixman_image_unref(dest);
231 pixman_image_unref(src);
232 }
234 static inline IntRect
235 RoundOut(Rect r)
236 {
237 r.RoundOut();
238 return IntRect(r.x, r.y, r.width, r.height);
239 }
241 void
242 BasicCompositor::DrawQuad(const gfx::Rect& aRect,
243 const gfx::Rect& aClipRect,
244 const EffectChain &aEffectChain,
245 gfx::Float aOpacity,
246 const gfx::Matrix4x4 &aTransform)
247 {
248 RefPtr<DrawTarget> buffer = mRenderTarget->mDrawTarget;
250 // For 2D drawing, |dest| and |buffer| are the same surface. For 3D drawing,
251 // |dest| is a temporary surface.
252 RefPtr<DrawTarget> dest = buffer;
254 buffer->PushClipRect(aClipRect);
255 AutoSaveTransform autoSaveTransform(dest);
257 Matrix newTransform;
258 Rect transformBounds;
259 gfx3DMatrix new3DTransform;
260 IntPoint offset = mRenderTarget->GetOrigin();
262 if (aTransform.Is2D()) {
263 newTransform = aTransform.As2D();
264 } else {
265 // Create a temporary surface for the transform.
266 dest = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(RoundOut(aRect).Size(), SurfaceFormat::B8G8R8A8);
267 if (!dest) {
268 return;
269 }
271 // Get the bounds post-transform.
272 To3DMatrix(aTransform, new3DTransform);
273 gfxRect bounds = new3DTransform.TransformBounds(ThebesRect(aRect));
274 bounds.IntersectRect(bounds, gfxRect(offset.x, offset.y, buffer->GetSize().width, buffer->GetSize().height));
276 transformBounds = ToRect(bounds);
277 transformBounds.RoundOut();
279 // Propagate the coordinate offset to our 2D draw target.
280 newTransform.Translate(transformBounds.x, transformBounds.y);
282 // When we apply the 3D transformation, we do it against a temporary
283 // surface, so undo the coordinate offset.
284 new3DTransform = new3DTransform * gfx3DMatrix::Translation(-transformBounds.x, -transformBounds.y, 0);
286 transformBounds.MoveTo(0, 0);
287 }
289 newTransform.PostTranslate(-offset.x, -offset.y);
290 buffer->SetTransform(newTransform);
292 RefPtr<SourceSurface> sourceMask;
293 Matrix maskTransform;
294 if (aEffectChain.mSecondaryEffects[EFFECT_MASK]) {
295 EffectMask *effectMask = static_cast<EffectMask*>(aEffectChain.mSecondaryEffects[EFFECT_MASK].get());
296 sourceMask = effectMask->mMaskTexture->AsSourceBasic()->GetSurface(dest);
297 MOZ_ASSERT(effectMask->mMaskTransform.Is2D(), "How did we end up with a 3D transform here?!");
298 MOZ_ASSERT(!effectMask->mIs3D);
299 maskTransform = effectMask->mMaskTransform.As2D();
300 maskTransform.Translate(-offset.x, -offset.y);
301 }
303 switch (aEffectChain.mPrimaryEffect->mType) {
304 case EFFECT_SOLID_COLOR: {
305 EffectSolidColor* effectSolidColor =
306 static_cast<EffectSolidColor*>(aEffectChain.mPrimaryEffect.get());
308 FillRectWithMask(dest, aRect, effectSolidColor->mColor,
309 DrawOptions(aOpacity), sourceMask, &maskTransform);
310 break;
311 }
312 case EFFECT_RGB: {
313 TexturedEffect* texturedEffect =
314 static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get());
315 TextureSourceBasic* source = texturedEffect->mTexture->AsSourceBasic();
317 DrawSurfaceWithTextureCoords(dest, aRect,
318 source->GetSurface(dest),
319 texturedEffect->mTextureCoords,
320 texturedEffect->mFilter,
321 aOpacity, sourceMask, &maskTransform);
322 break;
323 }
324 case EFFECT_YCBCR: {
325 NS_RUNTIMEABORT("Can't (easily) support component alpha with BasicCompositor!");
326 break;
327 }
328 case EFFECT_RENDER_TARGET: {
329 EffectRenderTarget* effectRenderTarget =
330 static_cast<EffectRenderTarget*>(aEffectChain.mPrimaryEffect.get());
331 RefPtr<BasicCompositingRenderTarget> surface
332 = static_cast<BasicCompositingRenderTarget*>(effectRenderTarget->mRenderTarget.get());
333 RefPtr<SourceSurface> sourceSurf = surface->mDrawTarget->Snapshot();
335 DrawSurfaceWithTextureCoords(dest, aRect,
336 sourceSurf,
337 effectRenderTarget->mTextureCoords,
338 effectRenderTarget->mFilter,
339 aOpacity, sourceMask, &maskTransform);
340 break;
341 }
342 case EFFECT_COMPONENT_ALPHA: {
343 NS_RUNTIMEABORT("Can't (easily) support component alpha with BasicCompositor!");
344 break;
345 }
346 default: {
347 NS_RUNTIMEABORT("Invalid effect type!");
348 break;
349 }
350 }
352 if (!aTransform.Is2D()) {
353 dest->Flush();
355 RefPtr<SourceSurface> snapshot = dest->Snapshot();
356 RefPtr<DataSourceSurface> source = snapshot->GetDataSurface();
357 RefPtr<DataSourceSurface> temp =
358 Factory::CreateDataSourceSurface(RoundOut(transformBounds).Size(), SurfaceFormat::B8G8R8A8);
359 if (!temp) {
360 return;
361 }
363 PixmanTransform(temp, source, new3DTransform, gfxPoint(0, 0));
365 buffer->DrawSurface(temp, transformBounds, transformBounds);
366 }
368 buffer->PopClip();
369 }
371 void
372 BasicCompositor::BeginFrame(const nsIntRegion& aInvalidRegion,
373 const gfx::Rect *aClipRectIn,
374 const gfx::Matrix& aTransform,
375 const gfx::Rect& aRenderBounds,
376 gfx::Rect *aClipRectOut /* = nullptr */,
377 gfx::Rect *aRenderBoundsOut /* = nullptr */)
378 {
379 nsIntRect intRect;
380 mWidget->GetClientBounds(intRect);
381 mWidgetSize = gfx::ToIntSize(intRect.Size());
383 // The result of GetClientBounds is shifted over by the size of the window
384 // manager styling. We want to ignore that.
385 intRect.MoveTo(0, 0);
386 Rect rect = Rect(0, 0, intRect.width, intRect.height);
388 // Sometimes the invalid region is larger than we want to draw.
389 nsIntRegion invalidRegionSafe;
390 invalidRegionSafe.And(aInvalidRegion, intRect);
392 // FIXME: Redraw the whole screen in every frame to work around bug 972728.
393 invalidRegionSafe = intRect;
395 nsIntRect invalidRect = invalidRegionSafe.GetBounds();
396 mInvalidRect = IntRect(invalidRect.x, invalidRect.y, invalidRect.width, invalidRect.height);
397 mInvalidRegion = invalidRegionSafe;
399 if (aRenderBoundsOut) {
400 *aRenderBoundsOut = Rect();
401 }
403 if (mInvalidRect.width <= 0 || mInvalidRect.height <= 0) {
404 return;
405 }
407 if (mCopyTarget) {
408 // If we have a copy target, then we don't have a widget-provided mDrawTarget (currently). Create a dummy
409 // placeholder so that CreateRenderTarget() works.
410 mDrawTarget = gfxPlatform::GetPlatform()->CreateOffscreenCanvasDrawTarget(IntSize(1,1), SurfaceFormat::B8G8R8A8);
411 } else {
412 mDrawTarget = mWidget->StartRemoteDrawing();
413 }
414 if (!mDrawTarget) {
415 return;
416 }
418 // Setup an intermediate render target to buffer all compositing. We will
419 // copy this into mDrawTarget (the widget), and/or mCopyTarget in EndFrame()
420 RefPtr<CompositingRenderTarget> target = CreateRenderTarget(mInvalidRect, INIT_MODE_CLEAR);
421 SetRenderTarget(target);
423 // We only allocate a surface sized to the invalidated region, so we need to
424 // translate future coordinates.
425 Matrix transform;
426 transform.Translate(-invalidRect.x, -invalidRect.y);
427 mRenderTarget->mDrawTarget->SetTransform(transform);
429 gfxUtils::ClipToRegion(mRenderTarget->mDrawTarget, invalidRegionSafe);
431 if (aRenderBoundsOut) {
432 *aRenderBoundsOut = rect;
433 }
435 if (aClipRectIn) {
436 mRenderTarget->mDrawTarget->PushClipRect(*aClipRectIn);
437 } else {
438 mRenderTarget->mDrawTarget->PushClipRect(rect);
439 if (aClipRectOut) {
440 *aClipRectOut = rect;
441 }
442 }
443 }
445 void
446 BasicCompositor::EndFrame()
447 {
448 // Pop aClipRectIn/bounds rect
449 mRenderTarget->mDrawTarget->PopClip();
451 if (gfxPrefs::WidgetUpdateFlashing()) {
452 float r = float(rand()) / RAND_MAX;
453 float g = float(rand()) / RAND_MAX;
454 float b = float(rand()) / RAND_MAX;
455 // We're still clipped to mInvalidRegion, so just fill the bounds.
456 mRenderTarget->mDrawTarget->FillRect(ToRect(mInvalidRegion.GetBounds()),
457 ColorPattern(Color(r, g, b, 0.2f)));
458 }
460 // Pop aInvalidregion
461 mRenderTarget->mDrawTarget->PopClip();
463 // Note: Most platforms require us to buffer drawing to the widget surface.
464 // That's why we don't draw to mDrawTarget directly.
465 RefPtr<SourceSurface> source = mRenderTarget->mDrawTarget->Snapshot();
466 RefPtr<DrawTarget> dest(mCopyTarget ? mCopyTarget : mDrawTarget);
468 // The source DrawTarget is clipped to the invalidation region, so we have
469 // to copy the individual rectangles in the region or else we'll draw blank
470 // pixels.
471 nsIntRegionRectIterator iter(mInvalidRegion);
472 for (const nsIntRect *r = iter.Next(); r; r = iter.Next()) {
473 dest->CopySurface(source,
474 IntRect(r->x - mInvalidRect.x, r->y - mInvalidRect.y, r->width, r->height),
475 IntPoint(r->x, r->y));
476 }
477 if (!mCopyTarget) {
478 mWidget->EndRemoteDrawing();
479 }
481 mDrawTarget = nullptr;
482 mRenderTarget = nullptr;
483 }
485 void
486 BasicCompositor::AbortFrame()
487 {
488 mRenderTarget->mDrawTarget->PopClip();
489 mRenderTarget->mDrawTarget->PopClip();
490 mDrawTarget = nullptr;
491 mRenderTarget = nullptr;
492 }
494 }
495 }