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