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 |