1 // Copyright 2017 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef CC_TEST_PAINT_OP_HELPER_H_ 6 #define CC_TEST_PAINT_OP_HELPER_H_ 7 8 #include <sstream> 9 #include <string> 10 11 #include "base/strings/stringprintf.h" 12 #include "cc/paint/paint_filter.h" 13 #include "cc/paint/paint_op_buffer.h" 14 15 namespace cc { 16 17 // A helper class to help with debugging PaintOp/PaintOpBuffer. 18 // Note that this file is primarily used for debugging. As such, it isn't 19 // typically a part of BUILD.gn (except for self-testing), so all of the 20 // implementation should be limited ot the header. 21 class PaintOpHelper { 22 public: ToString(const PaintOp * base_op)23 static std::string ToString(const PaintOp* base_op) { 24 std::ostringstream str; 25 str << std::boolalpha; 26 switch (base_op->GetType()) { 27 case PaintOpType::Annotate: { 28 const auto* op = static_cast<const AnnotateOp*>(base_op); 29 str << "AnnotateOp(type=" 30 << PaintOpHelper::EnumToString(op->annotation_type) 31 << ", rect=" << PaintOpHelper::SkiaTypeToString(op->rect) 32 << ", data=" << PaintOpHelper::SkiaTypeToString(op->data) << ")"; 33 break; 34 } 35 case PaintOpType::ClipPath: { 36 const auto* op = static_cast<const ClipPathOp*>(base_op); 37 str << "ClipPathOp(path=" << PaintOpHelper::SkiaTypeToString(op->path) 38 << ", op=" << PaintOpHelper::SkiaTypeToString(op->op) 39 << ", antialias=" << op->antialias << ")"; 40 break; 41 } 42 case PaintOpType::ClipRect: { 43 const auto* op = static_cast<const ClipRectOp*>(base_op); 44 str << "ClipRectOp(rect=" << PaintOpHelper::SkiaTypeToString(op->rect) 45 << ", op=" << PaintOpHelper::SkiaTypeToString(op->op) 46 << ", antialias=" << op->antialias << ")"; 47 break; 48 } 49 case PaintOpType::ClipRRect: { 50 const auto* op = static_cast<const ClipRRectOp*>(base_op); 51 str << "ClipRRectOp(rrect=" 52 << PaintOpHelper::SkiaTypeToString(op->rrect) 53 << ", op=" << PaintOpHelper::SkiaTypeToString(op->op) 54 << ", antialias=" << op->antialias << ")"; 55 break; 56 } 57 case PaintOpType::Concat: { 58 const auto* op = static_cast<const ConcatOp*>(base_op); 59 str << "ConcatOp(matrix=" << PaintOpHelper::SkiaTypeToString(op->matrix) 60 << ")"; 61 break; 62 } 63 case PaintOpType::CustomData: { 64 const auto* op = static_cast<const CustomDataOp*>(base_op); 65 str << "CustomDataOp(id=" << PaintOpHelper::SkiaTypeToString(op->id) 66 << ")"; 67 break; 68 } 69 case PaintOpType::DrawColor: { 70 const auto* op = static_cast<const DrawColorOp*>(base_op); 71 str << "DrawColorOp(color=" 72 << PaintOpHelper::SkiaTypeToString(op->color) 73 << ", mode=" << PaintOpHelper::SkiaTypeToString(op->mode) << ")"; 74 break; 75 } 76 case PaintOpType::DrawDRRect: { 77 const auto* op = static_cast<const DrawDRRectOp*>(base_op); 78 str << "DrawDRRectOp(outer=" 79 << PaintOpHelper::SkiaTypeToString(op->outer) 80 << ", inner=" << PaintOpHelper::SkiaTypeToString(op->inner) 81 << ", flags=" << PaintOpHelper::FlagsToString(op->flags) << ")"; 82 break; 83 } 84 case PaintOpType::DrawImage: { 85 const auto* op = static_cast<const DrawImageOp*>(base_op); 86 str << "DrawImageOp(image=" << PaintOpHelper::ImageToString(op->image) 87 << ", left=" << PaintOpHelper::SkiaTypeToString(op->left) 88 << ", top=" << PaintOpHelper::SkiaTypeToString(op->top) 89 << ", flags=" << PaintOpHelper::FlagsToString(op->flags) << ")"; 90 break; 91 } 92 case PaintOpType::DrawImageRect: { 93 const auto* op = static_cast<const DrawImageRectOp*>(base_op); 94 str << "DrawImageRectOp(image=" 95 << PaintOpHelper::ImageToString(op->image) 96 << ", src=" << PaintOpHelper::SkiaTypeToString(op->src) 97 << ", dst=" << PaintOpHelper::SkiaTypeToString(op->dst) 98 << ", constraint=" << PaintOpHelper::EnumToString(op->constraint) 99 << ", flags=" << PaintOpHelper::FlagsToString(op->flags) << ")"; 100 break; 101 } 102 case PaintOpType::DrawIRect: { 103 const auto* op = static_cast<const DrawIRectOp*>(base_op); 104 str << "DrawIRectOp(rect=" << PaintOpHelper::SkiaTypeToString(op->rect) 105 << ", flags=" << PaintOpHelper::FlagsToString(op->flags) << ")"; 106 break; 107 } 108 case PaintOpType::DrawLine: { 109 const auto* op = static_cast<const DrawLineOp*>(base_op); 110 str << "DrawLineOp(x0=" << PaintOpHelper::SkiaTypeToString(op->x0) 111 << ", y0=" << PaintOpHelper::SkiaTypeToString(op->y0) 112 << ", x1=" << PaintOpHelper::SkiaTypeToString(op->x1) 113 << ", y1=" << PaintOpHelper::SkiaTypeToString(op->y1) 114 << ", flags=" << PaintOpHelper::FlagsToString(op->flags) << ")"; 115 break; 116 } 117 case PaintOpType::DrawOval: { 118 const auto* op = static_cast<const DrawOvalOp*>(base_op); 119 str << "DrawOvalOp(oval=" << PaintOpHelper::SkiaTypeToString(op->oval) 120 << ", flags=" << PaintOpHelper::FlagsToString(op->flags) << ")"; 121 break; 122 } 123 case PaintOpType::DrawPath: { 124 const auto* op = static_cast<const DrawPathOp*>(base_op); 125 str << "DrawPathOp(path=" << PaintOpHelper::SkiaTypeToString(op->path) 126 << ", flags=" << PaintOpHelper::FlagsToString(op->flags) << ")"; 127 break; 128 } 129 case PaintOpType::DrawRecord: { 130 const auto* op = static_cast<const DrawRecordOp*>(base_op); 131 str << "DrawRecordOp(record=" 132 << PaintOpHelper::RecordToString(op->record) << ")"; 133 break; 134 } 135 case PaintOpType::DrawRect: { 136 const auto* op = static_cast<const DrawRectOp*>(base_op); 137 str << "DrawRectOp(rect=" << PaintOpHelper::SkiaTypeToString(op->rect) 138 << ", flags=" << PaintOpHelper::FlagsToString(op->flags) << ")"; 139 break; 140 } 141 case PaintOpType::DrawRRect: { 142 const auto* op = static_cast<const DrawRRectOp*>(base_op); 143 str << "DrawRRectOp(rrect=" 144 << PaintOpHelper::SkiaTypeToString(op->rrect) 145 << ", flags=" << PaintOpHelper::FlagsToString(op->flags) << ")"; 146 break; 147 } 148 case PaintOpType::DrawSkottie: { 149 const auto* op = static_cast<const DrawSkottieOp*>(base_op); 150 str << "DrawSkottieOp(" 151 << "skottie=" << PaintOpHelper::SkottieToString(op->skottie) 152 << ", dst=" << PaintOpHelper::SkiaTypeToString(op->dst) 153 << ", t=" << op->t << ")"; 154 break; 155 } 156 case PaintOpType::DrawTextBlob: { 157 const auto* op = static_cast<const DrawTextBlobOp*>(base_op); 158 str << "DrawTextBlobOp(blob=" 159 << PaintOpHelper::TextBlobToString(op->blob) 160 << ", x=" << PaintOpHelper::SkiaTypeToString(op->x) 161 << ", y=" << PaintOpHelper::SkiaTypeToString(op->y) 162 << ", flags=" << PaintOpHelper::FlagsToString(op->flags) << ")"; 163 break; 164 } 165 case PaintOpType::Noop: { 166 str << "NoopOp()"; 167 break; 168 } 169 case PaintOpType::Restore: { 170 str << "RestoreOp()"; 171 break; 172 } 173 case PaintOpType::Rotate: { 174 const auto* op = static_cast<const RotateOp*>(base_op); 175 str << "RotateOp(degrees=" 176 << PaintOpHelper::SkiaTypeToString(op->degrees) << ")"; 177 break; 178 } 179 case PaintOpType::Save: { 180 str << "SaveOp()"; 181 break; 182 } 183 case PaintOpType::SaveLayer: { 184 const auto* op = static_cast<const SaveLayerOp*>(base_op); 185 str << "SaveLayerOp(bounds=" 186 << PaintOpHelper::SkiaTypeToString(op->bounds) 187 << ", flags=" << PaintOpHelper::FlagsToString(op->flags) << ")"; 188 break; 189 } 190 case PaintOpType::SaveLayerAlpha: { 191 const auto* op = static_cast<const SaveLayerAlphaOp*>(base_op); 192 str << "SaveLayerAlphaOp(bounds=" 193 << PaintOpHelper::SkiaTypeToString(op->bounds) 194 << ", alpha=" << static_cast<uint32_t>(op->alpha) 195 << ")"; 196 break; 197 } 198 case PaintOpType::Scale: { 199 const auto* op = static_cast<const ScaleOp*>(base_op); 200 str << "ScaleOp(sx=" << PaintOpHelper::SkiaTypeToString(op->sx) 201 << ", sy=" << PaintOpHelper::SkiaTypeToString(op->sy) << ")"; 202 break; 203 } 204 case PaintOpType::SetMatrix: { 205 const auto* op = static_cast<const SetMatrixOp*>(base_op); 206 str << "SetMatrixOp(matrix=" 207 << PaintOpHelper::SkiaTypeToString(op->matrix) << ")"; 208 break; 209 } 210 case PaintOpType::Translate: { 211 const auto* op = static_cast<const TranslateOp*>(base_op); 212 str << "TranslateOp(dx=" << PaintOpHelper::SkiaTypeToString(op->dx) 213 << ", dy=" << PaintOpHelper::SkiaTypeToString(op->dy) << ")"; 214 break; 215 } 216 case PaintOpType::SetNodeId: { 217 const auto* op = static_cast<const SetNodeIdOp*>(base_op); 218 str << "SetNodeIdOp(id=" << op->node_id << ")"; 219 break; 220 } 221 } 222 return str.str(); 223 } 224 225 template <typename T> SkiaTypeToString(const T &)226 static std::string SkiaTypeToString(const T&) { 227 return "<unknown skia type>"; 228 } 229 SkiaTypeToString(const SkScalar & scalar)230 static std::string SkiaTypeToString(const SkScalar& scalar) { 231 return base::StringPrintf("%.3f", scalar); 232 } 233 SkiaTypeToString(const SkPoint & point)234 static std::string SkiaTypeToString(const SkPoint& point) { 235 return base::StringPrintf("[%.3f,%.3f]", point.fX, point.fY); 236 } 237 SkiaTypeToString(const SkRect & rect)238 static std::string SkiaTypeToString(const SkRect& rect) { 239 return base::StringPrintf("[%.3f,%.3f %.3fx%.3f]", rect.x(), rect.y(), 240 rect.width(), rect.height()); 241 } 242 SkiaTypeToString(const SkIRect & rect)243 static std::string SkiaTypeToString(const SkIRect& rect) { 244 return base::StringPrintf("[%d,%d %dx%d]", rect.x(), rect.y(), rect.width(), 245 rect.height()); 246 } 247 SkiaTypeToString(const SkRRect & rect)248 static std::string SkiaTypeToString(const SkRRect& rect) { 249 return base::StringPrintf("[bounded by %.3f,%.3f %.3fx%.3f]", 250 rect.rect().x(), rect.rect().y(), 251 rect.rect().width(), rect.rect().height()); 252 } 253 SkiaTypeToString(const ThreadsafeMatrix & matrix)254 static std::string SkiaTypeToString(const ThreadsafeMatrix& matrix) { 255 return SkiaTypeToString(static_cast<const SkMatrix&>(matrix)); 256 } 257 SkiaTypeToString(const SkMatrix & matrix)258 static std::string SkiaTypeToString(const SkMatrix& matrix) { 259 return base::StringPrintf( 260 "[%8.4f %8.4f %8.4f][%8.4f %8.4f %8.4f][%8.4f %8.4f %8.4f]", matrix[0], 261 matrix[1], matrix[2], matrix[3], matrix[4], matrix[5], matrix[6], 262 matrix[7], matrix[8]); 263 } 264 SkiaTypeToString(const SkColor & color)265 static std::string SkiaTypeToString(const SkColor& color) { 266 return base::StringPrintf("rgba(%d, %d, %d, %d)", SkColorGetR(color), 267 SkColorGetG(color), SkColorGetB(color), 268 SkColorGetA(color)); 269 } 270 SkiaTypeToString(const SkBlendMode & mode)271 static std::string SkiaTypeToString(const SkBlendMode& mode) { 272 switch (mode) { 273 default: 274 break; 275 case SkBlendMode::kClear: 276 return "kClear"; 277 case SkBlendMode::kSrc: 278 return "kSrc"; 279 case SkBlendMode::kDst: 280 return "kDst"; 281 case SkBlendMode::kSrcOver: 282 return "kSrcOver"; 283 case SkBlendMode::kDstOver: 284 return "kDstOver"; 285 case SkBlendMode::kSrcIn: 286 return "kSrcIn"; 287 case SkBlendMode::kDstIn: 288 return "kDstIn"; 289 case SkBlendMode::kSrcOut: 290 return "kSrcOut"; 291 case SkBlendMode::kDstOut: 292 return "kDstOut"; 293 case SkBlendMode::kSrcATop: 294 return "kSrcATop"; 295 case SkBlendMode::kDstATop: 296 return "kDstATop"; 297 case SkBlendMode::kXor: 298 return "kXor"; 299 case SkBlendMode::kPlus: 300 return "kPlus"; 301 case SkBlendMode::kModulate: 302 return "kModulate"; 303 case SkBlendMode::kScreen: 304 return "kScreen"; 305 case SkBlendMode::kOverlay: 306 return "kOverlay"; 307 case SkBlendMode::kDarken: 308 return "kDarken"; 309 case SkBlendMode::kLighten: 310 return "kLighten"; 311 case SkBlendMode::kColorDodge: 312 return "kColorDodge"; 313 case SkBlendMode::kColorBurn: 314 return "kColorBurn"; 315 case SkBlendMode::kHardLight: 316 return "kHardLight"; 317 case SkBlendMode::kSoftLight: 318 return "kSoftLight"; 319 case SkBlendMode::kDifference: 320 return "kDifference"; 321 case SkBlendMode::kExclusion: 322 return "kExclusion"; 323 case SkBlendMode::kMultiply: 324 return "kMultiply"; 325 case SkBlendMode::kHue: 326 return "kHue"; 327 case SkBlendMode::kSaturation: 328 return "kSaturation"; 329 case SkBlendMode::kColor: 330 return "kColor"; 331 case SkBlendMode::kLuminosity: 332 return "kLuminosity"; 333 } 334 return "<unknown SkBlendMode>"; 335 } 336 SkiaTypeToString(const SkClipOp & op)337 static std::string SkiaTypeToString(const SkClipOp& op) { 338 switch (op) { 339 default: 340 break; 341 case SkClipOp::kDifference: 342 return "kDifference"; 343 case SkClipOp::kIntersect: 344 return "kIntersect"; 345 } 346 return "<unknown SkClipOp>"; 347 } 348 SkiaTypeToString(const sk_sp<SkData> data)349 static std::string SkiaTypeToString(const sk_sp<SkData> data) { 350 return data ? "<SkData>" : "(nil)"; 351 } 352 SkiaTypeToString(const ThreadsafePath & path)353 static std::string SkiaTypeToString(const ThreadsafePath& path) { 354 return SkiaTypeToString(static_cast<const SkPath&>(path)); 355 } 356 SkiaTypeToString(const SkPath & path)357 static std::string SkiaTypeToString(const SkPath& path) { 358 // TODO(vmpstr): SkPath has a dump function which we can use here? 359 return "<SkPath>"; 360 } 361 SkiaTypeToString(SkFilterQuality quality)362 static std::string SkiaTypeToString(SkFilterQuality quality) { 363 switch (quality) { 364 case kNone_SkFilterQuality: 365 return "kNone_SkFilterQuality"; 366 case kLow_SkFilterQuality: 367 return "kLow_SkFilterQuality"; 368 case kMedium_SkFilterQuality: 369 return "kMedium_SkFilterQuality"; 370 case kHigh_SkFilterQuality: 371 return "kHigh_SkFilterQuality"; 372 } 373 return "<unknown SkFilterQuality>"; 374 } 375 SkiaTypeToString(PaintFlags::Cap cap)376 static std::string SkiaTypeToString(PaintFlags::Cap cap) { 377 switch (cap) { 378 case PaintFlags::kButt_Cap: 379 return "kButt_Cap"; 380 case PaintFlags::kRound_Cap: 381 return "kRound_Cap"; 382 case PaintFlags::kSquare_Cap: 383 return "kSquare_Cap"; 384 } 385 return "<unknown PaintFlags::Cap>"; 386 } 387 SkiaTypeToString(PaintFlags::Join join)388 static std::string SkiaTypeToString(PaintFlags::Join join) { 389 switch (join) { 390 case PaintFlags::kMiter_Join: 391 return "kMiter_Join"; 392 case PaintFlags::kRound_Join: 393 return "kRound_Join"; 394 case PaintFlags::kBevel_Join: 395 return "kBevel_Join"; 396 } 397 return "<unknown PaintFlags::Join>"; 398 } 399 SkiaTypeToString(const sk_sp<SkColorFilter> & filter)400 static std::string SkiaTypeToString(const sk_sp<SkColorFilter>& filter) { 401 if (!filter) 402 return "(nil)"; 403 return "SkColorFilter"; 404 } 405 SkiaTypeToString(const sk_sp<SkMaskFilter> & filter)406 static std::string SkiaTypeToString(const sk_sp<SkMaskFilter>& filter) { 407 if (!filter) 408 return "(nil)"; 409 return "SkMaskFilter"; 410 } 411 SkiaTypeToString(const sk_sp<SkPathEffect> & effect)412 static std::string SkiaTypeToString(const sk_sp<SkPathEffect>& effect) { 413 if (!effect) 414 return "(nil)"; 415 return "SkPathEffect"; 416 } 417 SkiaTypeToString(const sk_sp<SkDrawLooper> & looper)418 static std::string SkiaTypeToString(const sk_sp<SkDrawLooper>& looper) { 419 if (!looper) 420 return "(nil)"; 421 return "SkDrawLooper"; 422 } 423 424 template <typename T> EnumToString(T)425 static std::string EnumToString(T) { 426 return "<unknown enum type>"; 427 } 428 EnumToString(PaintCanvas::AnnotationType type)429 static std::string EnumToString(PaintCanvas::AnnotationType type) { 430 switch (type) { 431 default: 432 break; 433 case PaintCanvas::AnnotationType::URL: 434 return "URL"; 435 case PaintCanvas::AnnotationType::NAMED_DESTINATION: 436 return "NAMED_DESTINATION"; 437 case PaintCanvas::AnnotationType::LINK_TO_DESTINATION: 438 return "LINK_TO_DESTINATION"; 439 } 440 return "<unknown AnnotationType>"; 441 } 442 EnumToString(const SkCanvas::SrcRectConstraint & constraint)443 static std::string EnumToString( 444 const SkCanvas::SrcRectConstraint& constraint) { 445 switch (constraint) { 446 default: 447 break; 448 case SkCanvas::kStrict_SrcRectConstraint: 449 return "kStrict_SrcRectConstraint"; 450 case SkCanvas::kFast_SrcRectConstraint: 451 return "kFast_SrcRectConstraint"; 452 } 453 return "<unknown SrcRectConstraint>"; 454 } 455 EnumToString(PaintShader::ScalingBehavior behavior)456 static std::string EnumToString(PaintShader::ScalingBehavior behavior) { 457 switch (behavior) { 458 case PaintShader::ScalingBehavior::kRasterAtScale: 459 return "kRasterAtScale"; 460 case PaintShader::ScalingBehavior::kFixedScale: 461 return "kFixedScale"; 462 } 463 return "<unknown ScalingBehavior>"; 464 } 465 EnumToString(PaintShader::Type type)466 static std::string EnumToString(PaintShader::Type type) { 467 switch (type) { 468 case PaintShader::Type::kEmpty: 469 return "kEmpty"; 470 case PaintShader::Type::kColor: 471 return "kColor"; 472 case PaintShader::Type::kLinearGradient: 473 return "kLinearGradient"; 474 case PaintShader::Type::kRadialGradient: 475 return "kRadialGradient"; 476 case PaintShader::Type::kTwoPointConicalGradient: 477 return "kTwoPointConicalGradient"; 478 case PaintShader::Type::kSweepGradient: 479 return "kSweepGradient"; 480 case PaintShader::Type::kImage: 481 return "kImage"; 482 case PaintShader::Type::kPaintRecord: 483 return "kPaintRecord"; 484 case PaintShader::Type::kShaderCount: 485 return "kShaderCount"; 486 } 487 return "<unknown PaintShader::Type>"; 488 } 489 ImageToString(const PaintImage & image)490 static std::string ImageToString(const PaintImage& image) { 491 return "<paint image>"; 492 } 493 SkottieToString(scoped_refptr<SkottieWrapper> skottie)494 static std::string SkottieToString(scoped_refptr<SkottieWrapper> skottie) { 495 std::ostringstream str; 496 str << "<skottie ["; 497 str << "duration=" << skottie->duration() << " seconds"; 498 str << ", width=" 499 << PaintOpHelper::SkiaTypeToString(skottie->size().width()); 500 str << ", height=" 501 << PaintOpHelper::SkiaTypeToString(skottie->size().height()); 502 str << "]"; 503 return str.str(); 504 } 505 RecordToString(const sk_sp<const PaintRecord> & record)506 static std::string RecordToString(const sk_sp<const PaintRecord>& record) { 507 return record ? "<paint record>" : "(nil)"; 508 } 509 TextBlobToString(const sk_sp<SkTextBlob> & blob)510 static std::string TextBlobToString(const sk_sp<SkTextBlob>& blob) { 511 return blob ? "<sk text blob>" : "(nil)"; 512 } 513 PaintShaderToString(const PaintShader * shader)514 static std::string PaintShaderToString(const PaintShader* shader) { 515 if (!shader) 516 return "(nil)"; 517 std::ostringstream str; 518 str << "[type=" << EnumToString(shader->shader_type()); 519 str << ", flags=" << shader->flags_; 520 str << ", end_radius=" << shader->end_radius_; 521 str << ", start_radius=" << shader->start_radius_; 522 str << ", tx=" << static_cast<unsigned>(shader->tx_); 523 str << ", ty=" << static_cast<unsigned>(shader->ty_); 524 str << ", fallback_color=" << shader->fallback_color_; 525 str << ", scaling_behavior=" << EnumToString(shader->scaling_behavior_); 526 if (shader->local_matrix_.has_value()) { 527 str << ", local_matrix=" << SkiaTypeToString(*shader->local_matrix_); 528 } else { 529 str << ", local_matrix=(nil)"; 530 } 531 str << ", center=" << SkiaTypeToString(shader->center_); 532 str << ", tile=" << SkiaTypeToString(shader->tile_); 533 str << ", start_point=" << SkiaTypeToString(shader->start_point_); 534 str << ", end_point=" << SkiaTypeToString(shader->end_point_); 535 str << ", start_degrees=" << shader->start_degrees_; 536 str << ", end_degrees=" << shader->end_degrees_; 537 if (shader->shader_type() == PaintShader::Type::kImage) 538 str << ", image=" << ImageToString(shader->image_); 539 else 540 str << ", image=(nil)"; 541 str << ", record=" << RecordToString(shader->record_); 542 str << ", id=" << shader->id_; 543 str << ", tile_scale="; 544 if (shader->tile_scale_) { 545 str << "[" << shader->tile_scale_->ToString() << "]"; 546 } else { 547 str << "(nil)"; 548 } 549 if (shader->colors_.size() > 0) { 550 str << ", colors=[" << shader->colors_[0]; 551 for (size_t i = 1; i < shader->colors_.size(); ++i) { 552 str << ", " << shader->colors_[i]; 553 } 554 str << "]"; 555 } else { 556 str << ", colors=(nil)"; 557 } 558 if (shader->positions_.size() > 0) { 559 str << ", positions=[" << shader->positions_[0]; 560 for (size_t i = 1; i < shader->positions_.size(); ++i) { 561 str << ", " << shader->positions_[i]; 562 } 563 str << "]"; 564 } else { 565 str << ", positions=(nil)"; 566 } 567 str << "]"; 568 569 return str.str(); 570 } 571 PaintFilterToString(const sk_sp<PaintFilter> filter)572 static std::string PaintFilterToString(const sk_sp<PaintFilter> filter) { 573 return filter ? "<PaintFilter>" : "(nil)"; 574 } 575 FlagsToString(const PaintFlags & flags)576 static std::string FlagsToString(const PaintFlags& flags) { 577 std::ostringstream str; 578 str << std::boolalpha; 579 str << "[color=" << PaintOpHelper::SkiaTypeToString(flags.getColor()); 580 str << ", blendMode=" 581 << PaintOpHelper::SkiaTypeToString(flags.getBlendMode()); 582 str << ", isAntiAlias=" << flags.isAntiAlias(); 583 str << ", isDither=" << flags.isDither(); 584 str << ", filterQuality=" 585 << PaintOpHelper::SkiaTypeToString(flags.getFilterQuality()); 586 str << ", strokeWidth=" 587 << PaintOpHelper::SkiaTypeToString(flags.getStrokeWidth()); 588 str << ", strokeMiter=" 589 << PaintOpHelper::SkiaTypeToString(flags.getStrokeMiter()); 590 str << ", strokeCap=" 591 << PaintOpHelper::SkiaTypeToString(flags.getStrokeCap()); 592 str << ", strokeJoin=" 593 << PaintOpHelper::SkiaTypeToString(flags.getStrokeJoin()); 594 str << ", colorFilter=" 595 << PaintOpHelper::SkiaTypeToString(flags.getColorFilter()); 596 str << ", maskFilter=" 597 << PaintOpHelper::SkiaTypeToString(flags.getMaskFilter()); 598 str << ", shader=" << PaintOpHelper::PaintShaderToString(flags.getShader()); 599 str << ", hasShader=" << flags.HasShader(); 600 str << ", shaderIsOpaque=" << (flags.HasShader() && flags.ShaderIsOpaque()); 601 str << ", pathEffect=" 602 << PaintOpHelper::SkiaTypeToString(flags.getPathEffect()); 603 str << ", imageFilter=" 604 << PaintOpHelper::PaintFilterToString(flags.getImageFilter()); 605 str << ", drawLooper=" 606 << PaintOpHelper::SkiaTypeToString(flags.getLooper()); 607 str << ", isSimpleOpacity=" << flags.IsSimpleOpacity(); 608 str << ", supportsFoldingAlpha=" << flags.SupportsFoldingAlpha(); 609 str << ", isValid=" << flags.IsValid(); 610 str << ", hasDiscardableImages=" << flags.HasDiscardableImages(); 611 str << "]"; 612 return str.str(); 613 } 614 }; 615 616 } // namespace cc 617 618 inline ::std::ostream& operator<<(::std::ostream& os, const cc::PaintOp& op) { 619 return os << cc::PaintOpHelper::ToString(&op); 620 } 621 622 #endif // CC_TEST_PAINT_OP_HELPER_H_ 623