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) { | |
540 if (this->drawDash(pts, paint, mode)) { | |
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 calcDashScaling(SkScalar* parallelScale, SkScalar* perpScale, | |
bsalomon
2014/05/09 15:02:37
style nit: we've been tending towards naming_stati
egdaniel
2014/05/12 19:21:44
fixed
On 2014/05/09 15:02:37, bsalomon wrote:
| |
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 alignToXAxis(const SkPoint pts[2], SkMatrix* rotMatrix, SkPoint ptsR ot[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 // Assumes phase < sum of all intervals | |
bsalomon
2014/05/09 15:02:37
is that a valid assumption? add an assert?
egdaniel
2014/05/12 19:21:44
In the creation of SkDashEffect the phase is norma
| |
604 static SkScalar calcStartAdjustment(const SkPathEffect::DashInfo& info) { | |
605 SkScalar srcIntervalLen = info.fIntervals[0] + info.fIntervals[1]; | |
bsalomon
2014/05/09 15:02:37
don't need this until inside both ifs, right?
egdaniel
2014/05/12 19:21:44
yup
On 2014/05/09 15:02:37, bsalomon wrote:
| |
606 if (info.fPhase >= info.fIntervals[0]) { | |
607 if (info.fIntervals[0] !=0 || info.fPhase != 0) { | |
bsalomon
2014/05/09 15:02:37
if intervals[0] is != 0 then phase can't be either
egdaniel
2014/05/12 19:21:44
Ahh you're right. I was just inverting the logic i
| |
608 return srcIntervalLen - info.fPhase; | |
609 } | |
610 } | |
611 return 0; | |
612 } | |
613 | |
614 static SkScalar calcEndAdjustment(const SkPathEffect::DashInfo& info, const SkPo int pts[2]) { | |
615 SkScalar srcIntervalLen = info.fIntervals[0] + info.fIntervals[1]; | |
616 SkScalar totalLen = pts[1].fX - pts[0].fY; | |
617 SkScalar temp = SkScalarDiv(totalLen, srcIntervalLen); | |
618 SkScalar numFullIntervals = SkScalarFloorToScalar(temp); | |
619 SkScalar endingInt = totalLen - numFullIntervals * srcIntervalLen + info.fPh ase; | |
620 temp = SkScalarDiv(endingInt, srcIntervalLen); | |
621 endingInt = endingInt - SkScalarFloorToScalar(temp) * srcIntervalLen; | |
622 if (0 == endingInt) { | |
623 endingInt = srcIntervalLen; | |
624 } | |
625 if (endingInt > info.fIntervals[0]) { | |
626 if (0 == info.fIntervals[0]) { | |
627 endingInt -= 0.01; // make sure we capture the last zero size pnt (u sed if has caps) | |
628 } | |
629 return endingInt - info.fIntervals[0]; | |
630 } | |
631 return 0; | |
632 } | |
633 | |
634 bool SkGpuDevice::drawDash(const SkPoint pts[2], const SkPaint& paint, SkCanvas: :PointMode mode) { | |
bsalomon
2014/05/09 15:02:37
maybe this should be called drawDashedLine()? It o
egdaniel
2014/05/12 19:21:44
Name changed. Moved the mode check to the caller.
| |
635 if (SkCanvas::kLines_PointMode != mode) { | |
636 return false; | |
637 } | |
638 | |
639 const SkMatrix& viewMatrix = fContext->getMatrix(); | |
640 if (!viewMatrix.preservesRightAngles()) { | |
641 return false; | |
642 } | |
643 | |
644 const SkPathEffect* pe = paint.getPathEffect(); | |
645 SkPathEffect::DashInfo info; | |
646 SkPathEffect::DashType dashType = pe->asADash(&info); | |
647 // Must be a dash effect with 2 intervals (1 on and 1 off) | |
648 if (SkPathEffect::kDash_DashType != dashType || 2 != info.fCount) { | |
649 return false; | |
650 } | |
651 | |
652 GrPaint grPaint; | |
bsalomon
2014/05/09 15:02:37
maybe hold off on this until after your cap check?
egdaniel
2014/05/12 19:21:44
done
On 2014/05/09 15:02:37, bsalomon wrote:
| |
653 if (!skPaint2GrPaintShader(this, paint, true, &grPaint)) { | |
654 return false; | |
655 } | |
656 | |
657 SkPaint::Cap cap = paint.getStrokeCap(); | |
658 // Current we do don't handle Round or Square cap dashes | |
659 if (SkPaint::kRound_Cap == cap) { | |
660 return false; | |
661 } | |
662 | |
663 SkScalar srcStrokeWidth = paint.getStrokeWidth(); | |
664 | |
665 // Get all info about the dash effect | |
666 SkAutoTArray<SkScalar> intervals(info.fCount); | |
667 info.fIntervals = intervals.get(); | |
668 pe->asADash(&info); | |
669 | |
670 SkMatrix coordTrans; | |
671 | |
672 // If the src pts are not axis aligned, rotate them so that they are horizon tal | |
673 SkMatrix srcRotInv; | |
674 SkPoint ptsRot[2]; | |
675 if (pts[0].fY != pts[1].fY || pts[0].fX > pts[1].fX) { | |
676 alignToXAxis(pts, &coordTrans, ptsRot); | |
677 if(!coordTrans.invert(&srcRotInv)) { | |
678 return false; | |
679 } | |
680 } else { | |
681 coordTrans.reset(); | |
682 srcRotInv.reset(); | |
683 ptsRot[0] = pts[0]; | |
684 ptsRot[1] = pts[1]; | |
685 } | |
686 | |
687 // adjustments for start and end of bounding rect so we only draw dash inter vals | |
688 // contained in the original line segment. | |
689 // TODO: what happens if adjustments make degenerate line? | |
bsalomon
2014/05/09 15:02:37
Can these conditions cause us to draw incorrectly
egdaniel
2014/05/12 19:21:44
Changed so that if the first or last dashes in the
| |
690 // TODO: since we are using the bounding geometry to clip off bad parts, we now | |
691 // loss so AA that happens on end of dash segment. Better to draw first and last | |
692 // rects separately and use shader on middle? | |
693 SkScalar startAdj = calcStartAdjustment(info); | |
694 SkScalar endAdj = calcEndAdjustment(info, ptsRot); | |
695 | |
696 coordTrans.postConcat(viewMatrix); | |
697 | |
698 SkPoint devicePts[2]; | |
699 viewMatrix.mapPoints(devicePts, ptsRot, 2); | |
700 | |
701 // Scale corrections of intervals and stroke from view matrix | |
702 SkScalar parallelScale; | |
703 SkScalar perpScale; | |
704 calcDashScaling(¶llelScale, &perpScale, viewMatrix, ptsRot); | |
705 info.fIntervals[0] *= parallelScale; | |
706 info.fIntervals[1] *= parallelScale; | |
707 info.fPhase *= parallelScale; | |
708 SkScalar strokeWidth = srcStrokeWidth * perpScale; | |
709 | |
710 bool useAA = paint.isAntiAlias(); | |
711 if ((strokeWidth < 1.f && !useAA) || 0.f == strokeWidth) { | |
712 strokeWidth = 1.f; | |
713 } | |
714 | |
715 // Set up coordTransform for device space transforms | |
716 // We rotate the dashed line such that it is horizontal with the start point at smaller x | |
717 // then we translate the start point to the origin | |
718 if (devicePts[0].fY != devicePts[1].fY || devicePts[0].fX > devicePts[1].fX) { | |
719 SkMatrix rot; | |
720 alignToXAxis(devicePts, &rot); | |
721 coordTrans.postConcat(rot); | |
722 } | |
723 coordTrans.postTranslate(-devicePts[0].fX, -devicePts[0].fY); | |
724 coordTrans.postTranslate(info.fIntervals[1] * 0.5f + info.fPhase, 0); | |
725 | |
726 bool hasCap = false; | |
727 if (SkPaint::kSquare_Cap == cap && 0 != srcStrokeWidth) { | |
728 // add cap to on interveal and remove from off interval | |
729 info.fIntervals[0] += strokeWidth; | |
730 info.fIntervals[1] -= strokeWidth; | |
731 hasCap = true; | |
732 } | |
733 | |
734 if (info.fIntervals[1] > 0.f) { | |
735 GrEffectEdgeType edgeType= useAA ? kFillAA_GrEffectEdgeType : | |
736 kFillBW_GrEffectEdgeType; | |
737 grPaint.addCoverageEffect(GrDashingEffect::Create(edgeType, info, coordT rans, strokeWidth)); | |
738 grPaint.setAntiAlias(false); | |
739 } | |
740 | |
741 // We always want to at least stroke out half a pixel on each side in device space | |
742 // so 0.5f / perpScale gives us this min in src space | |
743 SkScalar halfStroke = SkMaxScalar(srcStrokeWidth * 0.5f, 0.5f / perpScale); | |
744 | |
745 SkRect rect; | |
746 bool bloat = useAA && info.fIntervals[1] > 0.f; | |
747 SkScalar bloatX = bloat ? 0.5f / parallelScale : 0.f; | |
748 SkScalar bloatY = bloat ? 0.5f / perpScale : 0.f; | |
749 SkScalar xStroke; | |
750 SkScalar yStroke; | |
751 if (!hasCap) { | |
752 bool horiz = ptsRot[0].fY == ptsRot[1].fY; | |
753 xStroke = horiz ? 0.f : halfStroke; | |
754 yStroke = horiz ? halfStroke : 0.f; | |
755 } else { | |
756 xStroke = halfStroke; | |
757 yStroke = halfStroke; | |
758 } | |
759 ptsRot[0].fX += startAdj; | |
760 ptsRot[1].fX -= endAdj; | |
761 rect.set(ptsRot, 2); | |
762 rect.outset(bloatX + xStroke, bloatY + yStroke); | |
763 fContext->drawRect(grPaint, rect, NULL, &srcRotInv); | |
764 | |
765 return true; | |
766 } | |
767 | |
768 /////////////////////////////////////////////////////////////////////////////// | |
769 | |
562 void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect, | 770 void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect, |
563 const SkPaint& paint) { | 771 const SkPaint& paint) { |
564 CHECK_FOR_ANNOTATION(paint); | 772 CHECK_FOR_ANNOTATION(paint); |
565 CHECK_SHOULD_DRAW(draw, false); | 773 CHECK_SHOULD_DRAW(draw, false); |
566 | 774 |
567 bool doStroke = paint.getStyle() != SkPaint::kFill_Style; | 775 bool doStroke = paint.getStyle() != SkPaint::kFill_Style; |
568 SkScalar width = paint.getStrokeWidth(); | 776 SkScalar width = paint.getStrokeWidth(); |
569 | 777 |
570 /* | 778 /* |
571 We have special code for hairline strokes, miter-strokes, bevel-stroke | 779 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); | 2328 GrCachedLayer* layer = fContext->getLayerCache()->findLayerOrCreate(pict ure, i); |
2121 | 2329 |
2122 if (NULL != layer->getTexture()) { | 2330 if (NULL != layer->getTexture()) { |
2123 fContext->unlockScratchTexture(layer->getTexture()); | 2331 fContext->unlockScratchTexture(layer->getTexture()); |
2124 layer->setTexture(NULL); | 2332 layer->setTexture(NULL); |
2125 } | 2333 } |
2126 } | 2334 } |
2127 | 2335 |
2128 return true; | 2336 return true; |
2129 } | 2337 } |
OLD | NEW |