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

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

Issue 274673004: Add Dashing gpu effect for simple dashed lines (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Updates Created 6 years, 7 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
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 "SkGpuDevice.h" 8 #include "SkGpuDevice.h"
9 9
10 #include "effects/GrBicubicEffect.h" 10 #include "effects/GrBicubicEffect.h"
11 #include "effects/GrDashingEffect.h"
11 #include "effects/GrTextureDomain.h" 12 #include "effects/GrTextureDomain.h"
12 #include "effects/GrSimpleTextureEffect.h" 13 #include "effects/GrSimpleTextureEffect.h"
13 14
14 #include "GrContext.h" 15 #include "GrContext.h"
15 #include "GrBitmapTextContext.h" 16 #include "GrBitmapTextContext.h"
16 #include "GrDistanceFieldTextContext.h" 17 #include "GrDistanceFieldTextContext.h"
17 #include "GrLayerCache.h" 18 #include "GrLayerCache.h"
18 #include "GrPictureUtils.h" 19 #include "GrPictureUtils.h"
19 20
20 #include "SkGrTexturePixelRef.h" 21 #include "SkGrTexturePixelRef.h"
(...skipping 507 matching lines...) Expand 10 before | Expand all | Expand 10 after
528 void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, 529 void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
529 size_t count, const SkPoint pts[], const SkPaint& p aint) { 530 size_t count, const SkPoint pts[], const SkPaint& p aint) {
530 CHECK_FOR_ANNOTATION(paint); 531 CHECK_FOR_ANNOTATION(paint);
531 CHECK_SHOULD_DRAW(draw, false); 532 CHECK_SHOULD_DRAW(draw, false);
532 533
533 SkScalar width = paint.getStrokeWidth(); 534 SkScalar width = paint.getStrokeWidth();
534 if (width < 0) { 535 if (width < 0) {
535 return; 536 return;
536 } 537 }
537 538
539 if (paint.getPathEffect() && 2 == count && SkCanvas::kLines_PointMode == mod e) {
540 if (this->drawDashLine(pts, paint)) {
541 return;
542 }
543 }
544
538 // we only handle hairlines and paints without path effects or mask filters, 545 // we only handle hairlines and paints without path effects or mask filters,
539 // else we let the SkDraw call our drawPath() 546 // else we let the SkDraw call our drawPath()
540 if (width > 0 || paint.getPathEffect() || paint.getMaskFilter()) { 547 if (width > 0 || paint.getPathEffect() || paint.getMaskFilter()) {
541 draw.drawPoints(mode, count, pts, paint, true); 548 draw.drawPoints(mode, count, pts, paint, true);
542 return; 549 return;
543 } 550 }
544 551
545 GrPaint grPaint; 552 GrPaint grPaint;
546 if (!skPaint2GrPaintShader(this, paint, true, &grPaint)) { 553 if (!skPaint2GrPaintShader(this, paint, true, &grPaint)) {
547 return; 554 return;
548 } 555 }
549 556
550 fContext->drawVertices(grPaint, 557 fContext->drawVertices(grPaint,
551 gPointMode2PrimtiveType[mode], 558 gPointMode2PrimtiveType[mode],
552 SkToS32(count), 559 SkToS32(count),
553 (SkPoint*)pts, 560 (SkPoint*)pts,
554 NULL, 561 NULL,
555 NULL, 562 NULL,
556 NULL, 563 NULL,
557 0); 564 0);
558 } 565 }
559 566
560 /////////////////////////////////////////////////////////////////////////////// 567 ///////////////////////////////////////////////////////////////////////////////
561 568
569 static void calc_dash_scaling(SkScalar* parallelScale, SkScalar* perpScale,
570 const SkMatrix& viewMatrix, const SkPoint pts[2]) {
571 SkVector vecSrc = pts[1] - pts[0];
572 SkScalar magSrc = vecSrc.length();
573 SkScalar invSrc = magSrc ? SkScalarInvert(magSrc) : 0;
574 vecSrc.scale(invSrc);
575
576 SkVector vecSrcPerp;
577 vecSrc.rotateCW(&vecSrcPerp);
578 viewMatrix.mapVectors(&vecSrc, 1);
579 viewMatrix.mapVectors(&vecSrcPerp, 1);
580
581 // parallelScale tells how much to scale along the line parallel to the dash line
582 // perpScale tells how much to scale in the direction perpendicular to the d ash line
583 *parallelScale = vecSrc.length();
584 *perpScale = vecSrcPerp.length();
585 }
586
587 // calculates the rotation needed to aligned pts to the x axis with pts[0] < pts [1]
588 // Stores the rotation matrix in rotMatrix, and the mapped points in ptsRot
589 static void align_to_x_axis(const SkPoint pts[2], SkMatrix* rotMatrix, SkPoint p tsRot[2] = NULL) {
590 SkVector vec = pts[1] - pts[0];
591 SkScalar mag = vec.length();
592 SkScalar inv = mag ? SkScalarInvert(mag) : 0;
593
594 vec.scale(inv);
595 rotMatrix->setSinCos(-vec.fY, vec.fX, pts[0].fX, pts[0].fY);
596 if (ptsRot) {
597 rotMatrix->mapPoints(ptsRot, pts, 2);
598 // correction for numerical issues if map doesn't make ptsRot exactly ho rizontal
599 ptsRot[1].fY = pts[0].fY;
600 }
601 }
602
603
604 // Assumes phase < sum of all intervals
605 static SkScalar calc_start_adjustment(const SkPathEffect::DashInfo& info) {
606 SkASSERT(info.fPhase < info.fIntervals[0] + info.fIntervals[1]);
607 if (info.fPhase >= info.fIntervals[0] && info.fPhase != 0) {
608 SkScalar srcIntervalLen = info.fIntervals[0] + info.fIntervals[1];
609 return srcIntervalLen - info.fPhase;
610 }
611 return 0;
612 }
613
614 static SkScalar calc_end_adjustment(const SkPathEffect::DashInfo& info, const Sk Point pts[2], SkScalar* endingInt) {
615 if (pts[1].fX <= pts[0].fX) {
616 return 0;
617 }
618 SkScalar srcIntervalLen = info.fIntervals[0] + info.fIntervals[1];
619 SkScalar totalLen = pts[1].fX - pts[0].fX;
620 SkScalar temp = SkScalarDiv(totalLen, srcIntervalLen);
621 SkScalar numFullIntervals = SkScalarFloorToScalar(temp);
622 *endingInt = totalLen - numFullIntervals * srcIntervalLen + info.fPhase;
623 temp = SkScalarDiv(*endingInt, srcIntervalLen);
624 *endingInt = *endingInt - SkScalarFloorToScalar(temp) * srcIntervalLen;
625 if (0 == *endingInt) {
626 *endingInt = srcIntervalLen;
627 }
628 if (*endingInt > info.fIntervals[0]) {
629 if (0 == info.fIntervals[0]) {
630 *endingInt -= 0.01; // make sure we capture the last zero size pnt ( used if has caps)
631 }
632 return *endingInt - info.fIntervals[0];
633 }
634 return 0;
635 }
636
637
bsalomon 2014/05/13 09:10:33 This file has gotten huge. It seems like the only
egdaniel 2014/05/13 14:00:11 Agree completely. Will move it out. On 2014/05/13
638 bool SkGpuDevice::drawDashLine(const SkPoint pts[2], const SkPaint& paint) {
bsalomon 2014/05/13 09:10:33 I think this function needs to check if the target
egdaniel 2014/05/13 14:00:11 is that not what the check below this comment is d
bsalomon 2014/05/13 14:14:36 dOn 2014/05/13 14:00:11, egdaniel wrote:
639 if (fContext->getRenderTarget()->isMultisampled()) {
640 return false;
641 }
642
643 const SkMatrix& viewMatrix = fContext->getMatrix();
644 if (!viewMatrix.preservesRightAngles()) {
645 return false;
646 }
647
648 const SkPathEffect* pe = paint.getPathEffect();
649 SkPathEffect::DashInfo info;
650 SkPathEffect::DashType dashType = pe->asADash(&info);
651 // Must be a dash effect with 2 intervals (1 on and 1 off)
652 if (SkPathEffect::kDash_DashType != dashType || 2 != info.fCount) {
653 return false;
654 }
655
656 SkPaint::Cap cap = paint.getStrokeCap();
657 // Current we do don't handle Round or Square cap dashes
658 if (SkPaint::kRound_Cap == cap) {
659 return false;
660 }
661
662 SkScalar srcStrokeWidth = paint.getStrokeWidth();
663
664 // Get all info about the dash effect
665 SkAutoTArray<SkScalar> intervals(info.fCount);
666 info.fIntervals = intervals.get();
667 pe->asADash(&info);
668
669 // the phase should be normalized to be [0, sum of all intervals)
670 SkASSERT(info.fPhase >= 0 && info.fPhase < info.fIntervals[0] + info.fInterv als[1]);
671
672 SkMatrix coordTrans;
673
674 // Rotate the src pts so they are aligned horizontally with pts[0].fX < pts[ 1].fX
675 SkMatrix srcRotInv;
676 SkPoint ptsRot[2];
677 if (pts[0].fY != pts[1].fY || pts[0].fX > pts[1].fX) {
678 align_to_x_axis(pts, &coordTrans, ptsRot);
679 if(!coordTrans.invert(&srcRotInv)) {
680 return false;
681 }
682 } else {
683 coordTrans.reset();
684 srcRotInv.reset();
685 memcpy(ptsRot, pts, 2 * sizeof(SkPoint));
686 }
687
688 GrPaint grPaint;
689 if (!skPaint2GrPaintShader(this, paint, true, &grPaint)) {
690 return false;
691 }
692
693 bool useAA = paint.isAntiAlias();
694
695 // Scale corrections of intervals and stroke from view matrix
696 SkScalar parallelScale;
697 SkScalar perpScale;
698 calc_dash_scaling(&parallelScale, &perpScale, viewMatrix, ptsRot);
699
700 bool hasCap =SkPaint::kSquare_Cap == cap && 0 != srcStrokeWidth;
bsalomon 2014/05/13 09:10:33 space after =
701
702 // We always want to at least stroke out half a pixel on each side in device space
703 // so 0.5f / perpScale gives us this min in src space
704 SkScalar halfStroke = SkMaxScalar(srcStrokeWidth * 0.5f, 0.5f / perpScale);
705
706 SkScalar xStroke;
707 if (!hasCap) {
708 xStroke = 0.f;
709 } else {
710 xStroke = halfStroke;
711 }
712
713 // If we are using AA, check to see if we are drawing a partial dash at the start. If so
714 // draw it separately here and adjust our start point accordingly
715 if (useAA) {
716 if (info.fPhase > 0 && info.fPhase < info.fIntervals[0]) {
717 SkPoint startPts[2];
718 startPts[0] = ptsRot[0];
719 startPts[1].fY = startPts[0].fY;
720 startPts[1].fX = SkMinScalar(startPts[0].fX + info.fIntervals[0] - i nfo.fPhase,
721 ptsRot[1].fX);
722 SkRect startRect;
723 startRect.set(startPts, 2);
724 startRect.outset(xStroke, halfStroke);
725 fContext->drawRect(grPaint, startRect, NULL, &srcRotInv);
726
727 ptsRot[0].fX += info.fIntervals[0] + info.fIntervals[1] - info.fPhas e;
728 info.fPhase = 0;
729 }
730 }
731
732 // adjustments for start and end of bounding rect so we only draw dash inter vals
733 // contained in the original line segment.
734 SkScalar startAdj = calc_start_adjustment(info);
735 SkScalar endingInterval = 0;
736 SkScalar endAdj = calc_end_adjustment(info, ptsRot, &endingInterval);
737 if (ptsRot[0].fX + startAdj >= ptsRot[1].fX - endAdj) {
738 // Nothing left to draw so just return
739 return true;
740 }
741
742 // If we are using AA, check to see if we are drawing a partial dash at then end. If so
743 // draw it separately here and adjust our end point accordingly
744 if (useAA) {
745 // If we adjusted the end then we will not be drawing a partial dash at the end.
746 // If we didn't adjust the end point then we just need to make sure the ending
747 // dash isn't a full dash
748 if (0 == endAdj && endingInterval != info.fIntervals[0]) {
749
750 SkPoint endPts[2];
751 endPts[1] = ptsRot[1];
752 endPts[0].fY = endPts[1].fY;
753 endPts[0].fX = endPts[1].fX - endingInterval;
754
755 SkRect endRect;
756 endRect.set(endPts, 2);
757 endRect.outset(xStroke, halfStroke);
758 fContext->drawRect(grPaint, endRect, NULL, &srcRotInv);
759
760 ptsRot[1].fX -= endingInterval + info.fIntervals[1];
761 if (ptsRot[0].fX >= ptsRot[1].fX) {
762 // Nothing left to draw so just return
763 return true;
764 }
765 }
766 }
767 coordTrans.postConcat(viewMatrix);
768
769 SkPoint devicePts[2];
770 viewMatrix.mapPoints(devicePts, ptsRot, 2);
771
772 info.fIntervals[0] *= parallelScale;
773 info.fIntervals[1] *= parallelScale;
774 info.fPhase *= parallelScale;
775 SkScalar strokeWidth = srcStrokeWidth * perpScale;
776
777 if ((strokeWidth < 1.f && !useAA) || 0.f == strokeWidth) {
778 strokeWidth = 1.f;
779 }
780
781 // Set up coordTransform for device space transforms
782 // We rotate the dashed line such that it is horizontal with the start point at smaller x
783 // then we translate the start point to the origin
784 if (devicePts[0].fY != devicePts[1].fY || devicePts[0].fX > devicePts[1].fX) {
785 SkMatrix rot;
786 align_to_x_axis(devicePts, &rot);
787 coordTrans.postConcat(rot);
788 }
789 coordTrans.postTranslate(-devicePts[0].fX, -devicePts[0].fY);
790 coordTrans.postTranslate(info.fIntervals[1] * 0.5f + info.fPhase, 0);
791
792 if (SkPaint::kSquare_Cap == cap && 0 != srcStrokeWidth) {
793 // add cap to on interveal and remove from off interval
794 info.fIntervals[0] += strokeWidth;
795 info.fIntervals[1] -= strokeWidth;
796 }
797
798 if (info.fIntervals[1] > 0.f) {
799 GrEffectEdgeType edgeType= useAA ? kFillAA_GrEffectEdgeType :
800 kFillBW_GrEffectEdgeType;
801 grPaint.addCoverageEffect(GrDashingEffect::Create(edgeType, info, coordT rans, strokeWidth))->unref();
802 grPaint.setAntiAlias(false);
803 }
804
805 SkRect rect;
806 bool bloat = useAA && info.fIntervals[1] > 0.f;
807 SkScalar bloatX = bloat ? 0.5f / parallelScale : 0.f;
808 SkScalar bloatY = bloat ? 0.5f / perpScale : 0.f;
809 ptsRot[0].fX += startAdj;
810 ptsRot[1].fX -= endAdj;
811 if (!hasCap) {
812 xStroke = 0.f;
813 } else {
814 xStroke = halfStroke;
815 }
816 rect.set(ptsRot, 2);
817 rect.outset(bloatX + xStroke, bloatY + halfStroke);
818 fContext->drawRect(grPaint, rect, NULL, &srcRotInv);
819
820 return true;
821 }
822
823 ///////////////////////////////////////////////////////////////////////////////
824
562 void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect, 825 void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
563 const SkPaint& paint) { 826 const SkPaint& paint) {
564 CHECK_FOR_ANNOTATION(paint); 827 CHECK_FOR_ANNOTATION(paint);
565 CHECK_SHOULD_DRAW(draw, false); 828 CHECK_SHOULD_DRAW(draw, false);
566 829
567 bool doStroke = paint.getStyle() != SkPaint::kFill_Style; 830 bool doStroke = paint.getStyle() != SkPaint::kFill_Style;
568 SkScalar width = paint.getStrokeWidth(); 831 SkScalar width = paint.getStrokeWidth();
569 832
570 /* 833 /*
571 We have special code for hairline strokes, miter-strokes, bevel-stroke 834 We have special code for hairline strokes, miter-strokes, bevel-stroke
(...skipping 1548 matching lines...) Expand 10 before | Expand all | Expand 10 after
2120 GrCachedLayer* layer = fContext->getLayerCache()->findLayerOrCreate(pict ure, i); 2383 GrCachedLayer* layer = fContext->getLayerCache()->findLayerOrCreate(pict ure, i);
2121 2384
2122 if (NULL != layer->getTexture()) { 2385 if (NULL != layer->getTexture()) {
2123 fContext->unlockScratchTexture(layer->getTexture()); 2386 fContext->unlockScratchTexture(layer->getTexture());
2124 layer->setTexture(NULL); 2387 layer->setTexture(NULL);
2125 } 2388 }
2126 } 2389 }
2127 2390
2128 return true; 2391 return true;
2129 } 2392 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698