Changeset 112182 in webkit
- Timestamp:
- Mar 26, 2012 5:16:30 PM (12 years ago)
- Location:
- trunk/Source
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r112178 r112182 1 2012-03-26 Vangelis Kokkevis <vangelis@chromium.org> 2 3 [chromium] Simplify and fix CCLayerSorter 4 https://bugs.webkit.org/show_bug.cgi?id=82114 5 6 A significant cleanup, simplification and improvement of the CCLayerSorter code. 7 Simplified the LayerShape structure to use WebCore's FloatQuad for all overlap tests. 8 By treating every layer as two triangles, the old overlap code did a lot of redundant work 9 including testing two of the vertices of the layer and its diagonal twice. The new overlap 10 tests check: 11 1. The four corners of each of the two layers against the other layer. 12 2. The four edges of each layer against the edges of the other layer. 13 Unlike the old code, the new code has no early-outs in the overlap tests as those where causing 14 us to miss legitimate overlaps. 15 A new technique for breaking dependency cycles introduced by intersecting layers is implemented. 16 Instead of arbitrarily breaking cycles by choosing the node in the graph with the smallest number of 17 incoming edges (i.e. layers that need to be drawn before it) we chose the one with the smallest sum 18 of graph edge weights (defined as the max depth difference between two layers). Layers that intersect 19 have their respective graph edge weight set to zero, making them more likely to be picked for breaking 20 the cycles (it's not a perfect solution but it seems to perform much better than the previous one). 21 22 In addition to being overly complex and doing reduntant work, the old code was missing a 23 perspective divide when computing the coordinates of the layer's corners in the projected plane 24 which was the source of a lot of mis-sorted results. 25 26 In all, these improvements, fix a lot of outstanding issues with layer sorting, on pages such as: 27 http://www.keithclark.co.uk/labs/3dcss/demo/ 28 http://2012.beercamp.com 29 https://developer.mozilla.org/fr/demos/detail/the-box/launch 30 31 Tests: CCLayerSorter unit tests. 32 33 Reviewed by Kenneth Russell. 34 35 * platform/graphics/chromium/cc/CCLayerSorter.cpp: 36 (WebCore): 37 (WebCore::perpProduct): 38 (WebCore::edgeEdgeTest): 39 (WebCore::CCLayerSorter::checkOverlap): 40 (WebCore::CCLayerSorter::LayerShape::LayerShape): 41 (WebCore::CCLayerSorter::LayerShape::layerZFromProjectedPoint): 42 (WebCore::CCLayerSorter::createGraphNodes): 43 (WebCore::CCLayerSorter::createGraphEdges): 44 (WebCore::CCLayerSorter::sort): 45 * platform/graphics/chromium/cc/CCLayerSorter.h: 46 (WebCore::CCLayerSorter::CCLayerSorter): 47 (CCLayerSorter): 48 (LayerShape): 49 (WebCore::CCLayerSorter::GraphNode::GraphNode): 50 (GraphNode): 51 (WebCore::CCLayerSorter::GraphEdge::GraphEdge): 52 (GraphEdge): 53 1 54 2012-03-26 Fady Samuel <fsamuel@chromium.org> 2 55 -
trunk/Source/WebCore/platform/graphics/chromium/cc/CCLayerSorter.cpp
r108886 r112182 47 47 namespace WebCore { 48 48 49 bool CCLayerSorter::pointInTriangle(const FloatPoint& point,50 const FloatPoint& a,51 const FloatPoint& b,52 const FloatPoint& c)53 {54 // Algorithm from http://www.blackpawn.com/texts/pointinpoly/default.html55 float x0 = c.x() - a.x();56 float y0 = c.y() - a.y();57 float x1 = b.x() - a.x();58 float y1 = b.y() - a.y();59 float x2 = point.x() - a.x();60 float y2 = point.y() - a.y();61 62 float dot00 = x0 * x0 + y0 * y0;63 float dot01 = x0 * x1 + y0 * y1;64 float dot02 = x0 * x2 + y0 * y2;65 float dot11 = x1 * x1 + y1 * y1;66 float dot12 = x1 * x2 + y1 * y2;67 float denominator = dot00 * dot11 - dot01 * dot01;68 if (!denominator)69 // Triangle is zero-area. Treat query point as not being inside.70 return false;71 // Compute72 float inverseDenominator = 1.0f / denominator;73 float u = (dot11 * dot02 - dot01 * dot12) * inverseDenominator;74 float v = (dot00 * dot12 - dot01 * dot02) * inverseDenominator;75 76 return (u > 0.0f) && (v > 0.0f) && (u + v < 1.0f);77 }78 79 49 inline static float perpProduct(const FloatSize& u, const FloatSize& v) 80 50 { 81 51 return u.width() * v.height() - u.height() * v.width(); 82 }83 84 inline static float innerProduct(const FloatSize& u, const FloatSize& v)85 {86 return u.width() * v.width() + u.height() * v.height();87 }88 89 90 inline static bool pointInColinearEdge(const FloatPoint& p, const FloatPoint& a, const FloatPoint& b)91 {92 // if ab is not vertical.93 if (a.x() != b.x())94 return (p.x() >= min(a.x(), b.x()) && p.x() <= max(a.x(), b.x()));95 96 return (p.y() >= min(a.y(), b.y()) && p.y() <= max(a.y(), b.y()));97 52 } 98 53 … … 107 62 float denom = perpProduct(u, v); 108 63 109 // If denom == 0 then the edges are parallel. 110 if (!denom) { 111 // If the edges are not colinear then there's no intersection. 112 if (perpProduct(u, w) || perpProduct(v, w)) 113 return false; 114 115 if (pointInColinearEdge(a, c, d)) { 116 r = a; 117 return true; 118 } 119 if (pointInColinearEdge(b, c, d)) { 120 r = b; 121 return true; 122 } 123 if (pointInColinearEdge(c, a, b)) { 124 r = c; 125 return true; 126 } 127 if (pointInColinearEdge(d, a, b)) { 128 r = d; 129 return true; 130 } 131 64 // If denom == 0 then the edges are parallel. While they could be overlapping 65 // we don't bother to check here as the we'll find their intersections from the 66 // corner to quad tests. 67 if (!denom) 132 68 return false; 133 } 69 134 70 float s = perpProduct(v, w) / denom; 135 71 if (s < 0 || s > 1) … … 145 81 } 146 82 147 float CCLayerSorter::calculateZDiff(const LayerShape& layerA, const LayerShape& layerB, float earlyExitThreshold) 148 { 149 LayerIntersector intersector(layerA, layerB, earlyExitThreshold); 150 intersector.go(); 151 return intersector.zDiff; 152 } 153 154 CCLayerSorter::LayerIntersector::LayerIntersector(const LayerShape& layerA, const LayerShape& layerB, float earlyExitThreshold) 155 : layerA(layerA)156 , layerB(layerB)157 , zDiff(0) 158 , earlyExitThreshold(earlyExitThreshold)159 { 160 } 161 162 void CCLayerSorter::LayerIntersector::go() 163 { 164 (triangleTriangleTest(layerA.c1, layerA.c2, layerA.c3, layerB.c1, layerB.c2, layerB.c3)165 || triangleTriangleTest(layerA.c3, layerA.c4, layerA.c1, layerB.c1, layerB.c2, layerB.c3)166 || triangleTriangleTest(layerA.c1, layerA.c2, layerA.c3, layerB.c3, layerB.c4, layerB.c1)167 || triangleTriangleTest(layerA.c3, layerA.c4, layerA.c1, layerB.c3, layerB.c4, layerB.c1));168 } 169 170 // Checks if segment pq intersects any of the sides of triangle abc. 171 bool CCLayerSorter::LayerIntersector::edgeTriangleTest(const FloatPoint& p, const FloatPoint& q, const FloatPoint& a, const FloatPoint& b, const FloatPoint& c) 172 { 83 // Checks whether layer "a" draws on top of layer "b". The weight value returned is an indication of 84 // the maximum z-depth difference between the layers or zero if the layers are found to be intesecting 85 // (some features are in front and some are behind). 86 CCLayerSorter::ABCompareResult CCLayerSorter::checkOverlap(LayerShape* a, LayerShape* b, float zThreshold, float& weight) 87 { 88 weight = 0; 89 90 // Early out if the projected bounds don't overlap. 91 if (!a->projectedBounds.intersects(b->projectedBounds)) 92 return None; 93 94 FloatPoint aPoints[4] = {a->projectedQuad.p1(), a->projectedQuad.p2(), a->projectedQuad.p3(), a->projectedQuad.p4() }; 95 FloatPoint bPoints[4] = {b->projectedQuad.p1(), b->projectedQuad.p2(), b->projectedQuad.p3(), b->projectedQuad.p4() }; 96 97 // Make a list of points that inside both layer quad projections. 98 Vector<FloatPoint> overlapPoints; 99 100 // Check all four corners of one layer against the other layer's quad. 101 for (int i = 0; i < 4; ++i) { 102 if (a->projectedQuad.containsPoint(bPoints[i])) 103 overlapPoints.append(bPoints[i]); 104 if (b->projectedQuad.containsPoint(aPoints[i])) 105 overlapPoints.append(aPoints[i]); 106 } 107 108 // Check all the edges of one layer for intersection with the other layer's edges. 173 109 FloatPoint r; 174 if ((edgeEdgeTest(p, q, a, b, r) && checkZDiff(r)) 175 || (edgeEdgeTest(p, q, a, c, r) && checkZDiff(r)) 176 || (edgeEdgeTest(p, q, b, c, r) && checkZDiff(r))) 177 return true; 178 179 return false; 180 } 181 182 // Checks if two co-planar triangles intersect. 183 bool CCLayerSorter::LayerIntersector::triangleTriangleTest(const FloatPoint& a1, const FloatPoint& b1, const FloatPoint& c1, const FloatPoint& a2, const FloatPoint& b2, const FloatPoint& c2) 184 { 185 // Check all edges of first triangle with edges of the second one. 186 if (edgeTriangleTest(a1, b1, a2, b2, c2) 187 || edgeTriangleTest(a1, c1, a2, b2, c2) 188 || edgeTriangleTest(b1, c1, a2, b2, c2)) 189 return true; 190 191 // Check all points of the first triangle for inclusion in the second triangle. 192 if ((pointInTriangle(a1, a2, b2, c2) && checkZDiff(a1)) 193 || (pointInTriangle(b1, a2, b2, c2) && checkZDiff(b1)) 194 || (pointInTriangle(c1, a2, b2, c2) && checkZDiff(c1))) 195 return true; 196 197 // Check all points of the second triangle for inclusion in the first triangle. 198 if ((pointInTriangle(a2, a1, b1, c1) && checkZDiff(a2)) 199 || (pointInTriangle(b2, a1, b1, c1) && checkZDiff(b2)) 200 || (pointInTriangle(c2, a1, b1, c1) && checkZDiff(c2))) 201 return true; 202 203 return false; 204 } 205 206 // Computes the z difference between point p projected onto the two layers to determine 207 // which layer is in front. If the new z difference is higher than the currently 208 // recorded one the this becomes the point of choice for doing the comparison between the 209 // layers. If the value of difference is higher than our early exit threshold then 210 // it means that the z difference is conclusive enough that we don't have to check 211 // other intersection points. 212 bool CCLayerSorter::LayerIntersector::checkZDiff(const FloatPoint& p) 213 { 214 float za = layerZFromProjectedPoint(layerA, p); 215 float zb = layerZFromProjectedPoint(layerB, p); 216 217 float diff = za - zb; 218 float absDiff = fabsf(diff); 219 if ((absDiff) > fabsf(zDiff)) { 220 intersectionPoint = p; 221 zDiff = diff; 222 } 223 224 if (absDiff > earlyExitThreshold) 225 return true; 226 227 return false; 228 } 229 230 231 // Returns the Z coordinate of a point on the given layer that projects 110 for (int ea = 0; ea < 4; ++ea) 111 for (int eb = 0; eb < 4; ++eb) 112 if (edgeEdgeTest(aPoints[ea], aPoints[(ea + 1) % 4], 113 bPoints[eb], bPoints[(eb + 1) % 4], 114 r)) 115 overlapPoints.append(r); 116 117 if (!overlapPoints.size()) 118 return None; 119 120 // Check the corresponding layer depth value for all overlap points to determine 121 // which layer is in front. 122 float maxPositive = 0; 123 float maxNegative = 0; 124 for (unsigned o = 0; o < overlapPoints.size(); o++) { 125 float za = a->layerZFromProjectedPoint(overlapPoints[o]); 126 float zb = b->layerZFromProjectedPoint(overlapPoints[o]); 127 128 float diff = za - zb; 129 if (diff > maxPositive) 130 maxPositive = diff; 131 if (diff < maxNegative) 132 maxNegative = diff; 133 } 134 135 float maxDiff = (fabsf(maxPositive) > fabsf(maxNegative) ? maxPositive : maxNegative); 136 137 // If the results are inconsistent (and the z difference substantial to rule out 138 // numerical errors) then the layers are intersecting. We will still return an 139 // order based on the maximum depth difference but with an edge weight of zero 140 // these layers will get priority if a graph cycle is present and needs to be broken. 141 if (maxPositive > zThreshold && maxNegative < -zThreshold) 142 weight = 0; 143 else 144 weight = fabsf(maxDiff); 145 146 // Maintain relative order if the layers have the same depth at all intersection points. 147 if (maxDiff <= 0) 148 return ABeforeB; 149 150 return BBeforeA; 151 } 152 153 CCLayerSorter::LayerShape::LayerShape(float width, float height, const TransformationMatrix& drawTransform) 154 { 155 FloatQuad layerQuad(FloatPoint(-width * 0.5, height * 0.5), 156 FloatPoint(width * 0.5, height * 0.5), 157 FloatPoint(width * 0.5, -height * 0.5), 158 FloatPoint(-width * 0.5, -height * 0.5)); 159 160 // Compute the projection of the layer quad onto the z = 0 plane. 161 projectedQuad = drawTransform.mapQuad(layerQuad); 162 projectedBounds = projectedQuad.boundingBox(); 163 164 // Compute the normal of the layer's plane. 165 FloatPoint3D c1 = drawTransform.mapPoint(FloatPoint3D(0, 0, 0)); 166 FloatPoint3D c2 = drawTransform.mapPoint(FloatPoint3D(0, 1, 0)); 167 FloatPoint3D c3 = drawTransform.mapPoint(FloatPoint3D(1, 0, 0)); 168 FloatPoint3D c12 = c2 - c1; 169 FloatPoint3D c13 = c3 - c1; 170 layerNormal = c13.cross(c12); 171 172 transformOrigin = c1; 173 } 174 175 // Returns the Z coordinate of a point on the layer that projects 232 176 // to point p which lies on the z = 0 plane. It does it by computing the 233 177 // intersection of a line starting from p along the Z axis and the plane 234 178 // of the layer. 235 float CCLayerSorter::Layer Intersector::layerZFromProjectedPoint(const LayerShape& layer, const FloatPoint& p)179 float CCLayerSorter::LayerShape::layerZFromProjectedPoint(const FloatPoint& p) const 236 180 { 237 181 const FloatPoint3D zAxis(0, 0, 1); 238 FloatPoint3D w = FloatPoint3D(p.x(), p.y(), 0) - layer.origin; 239 240 float d = layer.normal.dot(zAxis); 241 float n = -layer.normal.dot(w); 242 243 // Check if layer is parallel to the z = 0 axis 182 FloatPoint3D w = FloatPoint3D(p) - transformOrigin; 183 184 float d = layerNormal.dot(zAxis); 185 float n = -layerNormal.dot(w); 186 187 // Check if layer is parallel to the z = 0 axis which will make it 188 // invisible and hence returning zero is fine. 244 189 if (!d) 245 return layer.origin.z();190 return 0; 246 191 247 192 // The intersection point would be given by: … … 249 194 // z coordinate and p's z coord is zero, all we need is the value of n/d. 250 195 return n / d; 251 }252 253 CCLayerSorter::CCLayerSorter()254 : m_zRange(0)255 {256 }257 258 CCLayerSorter::ABCompareResult CCLayerSorter::checkOverlap(GraphNode* a, GraphNode* b)259 {260 if (!a->shape.boundingBox.intersects(b->shape.boundingBox))261 return None;262 263 // These thresholds are defined relative to the total Z range. If further Z-fighting264 // bugs come up due to precision errors, it may be worth considering doing an ulp265 // error measurement instead.266 float exitThreshold = m_zRange * 0.01;267 float nonZeroThreshold = max(exitThreshold, 0.001f);268 269 float zDiff = calculateZDiff(a->shape, b->shape, exitThreshold);270 271 if (zDiff > nonZeroThreshold)272 return BBeforeA;273 if (zDiff < -nonZeroThreshold)274 return ABeforeB;275 276 return None;277 }278 279 CCLayerSorter::LayerShape::LayerShape(const FloatPoint3D& p1, const FloatPoint3D& p2, const FloatPoint3D& p3, const FloatPoint3D& p4)280 : normal((p2 - p1).cross(p3 - p1))281 , c1(FloatPoint(p1.x(), p1.y()))282 , c2(FloatPoint(p2.x(), p2.y()))283 , c3(FloatPoint(p3.x(), p3.y()))284 , c4(FloatPoint(p4.x(), p4.y()))285 , origin(p1)286 {287 boundingBox.fitToPoints(c1, c2, c3, c4);288 196 } 289 197 … … 310 218 if (renderSurface) { 311 219 drawTransform = renderSurface->drawTransform(); 312 layerWidth = 0.5 *renderSurface->contentRect().width();313 layerHeight = 0.5 *renderSurface->contentRect().height();220 layerWidth = renderSurface->contentRect().width(); 221 layerHeight = renderSurface->contentRect().height(); 314 222 } else { 315 223 drawTransform = node.layer->drawTransform(); 316 layerWidth = 0.5 *node.layer->bounds().width();317 layerHeight = 0.5 *node.layer->bounds().height();224 layerWidth = node.layer->bounds().width(); 225 layerHeight = node.layer->bounds().height(); 318 226 } 319 227 320 FloatPoint3D c1 = drawTransform.mapPoint(FloatPoint3D(-layerWidth, layerHeight, 0)); 321 FloatPoint3D c2 = drawTransform.mapPoint(FloatPoint3D(layerWidth, layerHeight, 0)); 322 FloatPoint3D c3 = drawTransform.mapPoint(FloatPoint3D(layerWidth, -layerHeight, 0)); 323 FloatPoint3D c4 = drawTransform.mapPoint(FloatPoint3D(-layerWidth, -layerHeight, 0)); 324 node.shape = LayerShape(c1, c2, c3, c4); 325 326 maxZ = max(c4.z(), max(c3.z(), max(c2.z(), max(maxZ, c1.z())))); 327 minZ = min(c4.z(), min(c3.z(), min(c2.z(), min(minZ, c1.z())))); 328 } 329 if (last - first) 330 m_zRange = fabsf(maxZ - minZ); 228 node.shape = LayerShape(layerWidth, layerHeight, drawTransform); 229 230 maxZ = max(maxZ, node.shape.transformOrigin.z()); 231 minZ = min(minZ, node.shape.transformOrigin.z()); 232 } 233 234 m_zRange = fabsf(maxZ - minZ); 331 235 } 332 236 … … 336 240 LOG(CCLayerSorter, "Edges:\n"); 337 241 #endif 242 // Fraction of the total zRange below which z differences 243 // are not considered reliable. 244 const float zThresholdFactor = 0.01; 245 float zThreshold = m_zRange * zThresholdFactor; 246 338 247 for (unsigned na = 0; na < m_nodes.size(); na++) { 339 248 GraphNode& nodeA = m_nodes[na]; … … 344 253 if (!nodeB.layer->drawsContent() && !nodeB.layer->renderSurface()) 345 254 continue; 346 ABCompareResult overlapResult = checkOverlap(&nodeA, &nodeB); 255 float weight = 0; 256 ABCompareResult overlapResult = checkOverlap(&nodeA.shape, &nodeB.shape, zThreshold, weight); 347 257 GraphNode* startNode = 0; 348 258 GraphNode* endNode = 0; … … 359 269 LOG(CCLayerSorter, "%d -> %d\n", startNode->layer->debugID(), endNode->layer->debugID()); 360 270 #endif 361 m_edges.append(GraphEdge(startNode, endNode ));271 m_edges.append(GraphEdge(startNode, endNode, weight)); 362 272 } 363 273 } … … 369 279 edge.from->outgoing.append(&edge); 370 280 edge.to->incoming.append(&edge); 281 edge.to->incomingEdgeWeight += edge.weight; 371 282 } 372 283 } … … 391 302 // Sorts the given list of layers such that they can be painted in a back-to-front 392 303 // order. Sorting produces correct results for non-intersecting layers that don't have 393 // cyclical order dependencies. Cycles and intersections are broken aribtrarily.304 // cyclical order dependencies. Cycles and intersections are broken (somewhat) aribtrarily. 394 305 // Sorting of layers is done via a topological sort of a directed graph whose nodes are 395 306 // the layers themselves. An edge from node A to node B signifies that layer A needs to … … 451 362 m_activeEdges.remove(outgoingEdge); 452 363 removeEdgeFromList(outgoingEdge, outgoingEdge->to->incoming); 364 outgoingEdge->to->incomingEdgeWeight -= outgoingEdge->weight; 453 365 454 366 if (!outgoingEdge->to->incoming.size()) … … 463 375 // If there are still active edges but the list of nodes without incoming edges 464 376 // is empty then we have run into a cycle. Break the cycle by finding the node 465 // with the least number incoming edges and remove them all. 466 unsigned minIncomingEdgeCount = UINT_MAX; 377 // with the smallest overall incoming edge weight and use it. This will favor 378 // nodes that have zero-weight incoming edges i.e. layers that are being 379 // occluded by a layer that intersects them. 380 float minIncomingEdgeWeight = FLT_MAX; 467 381 GraphNode* nextNode = 0; 468 382 for (unsigned i = 0; i < m_nodes.size(); i++) { 469 if (m_nodes[i].incoming.size() && (m_nodes[i].incoming.size() < minIncomingEdgeCount)) {470 minIncomingEdge Count = m_nodes[i].incoming.size();383 if (m_nodes[i].incoming.size() && m_nodes[i].incomingEdgeWeight < minIncomingEdgeWeight) { 384 minIncomingEdgeWeight = m_nodes[i].incomingEdgeWeight; 471 385 nextNode = &m_nodes[i]; 472 386 } … … 481 395 } 482 396 nextNode->incoming.clear(); 397 nextNode->incomingEdgeWeight = 0; 483 398 noIncomingEdgeNodeList.append(nextNode); 484 399 #if !defined( NDEBUG ) 485 LOG(CCLayerSorter, "Breaking cycle by cleaning up %d edges from %d\n", minIncomingEdgeCount, nextNode->layer->debugID());400 LOG(CCLayerSorter, "Breaking cycle by cleaning up incoming edges from %d (weight = %f)\n", nextNode->layer->debugID(), minIncomingEdgeWeight); 486 401 #endif 487 402 } -
trunk/Source/WebCore/platform/graphics/chromium/cc/CCLayerSorter.h
r108886 r112182 27 27 28 28 #include "FloatPoint3D.h" 29 #include "FloatQuad.h" 29 30 #include "FloatRect.h" 30 31 #include "cc/CCLayerImpl.h" … … 38 39 WTF_MAKE_NONCOPYABLE(CCLayerSorter); 39 40 public: 40 CCLayerSorter() ;41 CCLayerSorter() : m_zRange(0) { } 41 42 42 43 typedef Vector<CCLayerImpl*> LayerList; … … 44 45 void sort(LayerList::iterator first, LayerList::iterator last); 45 46 46 // Helper methods, public for unit testing.47 static bool pointInTriangle(const FloatPoint&, const FloatPoint&, const FloatPoint&, const FloatPoint&);48 49 47 // Holds various useful properties derived from a layer's 3D outline. 50 48 struct LayerShape { 51 49 LayerShape() { } 52 LayerShape( const FloatPoint3D&, const FloatPoint3D&, const FloatPoint3D&, const FloatPoint3D&);50 LayerShape(float width, float height, const TransformationMatrix& drawTransform); 53 51 54 FloatPoint3D normal; 55 FloatPoint c1, c2, c3, c4; 56 FloatPoint3D origin; 57 FloatRect boundingBox; 52 float layerZFromProjectedPoint(const FloatPoint&) const; 53 54 FloatPoint3D layerNormal; 55 FloatPoint3D transformOrigin; 56 FloatQuad projectedQuad; 57 FloatRect projectedBounds; 58 58 }; 59 59 60 static float calculateZDiff(const LayerShape&, const LayerShape&, float earlyExitThreshold); 60 enum ABCompareResult { 61 ABeforeB, 62 BBeforeA, 63 None 64 }; 65 66 static ABCompareResult checkOverlap(LayerShape*, LayerShape*, float zThreshold, float& weight); 61 67 62 68 private: … … 64 70 65 71 struct GraphNode { 66 explicit GraphNode(CCLayerImpl* cclayer) : layer(cclayer) { }72 explicit GraphNode(CCLayerImpl* cclayer) : layer(cclayer), incomingEdgeWeight(0) { } 67 73 68 74 CCLayerImpl* layer; … … 70 76 Vector<GraphEdge*> incoming; 71 77 Vector<GraphEdge*> outgoing; 78 float incomingEdgeWeight; 72 79 }; 73 80 74 81 struct GraphEdge { 75 GraphEdge(GraphNode* fromNode, GraphNode* toNode ) : from(fromNode), to(toNode) { };82 GraphEdge(GraphNode* fromNode, GraphNode* toNode, float weight) : from(fromNode), to(toNode), weight(weight) { }; 76 83 77 84 GraphNode* from; 78 85 GraphNode* to; 79 }; 80 81 struct LayerIntersector { 82 LayerIntersector(const LayerShape&, const LayerShape&, float); 83 84 void go(); 85 86 float layerZFromProjectedPoint(const LayerShape&, const FloatPoint&); 87 bool triangleTriangleTest(const FloatPoint&, const FloatPoint&, const FloatPoint&, const FloatPoint&, const FloatPoint&, const FloatPoint&); 88 bool edgeTriangleTest(const FloatPoint&, const FloatPoint&, const FloatPoint&, const FloatPoint&, const FloatPoint&); 89 bool checkZDiff(const FloatPoint&); 90 91 FloatPoint intersectionPoint; 92 const LayerShape& layerA; 93 const LayerShape& layerB; 94 float zDiff; 95 float earlyExitThreshold; 86 float weight; 96 87 }; 97 88 … … 105 96 EdgeMap m_activeEdges; 106 97 107 float m_zDiffEpsilon;108 109 98 void createGraphNodes(LayerList::iterator first, LayerList::iterator last); 110 99 void createGraphEdges(); 111 100 void removeEdgeFromList(GraphEdge*, Vector<GraphEdge*>&); 112 113 enum ABCompareResult {114 ABeforeB,115 BBeforeA,116 None117 };118 ABCompareResult checkOverlap(GraphNode*, GraphNode*);119 101 }; 120 102 -
trunk/Source/WebKit/chromium/ChangeLog
r112142 r112182 1 2012-03-26 Vangelis Kokkevis <vangelis@chromium.org> 2 3 [chromium] Simplify and fix CCLayerSorter 4 https://bugs.webkit.org/show_bug.cgi?id=82114 5 6 Adjustments to the CCLayerSorter unit tests to account for API changes in the 7 CCLayerSorter class. 8 9 Reviewed by Kenneth Russell. 10 11 * tests/CCLayerSorterTest.cpp: 12 (WebCore): 13 (WebCore::TEST): 14 1 15 2012-03-26 James Robinson <jamesr@chromium.org> 2 16 -
trunk/Source/WebKit/chromium/tests/CCLayerSorterTest.cpp
r108886 r112182 35 35 namespace { 36 36 37 TEST(CCLayerSorterTest, PointInTriangle) 38 { 39 FloatPoint a(10.0, 10.0); 40 FloatPoint b(30.0, 10.0); 41 FloatPoint c(20.0, 20.0); 42 43 // Point in the center is in the triangle. 44 EXPECT_TRUE(CCLayerSorter::pointInTriangle(FloatPoint(20.0, 15.0), a, b, c)); 45 46 // Permuting the corners doesn't change the result. 47 EXPECT_TRUE(CCLayerSorter::pointInTriangle(FloatPoint(20.0, 15.0), a, c, b)); 48 EXPECT_TRUE(CCLayerSorter::pointInTriangle(FloatPoint(20.0, 15.0), b, a, c)); 49 EXPECT_TRUE(CCLayerSorter::pointInTriangle(FloatPoint(20.0, 15.0), b, c, a)); 50 EXPECT_TRUE(CCLayerSorter::pointInTriangle(FloatPoint(20.0, 15.0), c, a, b)); 51 EXPECT_TRUE(CCLayerSorter::pointInTriangle(FloatPoint(20.0, 15.0), c, b, a)); 52 53 // Points on the edges are not in the triangle. 54 EXPECT_FALSE(CCLayerSorter::pointInTriangle(FloatPoint(20.0, 10.0), a, b, c)); 55 EXPECT_FALSE(CCLayerSorter::pointInTriangle(FloatPoint(15.0, 15.0), a, b, c)); 56 EXPECT_FALSE(CCLayerSorter::pointInTriangle(FloatPoint(25.0, 15.0), a, b, c)); 57 58 // Points just inside the edges are in the triangle. 59 EXPECT_TRUE(CCLayerSorter::pointInTriangle(FloatPoint(20.0, 10.01), a, b, c)); 60 EXPECT_TRUE(CCLayerSorter::pointInTriangle(FloatPoint(15.01, 15.0), a, b, c)); 61 EXPECT_TRUE(CCLayerSorter::pointInTriangle(FloatPoint(24.99, 15.0), a, b, c)); 62 63 // Zero-area triangle doesn't intersect any point. 64 EXPECT_FALSE(CCLayerSorter::pointInTriangle(FloatPoint(15.0, 10.0), a, b, FloatPoint(20.0, 10.0))); 65 } 66 67 TEST(CCLayerSorterTest, CalculateZDiff) 68 { 69 // This should be bigger than the range of z values used. 70 const float threshold = 10.0; 37 // Note: In the following overlap tests, the "camera" is looking down the negative Z axis, 38 // meaning that layers with smaller z values (more negative) are further from the camera 39 // and therefore must be drawn before layers with higher z values. 40 41 TEST(CCLayerSorterTest, BasicOverlap) 42 { 43 CCLayerSorter::ABCompareResult overlapResult; 44 const float zThreshold = 0.1f; 45 float weight = 0; 71 46 72 47 // Trivial test, with one layer directly obscuring the other. 73 74 CCLayerSorter::LayerShape front( 75 FloatPoint3D(-1.0, 1.0, 5.0), 76 FloatPoint3D(1.0, 1.0, 5.0), 77 FloatPoint3D(1.0, -1.0, 5.0), 78 FloatPoint3D(-1.0, -1.0, 5.0)); 79 80 CCLayerSorter::LayerShape back( 81 FloatPoint3D(-1.0, 1.0, 4.0), 82 FloatPoint3D(1.0, 1.0, 4.0), 83 FloatPoint3D(1.0, -1.0, 4.0), 84 FloatPoint3D(-1.0, -1.0, 4.0)); 85 86 EXPECT_GT(CCLayerSorter::calculateZDiff(front, back, threshold), 0.0); 87 EXPECT_LT(CCLayerSorter::calculateZDiff(back, front, threshold), 0.0); 88 89 // When comparing a layer with itself, zDiff is always 0. 90 EXPECT_EQ(CCLayerSorter::calculateZDiff(front, front, threshold), 0.0); 91 EXPECT_EQ(CCLayerSorter::calculateZDiff(back, back, threshold), 0.0); 92 93 // Same again but with two layers that intersect only at one point (0,0). 94 // This *does* count as obscuring, so we should get the same results. 95 96 front = CCLayerSorter::LayerShape( 97 FloatPoint3D(-1.0, 0.0, 5.0), 98 FloatPoint3D(0.0, 0.0, 5.0), 99 FloatPoint3D(0.0, -1.0, 5.0), 100 FloatPoint3D(-1.0, -1.0, 5.0)); 101 102 back = CCLayerSorter::LayerShape( 103 FloatPoint3D(0.0, 1.0, 4.0), 104 FloatPoint3D(1.0, 1.0, 4.0), 105 FloatPoint3D(1.0, 0.0, 4.0), 106 FloatPoint3D(0.0, 0.0, 4.0)); 107 108 EXPECT_GT(CCLayerSorter::calculateZDiff(front, back, threshold), 0.0); 109 EXPECT_LT(CCLayerSorter::calculateZDiff(back, front, threshold), 0.0); 110 EXPECT_EQ(CCLayerSorter::calculateZDiff(front, front, threshold), 0.0); 111 EXPECT_EQ(CCLayerSorter::calculateZDiff(back, back, threshold), 0.0); 48 TransformationMatrix neg4Translate; 49 neg4Translate.translate3d(0, 0, -4); 50 CCLayerSorter::LayerShape front(2, 2, neg4Translate); 51 52 TransformationMatrix neg5Translate; 53 neg5Translate.translate3d(0, 0, -5); 54 CCLayerSorter::LayerShape back(2, 2, neg5Translate); 55 56 overlapResult = CCLayerSorter::checkOverlap(&front, &back, zThreshold, weight); 57 EXPECT_EQ(CCLayerSorter::BBeforeA, overlapResult); 58 EXPECT_EQ(1, weight); 59 60 overlapResult = CCLayerSorter::checkOverlap(&back, &front, zThreshold, weight); 61 EXPECT_EQ(CCLayerSorter::ABeforeB, overlapResult); 62 EXPECT_EQ(1, weight); 63 64 // One layer translated off to the right. No overlap should be detected. 65 TransformationMatrix rightTranslate; 66 rightTranslate.translate3d(10, 0, -5); 67 CCLayerSorter::LayerShape backRight(2, 2, rightTranslate); 68 overlapResult = CCLayerSorter::checkOverlap(&front, &backRight, zThreshold, weight); 69 EXPECT_EQ(CCLayerSorter::None, overlapResult); 70 71 // When comparing a layer with itself, z difference is always 0. 72 overlapResult = CCLayerSorter::checkOverlap(&front, &front, zThreshold, weight); 73 EXPECT_EQ(0, weight); 74 } 75 76 TEST(CCLayerSorterTest, RightAngleOverlap) 77 { 78 CCLayerSorter::ABCompareResult overlapResult; 79 const float zThreshold = 0.1f; 80 float weight = 0; 81 82 TransformationMatrix perspectiveMatrix; 83 perspectiveMatrix.applyPerspective(1000); 84 85 // Two layers forming a right angle with a perspective viewing transform. 86 TransformationMatrix leftFaceMatrix; 87 leftFaceMatrix.rotate3d(0, 1, 0, -90).translateRight3d(-1, 0, -5); 88 CCLayerSorter::LayerShape leftFace(2, 2, perspectiveMatrix * leftFaceMatrix); 89 TransformationMatrix frontFaceMatrix; 90 frontFaceMatrix.translate3d(0, 0, -4); 91 CCLayerSorter::LayerShape frontFace(2, 2, perspectiveMatrix * frontFaceMatrix); 92 93 overlapResult = CCLayerSorter::checkOverlap(&frontFace, &leftFace, zThreshold, weight); 94 EXPECT_EQ(CCLayerSorter::BBeforeA, overlapResult); 95 } 96 97 TEST(CCLayerSorterTest, IntersectingLayerOverlap) 98 { 99 CCLayerSorter::ABCompareResult overlapResult; 100 const float zThreshold = 0.1f; 101 float weight = 0; 102 103 TransformationMatrix perspectiveMatrix; 104 perspectiveMatrix.applyPerspective(1000); 105 106 // Intersecting layers. An explicit order will be returned based on relative z 107 // values at the overlapping features but the weight returned should be zero. 108 TransformationMatrix frontFaceMatrix; 109 frontFaceMatrix.translate3d(0, 0, -4); 110 CCLayerSorter::LayerShape frontFace(2, 2, perspectiveMatrix * frontFaceMatrix); 111 112 TransformationMatrix throughMatrix; 113 throughMatrix.rotate3d(0, 1, 0, 45).translateRight3d(0, 0, -4); 114 CCLayerSorter::LayerShape rotatedFace(2, 2, perspectiveMatrix * throughMatrix); 115 overlapResult = CCLayerSorter::checkOverlap(&frontFace, &rotatedFace, zThreshold, weight); 116 EXPECT_NE(CCLayerSorter::None, overlapResult); 117 EXPECT_EQ(0, weight); 118 } 119 120 TEST(CCLayerSorterTest, LayersAtAngleOverlap) 121 { 122 CCLayerSorter::ABCompareResult overlapResult; 123 const float zThreshold = 0.1f; 124 float weight = 0; 112 125 113 126 // Trickier test with layers at an angle. … … 121 134 // 122 135 // C is in front of A and behind B (not what you'd expect by comparing centers). 123 // A and B don't overlap, so they're incomparable (zDiff = 0). 124 125 const float yHi = 10.0; 126 const float yLo = -10.0; 127 const float zA = 1.0; 128 const float zB = -1.0; 129 130 CCLayerSorter::LayerShape layerA( 131 FloatPoint3D(-10.0, yHi, zA), 132 FloatPoint3D(-2.0, yHi, zA), 133 FloatPoint3D(-2.0, yLo, zA), 134 FloatPoint3D(-10.0, yLo, zA)); 135 136 CCLayerSorter::LayerShape layerB( 137 FloatPoint3D(2.0, yHi, zB), 138 FloatPoint3D(10.0, yHi, zB), 139 FloatPoint3D(10.0, yLo, zB), 140 FloatPoint3D(2.0, yLo, zB)); 141 142 CCLayerSorter::LayerShape layerC( 143 FloatPoint3D(-5.0, yHi, 5.0), 144 FloatPoint3D(5.0, yHi, -5.0), 145 FloatPoint3D(5.0, yLo, -5.0), 146 FloatPoint3D(-5.0, yLo, 5.0)); 147 148 EXPECT_EQ(CCLayerSorter::calculateZDiff(layerA, layerA, threshold), 0.0); 149 EXPECT_EQ(CCLayerSorter::calculateZDiff(layerA, layerB, threshold), 0.0); 150 EXPECT_LT(CCLayerSorter::calculateZDiff(layerA, layerC, threshold), 0.0); 151 152 EXPECT_EQ(CCLayerSorter::calculateZDiff(layerB, layerA, threshold), 0.0); 153 EXPECT_EQ(CCLayerSorter::calculateZDiff(layerB, layerB, threshold), 0.0); 154 EXPECT_GT(CCLayerSorter::calculateZDiff(layerB, layerC, threshold), 0.0); 155 156 EXPECT_GT(CCLayerSorter::calculateZDiff(layerC, layerA, threshold), 0.0); 157 EXPECT_LT(CCLayerSorter::calculateZDiff(layerC, layerB, threshold), 0.0); 158 EXPECT_EQ(CCLayerSorter::calculateZDiff(layerC, layerC, threshold), 0.0); 136 // A and B don't overlap, so they're incomparable. 137 138 TransformationMatrix transformA; 139 transformA.translate3d(-6, 0, 1); 140 CCLayerSorter::LayerShape layerA(8, 20, transformA); 141 142 TransformationMatrix transformB; 143 transformB.translate3d(6, 0, -1); 144 CCLayerSorter::LayerShape layerB(8, 20, transformB); 145 146 TransformationMatrix transformC; 147 transformC.rotate3d(0, 1, 0, 40); 148 CCLayerSorter::LayerShape layerC(8, 20, transformC); 149 150 overlapResult = CCLayerSorter::checkOverlap(&layerA, &layerC, zThreshold, weight); 151 EXPECT_EQ(CCLayerSorter::ABeforeB, overlapResult); 152 overlapResult = CCLayerSorter::checkOverlap(&layerC, &layerB, zThreshold, weight); 153 EXPECT_EQ(CCLayerSorter::ABeforeB, overlapResult); 154 overlapResult = CCLayerSorter::checkOverlap(&layerA, &layerB, zThreshold, weight); 155 EXPECT_EQ(CCLayerSorter::None, overlapResult); 159 156 } 160 157
Note: See TracChangeset
for help on using the changeset viewer.