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.

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

mercurial