SkStrokeRec.cpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. /*
  2. * Copyright 2012 Google Inc.
  3. *
  4. * Use of this source code is governed by a BSD-style license that can be
  5. * found in the LICENSE file.
  6. */
  7. #include "include/core/SkStrokeRec.h"
  8. #include "src/core/SkPaintDefaults.h"
  9. // must be < 0, since ==0 means hairline, and >0 means normal stroke
  10. #define kStrokeRec_FillStyleWidth (-SK_Scalar1)
  11. SkStrokeRec::SkStrokeRec(InitStyle s) {
  12. fResScale = 1;
  13. fWidth = (kFill_InitStyle == s) ? kStrokeRec_FillStyleWidth : 0;
  14. fMiterLimit = SkPaintDefaults_MiterLimit;
  15. fCap = SkPaint::kDefault_Cap;
  16. fJoin = SkPaint::kDefault_Join;
  17. fStrokeAndFill = false;
  18. }
  19. SkStrokeRec::SkStrokeRec(const SkPaint& paint, SkScalar resScale) {
  20. this->init(paint, paint.getStyle(), resScale);
  21. }
  22. SkStrokeRec::SkStrokeRec(const SkPaint& paint, SkPaint::Style styleOverride, SkScalar resScale) {
  23. this->init(paint, styleOverride, resScale);
  24. }
  25. void SkStrokeRec::init(const SkPaint& paint, SkPaint::Style style, SkScalar resScale) {
  26. fResScale = resScale;
  27. switch (style) {
  28. case SkPaint::kFill_Style:
  29. fWidth = kStrokeRec_FillStyleWidth;
  30. fStrokeAndFill = false;
  31. break;
  32. case SkPaint::kStroke_Style:
  33. fWidth = paint.getStrokeWidth();
  34. fStrokeAndFill = false;
  35. break;
  36. case SkPaint::kStrokeAndFill_Style:
  37. if (0 == paint.getStrokeWidth()) {
  38. // hairline+fill == fill
  39. fWidth = kStrokeRec_FillStyleWidth;
  40. fStrokeAndFill = false;
  41. } else {
  42. fWidth = paint.getStrokeWidth();
  43. fStrokeAndFill = true;
  44. }
  45. break;
  46. default:
  47. SkDEBUGFAIL("unknown paint style");
  48. // fall back on just fill
  49. fWidth = kStrokeRec_FillStyleWidth;
  50. fStrokeAndFill = false;
  51. break;
  52. }
  53. // copy these from the paint, regardless of our "style"
  54. fMiterLimit = paint.getStrokeMiter();
  55. fCap = paint.getStrokeCap();
  56. fJoin = paint.getStrokeJoin();
  57. }
  58. SkStrokeRec::Style SkStrokeRec::getStyle() const {
  59. if (fWidth < 0) {
  60. return kFill_Style;
  61. } else if (0 == fWidth) {
  62. return kHairline_Style;
  63. } else {
  64. return fStrokeAndFill ? kStrokeAndFill_Style : kStroke_Style;
  65. }
  66. }
  67. void SkStrokeRec::setFillStyle() {
  68. fWidth = kStrokeRec_FillStyleWidth;
  69. fStrokeAndFill = false;
  70. }
  71. void SkStrokeRec::setHairlineStyle() {
  72. fWidth = 0;
  73. fStrokeAndFill = false;
  74. }
  75. void SkStrokeRec::setStrokeStyle(SkScalar width, bool strokeAndFill) {
  76. if (strokeAndFill && (0 == width)) {
  77. // hairline+fill == fill
  78. this->setFillStyle();
  79. } else {
  80. fWidth = width;
  81. fStrokeAndFill = strokeAndFill;
  82. }
  83. }
  84. #include "src/core/SkStroke.h"
  85. #ifdef SK_DEBUG
  86. // enables tweaking these values at runtime from Viewer
  87. bool gDebugStrokerErrorSet = false;
  88. SkScalar gDebugStrokerError;
  89. #endif
  90. bool SkStrokeRec::applyToPath(SkPath* dst, const SkPath& src) const {
  91. if (fWidth <= 0) { // hairline or fill
  92. return false;
  93. }
  94. SkStroke stroker;
  95. stroker.setCap((SkPaint::Cap)fCap);
  96. stroker.setJoin((SkPaint::Join)fJoin);
  97. stroker.setMiterLimit(fMiterLimit);
  98. stroker.setWidth(fWidth);
  99. stroker.setDoFill(fStrokeAndFill);
  100. #ifdef SK_DEBUG
  101. stroker.setResScale(gDebugStrokerErrorSet ? gDebugStrokerError : fResScale);
  102. #else
  103. stroker.setResScale(fResScale);
  104. #endif
  105. stroker.strokePath(src, dst);
  106. return true;
  107. }
  108. void SkStrokeRec::applyToPaint(SkPaint* paint) const {
  109. if (fWidth < 0) { // fill
  110. paint->setStyle(SkPaint::kFill_Style);
  111. return;
  112. }
  113. paint->setStyle(fStrokeAndFill ? SkPaint::kStrokeAndFill_Style : SkPaint::kStroke_Style);
  114. paint->setStrokeWidth(fWidth);
  115. paint->setStrokeMiter(fMiterLimit);
  116. paint->setStrokeCap((SkPaint::Cap)fCap);
  117. paint->setStrokeJoin((SkPaint::Join)fJoin);
  118. }
  119. SkScalar SkStrokeRec::getInflationRadius() const {
  120. return GetInflationRadius((SkPaint::Join)fJoin, fMiterLimit, (SkPaint::Cap)fCap, fWidth);
  121. }
  122. SkScalar SkStrokeRec::GetInflationRadius(const SkPaint& paint, SkPaint::Style style) {
  123. SkScalar width = SkPaint::kFill_Style == style ? -SK_Scalar1 : paint.getStrokeWidth();
  124. return GetInflationRadius(paint.getStrokeJoin(), paint.getStrokeMiter(), paint.getStrokeCap(),
  125. width);
  126. }
  127. SkScalar SkStrokeRec::GetInflationRadius(SkPaint::Join join, SkScalar miterLimit, SkPaint::Cap cap,
  128. SkScalar strokeWidth) {
  129. if (strokeWidth < 0) { // fill
  130. return 0;
  131. } else if (0 == strokeWidth) {
  132. // FIXME: We need a "matrixScale" parameter here in order to properly handle hairlines.
  133. // Their with is determined in device space, unlike other strokes.
  134. // http://skbug.com/8157
  135. return SK_Scalar1;
  136. }
  137. // since we're stroked, outset the rect by the radius (and join type, caps)
  138. SkScalar multiplier = SK_Scalar1;
  139. if (SkPaint::kMiter_Join == join) {
  140. multiplier = SkTMax(multiplier, miterLimit);
  141. }
  142. if (SkPaint::kSquare_Cap == cap) {
  143. multiplier = SkTMax(multiplier, SK_ScalarSqrt2);
  144. }
  145. return strokeWidth/2 * multiplier;
  146. }