Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "cc/quads/draw_polygon.h" | 5 #include "cc/quads/draw_polygon.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| 11 #include "base/memory/ptr_util.h" | |
| 11 #include "cc/output/bsp_compare_result.h" | 12 #include "cc/output/bsp_compare_result.h" |
| 12 #include "cc/quads/draw_quad.h" | 13 #include "cc/quads/draw_quad.h" |
| 13 | 14 |
| 14 namespace { | 15 namespace { |
| 15 // This threshold controls how "thick" a plane is. If a point's distance is | 16 // This threshold controls how "thick" a plane is. If a point's distance is |
| 16 // <= |compare_threshold|, then it is considered on the plane. Only when this | 17 // <= |compare_threshold|, then it is considered on the plane. Only when this |
| 17 // boundary is crossed do we consider doing splitting. | 18 // boundary is crossed do we consider doing splitting. |
| 18 static const float compare_threshold = 0.1f; | 19 static const float compare_threshold = 0.1f; |
| 19 // |split_threshold| is lower in this case because we want the points created | 20 // |split_threshold| is lower in this case because we want the points created |
| 20 // during splitting to be well within the range of |compare_threshold| for | 21 // during splitting to be well within the range of |compare_threshold| for |
| 21 // comparison purposes. The splitting operation will produce intersection points | 22 // comparison purposes. The splitting operation will produce intersection points |
| 22 // that fit within a tighter distance to the splitting plane as a result of this | 23 // that fit within a tighter distance to the splitting plane as a result of this |
| 23 // value. By using a value >= |compare_threshold| we run the risk of creating | 24 // value. By using a value >= |compare_threshold| we run the risk of creating |
| 24 // points that SHOULD be intersecting the "thick plane", but actually fail to | 25 // points that SHOULD be intersecting the "thick plane", but actually fail to |
| 25 // test positively for it because |split_threshold| allowed them to be outside | 26 // test positively for it because |split_threshold| allowed them to be outside |
| 26 // this range. | 27 // this range. |
| 27 // This is really supposd to be compare_threshold / 2.0f, but that would | 28 // This is really supposd to be compare_threshold / 2.0f, but that would |
| 28 // create another static initializer. | 29 // create another static initializer. |
| 29 static const float split_threshold = 0.05f; | 30 static const float split_threshold = 0.05f; |
| 30 | 31 |
| 31 static const float normalized_threshold = 0.001f; | 32 static const float normalized_threshold = 0.001f; |
| 33 | |
| 34 void PointInterpolate(const gfx::Point3F& from, | |
| 35 const gfx::Point3F& to, | |
| 36 double delta, | |
| 37 gfx::Point3F* out) { | |
| 38 out->SetPoint(from.x() + (to.x() - from.x()) * delta, | |
| 39 from.y() + (to.y() - from.y()) * delta, | |
| 40 from.z() + (to.z() - from.z()) * delta); | |
| 41 } | |
| 32 } // namespace | 42 } // namespace |
| 33 | 43 |
| 34 namespace cc { | 44 namespace cc { |
| 35 | 45 |
| 36 DrawPolygon::DrawPolygon() { | 46 DrawPolygon::DrawPolygon() { |
| 37 } | 47 } |
| 38 | 48 |
| 39 DrawPolygon::DrawPolygon(const DrawQuad* original, | 49 DrawPolygon::DrawPolygon(const DrawQuad* original, |
| 40 const std::vector<gfx::Point3F>& in_points, | 50 const std::vector<gfx::Point3F>& in_points, |
| 41 const gfx::Vector3dF& normal, | 51 const gfx::Vector3dF& normal, |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 129 #endif | 139 #endif |
| 130 | 140 |
| 131 float DrawPolygon::SignedPointDistance(const gfx::Point3F& point) const { | 141 float DrawPolygon::SignedPointDistance(const gfx::Point3F& point) const { |
| 132 return gfx::DotProduct(point - points_[0], normal_); | 142 return gfx::DotProduct(point - points_[0], normal_); |
| 133 } | 143 } |
| 134 | 144 |
| 135 // Checks whether or not shape a lies on the front or back side of b, or | 145 // Checks whether or not shape a lies on the front or back side of b, or |
| 136 // whether they should be considered coplanar. If on the back side, we | 146 // whether they should be considered coplanar. If on the back side, we |
| 137 // say A_BEFORE_B because it should be drawn in that order. | 147 // say A_BEFORE_B because it should be drawn in that order. |
| 138 // Assumes that layers are split and there are no intersecting planes. | 148 // Assumes that layers are split and there are no intersecting planes. |
| 139 BspCompareResult DrawPolygon::SideCompare(const DrawPolygon& a, | 149 BspCompareResult DrawPolygon::SideCompare(const DrawPolygon& a, |
|
enne (OOO)
2016/06/08 22:02:51
Is this function used anymore?
Tobias Sargeant
2016/06/09 16:48:44
Only in tests.
| |
| 140 const DrawPolygon& b) { | 150 const DrawPolygon& b) { |
| 141 // Let's make sure that this is normalized. Without this SignedPointDistance | 151 // Let's make sure that this is normalized. Without this SignedPointDistance |
| 142 // will not be right, but putting the check in there will validate it | 152 // will not be right, but putting the check in there will validate it |
| 143 // redundantly for each point. | 153 // redundantly for each point. |
| 144 DCHECK_GE(normalized_threshold, std::abs(b.normal_.LengthSquared() - 1.0f)); | 154 DCHECK_GE(normalized_threshold, std::abs(b.normal_.LengthSquared() - 1.0f)); |
| 145 | 155 |
| 146 int pos_count = 0; | 156 int pos_count = 0; |
| 147 int neg_count = 0; | 157 int neg_count = 0; |
| 148 for (size_t i = 0; i < a.points_.size(); i++) { | 158 for (size_t i = 0; i < a.points_.size(); i++) { |
| 149 float sign = b.SignedPointDistance(a.points_[i]); | 159 float sign = b.SignedPointDistance(a.points_[i]); |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 170 if ((dot >= 0.0f && a.order_index_ >= b.order_index_) || | 180 if ((dot >= 0.0f && a.order_index_ >= b.order_index_) || |
| 171 (dot <= 0.0f && a.order_index_ <= b.order_index_)) { | 181 (dot <= 0.0f && a.order_index_ <= b.order_index_)) { |
| 172 // The sign of the dot product of the normals along with document order | 182 // The sign of the dot product of the normals along with document order |
| 173 // determine which side it goes on, the vertices are ambiguous. | 183 // determine which side it goes on, the vertices are ambiguous. |
| 174 return BSP_COPLANAR_BACK; | 184 return BSP_COPLANAR_BACK; |
| 175 } | 185 } |
| 176 | 186 |
| 177 return BSP_COPLANAR_FRONT; | 187 return BSP_COPLANAR_FRONT; |
| 178 } | 188 } |
| 179 | 189 |
| 180 static bool LineIntersectPlane(const gfx::Point3F& line_start, | |
| 181 const gfx::Point3F& line_end, | |
| 182 const gfx::Point3F& plane_origin, | |
| 183 const gfx::Vector3dF& plane_normal, | |
| 184 gfx::Point3F* intersection, | |
| 185 float distance_threshold) { | |
| 186 const gfx::Vector3dF line_start_vec(line_start.x(), line_start.y(), | |
| 187 line_start.z()); | |
| 188 const gfx::Vector3dF line_end_vec(line_end.x(), line_end.y(), line_end.z()); | |
| 189 const gfx::Vector3dF plane_origin_vec(plane_origin.x(), plane_origin.y(), | |
| 190 plane_origin.z()); | |
| 191 | |
| 192 double plane_d = -gfx::DotProduct(plane_origin_vec, plane_normal); | |
| 193 | |
| 194 double end_distance = gfx::DotProduct(line_end_vec, plane_normal) + plane_d; | |
| 195 if (std::abs(end_distance) <= distance_threshold) { | |
| 196 // No intersection if |line_end| is within |distance_threshold| of plane. | |
| 197 return false; | |
| 198 } | |
| 199 | |
| 200 double start_distance = | |
| 201 gfx::DotProduct(line_start_vec, plane_normal) + plane_d; | |
| 202 if (std::abs(start_distance) <= distance_threshold) { | |
| 203 // Intersection at |line_start| if |line_start| is within | |
| 204 // |distance_threshold| of plane. | |
| 205 intersection->SetPoint(line_start.x(), line_start.y(), line_start.z()); | |
| 206 return true; | |
| 207 } | |
| 208 | |
| 209 // If signs differ, we cross the plane. | |
| 210 if (start_distance * end_distance < 0.0) { | |
| 211 // Plane: P . N + d = 0 [ d = -(plane_normal . plane_origin) ] | |
| 212 // Ray: P = P0 + Pd * t [ P0 = line_start, Pd = line_end - line_start ] | |
| 213 // Substituting: | |
| 214 // (P0 + Pd * t) . N + d = 0 | |
| 215 // P0 . N + t * Pd . N + d = 0 | |
| 216 // t = -(P0 . N + d) / Pd . N | |
| 217 | |
| 218 gfx::Vector3dF line_delta = line_end - line_start; | |
| 219 double t = -start_distance / gfx::DotProduct(plane_normal, line_delta); | |
| 220 intersection->SetPoint(line_start.x() + line_delta.x() * t, | |
| 221 line_start.y() + line_delta.y() * t, | |
| 222 line_start.z() + line_delta.z() * t); | |
| 223 | |
| 224 return true; | |
| 225 } | |
| 226 return false; | |
| 227 } | |
| 228 | |
| 229 // This function is separate from ApplyTransform because it is often unnecessary | 190 // This function is separate from ApplyTransform because it is often unnecessary |
| 230 // to transform the normal with the rest of the polygon. | 191 // to transform the normal with the rest of the polygon. |
| 231 // When drawing these polygons, it is necessary to move them back into layer | 192 // When drawing these polygons, it is necessary to move them back into layer |
| 232 // space before sending them to OpenGL, which requires using ApplyTransform, | 193 // space before sending them to OpenGL, which requires using ApplyTransform, |
| 233 // but normal information is no longer needed after sorting. | 194 // but normal information is no longer needed after sorting. |
| 234 void DrawPolygon::ApplyTransformToNormal(const gfx::Transform& transform) { | 195 void DrawPolygon::ApplyTransformToNormal(const gfx::Transform& transform) { |
| 235 // Now we use the inverse transpose of |transform| to transform the normal. | 196 // Now we use the inverse transpose of |transform| to transform the normal. |
| 236 gfx::Transform inverse_transform; | 197 gfx::Transform inverse_transform; |
| 237 bool inverted = transform.GetInverse(&inverse_transform); | 198 bool inverted = transform.GetInverse(&inverse_transform); |
| 238 DCHECK(inverted); | 199 DCHECK(inverted); |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 268 // In the case of TransformToLayerSpace, we assume that we are giving the | 229 // In the case of TransformToLayerSpace, we assume that we are giving the |
| 269 // inverse transformation back to the polygon to move it back into layer space | 230 // inverse transformation back to the polygon to move it back into layer space |
| 270 // but we can ignore the costly process of applying the inverse to the normal | 231 // but we can ignore the costly process of applying the inverse to the normal |
| 271 // since we know the normal will just reset to its original state. | 232 // since we know the normal will just reset to its original state. |
| 272 void DrawPolygon::TransformToLayerSpace( | 233 void DrawPolygon::TransformToLayerSpace( |
| 273 const gfx::Transform& inverse_transform) { | 234 const gfx::Transform& inverse_transform) { |
| 274 ApplyTransform(inverse_transform); | 235 ApplyTransform(inverse_transform); |
| 275 normal_ = gfx::Vector3dF(0.0f, 0.0f, -1.0f); | 236 normal_ = gfx::Vector3dF(0.0f, 0.0f, -1.0f); |
| 276 } | 237 } |
| 277 | 238 |
| 278 bool DrawPolygon::Split(const DrawPolygon& splitter, | 239 // Split |polygon| based upon |this|, leaving the results in |front| and |back|. |
| 279 std::unique_ptr<DrawPolygon>* front, | 240 // If |polygon| is not split by |this|, then move it to either |front| or |back| |
| 280 std::unique_ptr<DrawPolygon>* back) { | 241 // depending on its orientation relative to |this|. Return true if |polygon| is |
| 281 gfx::Point3F intersections[2]; | 242 // actually coplanar with |this| (in which case whether it is front facing or |
| 282 std::vector<gfx::Point3F> out_points[2]; | 243 // back facing is determined by the dot products of normals, and document |
| 283 // vertex_before stores the index of the vertex before its matching | 244 // order). |
| 284 // intersection. | 245 bool DrawPolygon::SplitPolygon(std::unique_ptr<DrawPolygon> polygon, |
| 285 // i.e. vertex_before[0] stores the vertex we saw before we crossed the plane | 246 std::unique_ptr<DrawPolygon>* front, |
| 286 // which resulted in the line/plane intersection giving us intersections[0]. | 247 std::unique_ptr<DrawPolygon>* back) { |
| 287 size_t vertex_before[2]; | 248 DCHECK_GE(normalized_threshold, std::abs(normal_.LengthSquared() - 1.0f)); |
| 288 size_t points_size = points_.size(); | |
| 289 size_t current_intersection = 0; | |
| 290 | 249 |
| 291 size_t current_vertex = 0; | 250 const size_t N_points = polygon->points_.size(); |
|
enne (OOO)
2016/06/08 22:02:51
N_points isn't valid chromium style.
I think you'
Tobias Sargeant
2016/06/09 16:48:44
Done.
| |
| 292 // We will only have two intersection points because we assume all polygons | 251 const auto next = [N_points](size_t i) { |
| 293 // are convex. | 252 return (i + 1) % N_points; |
| 294 while (current_intersection < 2) { | 253 }; |
| 295 if (LineIntersectPlane(points_[(current_vertex % points_size)], | 254 const auto prev = [N_points](size_t i) { |
| 296 points_[(current_vertex + 1) % points_size], | 255 return (i + N_points - 1) % N_points; |
| 297 splitter.points_[0], | 256 }; |
| 298 splitter.normal_, | 257 |
| 299 &intersections[current_intersection], | 258 std::vector<float> vertex_distance; |
| 300 split_threshold)) { | 259 size_t pos_count = 0; |
| 301 vertex_before[current_intersection] = current_vertex % points_size; | 260 size_t neg_count = 0; |
| 302 current_intersection++; | 261 |
| 303 // We found both intersection points so we're done already. | 262 // Compute plane distances for each vertex of polygon. |
| 304 if (current_intersection == 2) { | 263 vertex_distance.resize(N_points); |
| 305 break; | 264 for (size_t i = 0; i < N_points; i++) { |
| 306 } | 265 vertex_distance[i] = SignedPointDistance(polygon->points_[i]); |
| 307 } | 266 if (vertex_distance[i] < -split_threshold) { |
| 308 if (current_vertex++ > (points_size)) { | 267 ++neg_count; |
| 309 break; | 268 } else if (vertex_distance[i] > split_threshold) { |
| 269 ++pos_count; | |
| 270 } else { | |
| 271 vertex_distance[i] = 0.0; | |
| 310 } | 272 } |
| 311 } | 273 } |
| 312 DCHECK_EQ(current_intersection, static_cast<size_t>(2)); | |
| 313 | 274 |
| 314 // Since we found both the intersection points, we can begin building the | 275 // Handle non-splitting cases. |
| 315 // vertex set for both our new polygons. | 276 if (!pos_count && !neg_count) { |
| 316 size_t start1 = (vertex_before[0] + 1) % points_size; | 277 // |polygon| is coplanar with |this|. |
| 317 size_t start2 = (vertex_before[1] + 1) % points_size; | 278 double dot = gfx::DotProduct(normal_, polygon->normal_); |
| 318 size_t points_remaining = points_size; | 279 if ((dot >= 0.0f && polygon->order_index_ >= order_index_) || |
| 280 (dot <= 0.0f && polygon->order_index_ <= order_index_)) { | |
| 281 *back = std::move(polygon); | |
| 282 } else { | |
| 283 *front = std::move(polygon); | |
| 284 } | |
| 285 return true; | |
| 286 } else if (!neg_count) { | |
| 287 *front = std::move(polygon); | |
| 288 return false; | |
| 289 } else if (!pos_count) { | |
| 290 *back = std::move(polygon); | |
| 291 return false; | |
| 292 } | |
| 319 | 293 |
| 320 // First polygon. | 294 // Handle splitting case. |
| 321 out_points[0].push_back(intersections[0]); | 295 size_t front_begin; |
| 322 DCHECK_GE(vertex_before[1], start1); | 296 size_t back_begin; |
| 323 for (size_t i = start1; i <= vertex_before[1]; i++) { | 297 size_t pre_front_begin; |
| 324 out_points[0].push_back(points_[i]); | 298 size_t pre_back_begin; |
| 325 --points_remaining; | |
| 326 } | |
| 327 out_points[0].push_back(intersections[1]); | |
| 328 | 299 |
| 329 // Second polygon. | 300 // Find the first vertex that is part of the front split polygon. |
| 330 out_points[1].push_back(intersections[1]); | 301 front_begin = std::find_if(vertex_distance.begin(), vertex_distance.end(), |
| 331 size_t index = start2; | 302 [](float val) { return val > 0.0; }) - |
| 332 for (size_t i = 0; i < points_remaining; i++) { | 303 vertex_distance.begin(); |
| 333 out_points[1].push_back(points_[index % points_size]); | 304 while (vertex_distance[pre_front_begin = prev(front_begin)] > 0.0) |
| 334 ++index; | 305 front_begin = pre_front_begin; |
| 335 } | |
| 336 out_points[1].push_back(intersections[0]); | |
| 337 | 306 |
| 338 // Give both polygons the original splitting polygon's ID, so that they'll | 307 // Find the first vertex that is part of the back split polygon. |
| 339 // still be sorted properly in co-planar instances. | 308 back_begin = std::find_if(vertex_distance.begin(), vertex_distance.end(), |
| 340 std::unique_ptr<DrawPolygon> poly1( | 309 [](float val) { return val < 0.0; }) - |
| 341 new DrawPolygon(original_ref_, out_points[0], normal_, order_index_)); | 310 vertex_distance.begin(); |
| 342 std::unique_ptr<DrawPolygon> poly2( | 311 while (vertex_distance[pre_back_begin = prev(back_begin)] < 0.0) |
| 343 new DrawPolygon(original_ref_, out_points[1], normal_, order_index_)); | 312 back_begin = pre_back_begin; |
| 344 | 313 |
| 345 DCHECK_GE(poly1->points().size(), 3u); | 314 DCHECK(vertex_distance[front_begin] > 0.0); |
| 346 DCHECK_GE(poly2->points().size(), 3u); | 315 DCHECK(vertex_distance[pre_front_begin] <= 0.0); |
| 316 DCHECK(vertex_distance[back_begin] < 0.0); | |
| 317 DCHECK(vertex_distance[pre_back_begin] >= 0.0); | |
| 347 | 318 |
| 348 if (SideCompare(*poly1, splitter) == BSP_FRONT) { | 319 gfx::Point3F pre_pos_intersection; |
| 349 *front = std::move(poly1); | 320 gfx::Point3F pre_neg_intersection; |
| 350 *back = std::move(poly2); | 321 |
| 351 } else { | 322 // Compute the intersection points. N.B.: If the "pre" vertex is on |
| 352 *front = std::move(poly2); | 323 // the thick plane, then the intersection will be at the same point, because |
| 353 *back = std::move(poly1); | 324 // we set vertex_distance to 0 in this case. |
| 354 } | 325 PointInterpolate( |
| 355 return true; | 326 polygon->points_[pre_front_begin], polygon->points_[front_begin], |
| 327 -vertex_distance[pre_front_begin] / | |
| 328 gfx::DotProduct(normal_, polygon->points_[front_begin] - | |
| 329 polygon->points_[pre_front_begin]), | |
| 330 &pre_pos_intersection); | |
| 331 PointInterpolate( | |
| 332 polygon->points_[pre_back_begin], polygon->points_[back_begin], | |
| 333 -vertex_distance[pre_back_begin] / | |
| 334 gfx::DotProduct(normal_, polygon->points_[back_begin] - | |
| 335 polygon->points_[pre_back_begin]), | |
| 336 &pre_neg_intersection); | |
| 337 | |
| 338 // Build the front and back polygons. | |
| 339 std::vector<gfx::Point3F> out_points; | |
| 340 | |
| 341 out_points.push_back(pre_pos_intersection); | |
| 342 do { | |
| 343 out_points.push_back(polygon->points_[front_begin]); | |
| 344 front_begin = next(front_begin); | |
| 345 } while (vertex_distance[front_begin] > 0.0); | |
| 346 out_points.push_back(pre_neg_intersection); | |
| 347 *front = | |
| 348 base::MakeUnique<DrawPolygon>(polygon->original_ref_, out_points, | |
| 349 polygon->normal_, polygon->order_index_); | |
| 350 | |
| 351 out_points.clear(); | |
| 352 | |
| 353 out_points.push_back(pre_neg_intersection); | |
| 354 do { | |
| 355 out_points.push_back(polygon->points_[back_begin]); | |
| 356 back_begin = next(back_begin); | |
| 357 } while (vertex_distance[back_begin] < 0.0); | |
| 358 out_points.push_back(pre_pos_intersection); | |
| 359 *back = | |
| 360 base::MakeUnique<DrawPolygon>(polygon->original_ref_, out_points, | |
| 361 polygon->normal_, polygon->order_index_); | |
| 362 | |
| 363 return false; | |
|
enne (OOO)
2016/06/08 22:02:51
Can you add some dchecks that out_points in both c
enne (OOO)
2016/06/08 22:02:51
Can you add some dchecks that out_points in both c
Tobias Sargeant
2016/06/09 16:48:44
Yes, but that latter condition is actually wrong i
enne (OOO)
2016/06/09 17:11:26
Yeah, that was my concern--I didn't want to lose v
| |
| 364 } | |
| 365 | |
| 366 // Convenience overload for testing purposes. | |
| 367 bool DrawPolygon::SplitPolygon(const DrawPolygon& polygon, | |
| 368 std::unique_ptr<DrawPolygon>* front, | |
| 369 std::unique_ptr<DrawPolygon>* back) { | |
| 370 return SplitPolygon( | |
| 371 base::MakeUnique<DrawPolygon>(polygon.original_ref_, polygon.points_, | |
| 372 polygon.normal_, polygon.order_index_), | |
| 373 front, back); | |
| 356 } | 374 } |
| 357 | 375 |
| 358 // This algorithm takes the first vertex in the polygon and uses that as a | 376 // This algorithm takes the first vertex in the polygon and uses that as a |
| 359 // pivot point to fan out and create quads from the rest of the vertices. | 377 // pivot point to fan out and create quads from the rest of the vertices. |
| 360 // |offset| starts off as the second vertex, and then |op1| and |op2| indicate | 378 // |offset| starts off as the second vertex, and then |op1| and |op2| indicate |
| 361 // offset+1 and offset+2 respectively. | 379 // offset+1 and offset+2 respectively. |
| 362 // After the first quad is created, the first vertex in the next quad is the | 380 // After the first quad is created, the first vertex in the next quad is the |
| 363 // same as all the rest, the pivot point. The second vertex in the next quad is | 381 // same as all the rest, the pivot point. The second vertex in the next quad is |
| 364 // the old |op2|, the last vertex added to the previous quad. This continues | 382 // the old |op2|, the last vertex added to the previous quad. This continues |
| 365 // until all points are exhausted. | 383 // until all points are exhausted. |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 382 quads->push_back( | 400 quads->push_back( |
| 383 gfx::QuadF(first, | 401 gfx::QuadF(first, |
| 384 gfx::PointF(points_[offset].x(), points_[offset].y()), | 402 gfx::PointF(points_[offset].x(), points_[offset].y()), |
| 385 gfx::PointF(points_[op1].x(), points_[op1].y()), | 403 gfx::PointF(points_[op1].x(), points_[op1].y()), |
| 386 gfx::PointF(points_[op2].x(), points_[op2].y()))); | 404 gfx::PointF(points_[op2].x(), points_[op2].y()))); |
| 387 offset = op2; | 405 offset = op2; |
| 388 } | 406 } |
| 389 } | 407 } |
| 390 | 408 |
| 391 } // namespace cc | 409 } // namespace cc |
| OLD | NEW |