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

Side by Side Diff: src/gpu/GrAAHairLinePathRenderer.cpp

Issue 815553003: Move ViewMatrix off of drawstate (Closed) Base URL: https://skia.googlesource.com/skia.git@remove-fragment-stage
Patch Set: more cleaning Created 5 years, 11 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
« no previous file with comments | « src/gpu/GrAAHairLinePathRenderer.h ('k') | src/gpu/GrAARectRenderer.h » ('j') | 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 2011 Google Inc. 2 * Copyright 2011 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 "GrAAHairLinePathRenderer.h" 8 #include "GrAAHairLinePathRenderer.h"
9 9
10 #include "GrContext.h" 10 #include "GrContext.h"
(...skipping 626 matching lines...) Expand 10 before | Expand all | Expand 10 after
637 637
638 *vert += kLineSegNumVertices; 638 *vert += kLineSegNumVertices;
639 } 639 }
640 640
641 } 641 }
642 642
643 /////////////////////////////////////////////////////////////////////////////// 643 ///////////////////////////////////////////////////////////////////////////////
644 644
645 bool GrAAHairLinePathRenderer::createLineGeom(GrDrawTarget* target, 645 bool GrAAHairLinePathRenderer::createLineGeom(GrDrawTarget* target,
646 GrDrawState* drawState, 646 GrDrawState* drawState,
647 const SkMatrix& viewMatrix,
647 uint8_t coverage, 648 uint8_t coverage,
648 size_t vertexStride, 649 size_t vertexStride,
649 GrDrawTarget::AutoReleaseGeometry* arg, 650 GrDrawTarget::AutoReleaseGeometry* arg,
650 SkRect* devBounds, 651 SkRect* devBounds,
651 const SkPath& path, 652 const SkPath& path,
652 const PtArray& lines, 653 const PtArray& lines,
653 int lineCnt) { 654 int lineCnt) {
654 const SkMatrix& viewM = drawState->getViewMatrix();
655
656 int vertCnt = kLineSegNumVertices * lineCnt; 655 int vertCnt = kLineSegNumVertices * lineCnt;
657 656
658 SkASSERT(vertexStride == sizeof(LineVertex)); 657 SkASSERT(vertexStride == sizeof(LineVertex));
659 if (!arg->set(target, vertCnt, vertexStride, 0)) { 658 if (!arg->set(target, vertCnt, vertexStride, 0)) {
660 return false; 659 return false;
661 } 660 }
662 661
663 LineVertex* verts = reinterpret_cast<LineVertex*>(arg->vertices()); 662 LineVertex* verts = reinterpret_cast<LineVertex*>(arg->vertices());
664 663
665 const SkMatrix* toSrc = NULL; 664 const SkMatrix* toSrc = NULL;
666 SkMatrix ivm; 665 SkMatrix ivm;
667 666
668 if (viewM.hasPerspective()) { 667 if (viewMatrix.hasPerspective()) {
669 if (viewM.invert(&ivm)) { 668 if (viewMatrix.invert(&ivm)) {
670 toSrc = &ivm; 669 toSrc = &ivm;
671 } 670 }
672 } 671 }
673 devBounds->set(lines.begin(), lines.count()); 672 devBounds->set(lines.begin(), lines.count());
674 for (int i = 0; i < lineCnt; ++i) { 673 for (int i = 0; i < lineCnt; ++i) {
675 add_line(&lines[2*i], toSrc, coverage, &verts); 674 add_line(&lines[2*i], toSrc, coverage, &verts);
676 } 675 }
677 // All the verts computed by add_line are within sqrt(1^2 + 0.5^2) of the en d points. 676 // All the verts computed by add_line are within sqrt(1^2 + 0.5^2) of the en d points.
678 static const SkScalar kSqrtOfOneAndAQuarter = 1.118f; 677 static const SkScalar kSqrtOfOneAndAQuarter = 1.118f;
679 // Add a little extra to account for vector normalization precision. 678 // Add a little extra to account for vector normalization precision.
680 static const SkScalar kOutset = kSqrtOfOneAndAQuarter + SK_Scalar1 / 20; 679 static const SkScalar kOutset = kSqrtOfOneAndAQuarter + SK_Scalar1 / 20;
681 devBounds->outset(kOutset, kOutset); 680 devBounds->outset(kOutset, kOutset);
682 681
683 return true; 682 return true;
684 } 683 }
685 684
686 bool GrAAHairLinePathRenderer::createBezierGeom(GrDrawTarget* target, 685 bool GrAAHairLinePathRenderer::createBezierGeom(GrDrawTarget* target,
687 GrDrawState* drawState, 686 GrDrawState* drawState,
687 const SkMatrix& viewMatrix,
688 GrDrawTarget::AutoReleaseGeometr y* arg, 688 GrDrawTarget::AutoReleaseGeometr y* arg,
689 SkRect* devBounds, 689 SkRect* devBounds,
690 const SkPath& path, 690 const SkPath& path,
691 const PtArray& quads, 691 const PtArray& quads,
692 int quadCnt, 692 int quadCnt,
693 const PtArray& conics, 693 const PtArray& conics,
694 int conicCnt, 694 int conicCnt,
695 const IntArray& qSubdivs, 695 const IntArray& qSubdivs,
696 const FloatArray& cWeights, 696 const FloatArray& cWeights,
697 size_t vertexStride) { 697 size_t vertexStride) {
698 const SkMatrix& viewM = drawState->getViewMatrix();
699
700 int vertCnt = kQuadNumVertices * quadCnt + kQuadNumVertices * conicCnt; 698 int vertCnt = kQuadNumVertices * quadCnt + kQuadNumVertices * conicCnt;
701 699
702 if (!arg->set(target, vertCnt, vertexStride, 0)) { 700 if (!arg->set(target, vertCnt, vertexStride, 0)) {
703 return false; 701 return false;
704 } 702 }
705 703
706 BezierVertex* verts = reinterpret_cast<BezierVertex*>(arg->vertices()); 704 BezierVertex* verts = reinterpret_cast<BezierVertex*>(arg->vertices());
707 705
708 const SkMatrix* toDevice = NULL; 706 const SkMatrix* toDevice = NULL;
709 const SkMatrix* toSrc = NULL; 707 const SkMatrix* toSrc = NULL;
710 SkMatrix ivm; 708 SkMatrix ivm;
711 709
712 if (viewM.hasPerspective()) { 710 if (viewMatrix.hasPerspective()) {
713 if (viewM.invert(&ivm)) { 711 if (viewMatrix.invert(&ivm)) {
714 toDevice = &viewM; 712 toDevice = &viewMatrix;
715 toSrc = &ivm; 713 toSrc = &ivm;
716 } 714 }
717 } 715 }
718 716
719 // Seed the dev bounds with some pts known to be inside. Each quad and conic grows the bounding 717 // Seed the dev bounds with some pts known to be inside. Each quad and conic grows the bounding
720 // box to include its vertices. 718 // box to include its vertices.
721 SkPoint seedPts[2]; 719 SkPoint seedPts[2];
722 if (quadCnt) { 720 if (quadCnt) {
723 seedPts[0] = quads[0]; 721 seedPts[0] = quads[0];
724 seedPts[1] = quads[2]; 722 seedPts[1] = quads[2];
(...skipping 14 matching lines...) Expand all
739 737
740 // Start Conics 738 // Start Conics
741 for (int i = 0; i < conicCnt; ++i) { 739 for (int i = 0; i < conicCnt; ++i) {
742 add_conics(&conics[3*i], cWeights[i], toDevice, toSrc, &verts, devBounds ); 740 add_conics(&conics[3*i], cWeights[i], toDevice, toSrc, &verts, devBounds );
743 } 741 }
744 return true; 742 return true;
745 } 743 }
746 744
747 bool GrAAHairLinePathRenderer::canDrawPath(const GrDrawTarget* target, 745 bool GrAAHairLinePathRenderer::canDrawPath(const GrDrawTarget* target,
748 const GrDrawState* drawState, 746 const GrDrawState* drawState,
747 const SkMatrix& viewMatrix,
749 const SkPath& path, 748 const SkPath& path,
750 const SkStrokeRec& stroke, 749 const SkStrokeRec& stroke,
751 bool antiAlias) const { 750 bool antiAlias) const {
752 if (!antiAlias) { 751 if (!antiAlias) {
753 return false; 752 return false;
754 } 753 }
755 754
756 if (!IsStrokeHairlineOrEquivalent(stroke, 755 if (!IsStrokeHairlineOrEquivalent(stroke, viewMatrix, NULL)) {
757 drawState->getViewMatrix(),
758 NULL)) {
759 return false; 756 return false;
760 } 757 }
761 758
762 if (SkPath::kLine_SegmentMask == path.getSegmentMasks() || 759 if (SkPath::kLine_SegmentMask == path.getSegmentMasks() ||
763 target->caps()->shaderDerivativeSupport()) { 760 target->caps()->shaderDerivativeSupport()) {
764 return true; 761 return true;
765 } 762 }
766 return false; 763 return false;
767 } 764 }
768 765
769 template <class VertexType> 766 template <class VertexType>
770 bool check_bounds(GrDrawState* drawState, const SkRect& devBounds, void* vertice s, int vCount) 767 bool check_bounds(const SkMatrix& viewMatrix, const SkRect& devBounds, void* ver tices, int vCount)
771 { 768 {
772 SkRect tolDevBounds = devBounds; 769 SkRect tolDevBounds = devBounds;
773 // The bounds ought to be tight, but in perspective the below code runs the verts 770 // The bounds ought to be tight, but in perspective the below code runs the verts
774 // through the view matrix to get back to dev coords, which can introduce im precision. 771 // through the view matrix to get back to dev coords, which can introduce im precision.
775 if (drawState->getViewMatrix().hasPerspective()) { 772 if (viewMatrix.hasPerspective()) {
776 tolDevBounds.outset(SK_Scalar1 / 1000, SK_Scalar1 / 1000); 773 tolDevBounds.outset(SK_Scalar1 / 1000, SK_Scalar1 / 1000);
777 } else { 774 } else {
778 // Non-persp matrices cause this path renderer to draw in device space. 775 // Non-persp matrices cause this path renderer to draw in device space.
779 SkASSERT(drawState->getViewMatrix().isIdentity()); 776 SkASSERT(viewMatrix.isIdentity());
780 } 777 }
781 SkRect actualBounds; 778 SkRect actualBounds;
782 779
783 VertexType* verts = reinterpret_cast<VertexType*>(vertices); 780 VertexType* verts = reinterpret_cast<VertexType*>(vertices);
784 bool first = true; 781 bool first = true;
785 for (int i = 0; i < vCount; ++i) { 782 for (int i = 0; i < vCount; ++i) {
786 SkPoint pos = verts[i].fPos; 783 SkPoint pos = verts[i].fPos;
787 // This is a hack to workaround the fact that we move some degenerate se gments offscreen. 784 // This is a hack to workaround the fact that we move some degenerate se gments offscreen.
788 if (SK_ScalarMax == pos.fX) { 785 if (SK_ScalarMax == pos.fX) {
789 continue; 786 continue;
790 } 787 }
791 drawState->getViewMatrix().mapPoints(&pos, 1); 788 viewMatrix.mapPoints(&pos, 1);
792 if (first) { 789 if (first) {
793 actualBounds.set(pos.fX, pos.fY, pos.fX, pos.fY); 790 actualBounds.set(pos.fX, pos.fY, pos.fX, pos.fY);
794 first = false; 791 first = false;
795 } else { 792 } else {
796 actualBounds.growToInclude(pos.fX, pos.fY); 793 actualBounds.growToInclude(pos.fX, pos.fY);
797 } 794 }
798 } 795 }
799 if (!first) { 796 if (!first) {
800 return tolDevBounds.contains(actualBounds); 797 return tolDevBounds.contains(actualBounds);
801 } 798 }
802 799
803 return true; 800 return true;
804 } 801 }
805 802
806 bool GrAAHairLinePathRenderer::onDrawPath(GrDrawTarget* target, 803 bool GrAAHairLinePathRenderer::onDrawPath(GrDrawTarget* target,
807 GrDrawState* drawState, 804 GrDrawState* drawState,
808 GrColor color, 805 GrColor color,
806 const SkMatrix& viewMatrix,
809 const SkPath& path, 807 const SkPath& path,
810 const SkStrokeRec& stroke, 808 const SkStrokeRec& stroke,
811 bool antiAlias) { 809 bool antiAlias) {
812 SkScalar hairlineCoverage; 810 SkScalar hairlineCoverage;
813 uint8_t newCoverage = 0xff; 811 uint8_t newCoverage = 0xff;
814 if (IsStrokeHairlineOrEquivalent(stroke, drawState->getViewMatrix(), 812 if (IsStrokeHairlineOrEquivalent(stroke, viewMatrix, &hairlineCoverage)) {
815 &hairlineCoverage)) {
816 newCoverage = SkScalarRoundToInt(hairlineCoverage * 0xff); 813 newCoverage = SkScalarRoundToInt(hairlineCoverage * 0xff);
817 } 814 }
818 815
819 SkIRect devClipBounds; 816 SkIRect devClipBounds;
820 target->getClip()->getConservativeBounds(drawState->getRenderTarget(), &devC lipBounds); 817 target->getClip()->getConservativeBounds(drawState->getRenderTarget(), &devC lipBounds);
821 818
822 int lineCnt; 819 int lineCnt;
823 int quadCnt; 820 int quadCnt;
824 int conicCnt; 821 int conicCnt;
825 PREALLOC_PTARRAY(128) lines; 822 PREALLOC_PTARRAY(128) lines;
826 PREALLOC_PTARRAY(128) quads; 823 PREALLOC_PTARRAY(128) quads;
827 PREALLOC_PTARRAY(128) conics; 824 PREALLOC_PTARRAY(128) conics;
828 IntArray qSubdivs; 825 IntArray qSubdivs;
829 FloatArray cWeights; 826 FloatArray cWeights;
830 quadCnt = generate_lines_and_quads(path, drawState->getViewMatrix(), devClip Bounds, 827 quadCnt = generate_lines_and_quads(path, viewMatrix, devClipBounds,
831 &lines, &quads, &conics, &qSubdivs, &cWei ghts); 828 &lines, &quads, &conics, &qSubdivs, &cWei ghts);
832 lineCnt = lines.count() / 2; 829 lineCnt = lines.count() / 2;
833 conicCnt = conics.count() / 3; 830 conicCnt = conics.count() / 3;
834 831
835 // createGeom transforms the geometry to device space when the matrix does n ot have 832 // createGeom transforms the geometry to device space when the matrix does n ot have
836 // perspective. 833 // perspective.
837 GrDrawState::AutoViewMatrixRestore avmr; 834 SkMatrix vm = viewMatrix;
838 SkMatrix invert = SkMatrix::I(); 835 SkMatrix invert = SkMatrix::I();
839 if (!drawState->getViewMatrix().hasPerspective()) { 836 if (!viewMatrix.hasPerspective()) {
840 avmr.setIdentity(drawState); 837 vm = SkMatrix::I();
841 if (!drawState->getViewMatrix().invert(&invert)) { 838 if (!viewMatrix.invert(&invert)) {
842 return false; 839 return false;
843 } 840 }
844 } 841 }
845 842
846 // do lines first 843 // do lines first
847 if (lineCnt) { 844 if (lineCnt) {
848 GrDrawTarget::AutoReleaseGeometry arg; 845 GrDrawTarget::AutoReleaseGeometry arg;
849 SkRect devBounds; 846 SkRect devBounds;
850 847
851 GrDrawState::AutoRestoreEffects are(drawState); 848 GrDrawState::AutoRestoreEffects are(drawState);
852 uint32_t gpFlags = GrDefaultGeoProcFactory::kPosition_GPType | 849 uint32_t gpFlags = GrDefaultGeoProcFactory::kPosition_GPType |
853 GrDefaultGeoProcFactory::kCoverage_GPType; 850 GrDefaultGeoProcFactory::kCoverage_GPType;
854 SkAutoTUnref<const GrGeometryProcessor> gp(GrDefaultGeoProcFactory::Crea te(color, 851 SkAutoTUnref<const GrGeometryProcessor> gp(GrDefaultGeoProcFactory::Crea te(gpFlags,
855 gpFlags, 852 color,
853 vm,
854 invert,
856 false, 855 false,
857 newCoverage, 856 newCoverage));
858 invert));
859 857
860 if (!this->createLineGeom(target, 858 if (!this->createLineGeom(target,
861 drawState, 859 drawState,
860 viewMatrix,
862 newCoverage, 861 newCoverage,
863 gp->getVertexStride(), 862 gp->getVertexStride(),
864 &arg, 863 &arg,
865 &devBounds, 864 &devBounds,
866 path, 865 path,
867 lines, 866 lines,
868 lineCnt)) { 867 lineCnt)) {
869 return false; 868 return false;
870 } 869 }
871 870
872 // Check devBounds 871 // Check devBounds
873 SkASSERT(check_bounds<LineVertex>(drawState, devBounds, arg.vertices(), 872 SkASSERT(check_bounds<LineVertex>(viewMatrix.hasPerspective() ? viewMatr ix : SkMatrix::I(),
873 devBounds,
874 arg.vertices(),
874 kLineSegNumVertices * lineCnt)); 875 kLineSegNumVertices * lineCnt));
875 876
876 { 877 {
877 target->setIndexSourceToBuffer(fLinesIndexBuffer); 878 target->setIndexSourceToBuffer(fLinesIndexBuffer);
878 int lines = 0; 879 int lines = 0;
879 while (lines < lineCnt) { 880 while (lines < lineCnt) {
880 int n = SkTMin(lineCnt - lines, kLineSegsNumInIdxBuffer); 881 int n = SkTMin(lineCnt - lines, kLineSegsNumInIdxBuffer);
881 target->drawIndexed(drawState, 882 target->drawIndexed(drawState,
882 gp, 883 gp,
883 kTriangles_GrPrimitiveType, 884 kTriangles_GrPrimitiveType,
884 kLineSegNumVertices*lines, // startV 885 kLineSegNumVertices*lines, // startV
885 0, // startI 886 0, // startI
886 kLineSegNumVertices*n, // vCount 887 kLineSegNumVertices*n, // vCount
887 kIdxsPerLineSeg*n, // iCount 888 kIdxsPerLineSeg*n, // iCount
888 &devBounds); 889 &devBounds);
889 lines += n; 890 lines += n;
890 } 891 }
891 } 892 }
892 } 893 }
893 894
894 // then quadratics/conics 895 // then quadratics/conics
895 if (quadCnt || conicCnt) { 896 if (quadCnt || conicCnt) {
896 GrDrawTarget::AutoReleaseGeometry arg; 897 GrDrawTarget::AutoReleaseGeometry arg;
897 SkRect devBounds; 898 SkRect devBounds;
898 899
899 if (!this->createBezierGeom(target, 900 if (!this->createBezierGeom(target,
900 drawState, 901 drawState,
902 viewMatrix,
901 &arg, 903 &arg,
902 &devBounds, 904 &devBounds,
903 path, 905 path,
904 quads, 906 quads,
905 quadCnt, 907 quadCnt,
906 conics, 908 conics,
907 conicCnt, 909 conicCnt,
908 qSubdivs, 910 qSubdivs,
909 cWeights, 911 cWeights,
910 sizeof(BezierVertex))) { 912 sizeof(BezierVertex))) {
911 return false; 913 return false;
912 } 914 }
913 915
914 // Check devBounds 916 // Check devBounds
915 SkASSERT(check_bounds<BezierVertex>(drawState, devBounds, arg.vertices() , 917 SkASSERT(check_bounds<BezierVertex>(viewMatrix.hasPerspective() ? viewMa trix :
916 kQuadNumVertices * quadCnt + kQuadNu mVertices * conicCnt)); 918 SkMatr ix::I(),
919 devBounds,
920 arg.vertices(),
921 kQuadNumVertices * quadCnt +
922 kQuadNumVertices * conicCnt));
917 923
918 if (quadCnt > 0) { 924 if (quadCnt > 0) {
919 SkAutoTUnref<GrGeometryProcessor> hairQuadProcessor( 925 SkAutoTUnref<GrGeometryProcessor> hairQuadProcessor(
920 GrQuadEffect::Create(color, 926 GrQuadEffect::Create(color,
927 vm,
921 kHairlineAA_GrProcessorEdgeType, 928 kHairlineAA_GrProcessorEdgeType,
922 *target->caps(), 929 *target->caps(),
923 invert, 930 invert,
924 newCoverage)); 931 newCoverage));
925 SkASSERT(hairQuadProcessor); 932 SkASSERT(hairQuadProcessor);
926 GrDrawState::AutoRestoreEffects are(drawState); 933 GrDrawState::AutoRestoreEffects are(drawState);
927 target->setIndexSourceToBuffer(fQuadsIndexBuffer); 934 target->setIndexSourceToBuffer(fQuadsIndexBuffer);
928 935
929 int quads = 0; 936 int quads = 0;
930 while (quads < quadCnt) { 937 while (quads < quadCnt) {
931 int n = SkTMin(quadCnt - quads, kQuadsNumInIdxBuffer); 938 int n = SkTMin(quadCnt - quads, kQuadsNumInIdxBuffer);
932 target->drawIndexed(drawState, 939 target->drawIndexed(drawState,
933 hairQuadProcessor, 940 hairQuadProcessor,
934 kTriangles_GrPrimitiveType, 941 kTriangles_GrPrimitiveType,
935 kQuadNumVertices*quads, // sta rtV 942 kQuadNumVertices*quads, // sta rtV
936 0, // sta rtI 943 0, // sta rtI
937 kQuadNumVertices*n, // vCo unt 944 kQuadNumVertices*n, // vCo unt
938 kIdxsPerQuad*n, // iCo unt 945 kIdxsPerQuad*n, // iCo unt
939 &devBounds); 946 &devBounds);
940 quads += n; 947 quads += n;
941 } 948 }
942 } 949 }
943 950
944 if (conicCnt > 0) { 951 if (conicCnt > 0) {
945 SkAutoTUnref<GrGeometryProcessor> hairConicProcessor( 952 SkAutoTUnref<GrGeometryProcessor> hairConicProcessor(
946 GrConicEffect::Create(color, kHairlineAA_GrProcessorEdgeType , *target->caps(), 953 GrConicEffect::Create(color, vm, kHairlineAA_GrProcessorEdge Type,
947 invert, newCoverage)); 954 *target->caps(), invert, newCoverage)) ;
948 SkASSERT(hairConicProcessor); 955 SkASSERT(hairConicProcessor);
949 GrDrawState::AutoRestoreEffects are(drawState); 956 GrDrawState::AutoRestoreEffects are(drawState);
950 target->setIndexSourceToBuffer(fQuadsIndexBuffer); 957 target->setIndexSourceToBuffer(fQuadsIndexBuffer);
951 958
952 int conics = 0; 959 int conics = 0;
953 while (conics < conicCnt) { 960 while (conics < conicCnt) {
954 int n = SkTMin(conicCnt - conics, kQuadsNumInIdxBuffer); 961 int n = SkTMin(conicCnt - conics, kQuadsNumInIdxBuffer);
955 target->drawIndexed(drawState, 962 target->drawIndexed(drawState,
956 hairConicProcessor, 963 hairConicProcessor,
957 kTriangles_GrPrimitiveType, 964 kTriangles_GrPrimitiveType,
958 kQuadNumVertices*(quadCnt + conics), // sta rtV 965 kQuadNumVertices*(quadCnt + conics), // sta rtV
959 0, // sta rtI 966 0, // sta rtI
960 kQuadNumVertices*n, // vCo unt 967 kQuadNumVertices*n, // vCo unt
961 kIdxsPerQuad*n, // iCo unt 968 kIdxsPerQuad*n, // iCo unt
962 &devBounds); 969 &devBounds);
963 conics += n; 970 conics += n;
964 } 971 }
965 } 972 }
966 } 973 }
967 974
968 target->resetIndexSource(); 975 target->resetIndexSource();
969 976
970 return true; 977 return true;
971 } 978 }
OLDNEW
« no previous file with comments | « src/gpu/GrAAHairLinePathRenderer.h ('k') | src/gpu/GrAARectRenderer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698