| 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 "SkPDFDevice.h" | 8 #include "SkPDFDevice.h" |
| 9 #include "SkAnnotationKeys.h" | 9 #include "SkAnnotationKeys.h" |
| 10 #include "SkBitmapDevice.h" | 10 #include "SkBitmapDevice.h" |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 141 fStackDepth++; | 141 fStackDepth++; |
| 142 fEntries[fStackDepth] = fEntries[fStackDepth - 1]; | 142 fEntries[fStackDepth] = fEntries[fStackDepth - 1]; |
| 143 } | 143 } |
| 144 | 144 |
| 145 void GraphicStackState::pop() { | 145 void GraphicStackState::pop() { |
| 146 SkASSERT(fStackDepth > 0); | 146 SkASSERT(fStackDepth > 0); |
| 147 fContentStream->writeText("Q\n"); | 147 fContentStream->writeText("Q\n"); |
| 148 fStackDepth--; | 148 fStackDepth--; |
| 149 } | 149 } |
| 150 | 150 |
| 151 // This function initializes iter to be an iterator on the "stack" argument | |
| 152 // and then skips over the leading entries as specified in prefix. It requires | |
| 153 // and asserts that "prefix" will be a prefix to "stack." | |
| 154 static void skip_clip_stack_prefix(const SkClipStack& prefix, | |
| 155 const SkClipStack& stack, | |
| 156 SkClipStack::Iter* iter) { | |
| 157 SkClipStack::B2TIter prefixIter(prefix); | |
| 158 iter->reset(stack, SkClipStack::Iter::kBottom_IterStart); | |
| 159 | |
| 160 const SkClipStack::Element* prefixEntry; | |
| 161 const SkClipStack::Element* iterEntry; | |
| 162 | |
| 163 for (prefixEntry = prefixIter.next(); prefixEntry; | |
| 164 prefixEntry = prefixIter.next()) { | |
| 165 iterEntry = iter->next(); | |
| 166 SkASSERT(iterEntry); | |
| 167 // Because of SkClipStack does internal intersection, the last clip | |
| 168 // entry may differ. | |
| 169 if (*prefixEntry != *iterEntry) { | |
| 170 SkASSERT(prefixEntry->getOp() == SkRegion::kIntersect_Op); | |
| 171 SkASSERT(iterEntry->getOp() == SkRegion::kIntersect_Op); | |
| 172 SkASSERT(iterEntry->getType() == prefixEntry->getType()); | |
| 173 // back up the iterator by one | |
| 174 iter->prev(); | |
| 175 prefixEntry = prefixIter.next(); | |
| 176 break; | |
| 177 } | |
| 178 } | |
| 179 | |
| 180 SkASSERT(prefixEntry == nullptr); | |
| 181 } | |
| 182 | |
| 183 static void emit_clip(SkPath* clipPath, SkRect* clipRect, | |
| 184 SkWStream* contentStream) { | |
| 185 SkASSERT(clipPath || clipRect); | |
| 186 | |
| 187 SkPath::FillType clipFill; | |
| 188 if (clipPath) { | |
| 189 SkPDFUtils::EmitPath(*clipPath, SkPaint::kFill_Style, contentStream); | |
| 190 clipFill = clipPath->getFillType(); | |
| 191 } else { | |
| 192 SkPDFUtils::AppendRectangle(*clipRect, contentStream); | |
| 193 clipFill = SkPath::kWinding_FillType; | |
| 194 } | |
| 195 | |
| 196 NOT_IMPLEMENTED(clipFill == SkPath::kInverseEvenOdd_FillType, false); | |
| 197 NOT_IMPLEMENTED(clipFill == SkPath::kInverseWinding_FillType, false); | |
| 198 if (clipFill == SkPath::kEvenOdd_FillType) { | |
| 199 contentStream->writeText("W* n\n"); | |
| 200 } else { | |
| 201 contentStream->writeText("W n\n"); | |
| 202 } | |
| 203 } | |
| 204 | |
| 205 /* Calculate an inverted path's equivalent non-inverted path, given the | 151 /* Calculate an inverted path's equivalent non-inverted path, given the |
| 206 * canvas bounds. | 152 * canvas bounds. |
| 207 * outPath may alias with invPath (since this is supported by PathOps). | 153 * outPath may alias with invPath (since this is supported by PathOps). |
| 208 */ | 154 */ |
| 209 static bool calculate_inverse_path(const SkRect& bounds, const SkPath& invPath, | 155 static bool calculate_inverse_path(const SkRect& bounds, const SkPath& invPath, |
| 210 SkPath* outPath) { | 156 SkPath* outPath) { |
| 211 SkASSERT(invPath.isInverseFillType()); | 157 SkASSERT(invPath.isInverseFillType()); |
| 212 | 158 |
| 213 SkPath clipPath; | 159 SkPath clipPath; |
| 214 clipPath.addRect(bounds); | 160 clipPath.addRect(bounds); |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 302 push(); | 248 push(); |
| 303 | 249 |
| 304 currentEntry()->fClipStack = clipStack; | 250 currentEntry()->fClipStack = clipStack; |
| 305 currentEntry()->fClipRegion = clipRegion; | 251 currentEntry()->fClipRegion = clipRegion; |
| 306 | 252 |
| 307 SkMatrix transform; | 253 SkMatrix transform; |
| 308 transform.setTranslate(translation.fX, translation.fY); | 254 transform.setTranslate(translation.fX, translation.fY); |
| 309 | 255 |
| 310 SkPath clipPath; | 256 SkPath clipPath; |
| 311 if (get_clip_stack_path(transform, clipStack, clipRegion, &clipPath)) { | 257 if (get_clip_stack_path(transform, clipStack, clipRegion, &clipPath)) { |
| 312 emit_clip(&clipPath, nullptr, fContentStream); | 258 SkPDFUtils::EmitPath(clipPath, SkPaint::kFill_Style, fContentStream); |
| 313 return; | 259 SkPath::FillType clipFill = clipPath.getFillType(); |
| 314 } | 260 NOT_IMPLEMENTED(clipFill == SkPath::kInverseEvenOdd_FillType, false); |
| 315 | 261 NOT_IMPLEMENTED(clipFill == SkPath::kInverseWinding_FillType, false); |
| 316 // gsState->initialEntry()->fClipStack/Region specifies the clip that has | 262 if (clipFill == SkPath::kEvenOdd_FillType) { |
| 317 // already been applied. (If this is a top level device, then it specifies | 263 fContentStream->writeText("W* n\n"); |
| 318 // a clip to the content area. If this is a layer, then it specifies | 264 } else { |
| 319 // the clip in effect when the layer was created.) There's no need to | 265 fContentStream->writeText("W n\n"); |
| 320 // reapply that clip; SKCanvas's SkDrawIter will draw anything outside the | |
| 321 // initial clip on the parent layer. (This means there's a bug if the user | |
| 322 // expands the clip and then uses any xfer mode that uses dst: | |
| 323 // http://code.google.com/p/skia/issues/detail?id=228 ) | |
| 324 SkClipStack::Iter iter; | |
| 325 skip_clip_stack_prefix(fEntries[0].fClipStack, clipStack, &iter); | |
| 326 | |
| 327 // If the clip stack does anything other than intersect or if it uses | |
| 328 // an inverse fill type, we have to fall back to the clip region. | |
| 329 bool needRegion = false; | |
| 330 const SkClipStack::Element* clipEntry; | |
| 331 for (clipEntry = iter.next(); clipEntry; clipEntry = iter.next()) { | |
| 332 if (clipEntry->getOp() != SkRegion::kIntersect_Op || | |
| 333 clipEntry->isInverseFilled()) { | |
| 334 needRegion = true; | |
| 335 break; | |
| 336 } | 266 } |
| 337 } | 267 } |
| 338 | 268 // If Op() fails (pathological case; e.g. input values are |
| 339 if (needRegion) { | 269 // extremely large or NaN), emit no clip at all. |
| 340 SkPath clipPath; | |
| 341 SkAssertResult(clipRegion.getBoundaryPath(&clipPath)); | |
| 342 emit_clip(&clipPath, nullptr, fContentStream); | |
| 343 } else { | |
| 344 skip_clip_stack_prefix(fEntries[0].fClipStack, clipStack, &iter); | |
| 345 const SkClipStack::Element* clipEntry; | |
| 346 for (clipEntry = iter.next(); clipEntry; clipEntry = iter.next()) { | |
| 347 SkASSERT(clipEntry->getOp() == SkRegion::kIntersect_Op); | |
| 348 switch (clipEntry->getType()) { | |
| 349 case SkClipStack::Element::kRect_Type: { | |
| 350 SkRect translatedClip; | |
| 351 transform.mapRect(&translatedClip, clipEntry->getRect()); | |
| 352 emit_clip(nullptr, &translatedClip, fContentStream); | |
| 353 break; | |
| 354 } | |
| 355 default: { | |
| 356 SkPath translatedPath; | |
| 357 clipEntry->asPath(&translatedPath); | |
| 358 translatedPath.transform(transform, &translatedPath); | |
| 359 emit_clip(&translatedPath, nullptr, fContentStream); | |
| 360 break; | |
| 361 } | |
| 362 } | |
| 363 } | |
| 364 } | |
| 365 } | 270 } |
| 366 | 271 |
| 367 void GraphicStackState::updateMatrix(const SkMatrix& matrix) { | 272 void GraphicStackState::updateMatrix(const SkMatrix& matrix) { |
| 368 if (matrix == currentEntry()->fMatrix) { | 273 if (matrix == currentEntry()->fMatrix) { |
| 369 return; | 274 return; |
| 370 } | 275 } |
| 371 | 276 |
| 372 if (currentEntry()->fMatrix.getType() != SkMatrix::kIdentity_Mask) { | 277 if (currentEntry()->fMatrix.getType() != SkMatrix::kIdentity_Mask) { |
| 373 SkASSERT(fStackDepth > 0); | 278 SkASSERT(fStackDepth > 0); |
| 374 SkASSERT(fEntries[fStackDepth].fClipStack == | 279 SkASSERT(fEntries[fStackDepth].fClipStack == |
| (...skipping 1768 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2143 } | 2048 } |
| 2144 | 2049 |
| 2145 sk_sp<SkSpecialImage> SkPDFDevice::makeSpecial(const SkImage* image) { | 2050 sk_sp<SkSpecialImage> SkPDFDevice::makeSpecial(const SkImage* image) { |
| 2146 return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(image->width(), image->
height()), | 2051 return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(image->width(), image->
height()), |
| 2147 image->makeNonTextureImage()); | 2052 image->makeNonTextureImage()); |
| 2148 } | 2053 } |
| 2149 | 2054 |
| 2150 sk_sp<SkSpecialImage> SkPDFDevice::snapSpecial() { | 2055 sk_sp<SkSpecialImage> SkPDFDevice::snapSpecial() { |
| 2151 return nullptr; | 2056 return nullptr; |
| 2152 } | 2057 } |
| OLD | NEW |