OLD | NEW |
---|---|
1 // Copyright 2014 PDFium Authors. All rights reserved. | 1 // Copyright 2014 PDFium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "core/include/fxge/fx_ge.h" | 5 #include "core/include/fxge/fx_ge.h" |
6 | 6 |
7 #if defined(_SKIA_SUPPORT_) | 7 #if defined(_SKIA_SUPPORT_) |
8 #include "core/include/fxcodec/fx_codec.h" | 8 #include "core/include/fxcodec/fx_codec.h" |
9 | 9 |
10 #include "core/fpdfapi/fpdf_page/cpdf_shadingpattern.h" | 10 #include "core/fpdfapi/fpdf_page/cpdf_shadingpattern.h" |
11 #include "core/fpdfapi/fpdf_page/pageint.h" | 11 #include "core/fpdfapi/fpdf_page/pageint.h" |
12 #include "core/fpdfapi/fpdf_parser/include/cpdf_array.h" | 12 #include "core/fpdfapi/fpdf_parser/include/cpdf_array.h" |
13 #include "core/fpdfapi/fpdf_parser/include/cpdf_dictionary.h" | 13 #include "core/fpdfapi/fpdf_parser/include/cpdf_dictionary.h" |
14 #include "core/fpdfapi/fpdf_parser/include/cpdf_stream_acc.h" | |
14 #include "core/fxge/skia/fx_skia_device.h" | 15 #include "core/fxge/skia/fx_skia_device.h" |
15 | 16 |
16 #include "third_party/skia/include/core/SkCanvas.h" | 17 #include "third_party/skia/include/core/SkCanvas.h" |
17 #include "third_party/skia/include/core/SkColorPriv.h" | 18 #include "third_party/skia/include/core/SkColorPriv.h" |
18 #include "third_party/skia/include/core/SkPaint.h" | 19 #include "third_party/skia/include/core/SkPaint.h" |
19 #include "third_party/skia/include/core/SkPath.h" | 20 #include "third_party/skia/include/core/SkPath.h" |
20 #include "third_party/skia/include/core/SkPictureRecorder.h" | 21 #include "third_party/skia/include/core/SkPictureRecorder.h" |
21 #include "third_party/skia/include/core/SkStream.h" | 22 #include "third_party/skia/include/core/SkStream.h" |
22 #include "third_party/skia/include/core/SkTypeface.h" | 23 #include "third_party/skia/include/core/SkTypeface.h" |
23 #include "third_party/skia/include/effects/SkDashPathEffect.h" | 24 #include "third_party/skia/include/effects/SkDashPathEffect.h" |
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
170 0xFF, SkUnitScalarClampToByte(expIntFunc->m_pBeginValues[0]), | 171 0xFF, SkUnitScalarClampToByte(expIntFunc->m_pBeginValues[0]), |
171 SkUnitScalarClampToByte(expIntFunc->m_pBeginValues[1]), | 172 SkUnitScalarClampToByte(expIntFunc->m_pBeginValues[1]), |
172 SkUnitScalarClampToByte(expIntFunc->m_pBeginValues[2]))); | 173 SkUnitScalarClampToByte(expIntFunc->m_pBeginValues[2]))); |
173 skColors->push( | 174 skColors->push( |
174 SkColorSetARGB(0xFF, SkUnitScalarClampToByte(expIntFunc->m_pEndValues[0]), | 175 SkColorSetARGB(0xFF, SkUnitScalarClampToByte(expIntFunc->m_pEndValues[0]), |
175 SkUnitScalarClampToByte(expIntFunc->m_pEndValues[1]), | 176 SkUnitScalarClampToByte(expIntFunc->m_pEndValues[1]), |
176 SkUnitScalarClampToByte(expIntFunc->m_pEndValues[2]))); | 177 SkUnitScalarClampToByte(expIntFunc->m_pEndValues[2]))); |
177 return true; | 178 return true; |
178 } | 179 } |
179 | 180 |
181 uint32_t GetBits32(const uint8_t* pData, int bitpos, int nbits) { | |
182 ASSERT(0 < nbits && nbits <= 32); | |
183 const uint8_t* dataPtr = &pData[bitpos / 8]; | |
184 int bitShift, bitMask, dstShift; | |
dsinclair
2016/04/11 14:29:28
nit: one per line.
caryclark
2016/04/11 15:01:50
Done.
| |
185 if (nbits < 8) { | |
186 bitShift = 8 - nbits - (bitpos & 0x07); | |
187 bitMask = (1 << nbits) - 1; | |
188 dstShift = 0; | |
189 } else { | |
190 bitShift = 0; | |
191 bitMask = 0xFF; | |
192 dstShift = nbits - 8 + (bitpos & 0x07); | |
193 } | |
194 uint32_t result = (*dataPtr++ >> bitShift & bitMask) << dstShift; | |
195 while (dstShift >= 8) { | |
196 dstShift -= 8; | |
197 result |= *dataPtr++ << dstShift; | |
198 } | |
199 if (dstShift > 0) { | |
200 bitShift = 8 - dstShift; | |
201 bitMask = (1 << dstShift) - 1; | |
202 result |= *dataPtr++ >> bitShift & bitMask; | |
203 } | |
204 return result; | |
205 } | |
206 | |
207 uint8_t FloatToByte(FX_FLOAT f) { | |
208 ASSERT(0 <= f && f <= 1); | |
209 return (uint8_t)(f * 255.99f); | |
210 } | |
211 | |
212 bool AddSamples(const CPDF_Function* pFunc, | |
213 SkTDArray<SkColor>* skColors, | |
214 SkTDArray<SkScalar>* skPos) { | |
215 if (pFunc->CountInputs() != 1) | |
216 return false; | |
217 if (pFunc->CountOutputs() != 3) // expect rgb | |
218 return false; | |
219 ASSERT(CPDF_Function::Type::kType0Sampled == pFunc->GetType()); | |
220 const CPDF_SampledFunc* sampledFunc = | |
221 static_cast<const CPDF_SampledFunc*>(pFunc); | |
222 if (!sampledFunc->m_pEncodeInfo) | |
223 return false; | |
224 const CPDF_SampledFunc::SampleEncodeInfo& encodeInfo = | |
225 sampledFunc->m_pEncodeInfo[0]; | |
226 if (encodeInfo.encode_min != 0) | |
227 return false; | |
228 if (encodeInfo.encode_max != encodeInfo.sizes - 1) | |
229 return false; | |
230 int sampleSize = sampledFunc->m_nBitsPerSample; | |
231 int sampleCount = encodeInfo.sizes; | |
232 if (sampleCount != 1 << sampleSize) | |
233 return false; | |
234 FX_FLOAT colorsMin[3]; | |
235 FX_FLOAT colorsMax[3]; | |
236 for (int i = 0; i < 3; ++i) { | |
237 colorsMin[i] = sampledFunc->GetRange(i * 2); | |
238 colorsMax[i] = sampledFunc->GetRange(i * 2 + 1); | |
239 } | |
240 const uint8_t* pSampleData = sampledFunc->m_pSampleStream->GetData(); | |
241 for (int i = 0; i < sampleCount; ++i) { | |
242 FX_FLOAT floatColors[3]; | |
243 for (int j = 0; j < 3; ++j) { | |
244 int sample = GetBits32(pSampleData, (i * 3 + j) * sampleSize, sampleSize); | |
245 FX_FLOAT interp = (FX_FLOAT)sample / (sampleCount - 1); | |
246 floatColors[j] = colorsMin[j] + (colorsMax[j] - colorsMin[j]) * interp; | |
247 } | |
248 SkColor color = | |
249 SkPackARGB32(0xFF, FloatToByte(floatColors[0]), | |
250 FloatToByte(floatColors[1]), FloatToByte(floatColors[2])); | |
251 skColors->push(color); | |
252 skPos->push((FX_FLOAT)i / (sampleCount - 1)); | |
253 } | |
254 return true; | |
255 } | |
256 | |
180 bool AddStitching(const CPDF_Function* pFunc, | 257 bool AddStitching(const CPDF_Function* pFunc, |
181 SkTDArray<SkColor>* skColors, | 258 SkTDArray<SkColor>* skColors, |
182 SkTDArray<SkScalar>* skPos) { | 259 SkTDArray<SkScalar>* skPos) { |
183 int inputs = pFunc->CountInputs(); | 260 int inputs = pFunc->CountInputs(); |
184 ASSERT(CPDF_Function::Type::kType3Stitching == pFunc->GetType()); | 261 ASSERT(CPDF_Function::Type::kType3Stitching == pFunc->GetType()); |
185 const CPDF_StitchFunc* stitchFunc = | 262 const CPDF_StitchFunc* stitchFunc = |
186 static_cast<const CPDF_StitchFunc*>(pFunc); | 263 static_cast<const CPDF_StitchFunc*>(pFunc); |
187 FX_FLOAT boundsStart = stitchFunc->GetDomain(0); | 264 FX_FLOAT boundsStart = stitchFunc->GetDomain(0); |
188 | 265 |
189 for (int i = 0; i < inputs; ++i) { | 266 for (int i = 0; i < inputs; ++i) { |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
297 src_scan += 4; | 374 src_scan += 4; |
298 dest_scan += 4; | 375 dest_scan += 4; |
299 } | 376 } |
300 } | 377 } |
301 } | 378 } |
302 } else { | 379 } else { |
303 ASSERT(FALSE); | 380 ASSERT(FALSE); |
304 } | 381 } |
305 } | 382 } |
306 | 383 |
384 // see en.wikipedia.org/wiki/Distance_from_a_point_to_a_line | |
385 SkScalar LineSide(const SkPoint l[2], const SkPoint& pt) { | |
386 return (l[1].fY - l[0].fY) * pt.fX - (l[1].fX - l[0].fX) * pt.fY + | |
387 l[1].fX * l[0].fY - l[1].fY * l[0].fX; | |
388 } | |
389 | |
390 SkPoint IntersectSides(const SkPoint& parallelPt, | |
391 const SkVector& paraRay, | |
392 const SkPoint& perpendicularPt) { | |
393 SkVector perpRay = {paraRay.fY, -paraRay.fX}; | |
394 double denom = perpRay.fY * paraRay.fX - paraRay.fY * perpRay.fX; | |
395 SkVector ab0 = parallelPt - perpendicularPt; | |
396 double numerA = ab0.fY * perpRay.fX - perpRay.fY * ab0.fX; | |
397 numerA /= denom; | |
398 SkPoint result = {parallelPt.fX + paraRay.fX * numerA, | |
399 parallelPt.fY + paraRay.fY * numerA}; | |
400 return result; | |
401 } | |
402 | |
403 void ClipAngledGradient(const SkPoint pts[2], | |
404 SkPoint rectPts[4], | |
405 bool clipStart, | |
406 bool clipEnd, | |
407 SkPath* clip) { | |
408 // find the corners furthest from the gradient perpendiculars | |
409 SkScalar minPerpDist = SK_ScalarMax; | |
410 SkScalar maxPerpDist = SK_ScalarMin; | |
411 int minPerpPtIndex = -1; | |
412 int maxPerpPtIndex = -1; | |
413 SkVector slope = pts[1] - pts[0]; | |
414 SkPoint startPerp[2] = {pts[0], {pts[0].fX + slope.fY, pts[0].fY - slope.fX}}; | |
415 SkPoint endPerp[2] = {pts[1], {pts[1].fX + slope.fY, pts[1].fY - slope.fX}}; | |
416 for (int i = 0; i < 4; ++i) { | |
417 SkScalar sDist = LineSide(startPerp, rectPts[i]); | |
418 SkScalar eDist = LineSide(endPerp, rectPts[i]); | |
419 if (sDist * eDist <= 0) // if the signs are different, | |
420 continue; // the point is inside the gradient | |
421 if (sDist < 0) { | |
422 SkScalar smaller = SkTMin(sDist, eDist); | |
423 if (minPerpDist > smaller) { | |
424 minPerpDist = smaller; | |
425 minPerpPtIndex = i; | |
426 } | |
427 } else { | |
428 SkScalar larger = SkTMax(sDist, eDist); | |
429 if (maxPerpDist < larger) { | |
430 maxPerpDist = larger; | |
431 maxPerpPtIndex = i; | |
432 } | |
433 } | |
434 } | |
435 if (minPerpPtIndex < 0 && maxPerpPtIndex < 0) // nothing's outside | |
436 return; | |
437 // determine if negative distances are before start or after end | |
438 SkPoint beforeStart = {pts[0].fX * 2 - pts[1].fX, pts[0].fY * 2 - pts[1].fY}; | |
439 bool beforeNeg = LineSide(startPerp, beforeStart) < 0; | |
440 const SkPoint& startEdgePt = | |
441 clipStart ? pts[0] : beforeNeg ? rectPts[minPerpPtIndex] | |
442 : rectPts[maxPerpPtIndex]; | |
443 const SkPoint& endEdgePt = clipEnd ? pts[1] : beforeNeg | |
444 ? rectPts[maxPerpPtIndex] | |
445 : rectPts[minPerpPtIndex]; | |
446 // find the corners that bound the gradient | |
447 SkScalar minDist = SK_ScalarMax; | |
448 SkScalar maxDist = SK_ScalarMin; | |
449 int minBounds = -1; | |
450 int maxBounds = -1; | |
451 for (int i = 0; i < 4; ++i) { | |
452 SkScalar dist = LineSide(pts, rectPts[i]); | |
453 if (minDist > dist) { | |
454 minDist = dist; | |
455 minBounds = i; | |
456 } | |
457 if (maxDist < dist) { | |
458 maxDist = dist; | |
459 maxBounds = i; | |
460 } | |
461 } | |
462 ASSERT(minBounds >= 0); | |
463 ASSERT(maxBounds != minBounds && maxBounds >= 0); | |
464 // construct a clip parallel to the gradient that goes through | |
465 // rectPts[minBounds] and rectPts[maxBounds] and perpendicular to the | |
466 // gradient that goes through startEdgePt, endEdgePt. | |
467 clip->moveTo(IntersectSides(rectPts[minBounds], slope, startEdgePt)); | |
468 clip->lineTo(IntersectSides(rectPts[minBounds], slope, endEdgePt)); | |
469 clip->lineTo(IntersectSides(rectPts[maxBounds], slope, endEdgePt)); | |
470 clip->lineTo(IntersectSides(rectPts[maxBounds], slope, startEdgePt)); | |
471 } | |
472 | |
307 } // namespace | 473 } // namespace |
308 | 474 |
309 // convert a stroking path to scanlines | 475 // convert a stroking path to scanlines |
310 void CFX_SkiaDeviceDriver::PaintStroke(SkPaint* spaint, | 476 void CFX_SkiaDeviceDriver::PaintStroke(SkPaint* spaint, |
311 const CFX_GraphStateData* pGraphState, | 477 const CFX_GraphStateData* pGraphState, |
312 const SkMatrix& matrix) { | 478 const SkMatrix& matrix) { |
313 SkPaint::Cap cap; | 479 SkPaint::Cap cap; |
314 switch (pGraphState->m_LineCap) { | 480 switch (pGraphState->m_LineCap) { |
315 case CFX_GraphStateData::LineCapRound: | 481 case CFX_GraphStateData::LineCapRound: |
316 cap = SkPaint::kRound_Cap; | 482 cap = SkPaint::kRound_Cap; |
(...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
597 spaint.setAntiAlias(true); | 763 spaint.setAntiAlias(true); |
598 spaint.setColor(fill_color); | 764 spaint.setColor(fill_color); |
599 spaint.setXfermodeMode(GetSkiaBlendMode(blend_type)); | 765 spaint.setXfermodeMode(GetSkiaBlendMode(blend_type)); |
600 | 766 |
601 m_pCanvas->drawRect( | 767 m_pCanvas->drawRect( |
602 SkRect::MakeLTRB(pRect->left, pRect->top, pRect->right, pRect->bottom), | 768 SkRect::MakeLTRB(pRect->left, pRect->top, pRect->right, pRect->bottom), |
603 spaint); | 769 spaint); |
604 return TRUE; | 770 return TRUE; |
605 } | 771 } |
606 | 772 |
607 FX_BOOL CFX_SkiaDeviceDriver::DrawShading(CPDF_ShadingPattern* pPattern, | 773 FX_BOOL CFX_SkiaDeviceDriver::DrawShading(const CPDF_ShadingPattern* pPattern, |
608 CFX_Matrix* pMatrix, | 774 const CFX_Matrix* pMatrix, |
775 const FX_RECT& clip_rect, | |
609 int alpha, | 776 int alpha, |
610 FX_BOOL bAlphaMode) { | 777 FX_BOOL bAlphaMode) { |
611 CPDF_Function** pFuncs = pPattern->m_pFunctions; | 778 if (kAxialShading != pPattern->m_ShadingType && |
779 kRadialShading != | |
780 pPattern->m_ShadingType) { // TODO(caryclark) more types | |
781 return false; | |
782 } | |
783 CPDF_Function* const* pFuncs = pPattern->m_pFunctions; | |
612 int nFuncs = pPattern->m_nFuncs; | 784 int nFuncs = pPattern->m_nFuncs; |
613 if (nFuncs != 1) // TODO(caryclark) remove this restriction | 785 if (nFuncs != 1) // TODO(caryclark) remove this restriction |
614 return false; | 786 return false; |
615 CPDF_Dictionary* pDict = pPattern->m_pShadingObj->GetDict(); | 787 CPDF_Dictionary* pDict = pPattern->m_pShadingObj->GetDict(); |
616 CPDF_Array* pCoords = pDict->GetArrayBy("Coords"); | 788 CPDF_Array* pCoords = pDict->GetArrayBy("Coords"); |
617 if (!pCoords) | 789 if (!pCoords) |
618 return true; | 790 return true; |
619 FX_FLOAT start_x = pCoords->GetNumberAt(0); | 791 // TODO(caryclark) Respect Domain[0], Domain[1]. (Don't know what they do |
620 FX_FLOAT start_y = pCoords->GetNumberAt(1); | 792 // yet.) |
621 FX_FLOAT end_x = pCoords->GetNumberAt(2); | |
622 FX_FLOAT end_y = pCoords->GetNumberAt(3); | |
623 FX_FLOAT t_min = 0; | |
624 FX_FLOAT t_max = 1; | |
625 CPDF_Array* pArray = pDict->GetArrayBy("Domain"); | |
626 if (pArray) { | |
627 t_min = pArray->GetNumberAt(0); | |
628 t_max = pArray->GetNumberAt(1); | |
629 } | |
630 FX_BOOL bStartExtend = FALSE, bEndExtend = FALSE; | |
631 pArray = pDict->GetArrayBy("Extend"); | |
632 if (pArray) { | |
633 bStartExtend = pArray->GetIntegerAt(0); | |
634 bEndExtend = pArray->GetIntegerAt(1); | |
635 } | |
636 SkTDArray<SkColor> skColors; | 793 SkTDArray<SkColor> skColors; |
637 SkTDArray<SkScalar> skPos; | 794 SkTDArray<SkScalar> skPos; |
638 for (int j = 0; j < nFuncs; j++) { | 795 for (int j = 0; j < nFuncs; j++) { |
639 const CPDF_Function* pFunc = pFuncs[j]; | 796 const CPDF_Function* pFunc = pFuncs[j]; |
640 if (!pFunc) | 797 if (!pFunc) |
641 continue; | 798 continue; |
642 switch (pFunc->GetType()) { | 799 switch (pFunc->GetType()) { |
800 case CPDF_Function::Type::kType0Sampled: | |
801 /* TODO(caryclark) | |
802 Type 0 Sampled Functions in PostScript can also have an Order integer | |
803 in the dictionary. PDFium doesn't appear to check for this anywhere. | |
804 */ | |
805 if (!AddSamples(pFunc, &skColors, &skPos)) | |
806 return false; | |
807 break; | |
643 case CPDF_Function::Type::kType2ExpotentialInterpolation: | 808 case CPDF_Function::Type::kType2ExpotentialInterpolation: |
644 if (!AddColors(pFunc, &skColors)) | 809 if (!AddColors(pFunc, &skColors)) |
645 return false; | 810 return false; |
646 skPos.push(0); | 811 skPos.push(0); |
647 skPos.push(1); | 812 skPos.push(1); |
648 break; | 813 break; |
649 case CPDF_Function::Type::kType3Stitching: | 814 case CPDF_Function::Type::kType3Stitching: |
650 if (!AddStitching(pFunc, &skColors, &skPos)) | 815 if (!AddStitching(pFunc, &skColors, &skPos)) |
651 return false; | 816 return false; |
652 break; | 817 break; |
653 default: | 818 default: |
654 return false; | 819 return false; |
655 } | 820 } |
656 } | 821 } |
657 SkMatrix skMatrix = ToSkMatrix(*pMatrix); | 822 CPDF_Array* pArray = pDict->GetArrayBy("Extend"); |
658 SkPoint pts[] = {{start_x, start_y}, {end_x, end_y}}; | 823 bool clipStart = !pArray || !pArray->GetIntegerAt(0); |
824 bool clipEnd = !pArray || !pArray->GetIntegerAt(1); | |
659 SkPaint paint; | 825 SkPaint paint; |
660 paint.setAntiAlias(true); | 826 paint.setAntiAlias(true); |
661 paint.setShader(SkGradientShader::MakeLinear(pts, skColors.begin(), | |
662 skPos.begin(), skColors.count(), | |
663 SkShader::kClamp_TileMode)); | |
664 paint.setAlpha(alpha); | 827 paint.setAlpha(alpha); |
828 SkMatrix skMatrix = ToSkMatrix(*pMatrix); | |
829 SkRect skRect = SkRect::MakeLTRB(clip_rect.left, clip_rect.top, | |
830 clip_rect.right, clip_rect.bottom); | |
831 SkPath skClip; | |
832 SkPath skPath; | |
833 if (kAxialShading == pPattern->m_ShadingType) { | |
834 FX_FLOAT start_x = pCoords->GetNumberAt(0); | |
835 FX_FLOAT start_y = pCoords->GetNumberAt(1); | |
836 FX_FLOAT end_x = pCoords->GetNumberAt(2); | |
837 FX_FLOAT end_y = pCoords->GetNumberAt(3); | |
838 SkPoint pts[] = {{start_x, start_y}, {end_x, end_y}}; | |
839 skMatrix.mapPoints(pts, SK_ARRAY_COUNT(pts)); | |
840 paint.setShader(SkGradientShader::MakeLinear( | |
841 pts, skColors.begin(), skPos.begin(), skColors.count(), | |
842 SkShader::kClamp_TileMode)); | |
843 if (clipStart || clipEnd) { | |
844 // if the gradient is horizontal or vertical, modify the draw rectangle | |
845 if (pts[0].fX == pts[1].fX) { // vertical | |
846 if (pts[0].fY > pts[1].fY) { | |
847 SkTSwap(pts[0].fY, pts[1].fY); | |
848 SkTSwap(clipStart, clipEnd); | |
849 } | |
850 if (clipStart) | |
851 skRect.fTop = SkTMax(skRect.fTop, pts[0].fY); | |
852 if (clipEnd) | |
853 skRect.fBottom = SkTMin(skRect.fBottom, pts[1].fY); | |
854 } else if (pts[0].fY == pts[1].fY) { // horizontal | |
855 if (pts[0].fX > pts[1].fX) { | |
856 SkTSwap(pts[0].fX, pts[1].fX); | |
857 SkTSwap(clipStart, clipEnd); | |
858 } | |
859 if (clipStart) | |
860 skRect.fLeft = SkTMax(skRect.fLeft, pts[0].fX); | |
861 if (clipEnd) | |
862 skRect.fRight = SkTMin(skRect.fRight, pts[1].fX); | |
863 } else { // if the gradient is angled and contained by the rect, clip | |
864 SkPoint rectPts[4] = {{skRect.fLeft, skRect.fTop}, | |
865 {skRect.fRight, skRect.fTop}, | |
866 {skRect.fRight, skRect.fBottom}, | |
867 {skRect.fLeft, skRect.fBottom}}; | |
868 ClipAngledGradient(pts, rectPts, clipStart, clipEnd, &skClip); | |
869 } | |
870 } | |
871 skPath.addRect(skRect); | |
872 skMatrix.setIdentity(); | |
873 } else { | |
874 ASSERT(kRadialShading == pPattern->m_ShadingType); | |
875 FX_FLOAT start_x = pCoords->GetNumberAt(0); | |
876 FX_FLOAT start_y = pCoords->GetNumberAt(1); | |
877 FX_FLOAT start_r = pCoords->GetNumberAt(2); | |
878 FX_FLOAT end_x = pCoords->GetNumberAt(3); | |
879 FX_FLOAT end_y = pCoords->GetNumberAt(4); | |
880 FX_FLOAT end_r = pCoords->GetNumberAt(5); | |
881 SkPoint pts[] = {{start_x, start_y}, {end_x, end_y}}; | |
882 | |
883 // skMatrix.mapPoints(pts, SK_ARRAY_COUNT(pts)); | |
dsinclair
2016/04/11 14:29:28
nit: remove
caryclark
2016/04/11 15:01:50
Done.
| |
884 paint.setShader(SkGradientShader::MakeTwoPointConical( | |
885 pts[0], start_r, pts[1], end_r, skColors.begin(), skPos.begin(), | |
886 skColors.count(), SkShader::kClamp_TileMode)); | |
887 if (clipStart || clipEnd) { | |
888 if (clipStart && start_r) | |
889 skClip.addCircle(pts[0].fX, pts[0].fY, start_r); | |
890 if (clipEnd) | |
891 skClip.addCircle(pts[1].fX, pts[1].fY, end_r, SkPath::kCCW_Direction); | |
892 else | |
893 skClip.setFillType(SkPath::kInverseWinding_FillType); | |
894 skClip.transform(skMatrix); | |
895 } | |
896 SkMatrix inverse; | |
897 skMatrix.invert(&inverse); | |
898 skPath.addRect(skRect); | |
899 skPath.transform(inverse); | |
900 } | |
665 m_pCanvas->save(); | 901 m_pCanvas->save(); |
902 if (!skClip.isEmpty()) | |
903 m_pCanvas->clipPath(skClip); | |
666 m_pCanvas->concat(skMatrix); | 904 m_pCanvas->concat(skMatrix); |
667 m_pCanvas->drawRect(SkRect::MakeWH(1, 1), paint); | 905 m_pCanvas->drawPath(skPath, paint); |
668 m_pCanvas->restore(); | 906 m_pCanvas->restore(); |
669 return true; | 907 return true; |
670 } | 908 } |
671 | 909 |
672 FX_BOOL CFX_SkiaDeviceDriver::GetClipBox(FX_RECT* pRect) { | 910 FX_BOOL CFX_SkiaDeviceDriver::GetClipBox(FX_RECT* pRect) { |
673 // TODO(caryclark) call m_canvas->getClipDeviceBounds() instead | 911 // TODO(caryclark) call m_canvas->getClipDeviceBounds() instead |
674 pRect->left = 0; | 912 pRect->left = 0; |
675 pRect->top = 0; | 913 pRect->top = 0; |
676 const SkImageInfo& canvasSize = m_pCanvas->imageInfo(); | 914 const SkImageInfo& canvasSize = m_pCanvas->imageInfo(); |
677 pRect->right = canvasSize.width(); | 915 pRect->right = canvasSize.width(); |
(...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
928 SetDeviceDriver(pDriver); | 1166 SetDeviceDriver(pDriver); |
929 return TRUE; | 1167 return TRUE; |
930 } | 1168 } |
931 | 1169 |
932 CFX_SkiaDevice::~CFX_SkiaDevice() { | 1170 CFX_SkiaDevice::~CFX_SkiaDevice() { |
933 if (m_bOwnedBitmap && GetBitmap()) | 1171 if (m_bOwnedBitmap && GetBitmap()) |
934 delete GetBitmap(); | 1172 delete GetBitmap(); |
935 } | 1173 } |
936 | 1174 |
937 #endif | 1175 #endif |
OLD | NEW |