OLD | NEW |
---|---|
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 Loading... | |
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(¶llelScale, &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 Loading... | |
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 } |
OLD | NEW |