gfx/layers/ReadbackProcessor.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
michael@0 2 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "ReadbackProcessor.h"
michael@0 7 #include <sys/types.h> // for int32_t
michael@0 8 #include "Layers.h" // for Layer, ThebesLayer, etc
michael@0 9 #include "ReadbackLayer.h" // for ReadbackLayer, ReadbackSink
michael@0 10 #include "gfx3DMatrix.h" // for gfx3DMatrix
michael@0 11 #include "gfxColor.h" // for gfxRGBA
michael@0 12 #include "gfxContext.h" // for gfxContext
michael@0 13 #include "gfxRect.h" // for gfxRect
michael@0 14 #include "mozilla/gfx/BasePoint.h" // for BasePoint
michael@0 15 #include "mozilla/gfx/BaseRect.h" // for BaseRect
michael@0 16 #include "nsAutoPtr.h" // for nsRefPtr, nsAutoPtr
michael@0 17 #include "nsDebug.h" // for NS_ASSERTION
michael@0 18 #include "nsISupportsImpl.h" // for gfxContext::Release, etc
michael@0 19 #include "nsPoint.h" // for nsIntPoint
michael@0 20 #include "nsRegion.h" // for nsIntRegion
michael@0 21 #include "nsSize.h" // for nsIntSize
michael@0 22
michael@0 23 namespace mozilla {
michael@0 24 namespace layers {
michael@0 25
michael@0 26 void
michael@0 27 ReadbackProcessor::BuildUpdates(ContainerLayer* aContainer)
michael@0 28 {
michael@0 29 NS_ASSERTION(mAllUpdates.IsEmpty(), "Some updates not processed?");
michael@0 30
michael@0 31 if (!aContainer->mMayHaveReadbackChild)
michael@0 32 return;
michael@0 33
michael@0 34 aContainer->mMayHaveReadbackChild = false;
michael@0 35 // go backwards so the updates read from earlier layers are later in the
michael@0 36 // array.
michael@0 37 for (Layer* l = aContainer->GetLastChild(); l; l = l->GetPrevSibling()) {
michael@0 38 if (l->GetType() == Layer::TYPE_READBACK) {
michael@0 39 aContainer->mMayHaveReadbackChild = true;
michael@0 40 BuildUpdatesForLayer(static_cast<ReadbackLayer*>(l));
michael@0 41 }
michael@0 42 }
michael@0 43 }
michael@0 44
michael@0 45 static Layer*
michael@0 46 FindBackgroundLayer(ReadbackLayer* aLayer, nsIntPoint* aOffset)
michael@0 47 {
michael@0 48 gfx::Matrix transform;
michael@0 49 if (!aLayer->GetTransform().Is2D(&transform) ||
michael@0 50 transform.HasNonIntegerTranslation())
michael@0 51 return nullptr;
michael@0 52 nsIntPoint transformOffset(int32_t(transform._31), int32_t(transform._32));
michael@0 53
michael@0 54 for (Layer* l = aLayer->GetPrevSibling(); l; l = l->GetPrevSibling()) {
michael@0 55 gfx::Matrix backgroundTransform;
michael@0 56 if (!l->GetTransform().Is2D(&backgroundTransform) ||
michael@0 57 gfx::ThebesMatrix(backgroundTransform).HasNonIntegerTranslation())
michael@0 58 return nullptr;
michael@0 59
michael@0 60 nsIntPoint backgroundOffset(int32_t(backgroundTransform._31), int32_t(backgroundTransform._32));
michael@0 61 nsIntRect rectInBackground(transformOffset - backgroundOffset, aLayer->GetSize());
michael@0 62 const nsIntRegion& visibleRegion = l->GetEffectiveVisibleRegion();
michael@0 63 if (!visibleRegion.Intersects(rectInBackground))
michael@0 64 continue;
michael@0 65 // Since l is present in the background, from here on we either choose l
michael@0 66 // or nothing.
michael@0 67 if (!visibleRegion.Contains(rectInBackground))
michael@0 68 return nullptr;
michael@0 69
michael@0 70 if (l->GetEffectiveOpacity() != 1.0 ||
michael@0 71 !(l->GetContentFlags() & Layer::CONTENT_OPAQUE))
michael@0 72 return nullptr;
michael@0 73
michael@0 74 // cliprects are post-transform
michael@0 75 const nsIntRect* clipRect = l->GetEffectiveClipRect();
michael@0 76 if (clipRect && !clipRect->Contains(nsIntRect(transformOffset, aLayer->GetSize())))
michael@0 77 return nullptr;
michael@0 78
michael@0 79 Layer::LayerType type = l->GetType();
michael@0 80 if (type != Layer::TYPE_COLOR && type != Layer::TYPE_THEBES)
michael@0 81 return nullptr;
michael@0 82
michael@0 83 *aOffset = backgroundOffset - transformOffset;
michael@0 84 return l;
michael@0 85 }
michael@0 86
michael@0 87 return nullptr;
michael@0 88 }
michael@0 89
michael@0 90 void
michael@0 91 ReadbackProcessor::BuildUpdatesForLayer(ReadbackLayer* aLayer)
michael@0 92 {
michael@0 93 if (!aLayer->mSink)
michael@0 94 return;
michael@0 95
michael@0 96 nsIntPoint offset;
michael@0 97 Layer* newBackground = FindBackgroundLayer(aLayer, &offset);
michael@0 98 if (!newBackground) {
michael@0 99 aLayer->SetUnknown();
michael@0 100 return;
michael@0 101 }
michael@0 102
michael@0 103 if (newBackground->GetType() == Layer::TYPE_COLOR) {
michael@0 104 ColorLayer* colorLayer = static_cast<ColorLayer*>(newBackground);
michael@0 105 if (aLayer->mBackgroundColor != colorLayer->GetColor()) {
michael@0 106 aLayer->mBackgroundLayer = nullptr;
michael@0 107 aLayer->mBackgroundColor = colorLayer->GetColor();
michael@0 108 NS_ASSERTION(aLayer->mBackgroundColor.a == 1.0,
michael@0 109 "Color layer said it was opaque!");
michael@0 110 nsRefPtr<gfxContext> ctx =
michael@0 111 aLayer->mSink->BeginUpdate(aLayer->GetRect(),
michael@0 112 aLayer->AllocateSequenceNumber());
michael@0 113 if (ctx) {
michael@0 114 ctx->SetColor(aLayer->mBackgroundColor);
michael@0 115 nsIntSize size = aLayer->GetSize();
michael@0 116 ctx->Rectangle(gfxRect(0, 0, size.width, size.height));
michael@0 117 ctx->Fill();
michael@0 118 aLayer->mSink->EndUpdate(ctx, aLayer->GetRect());
michael@0 119 }
michael@0 120 }
michael@0 121 } else {
michael@0 122 NS_ASSERTION(newBackground->AsThebesLayer(), "Must be ThebesLayer");
michael@0 123 ThebesLayer* thebesLayer = static_cast<ThebesLayer*>(newBackground);
michael@0 124 // updateRect is relative to the ThebesLayer
michael@0 125 nsIntRect updateRect = aLayer->GetRect() - offset;
michael@0 126 if (thebesLayer != aLayer->mBackgroundLayer ||
michael@0 127 offset != aLayer->mBackgroundLayerOffset) {
michael@0 128 aLayer->mBackgroundLayer = thebesLayer;
michael@0 129 aLayer->mBackgroundLayerOffset = offset;
michael@0 130 aLayer->mBackgroundColor = gfxRGBA(0,0,0,0);
michael@0 131 thebesLayer->SetUsedForReadback(true);
michael@0 132 } else {
michael@0 133 nsIntRegion invalid;
michael@0 134 invalid.Sub(updateRect, thebesLayer->GetValidRegion());
michael@0 135 updateRect = invalid.GetBounds();
michael@0 136 }
michael@0 137
michael@0 138 Update update = { aLayer, updateRect, aLayer->AllocateSequenceNumber() };
michael@0 139 mAllUpdates.AppendElement(update);
michael@0 140 }
michael@0 141 }
michael@0 142
michael@0 143 void
michael@0 144 ReadbackProcessor::GetThebesLayerUpdates(ThebesLayer* aLayer,
michael@0 145 nsTArray<Update>* aUpdates,
michael@0 146 nsIntRegion* aUpdateRegion)
michael@0 147 {
michael@0 148 // All ThebesLayers used for readback are in mAllUpdates (some possibly
michael@0 149 // with an empty update rect).
michael@0 150 aLayer->SetUsedForReadback(false);
michael@0 151 if (aUpdateRegion) {
michael@0 152 aUpdateRegion->SetEmpty();
michael@0 153 }
michael@0 154 for (uint32_t i = mAllUpdates.Length(); i > 0; --i) {
michael@0 155 const Update& update = mAllUpdates[i - 1];
michael@0 156 if (update.mLayer->mBackgroundLayer == aLayer) {
michael@0 157 aLayer->SetUsedForReadback(true);
michael@0 158 // Don't bother asking for updates if we have an empty update rect.
michael@0 159 if (!update.mUpdateRect.IsEmpty()) {
michael@0 160 aUpdates->AppendElement(update);
michael@0 161 if (aUpdateRegion) {
michael@0 162 aUpdateRegion->Or(*aUpdateRegion, update.mUpdateRect);
michael@0 163 }
michael@0 164 }
michael@0 165 mAllUpdates.RemoveElementAt(i - 1);
michael@0 166 }
michael@0 167 }
michael@0 168 }
michael@0 169
michael@0 170 ReadbackProcessor::~ReadbackProcessor()
michael@0 171 {
michael@0 172 for (uint32_t i = mAllUpdates.Length(); i > 0; --i) {
michael@0 173 const Update& update = mAllUpdates[i - 1];
michael@0 174 // Unprocessed update. Notify the readback sink that this content is
michael@0 175 // unknown.
michael@0 176 update.mLayer->SetUnknown();
michael@0 177 }
michael@0 178 }
michael@0 179
michael@0 180 }
michael@0 181 }

mercurial