Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(469)

Side by Side Diff: src/gpu/effects/GrRRectEffect.cpp

Issue 200723011: When clipping treat rrect corners where either the x or y radius is < 0.5 as square. (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: address comments Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2014 Google Inc. 2 * Copyright 2014 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "GrRRectEffect.h" 8 #include "GrRRectEffect.h"
9 9
10 #include "gl/GrGLEffect.h" 10 #include "gl/GrGLEffect.h"
11 #include "gl/GrGLSL.h" 11 #include "gl/GrGLSL.h"
12 #include "GrConvexPolyEffect.h"
12 #include "GrTBackendEffectFactory.h" 13 #include "GrTBackendEffectFactory.h"
13 14
14 #include "SkRRect.h" 15 #include "SkRRect.h"
15 16
17 // The effects defined here only handle rrect radii >= kRadiusMin.
18 static const SkScalar kRadiusMin = SK_ScalarHalf;
19
20 //////////////////////////////////////////////////////////////////////////////
21
16 class GLCircularRRectEffect; 22 class GLCircularRRectEffect;
17 23
18 class CircularRRectEffect : public GrEffect { 24 class CircularRRectEffect : public GrEffect {
19 public: 25 public:
20 // This effect only supports circular corner rrects where the radius is >= k RadiusMin.
21 static const SkScalar kRadiusMin;
22 26
23 enum CornerFlags { 27 enum CornerFlags {
24 kTopLeft_CornerFlag = (1 << SkRRect::kUpperLeft_Corner), 28 kTopLeft_CornerFlag = (1 << SkRRect::kUpperLeft_Corner),
25 kTopRight_CornerFlag = (1 << SkRRect::kUpperRight_Corner), 29 kTopRight_CornerFlag = (1 << SkRRect::kUpperRight_Corner),
26 kBottomRight_CornerFlag = (1 << SkRRect::kLowerRight_Corner), 30 kBottomRight_CornerFlag = (1 << SkRRect::kLowerRight_Corner),
27 kBottomLeft_CornerFlag = (1 << SkRRect::kLowerLeft_Corner), 31 kBottomLeft_CornerFlag = (1 << SkRRect::kLowerLeft_Corner),
28 32
29 kLeft_CornerFlags = kTopLeft_CornerFlag | kBottomLeft_CornerFlag, 33 kLeft_CornerFlags = kTopLeft_CornerFlag | kBottomLeft_CornerFlag,
30 kTop_CornerFlags = kTopLeft_CornerFlag | kTopRight_CornerFlag, 34 kTop_CornerFlags = kTopLeft_CornerFlag | kTopRight_CornerFlag,
31 kRight_CornerFlags = kTopRight_CornerFlag | kBottomRight_CornerFlag, 35 kRight_CornerFlags = kTopRight_CornerFlag | kBottomRight_CornerFlag,
32 kBottom_CornerFlags = kBottomLeft_CornerFlag | kBottomRight_CornerFlag, 36 kBottom_CornerFlags = kBottomLeft_CornerFlag | kBottomRight_CornerFlag,
33 37
34 kAll_CornerFlags = kTopLeft_CornerFlag | kTopRight_CornerFlag | 38 kAll_CornerFlags = kTopLeft_CornerFlag | kTopRight_CornerFlag |
35 kBottomLeft_CornerFlag | kBottomRight_CornerFlag, 39 kBottomLeft_CornerFlag | kBottomRight_CornerFlag,
36 40
41 kNone_CornerFlags = 0
37 }; 42 };
38 43
39 // The flags are used to indicate which corners are circluar (unflagged corn ers are assumed to 44 // The flags are used to indicate which corners are circluar (unflagged corn ers are assumed to
40 // be square). 45 // be square).
41 static GrEffectRef* Create(GrEffectEdgeType, uint32_t circularCornerFlags, c onst SkRRect&); 46 static GrEffectRef* Create(GrEffectEdgeType, uint32_t circularCornerFlags, c onst SkRRect&);
42 47
43 virtual ~CircularRRectEffect() {}; 48 virtual ~CircularRRectEffect() {};
44 static const char* Name() { return "CircularRRect"; } 49 static const char* Name() { return "CircularRRect"; }
45 50
46 const SkRRect& getRRect() const { return fRRect; } 51 const SkRRect& getRRect() const { return fRRect; }
(...skipping 15 matching lines...) Expand all
62 67
63 SkRRect fRRect; 68 SkRRect fRRect;
64 GrEffectEdgeType fEdgeType; 69 GrEffectEdgeType fEdgeType;
65 uint32_t fCircularCornerFlags; 70 uint32_t fCircularCornerFlags;
66 71
67 GR_DECLARE_EFFECT_TEST; 72 GR_DECLARE_EFFECT_TEST;
68 73
69 typedef GrEffect INHERITED; 74 typedef GrEffect INHERITED;
70 }; 75 };
71 76
72 const SkScalar CircularRRectEffect::kRadiusMin = 0.5f;
73
74 GrEffectRef* CircularRRectEffect::Create(GrEffectEdgeType edgeType, 77 GrEffectRef* CircularRRectEffect::Create(GrEffectEdgeType edgeType,
75 uint32_t circularCornerFlags, 78 uint32_t circularCornerFlags,
76 const SkRRect& rrect) { 79 const SkRRect& rrect) {
77 SkASSERT(kFillAA_GrEffectEdgeType == edgeType || kInverseFillAA_GrEffectEdge Type == edgeType); 80 SkASSERT(kFillAA_GrEffectEdgeType == edgeType || kInverseFillAA_GrEffectEdge Type == edgeType);
78 return CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(CircularRRectEffect, 81 return CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(CircularRRectEffect,
79 (edgeType, circularCornerF lags, rrect)))); 82 (edgeType, circularCornerF lags, rrect))));
80 } 83 }
81 84
82 void CircularRRectEffect::getConstantColorComponents(GrColor* color, uint32_t* v alidFlags) const { 85 void CircularRRectEffect::getConstantColorComponents(GrColor* color, uint32_t* v alidFlags) const {
83 *validFlags = 0; 86 *validFlags = 0;
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after
296 const GrDrawEffect& drawEffect) { 299 const GrDrawEffect& drawEffect) {
297 const CircularRRectEffect& crre = drawEffect.castEffect<CircularRRectEffect> (); 300 const CircularRRectEffect& crre = drawEffect.castEffect<CircularRRectEffect> ();
298 const SkRRect& rrect = crre.getRRect(); 301 const SkRRect& rrect = crre.getRRect();
299 if (rrect != fPrevRRect) { 302 if (rrect != fPrevRRect) {
300 SkRect rect = rrect.getBounds(); 303 SkRect rect = rrect.getBounds();
301 SkScalar radius = 0; 304 SkScalar radius = 0;
302 switch (crre.getCircularCornerFlags()) { 305 switch (crre.getCircularCornerFlags()) {
303 case CircularRRectEffect::kAll_CornerFlags: 306 case CircularRRectEffect::kAll_CornerFlags:
304 SkASSERT(rrect.isSimpleCircular()); 307 SkASSERT(rrect.isSimpleCircular());
305 radius = rrect.getSimpleRadii().fX; 308 radius = rrect.getSimpleRadii().fX;
306 SkASSERT(radius >= CircularRRectEffect::kRadiusMin); 309 SkASSERT(radius >= kRadiusMin);
307 rect.inset(radius, radius); 310 rect.inset(radius, radius);
308 break; 311 break;
309 case CircularRRectEffect::kTopLeft_CornerFlag: 312 case CircularRRectEffect::kTopLeft_CornerFlag:
310 radius = rrect.radii(SkRRect::kUpperLeft_Corner).fX; 313 radius = rrect.radii(SkRRect::kUpperLeft_Corner).fX;
311 rect.fLeft += radius; 314 rect.fLeft += radius;
312 rect.fTop += radius; 315 rect.fTop += radius;
313 rect.fRight += 0.5f; 316 rect.fRight += 0.5f;
314 rect.fBottom += 0.5f; 317 rect.fBottom += 0.5f;
315 break; 318 break;
316 case CircularRRectEffect::kTopRight_CornerFlag: 319 case CircularRRectEffect::kTopRight_CornerFlag:
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
370 fPrevRRect = rrect; 373 fPrevRRect = rrect;
371 } 374 }
372 } 375 }
373 376
374 ////////////////////////////////////////////////////////////////////////////// 377 //////////////////////////////////////////////////////////////////////////////
375 378
376 class GLEllipticalRRectEffect; 379 class GLEllipticalRRectEffect;
377 380
378 class EllipticalRRectEffect : public GrEffect { 381 class EllipticalRRectEffect : public GrEffect {
379 public: 382 public:
380 // This effect only supports rrects where the radii are >= kRadiusMin.
381 static const SkScalar kRadiusMin;
382
383 static GrEffectRef* Create(GrEffectEdgeType, const SkRRect&); 383 static GrEffectRef* Create(GrEffectEdgeType, const SkRRect&);
384 384
385 virtual ~EllipticalRRectEffect() {}; 385 virtual ~EllipticalRRectEffect() {};
386 static const char* Name() { return "EllipticalRRect"; } 386 static const char* Name() { return "EllipticalRRect"; }
387 387
388 const SkRRect& getRRect() const { return fRRect; } 388 const SkRRect& getRRect() const { return fRRect; }
389 389
390 390
391 GrEffectEdgeType getEdgeType() const { return fEdgeType; } 391 GrEffectEdgeType getEdgeType() const { return fEdgeType; }
392 392
393 typedef GLEllipticalRRectEffect GLEffect; 393 typedef GLEllipticalRRectEffect GLEffect;
394 394
395 virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags ) const SK_OVERRIDE; 395 virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags ) const SK_OVERRIDE;
396 396
397 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE; 397 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
398 398
399 private: 399 private:
400 EllipticalRRectEffect(GrEffectEdgeType, const SkRRect&); 400 EllipticalRRectEffect(GrEffectEdgeType, const SkRRect&);
401 401
402 virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE; 402 virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE;
403 403
404 SkRRect fRRect; 404 SkRRect fRRect;
405 GrEffectEdgeType fEdgeType; 405 GrEffectEdgeType fEdgeType;
406 406
407 GR_DECLARE_EFFECT_TEST; 407 GR_DECLARE_EFFECT_TEST;
408 408
409 typedef GrEffect INHERITED; 409 typedef GrEffect INHERITED;
410 }; 410 };
411 411
412 const SkScalar EllipticalRRectEffect::kRadiusMin = 0.5f;
413
414 GrEffectRef* EllipticalRRectEffect::Create(GrEffectEdgeType edgeType, const SkRR ect& rrect) { 412 GrEffectRef* EllipticalRRectEffect::Create(GrEffectEdgeType edgeType, const SkRR ect& rrect) {
415 SkASSERT(kFillAA_GrEffectEdgeType == edgeType || kInverseFillAA_GrEffectEdge Type == edgeType); 413 SkASSERT(kFillAA_GrEffectEdgeType == edgeType || kInverseFillAA_GrEffectEdge Type == edgeType);
416 return CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(EllipticalRRectEffect, (ed geType, rrect)))); 414 return CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(EllipticalRRectEffect, (ed geType, rrect))));
417 } 415 }
418 416
419 void EllipticalRRectEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const { 417 void EllipticalRRectEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
420 *validFlags = 0; 418 *validFlags = 0;
421 } 419 }
422 420
423 const GrBackendEffectFactory& EllipticalRRectEffect::getFactory() const { 421 const GrBackendEffectFactory& EllipticalRRectEffect::getFactory() const {
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after
589 return erre.getRRect().getType() | erre.getEdgeType() << 3; 587 return erre.getRRect().getType() | erre.getEdgeType() << 3;
590 } 588 }
591 589
592 void GLEllipticalRRectEffect::setData(const GrGLUniformManager& uman, 590 void GLEllipticalRRectEffect::setData(const GrGLUniformManager& uman,
593 const GrDrawEffect& drawEffect) { 591 const GrDrawEffect& drawEffect) {
594 const EllipticalRRectEffect& erre = drawEffect.castEffect<EllipticalRRectEff ect>(); 592 const EllipticalRRectEffect& erre = drawEffect.castEffect<EllipticalRRectEff ect>();
595 const SkRRect& rrect = erre.getRRect(); 593 const SkRRect& rrect = erre.getRRect();
596 if (rrect != fPrevRRect) { 594 if (rrect != fPrevRRect) {
597 SkRect rect = rrect.getBounds(); 595 SkRect rect = rrect.getBounds();
598 const SkVector& r0 = rrect.radii(SkRRect::kUpperLeft_Corner); 596 const SkVector& r0 = rrect.radii(SkRRect::kUpperLeft_Corner);
599 SkASSERT(r0.fX >= EllipticalRRectEffect::kRadiusMin); 597 SkASSERT(r0.fX >= kRadiusMin);
600 SkASSERT(r0.fY >= EllipticalRRectEffect::kRadiusMin); 598 SkASSERT(r0.fY >= kRadiusMin);
601 switch (erre.getRRect().getType()) { 599 switch (erre.getRRect().getType()) {
602 case SkRRect::kSimple_Type: 600 case SkRRect::kSimple_Type:
603 rect.inset(r0.fX, r0.fY); 601 rect.inset(r0.fX, r0.fY);
604 uman.set2f(fInvRadiiSqdUniform, 1.f / (r0.fX * r0.fX), 602 uman.set2f(fInvRadiiSqdUniform, 1.f / (r0.fX * r0.fX),
605 1.f / (r0.fY * r0.fY)); 603 1.f / (r0.fY * r0.fY));
606 break; 604 break;
607 case SkRRect::kNinePatch_Type: { 605 case SkRRect::kNinePatch_Type: {
608 const SkVector& r1 = rrect.radii(SkRRect::kLowerRight_Corner); 606 const SkVector& r1 = rrect.radii(SkRRect::kLowerRight_Corner);
609 SkASSERT(r1.fX >= EllipticalRRectEffect::kRadiusMin); 607 SkASSERT(r1.fX >= kRadiusMin);
610 SkASSERT(r1.fY >= EllipticalRRectEffect::kRadiusMin); 608 SkASSERT(r1.fY >= kRadiusMin);
611 rect.fLeft += r0.fX; 609 rect.fLeft += r0.fX;
612 rect.fTop += r0.fY; 610 rect.fTop += r0.fY;
613 rect.fRight -= r1.fX; 611 rect.fRight -= r1.fX;
614 rect.fBottom -= r1.fY; 612 rect.fBottom -= r1.fY;
615 uman.set4f(fInvRadiiSqdUniform, 1.f / (r0.fX * r0.fX), 613 uman.set4f(fInvRadiiSqdUniform, 1.f / (r0.fX * r0.fX),
616 1.f / (r0.fY * r0.fY), 614 1.f / (r0.fY * r0.fY),
617 1.f / (r1.fX * r1.fX), 615 1.f / (r1.fX * r1.fX),
618 1.f / (r1.fY * r1.fY)); 616 1.f / (r1.fY * r1.fY));
619 break; 617 break;
620 } 618 }
621 default: 619 default:
622 GrCrash("RRect should always be simple or nine-patch."); 620 GrCrash("RRect should always be simple or nine-patch.");
623 } 621 }
624 uman.set4f(fInnerRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.f Bottom); 622 uman.set4f(fInnerRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.f Bottom);
625 fPrevRRect = rrect; 623 fPrevRRect = rrect;
626 } 624 }
627 } 625 }
628 626
629 ////////////////////////////////////////////////////////////////////////////// 627 //////////////////////////////////////////////////////////////////////////////
630 628
631 GrEffectRef* GrRRectEffect::Create(GrEffectEdgeType edgeType, const SkRRect& rre ct) { 629 GrEffectRef* GrRRectEffect::Create(GrEffectEdgeType edgeType, const SkRRect& rre ct) {
632 if (kFillAA_GrEffectEdgeType != edgeType && kInverseFillAA_GrEffectEdgeType != edgeType) { 630 if (kFillAA_GrEffectEdgeType != edgeType && kInverseFillAA_GrEffectEdgeType != edgeType) {
633 return NULL; 631 return NULL;
634 } 632 }
635 uint32_t cornerFlags; 633
634 if (rrect.isRect()) {
635 return GrConvexPolyEffect::Create(edgeType, rrect.getBounds());
636 }
637
636 if (rrect.isSimple()) { 638 if (rrect.isSimple()) {
639 if (rrect.getSimpleRadii().fX < kRadiusMin || rrect.getSimpleRadii().fY < kRadiusMin) {
640 // In this case the corners are extremely close to rectangular and w e collapse the
641 // clip to a rectangular clip.
642 return GrConvexPolyEffect::Create(edgeType, rrect.getBounds());
643 }
637 if (rrect.getSimpleRadii().fX == rrect.getSimpleRadii().fY) { 644 if (rrect.getSimpleRadii().fX == rrect.getSimpleRadii().fY) {
638 if (rrect.getSimpleRadii().fX < CircularRRectEffect::kRadiusMin) { 645 return CircularRRectEffect::Create(edgeType, CircularRRectEffect::kA ll_CornerFlags,
639 return NULL; 646 rrect);
640 }
641 cornerFlags = CircularRRectEffect::kAll_CornerFlags;
642 } else { 647 } else {
643 if (rrect.getSimpleRadii().fX < EllipticalRRectEffect::kRadiusMin ||
644 rrect.getSimpleRadii().fY < EllipticalRRectEffect::kRadiusMin) {
645 return NULL;
646 }
647 return EllipticalRRectEffect::Create(edgeType, rrect); 648 return EllipticalRRectEffect::Create(edgeType, rrect);
648 } 649 }
649 } else if (rrect.isComplex() || rrect.isNinePatch()) { 650 }
651
652 if (rrect.isComplex() || rrect.isNinePatch()) {
650 // Check for the "tab" cases - two adjacent circular corners and two squ are corners. 653 // Check for the "tab" cases - two adjacent circular corners and two squ are corners.
651 SkScalar radius = 0; 654 SkScalar circularRadius = 0;
652 cornerFlags = 0; 655 uint32_t cornerFlags = 0;
656
657 SkVector radii[4];
658 bool squashedRadii = false;
653 for (int c = 0; c < 4; ++c) { 659 for (int c = 0; c < 4; ++c) {
654 const SkVector& r = rrect.radii((SkRRect::Corner)c); 660 radii[c] = rrect.radii((SkRRect::Corner)c);
655 SkASSERT((0 == r.fX) == (0 == r.fY)); 661 SkASSERT((0 == radii[c].fX) == (0 == radii[c].fY));
656 if (0 == r.fX) { 662 if (0 == radii[c].fX) {
663 // The corner is square, so no need to squash or flag as circula r.
657 continue; 664 continue;
658 } 665 }
659 if (r.fX != r.fY) { 666 if (radii[c].fX < kRadiusMin || radii[c].fY < kRadiusMin) {
667 radii[c].set(0, 0);
668 squashedRadii = true;
669 continue;
670 }
671 if (radii[c].fX != radii[c].fY) {
660 cornerFlags = ~0U; 672 cornerFlags = ~0U;
661 break; 673 break;
662 } 674 }
663 if (!cornerFlags) { 675 if (!cornerFlags) {
664 radius = r.fX; 676 circularRadius = radii[c].fX;
665 if (radius < CircularRRectEffect::kRadiusMin) {
666 cornerFlags = ~0U;
667 break;
668 }
669 cornerFlags = 1 << c; 677 cornerFlags = 1 << c;
670 } else { 678 } else {
671 if (r.fX != radius) { 679 if (radii[c].fX != circularRadius) {
672 cornerFlags = ~0U; 680 cornerFlags = ~0U;
673 break; 681 break;
674 } 682 }
675 cornerFlags |= 1 << c; 683 cornerFlags |= 1 << c;
676 } 684 }
677 } 685 }
678 686
679 switch (cornerFlags) { 687 switch (cornerFlags) {
688 case CircularRRectEffect::kAll_CornerFlags:
689 // This rrect should have been caught in the simple case above. Though, it would
690 // be correctly handled in the fallthrough code.
691 SkASSERT(false);
680 case CircularRRectEffect::kTopLeft_CornerFlag: 692 case CircularRRectEffect::kTopLeft_CornerFlag:
681 case CircularRRectEffect::kTopRight_CornerFlag: 693 case CircularRRectEffect::kTopRight_CornerFlag:
682 case CircularRRectEffect::kBottomRight_CornerFlag: 694 case CircularRRectEffect::kBottomRight_CornerFlag:
683 case CircularRRectEffect::kBottomLeft_CornerFlag: 695 case CircularRRectEffect::kBottomLeft_CornerFlag:
684 case CircularRRectEffect::kLeft_CornerFlags: 696 case CircularRRectEffect::kLeft_CornerFlags:
685 case CircularRRectEffect::kTop_CornerFlags: 697 case CircularRRectEffect::kTop_CornerFlags:
686 case CircularRRectEffect::kRight_CornerFlags: 698 case CircularRRectEffect::kRight_CornerFlags:
687 case CircularRRectEffect::kBottom_CornerFlags: 699 case CircularRRectEffect::kBottom_CornerFlags: {
688 case CircularRRectEffect::kAll_CornerFlags: 700 SkTCopyOnFirstWrite<SkRRect> rr(rrect);
689 break; 701 if (squashedRadii) {
690 default: 702 rr.writable()->setRectRadii(rrect.getBounds(), radii);
703 }
704 return CircularRRectEffect::Create(edgeType, cornerFlags, *rr);
705 }
706 case CircularRRectEffect::kNone_CornerFlags:
707 return GrConvexPolyEffect::Create(edgeType, rrect.getBounds());
708 default: {
709 if (squashedRadii) {
710 // If we got here then we squashed some but not all the radi i to zero. (If all
711 // had been squashed cornerFlags would be 0.) The elliptical effect doesn't
712 // support some rounded and some square corners.
713 return NULL;
714 }
691 if (rrect.isNinePatch()) { 715 if (rrect.isNinePatch()) {
692 const SkVector& r0 = rrect.radii(SkRRect::kUpperLeft_Corner) ; 716 return EllipticalRRectEffect::Create(edgeType, rrect);
693 const SkVector& r1 = rrect.radii(SkRRect::kLowerRight_Corner );
694 if (r0.fX >= EllipticalRRectEffect::kRadiusMin &&
695 r0.fY >= EllipticalRRectEffect::kRadiusMin &&
696 r1.fX >= EllipticalRRectEffect::kRadiusMin &&
697 r1.fY >= EllipticalRRectEffect::kRadiusMin) {
698 return EllipticalRRectEffect::Create(edgeType, rrect);
699 }
700 } 717 }
701 return NULL; 718 return NULL;
719 }
702 } 720 }
703 } else {
704 return NULL;
705 } 721 }
706 return CircularRRectEffect::Create(edgeType, cornerFlags, rrect); 722
723 return NULL;
707 } 724 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698