gfx/layers/LayerSorter.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

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.

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 "LayerSorter.h"
michael@0 7 #include <math.h> // for fabs
michael@0 8 #include <stdint.h> // for uint32_t
michael@0 9 #include <stdio.h> // for fprintf, stderr, FILE
michael@0 10 #include <stdlib.h> // for getenv
michael@0 11 #include "DirectedGraph.h" // for DirectedGraph
michael@0 12 #include "Layers.h" // for Layer
michael@0 13 #include "gfx3DMatrix.h" // for gfx3DMatrix
michael@0 14 #include "gfxLineSegment.h" // for gfxLineSegment
michael@0 15 #include "gfxPoint.h" // for gfxPoint
michael@0 16 #include "gfxPoint3D.h" // for gfxPoint3D
michael@0 17 #include "gfxQuad.h" // for gfxQuad
michael@0 18 #include "gfxRect.h" // for gfxRect
michael@0 19 #include "gfxTypes.h" // for gfxFloat
michael@0 20 #include "mozilla/gfx/BasePoint3D.h" // for BasePoint3D
michael@0 21 #include "nsRegion.h" // for nsIntRegion
michael@0 22 #include "nsTArray.h" // for nsTArray, etc
michael@0 23 #include "limits.h"
michael@0 24 #include "mozilla/Assertions.h"
michael@0 25
michael@0 26 using namespace mozilla::gfx;
michael@0 27
michael@0 28 namespace mozilla {
michael@0 29 namespace layers {
michael@0 30
michael@0 31 enum LayerSortOrder {
michael@0 32 Undefined,
michael@0 33 ABeforeB,
michael@0 34 BBeforeA,
michael@0 35 };
michael@0 36
michael@0 37 /**
michael@0 38 * Recover the z component from a 2d transformed point by finding the intersection
michael@0 39 * of a line through the point in the z direction and the transformed plane.
michael@0 40 *
michael@0 41 * We want to solve:
michael@0 42 *
michael@0 43 * point = normal . (p0 - l0) / normal . l
michael@0 44 */
michael@0 45 static gfxFloat RecoverZDepth(const gfx3DMatrix& aTransform, const gfxPoint& aPoint)
michael@0 46 {
michael@0 47 const gfxPoint3D l(0, 0, 1);
michael@0 48 gfxPoint3D l0 = gfxPoint3D(aPoint.x, aPoint.y, 0);
michael@0 49 gfxPoint3D p0 = aTransform.Transform3D(gfxPoint3D(0, 0, 0));
michael@0 50 gfxPoint3D normal = aTransform.GetNormalVector();
michael@0 51
michael@0 52 gfxFloat n = normal.DotProduct(p0 - l0);
michael@0 53 gfxFloat d = normal.DotProduct(l);
michael@0 54
michael@0 55 if (!d) {
michael@0 56 return 0;
michael@0 57 }
michael@0 58
michael@0 59 return n/d;
michael@0 60 }
michael@0 61
michael@0 62 /**
michael@0 63 * Determine if this transform layer should be drawn before another when they
michael@0 64 * are both preserve-3d children.
michael@0 65 *
michael@0 66 * We want to find the relative z depths of the 2 layers at points where they
michael@0 67 * intersect when projected onto the 2d screen plane. Intersections are defined
michael@0 68 * as corners that are positioned within the other quad, as well as intersections
michael@0 69 * of the lines.
michael@0 70 *
michael@0 71 * We then choose the intersection point with the greatest difference in Z
michael@0 72 * depths and use this point to determine an ordering for the two layers.
michael@0 73 * For layers that are intersecting in 3d space, this essentially guesses an
michael@0 74 * order. In a lot of cases we only intersect right at the edge point (3d cubes
michael@0 75 * in particular) and this generates the 'correct' looking ordering. For planes
michael@0 76 * that truely intersect, then there is no correct ordering and this remains
michael@0 77 * unsolved without changing our rendering code.
michael@0 78 */
michael@0 79 static LayerSortOrder CompareDepth(Layer* aOne, Layer* aTwo) {
michael@0 80 gfxRect ourRect = aOne->GetEffectiveVisibleRegion().GetBounds();
michael@0 81 gfxRect otherRect = aTwo->GetEffectiveVisibleRegion().GetBounds();
michael@0 82
michael@0 83 gfx3DMatrix ourTransform;
michael@0 84 To3DMatrix(aOne->GetTransform(), ourTransform);
michael@0 85 gfx3DMatrix otherTransform;
michael@0 86 To3DMatrix(aTwo->GetTransform(), otherTransform);
michael@0 87
michael@0 88 // Transform both rectangles and project into 2d space.
michael@0 89 gfxQuad ourTransformedRect = ourTransform.TransformRect(ourRect);
michael@0 90 gfxQuad otherTransformedRect = otherTransform.TransformRect(otherRect);
michael@0 91
michael@0 92 gfxRect ourBounds = ourTransformedRect.GetBounds();
michael@0 93 gfxRect otherBounds = otherTransformedRect.GetBounds();
michael@0 94
michael@0 95 if (!ourBounds.Intersects(otherBounds)) {
michael@0 96 return Undefined;
michael@0 97 }
michael@0 98
michael@0 99 // Make a list of all points that are within the other rect.
michael@0 100 // Could we just check Contains() on the bounds rects. ie, is it possible
michael@0 101 // for layers to overlap without intersections (in 2d space) and yet still
michael@0 102 // have their bounds rects not completely enclose each other?
michael@0 103 nsTArray<gfxPoint> points;
michael@0 104 for (uint32_t i = 0; i < 4; i++) {
michael@0 105 if (ourTransformedRect.Contains(otherTransformedRect.mPoints[i])) {
michael@0 106 points.AppendElement(otherTransformedRect.mPoints[i]);
michael@0 107 }
michael@0 108 if (otherTransformedRect.Contains(ourTransformedRect.mPoints[i])) {
michael@0 109 points.AppendElement(ourTransformedRect.mPoints[i]);
michael@0 110 }
michael@0 111 }
michael@0 112
michael@0 113 // Look for intersections between lines (in 2d space) and use these as
michael@0 114 // depth testing points.
michael@0 115 for (uint32_t i = 0; i < 4; i++) {
michael@0 116 for (uint32_t j = 0; j < 4; j++) {
michael@0 117 gfxPoint intersection;
michael@0 118 gfxLineSegment one(ourTransformedRect.mPoints[i],
michael@0 119 ourTransformedRect.mPoints[(i + 1) % 4]);
michael@0 120 gfxLineSegment two(otherTransformedRect.mPoints[j],
michael@0 121 otherTransformedRect.mPoints[(j + 1) % 4]);
michael@0 122 if (one.Intersects(two, intersection)) {
michael@0 123 points.AppendElement(intersection);
michael@0 124 }
michael@0 125 }
michael@0 126 }
michael@0 127
michael@0 128 // No intersections, no defined order between these layers.
michael@0 129 if (points.IsEmpty()) {
michael@0 130 return Undefined;
michael@0 131 }
michael@0 132
michael@0 133 // Find the relative Z depths of each intersection point and check that the layers are in the same order.
michael@0 134 gfxFloat highest = 0;
michael@0 135 for (uint32_t i = 0; i < points.Length(); i++) {
michael@0 136 gfxFloat ourDepth = RecoverZDepth(ourTransform, points.ElementAt(i));
michael@0 137 gfxFloat otherDepth = RecoverZDepth(otherTransform, points.ElementAt(i));
michael@0 138
michael@0 139 gfxFloat difference = otherDepth - ourDepth;
michael@0 140
michael@0 141 if (fabs(difference) > fabs(highest)) {
michael@0 142 highest = difference;
michael@0 143 }
michael@0 144 }
michael@0 145 // If layers have the same depth keep the original order
michael@0 146 if (fabs(highest) < 0.1 || highest >= 0) {
michael@0 147 return ABeforeB;
michael@0 148 } else {
michael@0 149 return BBeforeA;
michael@0 150 }
michael@0 151 }
michael@0 152
michael@0 153 #ifdef DEBUG
michael@0 154 static bool gDumpLayerSortList = getenv("MOZ_DUMP_LAYER_SORT_LIST") != 0;
michael@0 155
michael@0 156 static const int BLACK = 0;
michael@0 157 static const int RED = 1;
michael@0 158 static const int GREEN = 2;
michael@0 159 static const int YELLOW = 3;
michael@0 160 static const int BLUE = 4;
michael@0 161 static const int MAGENTA = 5;
michael@0 162 static const int CYAN = 6;
michael@0 163 static const int WHITE = 7;
michael@0 164
michael@0 165 //#define USE_XTERM_COLORING
michael@0 166 #ifdef USE_XTERM_COLORING
michael@0 167
michael@0 168 static const int RESET = 0;
michael@0 169 static const int BRIGHT = 1;
michael@0 170 static const int DIM = 2;
michael@0 171 static const int UNDERLINE = 3;
michael@0 172 static const int BLINK = 4;
michael@0 173 static const int REVERSE = 7;
michael@0 174 static const int HIDDEN = 8;
michael@0 175
michael@0 176 static void SetTextColor(uint32_t aColor)
michael@0 177 {
michael@0 178 char command[13];
michael@0 179
michael@0 180 /* Command is the control command to the terminal */
michael@0 181 sprintf(command, "%c[%d;%d;%dm", 0x1B, RESET, aColor + 30, BLACK + 40);
michael@0 182 printf("%s", command);
michael@0 183 }
michael@0 184
michael@0 185 static void print_layer_internal(FILE* aFile, Layer* aLayer, uint32_t aColor)
michael@0 186 {
michael@0 187 SetTextColor(aColor);
michael@0 188 fprintf(aFile, "%p", aLayer);
michael@0 189 SetTextColor(GREEN);
michael@0 190 }
michael@0 191 #else
michael@0 192
michael@0 193 const char *colors[] = { "Black", "Red", "Green", "Yellow", "Blue", "Magenta", "Cyan", "White" };
michael@0 194
michael@0 195 static void print_layer_internal(FILE* aFile, Layer* aLayer, uint32_t aColor)
michael@0 196 {
michael@0 197 fprintf(aFile, "%p(%s)", aLayer, colors[aColor]);
michael@0 198 }
michael@0 199 #endif
michael@0 200
michael@0 201 static void print_layer(FILE* aFile, Layer* aLayer)
michael@0 202 {
michael@0 203 print_layer_internal(aFile, aLayer, aLayer->GetDebugColorIndex());
michael@0 204 }
michael@0 205
michael@0 206 static void DumpLayerList(nsTArray<Layer*>& aLayers)
michael@0 207 {
michael@0 208 for (uint32_t i = 0; i < aLayers.Length(); i++) {
michael@0 209 print_layer(stderr, aLayers.ElementAt(i));
michael@0 210 fprintf(stderr, " ");
michael@0 211 }
michael@0 212 fprintf(stderr, "\n");
michael@0 213 }
michael@0 214
michael@0 215 static void DumpEdgeList(DirectedGraph<Layer*>& aGraph)
michael@0 216 {
michael@0 217 const nsTArray<DirectedGraph<Layer*>::Edge>& edges = aGraph.GetEdgeList();
michael@0 218
michael@0 219 for (uint32_t i = 0; i < edges.Length(); i++) {
michael@0 220 fprintf(stderr, "From: ");
michael@0 221 print_layer(stderr, edges.ElementAt(i).mFrom);
michael@0 222 fprintf(stderr, ", To: ");
michael@0 223 print_layer(stderr, edges.ElementAt(i).mTo);
michael@0 224 fprintf(stderr, "\n");
michael@0 225 }
michael@0 226 }
michael@0 227 #endif
michael@0 228
michael@0 229 // The maximum number of layers that we will attempt to sort. Anything
michael@0 230 // greater than this will be left unsorted. We should consider enabling
michael@0 231 // depth buffering for the scene in this case.
michael@0 232 #define MAX_SORTABLE_LAYERS 100
michael@0 233
michael@0 234
michael@0 235 uint32_t gColorIndex = 1;
michael@0 236
michael@0 237 void SortLayersBy3DZOrder(nsTArray<Layer*>& aLayers)
michael@0 238 {
michael@0 239 uint32_t nodeCount = aLayers.Length();
michael@0 240 if (nodeCount > MAX_SORTABLE_LAYERS) {
michael@0 241 return;
michael@0 242 }
michael@0 243 DirectedGraph<Layer*> graph;
michael@0 244
michael@0 245 #ifdef DEBUG
michael@0 246 if (gDumpLayerSortList) {
michael@0 247 for (uint32_t i = 0; i < nodeCount; i++) {
michael@0 248 if (aLayers.ElementAt(i)->GetDebugColorIndex() == 0) {
michael@0 249 aLayers.ElementAt(i)->SetDebugColorIndex(gColorIndex++);
michael@0 250 if (gColorIndex > 7) {
michael@0 251 gColorIndex = 1;
michael@0 252 }
michael@0 253 }
michael@0 254 }
michael@0 255 fprintf(stderr, " --- Layers before sorting: --- \n");
michael@0 256 DumpLayerList(aLayers);
michael@0 257 }
michael@0 258 #endif
michael@0 259
michael@0 260 // Iterate layers and determine edges.
michael@0 261 for (uint32_t i = 0; i < nodeCount; i++) {
michael@0 262 for (uint32_t j = i + 1; j < nodeCount; j++) {
michael@0 263 Layer* a = aLayers.ElementAt(i);
michael@0 264 Layer* b = aLayers.ElementAt(j);
michael@0 265 LayerSortOrder order = CompareDepth(a, b);
michael@0 266 if (order == ABeforeB) {
michael@0 267 graph.AddEdge(a, b);
michael@0 268 } else if (order == BBeforeA) {
michael@0 269 graph.AddEdge(b, a);
michael@0 270 }
michael@0 271 }
michael@0 272 }
michael@0 273
michael@0 274 #ifdef DEBUG
michael@0 275 if (gDumpLayerSortList) {
michael@0 276 fprintf(stderr, " --- Edge List: --- \n");
michael@0 277 DumpEdgeList(graph);
michael@0 278 }
michael@0 279 #endif
michael@0 280
michael@0 281 // Build a new array using the graph.
michael@0 282 nsTArray<Layer*> noIncoming;
michael@0 283 nsTArray<Layer*> sortedList;
michael@0 284
michael@0 285 // Make a list of all layers with no incoming edges.
michael@0 286 noIncoming.AppendElements(aLayers);
michael@0 287 const nsTArray<DirectedGraph<Layer*>::Edge>& edges = graph.GetEdgeList();
michael@0 288 for (uint32_t i = 0; i < edges.Length(); i++) {
michael@0 289 noIncoming.RemoveElement(edges.ElementAt(i).mTo);
michael@0 290 }
michael@0 291
michael@0 292 // Move each item without incoming edges into the sorted list,
michael@0 293 // and remove edges from it.
michael@0 294 do {
michael@0 295 if (!noIncoming.IsEmpty()) {
michael@0 296 uint32_t last = noIncoming.Length() - 1;
michael@0 297
michael@0 298 Layer* layer = noIncoming.ElementAt(last);
michael@0 299 MOZ_ASSERT(layer); // don't let null layer pointers sneak into sortedList
michael@0 300
michael@0 301 noIncoming.RemoveElementAt(last);
michael@0 302 sortedList.AppendElement(layer);
michael@0 303
michael@0 304 nsTArray<DirectedGraph<Layer*>::Edge> outgoing;
michael@0 305 graph.GetEdgesFrom(layer, outgoing);
michael@0 306 for (uint32_t i = 0; i < outgoing.Length(); i++) {
michael@0 307 DirectedGraph<Layer*>::Edge edge = outgoing.ElementAt(i);
michael@0 308 graph.RemoveEdge(edge);
michael@0 309 if (!graph.NumEdgesTo(edge.mTo)) {
michael@0 310 // If this node also has no edges now, add it to the list
michael@0 311 noIncoming.AppendElement(edge.mTo);
michael@0 312 }
michael@0 313 }
michael@0 314 }
michael@0 315
michael@0 316 // If there are no nodes without incoming edges, but there
michael@0 317 // are still edges, then we have a cycle.
michael@0 318 if (noIncoming.IsEmpty() && graph.GetEdgeCount()) {
michael@0 319 // Find the node with the least incoming edges.
michael@0 320 uint32_t minEdges = UINT_MAX;
michael@0 321 Layer* minNode = nullptr;
michael@0 322 for (uint32_t i = 0; i < aLayers.Length(); i++) {
michael@0 323 uint32_t edgeCount = graph.NumEdgesTo(aLayers.ElementAt(i));
michael@0 324 if (edgeCount && edgeCount < minEdges) {
michael@0 325 minEdges = edgeCount;
michael@0 326 minNode = aLayers.ElementAt(i);
michael@0 327 if (minEdges == 1) {
michael@0 328 break;
michael@0 329 }
michael@0 330 }
michael@0 331 }
michael@0 332
michael@0 333 if (minNode) {
michael@0 334 // Remove all of them!
michael@0 335 graph.RemoveEdgesTo(minNode);
michael@0 336 noIncoming.AppendElement(minNode);
michael@0 337 }
michael@0 338 }
michael@0 339 } while (!noIncoming.IsEmpty());
michael@0 340 NS_ASSERTION(!graph.GetEdgeCount(), "Cycles detected!");
michael@0 341 #ifdef DEBUG
michael@0 342 if (gDumpLayerSortList) {
michael@0 343 fprintf(stderr, " --- Layers after sorting: --- \n");
michael@0 344 DumpLayerList(sortedList);
michael@0 345 }
michael@0 346 #endif
michael@0 347
michael@0 348 aLayers.Clear();
michael@0 349 aLayers.AppendElements(sortedList);
michael@0 350 }
michael@0 351
michael@0 352 }
michael@0 353 }

mercurial