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