1 /* -*- Mode: C++; tab-width: 2; 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 "BasicThebesLayer.h"
9 #include "RenderTrace.h"
15 using namespace mozilla::gfx
;
20 already_AddRefed
<gfxASurface
>
21 BasicThebesLayer::CreateBuffer(Buffer::ContentType aType
, const nsIntSize
& aSize
)
23 nsRefPtr
<gfxASurface
> referenceSurface
= mBuffer
.GetBuffer();
24 if (!referenceSurface
) {
25 gfxContext
* defaultTarget
= BasicManager()->GetDefaultTarget();
27 referenceSurface
= defaultTarget
->CurrentSurface();
29 nsIWidget
* widget
= BasicManager()->GetRetainerWidget();
30 if (!widget
|| !(referenceSurface
= widget
->GetThebesSurface())) {
31 referenceSurface
= BasicManager()->GetTarget()->CurrentSurface();
35 return referenceSurface
->CreateSimilarSurface(
36 aType
, gfxIntSize(aSize
.width
, aSize
.height
));
40 IntersectWithClip(const nsIntRegion
& aRegion
, gfxContext
* aContext
)
42 gfxRect clip
= aContext
->GetClipExtents();
44 nsIntRect
r(clip
.X(), clip
.Y(), clip
.Width(), clip
.Height());
46 result
.And(aRegion
, r
);
51 SetAntialiasingFlags(Layer
* aLayer
, gfxContext
* aTarget
)
53 if (!aTarget
->IsCairo()) {
54 RefPtr
<DrawTarget
> dt
= aTarget
->GetDrawTarget();
56 if (dt
->GetFormat() != FORMAT_B8G8R8A8
) {
60 const nsIntRect
& bounds
= aLayer
->GetVisibleRegion().GetBounds();
61 gfx::Rect transformedBounds
= dt
->GetTransform().TransformBounds(gfx::Rect(Float(bounds
.x
), Float(bounds
.y
),
62 Float(bounds
.width
), Float(bounds
.height
)));
63 transformedBounds
.RoundOut();
64 IntRect intTransformedBounds
;
65 transformedBounds
.ToIntRect(&intTransformedBounds
);
66 dt
->SetPermitSubpixelAA(!(aLayer
->GetContentFlags() & Layer::CONTENT_COMPONENT_ALPHA
) ||
67 dt
->GetOpaqueRect().Contains(intTransformedBounds
));
69 nsRefPtr
<gfxASurface
> surface
= aTarget
->CurrentSurface();
70 if (surface
->GetContentType() != gfxASurface::CONTENT_COLOR_ALPHA
) {
71 // Destination doesn't have alpha channel; no need to set any special flags
75 const nsIntRect
& bounds
= aLayer
->GetVisibleRegion().GetBounds();
76 surface
->SetSubpixelAntialiasingEnabled(
77 !(aLayer
->GetContentFlags() & Layer::CONTENT_COMPONENT_ALPHA
) ||
78 surface
->GetOpaqueRect().Contains(
79 aTarget
->UserToDevice(gfxRect(bounds
.x
, bounds
.y
, bounds
.width
, bounds
.height
))));
84 BasicThebesLayer::PaintThebes(gfxContext
* aContext
,
86 LayerManager::DrawThebesLayerCallback aCallback
,
88 ReadbackProcessor
* aReadback
)
90 SAMPLE_LABEL("BasicThebesLayer", "PaintThebes");
91 NS_ASSERTION(BasicManager()->InDrawing(),
92 "Can only draw in drawing phase");
93 nsRefPtr
<gfxASurface
> targetSurface
= aContext
->CurrentSurface();
95 nsTArray
<ReadbackProcessor::Update
> readbackUpdates
;
96 if (aReadback
&& UsedForReadback()) {
97 aReadback
->GetThebesLayerUpdates(this, &readbackUpdates
);
99 SyncFrontBufferToBackBuffer();
101 bool canUseOpaqueSurface
= CanUseOpaqueSurface();
102 Buffer::ContentType contentType
=
103 canUseOpaqueSurface
? gfxASurface::CONTENT_COLOR
:
104 gfxASurface::CONTENT_COLOR_ALPHA
;
105 float opacity
= GetEffectiveOpacity();
107 if (!BasicManager()->IsRetained()) {
108 NS_ASSERTION(readbackUpdates
.IsEmpty(), "Can't do readback for non-retained layer");
110 mValidRegion
.SetEmpty();
113 nsIntRegion toDraw
= IntersectWithClip(GetEffectiveVisibleRegion(), aContext
);
115 RenderTraceInvalidateStart(this, "FFFF00", toDraw
.GetBounds());
117 if (!toDraw
.IsEmpty() && !IsHidden()) {
119 BasicManager()->SetTransactionIncomplete();
125 bool needsClipToVisibleRegion
= GetClipToVisibleRegion();
127 opacity
!= 1.0 || GetOperator() != gfxContext::OPERATOR_OVER
|| aMaskLayer
;
128 nsRefPtr
<gfxContext
> groupContext
;
131 BasicManager()->PushGroupForLayer(aContext
, this, toDraw
,
132 &needsClipToVisibleRegion
);
133 if (GetOperator() != gfxContext::OPERATOR_OVER
) {
134 needsClipToVisibleRegion
= true;
137 groupContext
= aContext
;
139 SetAntialiasingFlags(this, groupContext
);
140 aCallback(this, groupContext
, toDraw
, nsIntRegion(), aCallbackData
);
142 BasicManager()->PopGroupToSourceWithCachedSurface(aContext
, groupContext
);
143 if (needsClipToVisibleRegion
) {
144 gfxUtils::ClipToRegion(aContext
, toDraw
);
146 AutoSetOperator
setOperator(aContext
, GetOperator());
147 PaintWithMask(aContext
, opacity
, aMaskLayer
);
153 RenderTraceInvalidateEnd(this, "FFFF00");
159 #ifndef MOZ_GFX_OPTIMIZE_MOBILE
161 if (!GetEffectiveTransform().CanDraw2D(&transform
) ||
162 transform
.HasNonIntegerTranslation()) {
163 flags
|= ThebesLayerBuffer::PAINT_WILL_RESAMPLE
;
166 if (mDrawAtomically
) {
167 flags
|= ThebesLayerBuffer::PAINT_NO_ROTATION
;
169 Buffer::PaintState state
=
170 mBuffer
.BeginPaint(this, contentType
, flags
);
171 mValidRegion
.Sub(mValidRegion
, state
.mRegionToInvalidate
);
173 if (state
.mContext
) {
174 // The area that became invalid and is visible needs to be repainted
175 // (this could be the whole visible area if our buffer switched
176 // from RGB to RGBA, because we might need to repaint with
178 state
.mRegionToInvalidate
.And(state
.mRegionToInvalidate
,
179 GetEffectiveVisibleRegion());
180 nsIntRegion extendedDrawRegion
= state
.mRegionToDraw
;
181 SetAntialiasingFlags(this, state
.mContext
);
183 RenderTraceInvalidateStart(this, "FFFF00", state
.mRegionToDraw
.GetBounds());
185 PaintBuffer(state
.mContext
,
186 state
.mRegionToDraw
, extendedDrawRegion
, state
.mRegionToInvalidate
,
188 aCallback
, aCallbackData
);
191 RenderTraceInvalidateEnd(this, "FFFF00");
193 // It's possible that state.mRegionToInvalidate is nonempty here,
194 // if we are shrinking the valid region to nothing. So use mRegionToDraw
196 NS_WARN_IF_FALSE(state
.mRegionToDraw
.IsEmpty(),
197 "No context when we have something to draw; resource exhaustion?");
201 if (BasicManager()->IsTransactionIncomplete())
205 clipExtents
= aContext
->GetClipExtents();
206 if (!IsHidden() && !clipExtents
.IsEmpty()) {
207 AutoSetOperator
setOperator(aContext
, GetOperator());
208 mBuffer
.DrawTo(this, aContext
, opacity
, aMaskLayer
);
211 for (uint32_t i
= 0; i
< readbackUpdates
.Length(); ++i
) {
212 ReadbackProcessor::Update
& update
= readbackUpdates
[i
];
213 nsIntPoint offset
= update
.mLayer
->GetBackgroundLayerOffset();
214 nsRefPtr
<gfxContext
> ctx
=
215 update
.mLayer
->GetSink()->BeginUpdate(update
.mUpdateRect
+ offset
,
216 update
.mSequenceCounter
);
218 NS_ASSERTION(opacity
== 1.0, "Should only read back opaque layers");
219 ctx
->Translate(gfxPoint(offset
.x
, offset
.y
));
220 mBuffer
.DrawTo(this, ctx
, 1.0, aMaskLayer
);
221 update
.mLayer
->GetSink()->EndUpdate(ctx
, update
.mUpdateRect
+ offset
);
227 * AutoOpenBuffer is a helper that builds on top of AutoOpenSurface,
228 * which we need to get a gfxASurface from a SurfaceDescriptor. For
229 * other layer types, simple lexical scoping of AutoOpenSurface is
230 * easy. For ThebesLayers, the lifetime of buffer mappings doesn't
231 * exactly match simple lexical scopes, so naively putting
232 * AutoOpenSurfaces on the stack doesn't always work. We use this
233 * helper to track openings instead.
235 * Any surface that's opened while painting this ThebesLayer will
236 * notify this helper and register itself for unmapping.
238 * We ignore buffer destruction here because the shadow layers
239 * protocol already ensures that destroyed buffers stay alive until
240 * end-of-transaction.
242 struct NS_STACK_CLASS AutoBufferTracker
{
243 AutoBufferTracker(BasicShadowableThebesLayer
* aLayer
)
246 MOZ_ASSERT(!mLayer
->mBufferTracker
);
248 mLayer
->mBufferTracker
= this;
249 if (IsSurfaceDescriptorValid(mLayer
->mBackBuffer
)) {
250 mInitialBuffer
.construct(OPEN_READ_WRITE
, mLayer
->mBackBuffer
);
251 mLayer
->mBuffer
.ProvideBuffer(&mInitialBuffer
.ref());
255 ~AutoBufferTracker() {
256 mLayer
->mBufferTracker
= nullptr;
257 mLayer
->mBuffer
.RevokeBuffer();
258 // mInitialBuffer and mNewBuffer will clean up after themselves if
259 // they were constructed.
263 CreatedBuffer(const SurfaceDescriptor
& aDescriptor
) {
264 Maybe
<AutoOpenSurface
>* surface
= mNewBuffers
.AppendElement();
265 surface
->construct(OPEN_READ_WRITE
, aDescriptor
);
266 return surface
->ref().Get();
269 Maybe
<AutoOpenSurface
> mInitialBuffer
;
270 nsAutoTArray
<Maybe
<AutoOpenSurface
>, 2> mNewBuffers
;
271 BasicShadowableThebesLayer
* mLayer
;
274 AutoBufferTracker(const AutoBufferTracker
&) MOZ_DELETE
;
275 AutoBufferTracker
& operator=(const AutoBufferTracker
&) MOZ_DELETE
;
279 BasicShadowableThebesLayer::PaintThebes(gfxContext
* aContext
,
281 LayerManager::DrawThebesLayerCallback aCallback
,
283 ReadbackProcessor
* aReadback
)
286 BasicThebesLayer::PaintThebes(aContext
, aMaskLayer
, aCallback
, aCallbackData
, aReadback
);
290 AutoBufferTracker
tracker(this);
292 BasicThebesLayer::PaintThebes(aContext
, nullptr, aCallback
, aCallbackData
, aReadback
);
294 static_cast<BasicImplData
*>(aMaskLayer
->ImplData())
295 ->Paint(aContext
, nullptr);
301 BasicShadowableThebesLayer::SetBackBufferAndAttrs(const OptionalThebesBuffer
& aBuffer
,
302 const nsIntRegion
& aValidRegion
,
303 const OptionalThebesBuffer
& aReadOnlyFrontBuffer
,
304 const nsIntRegion
& aFrontUpdatedRegion
)
306 if (OptionalThebesBuffer::Tnull_t
== aBuffer
.type()) {
307 mBackBuffer
= SurfaceDescriptor();
309 mBackBuffer
= aBuffer
.get_ThebesBuffer().buffer();
310 mBackBufferRect
= aBuffer
.get_ThebesBuffer().rect();
311 mBackBufferRectRotation
= aBuffer
.get_ThebesBuffer().rotation();
313 mFrontAndBackBufferDiffer
= true;
314 mROFrontBuffer
= aReadOnlyFrontBuffer
;
315 mFrontUpdatedRegion
= aFrontUpdatedRegion
;
316 mFrontValidRegion
= aValidRegion
;
320 BasicShadowableThebesLayer::SyncFrontBufferToBackBuffer()
322 if (!mFrontAndBackBufferDiffer
) {
326 // We temporarily map our back buffer here in order to copy from the
327 // front buffer. We need a live buffer tracker in order to unmap
328 // that buffer when appropriate.
329 MOZ_ASSERT(mBufferTracker
);
331 gfxASurface
* backBuffer
= mBuffer
.GetBuffer();
332 if (!IsSurfaceDescriptorValid(mBackBuffer
)) {
333 MOZ_ASSERT(!backBuffer
);
334 MOZ_ASSERT(mROFrontBuffer
.type() == OptionalThebesBuffer::TThebesBuffer
);
335 const ThebesBuffer roFront
= mROFrontBuffer
.get_ThebesBuffer();
336 AutoOpenSurface
roFrontBuffer(OPEN_READ_ONLY
, roFront
.buffer());
337 AllocBackBuffer(roFrontBuffer
.ContentType(), roFrontBuffer
.Size());
339 mFrontAndBackBufferDiffer
= false;
341 Maybe
<AutoOpenSurface
> autoBackBuffer
;
343 autoBackBuffer
.construct(OPEN_READ_WRITE
, mBackBuffer
);
344 backBuffer
= autoBackBuffer
.ref().Get();
347 if (OptionalThebesBuffer::Tnull_t
== mROFrontBuffer
.type()) {
348 // We didn't get back a read-only ref to our old back buffer (the
349 // parent's new front buffer). If the parent is pushing updates
350 // to a texture it owns, then we probably got back the same buffer
351 // we pushed in the update and all is well. If not, ...
352 mValidRegion
= mFrontValidRegion
;
353 mBuffer
.SetBackingBuffer(backBuffer
, mBackBufferRect
, mBackBufferRectRotation
);
357 MOZ_LAYERS_LOG(("BasicShadowableThebes(%p): reading back <x=%d,y=%d,w=%d,h=%d>",
359 mFrontUpdatedRegion
.GetBounds().x
,
360 mFrontUpdatedRegion
.GetBounds().y
,
361 mFrontUpdatedRegion
.GetBounds().width
,
362 mFrontUpdatedRegion
.GetBounds().height
));
364 const ThebesBuffer roFront
= mROFrontBuffer
.get_ThebesBuffer();
365 AutoOpenSurface
autoROFront(OPEN_READ_ONLY
, roFront
.buffer());
366 mBuffer
.SetBackingBufferAndUpdateFrom(
368 autoROFront
.Get(), roFront
.rect(), roFront
.rotation(),
369 mFrontUpdatedRegion
);
370 mIsNewBuffer
= false;
371 // Now the new back buffer has the same (interesting) pixels as the
372 // new front buffer, and mValidRegion et al. are correct wrt the new
373 // back buffer (i.e. as they were for the old back buffer)
377 BasicShadowableThebesLayer::PaintBuffer(gfxContext
* aContext
,
378 const nsIntRegion
& aRegionToDraw
,
379 const nsIntRegion
& aExtendedRegionToDraw
,
380 const nsIntRegion
& aRegionToInvalidate
,
382 LayerManager::DrawThebesLayerCallback aCallback
,
385 Base::PaintBuffer(aContext
,
386 aRegionToDraw
, aExtendedRegionToDraw
, aRegionToInvalidate
,
388 aCallback
, aCallbackData
);
389 if (!HasShadow() || BasicManager()->IsTransactionIncomplete()) {
393 nsIntRegion updatedRegion
;
394 if (mIsNewBuffer
|| aDidSelfCopy
) {
395 // A buffer reallocation clears both buffers. The front buffer has all the
396 // content by now, but the back buffer is still clear. Here, in effect, we
397 // are saying to copy all of the pixels of the front buffer to the back.
398 // Also when we self-copied in the buffer, the buffer space
399 // changes and some changed buffer content isn't reflected in the
400 // draw or invalidate region (on purpose!). When this happens, we
401 // need to read back the entire buffer too.
402 updatedRegion
= mVisibleRegion
;
403 mIsNewBuffer
= false;
405 updatedRegion
= aRegionToDraw
;
408 NS_ASSERTION(mBuffer
.BufferRect().Contains(aRegionToDraw
.GetBounds()),
409 "Update outside of buffer rect!");
410 NS_ABORT_IF_FALSE(IsSurfaceDescriptorValid(mBackBuffer
),
411 "should have a back buffer by now");
412 BasicManager()->PaintedThebesBuffer(BasicManager()->Hold(this),
414 mBuffer
.BufferRect(),
415 mBuffer
.BufferRotation(),
420 BasicShadowableThebesLayer::AllocBackBuffer(Buffer::ContentType aType
,
421 const nsIntSize
& aSize
)
423 // This function may *not* open the buffer it allocates.
424 if (!BasicManager()->AllocBuffer(gfxIntSize(aSize
.width
, aSize
.height
),
427 enum { buflen
= 256 };
429 PR_snprintf(buf
, buflen
,
430 "creating ThebesLayer 'back buffer' failed! width=%d, height=%d, type=%x",
431 aSize
.width
, aSize
.height
, int(aType
));
432 NS_RUNTIMEABORT(buf
);
436 already_AddRefed
<gfxASurface
>
437 BasicShadowableThebesLayer::CreateBuffer(Buffer::ContentType aType
,
438 const nsIntSize
& aSize
)
441 return BasicThebesLayer::CreateBuffer(aType
, aSize
);
444 MOZ_LAYERS_LOG(("BasicShadowableThebes(%p): creating %d x %d buffer(x2)",
446 aSize
.width
, aSize
.height
));
448 if (IsSurfaceDescriptorValid(mBackBuffer
)) {
449 BasicManager()->DestroyedThebesBuffer(BasicManager()->Hold(this),
451 mBackBuffer
= SurfaceDescriptor();
454 AllocBackBuffer(aType
, aSize
);
456 NS_ABORT_IF_FALSE(!mIsNewBuffer
,
457 "Bad! Did we create a buffer twice without painting?");
461 nsRefPtr
<gfxASurface
> buffer
= mBufferTracker
->CreatedBuffer(mBackBuffer
);
462 return buffer
.forget();
466 BasicShadowableThebesLayer::Disconnect()
468 mBackBuffer
= SurfaceDescriptor();
469 BasicShadowableLayer::Disconnect();
473 class BasicShadowThebesLayer
: public ShadowThebesLayer
, public BasicImplData
{
475 BasicShadowThebesLayer(BasicShadowLayerManager
* aLayerManager
)
476 : ShadowThebesLayer(aLayerManager
, static_cast<BasicImplData
*>(this))
478 MOZ_COUNT_CTOR(BasicShadowThebesLayer
);
480 virtual ~BasicShadowThebesLayer()
482 // If Disconnect() wasn't called on us, then we assume that the
483 // remote side shut down and IPC is disconnected, so we let IPDL
484 // clean up our front surface Shmem.
485 MOZ_COUNT_DTOR(BasicShadowThebesLayer
);
488 virtual void SetValidRegion(const nsIntRegion
& aRegion
)
490 mOldValidRegion
= mValidRegion
;
491 ShadowThebesLayer::SetValidRegion(aRegion
);
494 virtual void Disconnect()
496 DestroyFrontBuffer();
497 ShadowThebesLayer::Disconnect();
501 Swap(const ThebesBuffer
& aNewFront
, const nsIntRegion
& aUpdatedRegion
,
502 OptionalThebesBuffer
* aNewBack
, nsIntRegion
* aNewBackValidRegion
,
503 OptionalThebesBuffer
* aReadOnlyFront
, nsIntRegion
* aFrontUpdatedRegion
);
505 virtual void DestroyFrontBuffer()
507 mFrontBuffer
.Clear();
508 mValidRegion
.SetEmpty();
509 mOldValidRegion
.SetEmpty();
511 if (IsSurfaceDescriptorValid(mFrontBufferDescriptor
)) {
512 mAllocator
->DestroySharedSurface(&mFrontBufferDescriptor
);
516 virtual void PaintThebes(gfxContext
* aContext
,
518 LayerManager::DrawThebesLayerCallback aCallback
,
520 ReadbackProcessor
* aReadback
);
523 BasicShadowLayerManager
* BasicManager()
525 return static_cast<BasicShadowLayerManager
*>(mManager
);
528 ShadowThebesLayerBuffer mFrontBuffer
;
529 // Describes the gfxASurface we hand out to |mFrontBuffer|.
530 SurfaceDescriptor mFrontBufferDescriptor
;
531 // When we receive an update from our remote partner, we stow away
532 // our previous parameters that described our previous front buffer.
533 // Then when we Swap() back/front buffers, we can return these
534 // parameters to our partner (adjusted as needed).
535 nsIntRegion mOldValidRegion
;
539 BasicShadowThebesLayer::Swap(const ThebesBuffer
& aNewFront
,
540 const nsIntRegion
& aUpdatedRegion
,
541 OptionalThebesBuffer
* aNewBack
,
542 nsIntRegion
* aNewBackValidRegion
,
543 OptionalThebesBuffer
* aReadOnlyFront
,
544 nsIntRegion
* aFrontUpdatedRegion
)
546 if (IsSurfaceDescriptorValid(mFrontBufferDescriptor
)) {
547 AutoOpenSurface
autoNewFrontBuffer(OPEN_READ_ONLY
, aNewFront
.buffer());
548 AutoOpenSurface
autoCurrentFront(OPEN_READ_ONLY
, mFrontBufferDescriptor
);
549 if (autoCurrentFront
.Size() != autoNewFrontBuffer
.Size()) {
550 // Current front buffer is obsolete
551 DestroyFrontBuffer();
554 // This code relies on Swap() arriving *after* attribute mutations.
555 if (IsSurfaceDescriptorValid(mFrontBufferDescriptor
)) {
556 *aNewBack
= ThebesBuffer();
557 aNewBack
->get_ThebesBuffer().buffer() = mFrontBufferDescriptor
;
559 *aNewBack
= null_t();
561 // We have to invalidate the pixels painted into the new buffer.
562 // They might overlap with our old pixels.
563 aNewBackValidRegion
->Sub(mOldValidRegion
, aUpdatedRegion
);
566 nsIntPoint backRotation
;
568 aNewFront
.rect(), aNewFront
.rotation(),
569 &backRect
, &backRotation
);
571 if (aNewBack
->type() != OptionalThebesBuffer::Tnull_t
) {
572 aNewBack
->get_ThebesBuffer().rect() = backRect
;
573 aNewBack
->get_ThebesBuffer().rotation() = backRotation
;
576 mFrontBufferDescriptor
= aNewFront
.buffer();
578 *aReadOnlyFront
= aNewFront
;
579 *aFrontUpdatedRegion
= aUpdatedRegion
;
583 BasicShadowThebesLayer::PaintThebes(gfxContext
* aContext
,
585 LayerManager::DrawThebesLayerCallback aCallback
,
587 ReadbackProcessor
* aReadback
)
589 NS_ASSERTION(BasicManager()->InDrawing(),
590 "Can only draw in drawing phase");
591 NS_ASSERTION(BasicManager()->IsRetained(),
592 "ShadowThebesLayer makes no sense without retained mode");
594 if (!IsSurfaceDescriptorValid(mFrontBufferDescriptor
)) {
598 AutoOpenSurface
autoFrontBuffer(OPEN_READ_ONLY
, mFrontBufferDescriptor
);
599 mFrontBuffer
.ProvideBuffer(&autoFrontBuffer
);
601 mFrontBuffer
.DrawTo(this, aContext
, GetEffectiveOpacity(), aMaskLayer
);
603 mFrontBuffer
.RevokeBuffer();
606 already_AddRefed
<ThebesLayer
>
607 BasicLayerManager::CreateThebesLayer()
609 NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
610 nsRefPtr
<ThebesLayer
> layer
= new BasicThebesLayer(this);
611 return layer
.forget();
614 already_AddRefed
<ShadowThebesLayer
>
615 BasicShadowLayerManager::CreateShadowThebesLayer()
617 NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
618 nsRefPtr
<ShadowThebesLayer
> layer
= new BasicShadowThebesLayer(this);
619 return layer
.forget();