bl_bench_backend_coregraphics.cpp (22105B)
1 // This file is part of Blend2D project <https://blend2d.com> 2 // 3 // See LICENSE.md for license and copyright information 4 // SPDX-License-Identifier: Zlib 5 6 #ifdef BL_BENCH_ENABLE_COREGRAPHICS 7 8 #include "bl_bench_app.h" 9 #include "bl_bench_backend.h" 10 11 #include <ApplicationServices/ApplicationServices.h> 12 #include <utility> 13 14 namespace blbench { 15 16 static uint32_t to_cg_bitmap_info(BLFormat format) noexcept { 17 switch (format) { 18 case BL_FORMAT_PRGB32: return kCGImageByteOrder32Little | kCGImageAlphaPremultipliedFirst; 19 case BL_FORMAT_XRGB32: return kCGImageByteOrder32Little | kCGImageAlphaNoneSkipFirst; 20 21 default: return 0; 22 } 23 } 24 25 static CGBlendMode to_cg_blend_mode(BLCompOp comp_op) noexcept { 26 switch (comp_op) { 27 case BL_COMP_OP_SRC_OVER : return kCGBlendModeNormal; 28 case BL_COMP_OP_SRC_COPY : return kCGBlendModeCopy; 29 case BL_COMP_OP_SRC_IN : return kCGBlendModeSourceIn; 30 case BL_COMP_OP_SRC_OUT : return kCGBlendModeSourceOut; 31 case BL_COMP_OP_SRC_ATOP : return kCGBlendModeSourceAtop; 32 case BL_COMP_OP_DST_OVER : return kCGBlendModeDestinationOver; 33 case BL_COMP_OP_DST_IN : return kCGBlendModeDestinationIn; 34 case BL_COMP_OP_DST_OUT : return kCGBlendModeDestinationOut; 35 case BL_COMP_OP_DST_ATOP : return kCGBlendModeDestinationAtop; 36 case BL_COMP_OP_XOR : return kCGBlendModeXOR; 37 case BL_COMP_OP_CLEAR : return kCGBlendModeClear; 38 case BL_COMP_OP_PLUS : return kCGBlendModePlusLighter; 39 case BL_COMP_OP_MULTIPLY : return kCGBlendModeMultiply; 40 case BL_COMP_OP_SCREEN : return kCGBlendModeScreen; 41 case BL_COMP_OP_OVERLAY : return kCGBlendModeOverlay; 42 case BL_COMP_OP_DARKEN : return kCGBlendModeDarken; 43 case BL_COMP_OP_LIGHTEN : return kCGBlendModeLighten; 44 case BL_COMP_OP_COLOR_DODGE: return kCGBlendModeColorDodge; 45 case BL_COMP_OP_COLOR_BURN : return kCGBlendModeColorBurn; 46 case BL_COMP_OP_HARD_LIGHT : return kCGBlendModeHardLight; 47 case BL_COMP_OP_SOFT_LIGHT : return kCGBlendModeSoftLight; 48 case BL_COMP_OP_DIFFERENCE : return kCGBlendModeDifference; 49 case BL_COMP_OP_EXCLUSION : return kCGBlendModeExclusion; 50 51 default: 52 return kCGBlendModeNormal; 53 } 54 } 55 56 template<typename RectT> 57 static inline CGRect to_cg_rect(const RectT& rect) noexcept { 58 return CGRectMake(CGFloat(rect.x), CGFloat(rect.y), CGFloat(rect.w), CGFloat(rect.h)); 59 } 60 61 static inline void to_cg_color_components(CGFloat components[4], BLRgba32 color) noexcept { 62 constexpr CGFloat scale = CGFloat(1.0f / 255.0f); 63 components[0] = CGFloat(int(color.r())) * scale; 64 components[1] = CGFloat(int(color.g())) * scale; 65 components[2] = CGFloat(int(color.b())) * scale; 66 components[3] = CGFloat(int(color.a())) * scale; 67 } 68 69 static void flipImage(BLImage& img) noexcept { 70 BLImageData imgData; 71 img.make_mutable(&imgData); 72 73 uint32_t h = uint32_t(imgData.size.h); 74 intptr_t stride = imgData.stride; 75 uint8_t* pixel_data = static_cast<uint8_t*>(imgData.pixel_data); 76 77 for (uint32_t y = 0; y < h / 2; y++) { 78 uint8_t* a = pixel_data + intptr_t(y) * stride; 79 uint8_t* b = pixel_data + intptr_t(h - y - 1) * stride; 80 81 for (size_t x = 0; x < size_t(stride); x++) { 82 std::swap(a[x], b[x]); 83 } 84 85 } 86 } 87 88 struct CoreGraphicsModule : public Backend { 89 CGImageRef _cg_sprites[kBenchNumSprites] {}; 90 91 CGColorSpaceRef _cg_colorspace {}; 92 CGContextRef _cg_ctx {}; 93 94 CoreGraphicsModule(); 95 ~CoreGraphicsModule() override; 96 97 void serialize_info(JSONBuilder& json) const override; 98 99 bool supports_comp_op(BLCompOp comp_op) const override; 100 bool supports_style(StyleKind style) const override; 101 102 void before_run() override; 103 void flush() override; 104 void after_run() override; 105 106 CGGradientRef create_gradient(StyleKind style) noexcept; 107 108 BL_INLINE void render_solid_path(RenderOp op) noexcept; 109 110 template<typename RectT> 111 BL_INLINE void render_solid_rect(const RectT& rect, RenderOp op) noexcept; 112 113 template<bool kSaveGState, typename RectT> 114 BL_INLINE void render_styled_path(const RectT& rect, StyleKind style, RenderOp op) noexcept; 115 116 template<bool kSaveGState, typename RectT> 117 BL_INLINE void render_styled_rect(const RectT& rect, StyleKind style, RenderOp op) noexcept; 118 119 void render_rect_a(RenderOp op) override; 120 void render_rect_f(RenderOp op) override; 121 void render_rect_rotated(RenderOp op) override; 122 void render_round_f(RenderOp op) override; 123 void render_round_rotated(RenderOp op) override; 124 void render_polygon(RenderOp op, uint32_t complexity) override; 125 void render_shape(RenderOp op, ShapeData shape) override; 126 }; 127 128 CoreGraphicsModule::CoreGraphicsModule() { 129 strcpy(_name, "CoreGraphics"); 130 } 131 132 CoreGraphicsModule::~CoreGraphicsModule() {} 133 134 void CoreGraphicsModule::serialize_info(JSONBuilder& json) const { 135 } 136 137 bool CoreGraphicsModule::supports_comp_op(BLCompOp comp_op) const { 138 return comp_op == BL_COMP_OP_SRC_OVER || 139 comp_op == BL_COMP_OP_SRC_COPY || 140 comp_op == BL_COMP_OP_SRC_IN || 141 comp_op == BL_COMP_OP_SRC_OUT || 142 comp_op == BL_COMP_OP_SRC_ATOP || 143 comp_op == BL_COMP_OP_DST_OVER || 144 comp_op == BL_COMP_OP_DST_IN || 145 comp_op == BL_COMP_OP_DST_OUT || 146 comp_op == BL_COMP_OP_DST_ATOP || 147 comp_op == BL_COMP_OP_XOR || 148 comp_op == BL_COMP_OP_CLEAR || 149 comp_op == BL_COMP_OP_PLUS || 150 comp_op == BL_COMP_OP_MULTIPLY || 151 comp_op == BL_COMP_OP_SCREEN || 152 comp_op == BL_COMP_OP_OVERLAY || 153 comp_op == BL_COMP_OP_DARKEN || 154 comp_op == BL_COMP_OP_LIGHTEN || 155 comp_op == BL_COMP_OP_COLOR_DODGE || 156 comp_op == BL_COMP_OP_COLOR_BURN || 157 comp_op == BL_COMP_OP_HARD_LIGHT || 158 comp_op == BL_COMP_OP_SOFT_LIGHT || 159 comp_op == BL_COMP_OP_DIFFERENCE || 160 comp_op == BL_COMP_OP_EXCLUSION ; 161 } 162 163 bool CoreGraphicsModule::supports_style(StyleKind style) const { 164 return style == StyleKind::kSolid || 165 style == StyleKind::kLinearPad || 166 style == StyleKind::kRadialPad || 167 style == StyleKind::kConic || 168 style == StyleKind::kPatternNN || 169 style == StyleKind::kPatternBI ; 170 } 171 172 void CoreGraphicsModule::before_run() { 173 int w = int(_params.screen_w); 174 int h = int(_params.screen_h); 175 StyleKind style = _params.style; 176 177 _cg_colorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGBLinear); 178 179 // Initialize the sprites. 180 for (uint32_t i = 0; i < kBenchNumSprites; i++) { 181 BLImage& sprite = _sprites[i]; 182 flipImage(sprite); 183 184 BLImageData sprite_data; 185 sprite.get_data(&sprite_data); 186 187 BLFormat sprite_format = BLFormat(sprite_data.format); 188 189 CGDataProviderRef dp = CGDataProviderCreateWithData( 190 nullptr, 191 sprite_data.pixel_data, 192 size_t(sprite_data.size.h) * size_t(sprite_data.stride), 193 nullptr); 194 195 if (!dp) { 196 printf("Failed to create CGDataProvider\n"); 197 continue; 198 } 199 200 CGImageRef cg_sprite = CGImageCreate( 201 size_t(sprite_data.size.w), // Width. 202 size_t(sprite_data.size.h), // Height. 203 8, // Bits per component. 204 32, // Bits per pixel. 205 size_t(sprite_data.stride), // Bytes per row. 206 _cg_colorspace, // Colorspace. 207 to_cg_bitmap_info(sprite_format), // Bitmap info. 208 dp, // Data provider. 209 nullptr, // Decode. 210 style == StyleKind::kPatternBI, // Should interpolate. 211 kCGRenderingIntentDefault); // Color rendering intent. 212 213 if (!cg_sprite) { 214 printf("Failed to create CGImage\n"); 215 continue; 216 } 217 218 _cg_sprites[i] = cg_sprite; 219 CGDataProviderRelease(dp); 220 } 221 222 // Initialize the surface and the context. 223 BLImageData surface_data; 224 _surface.create(w, h, _params.format); 225 _surface.make_mutable(&surface_data); 226 227 _cg_ctx = CGBitmapContextCreate( 228 surface_data.pixel_data, 229 uint32_t(surface_data.size.w), 230 uint32_t(surface_data.size.h), 231 8, 232 size_t(surface_data.stride), 233 _cg_colorspace, 234 to_cg_bitmap_info(BLFormat(surface_data.format))); 235 236 const CGFloat transparent[4] {}; 237 238 // Setup the context. 239 CGContextSetBlendMode(_cg_ctx, kCGBlendModeCopy); 240 CGContextSetFillColorSpace(_cg_ctx, _cg_colorspace); 241 CGContextSetStrokeColorSpace(_cg_ctx, _cg_colorspace); 242 243 CGContextSetFillColor(_cg_ctx, transparent); 244 CGContextFillRect(_cg_ctx, CGRectMake(0, 0, CGFloat(surface_data.size.w), CGFloat(surface_data.size.h))); 245 246 CGContextSetBlendMode(_cg_ctx, to_cg_blend_mode(_params.comp_op)); 247 CGContextSetAllowsAntialiasing(_cg_ctx, true); 248 249 CGContextSetLineJoin(_cg_ctx, kCGLineJoinMiter); 250 CGContextSetLineWidth(_cg_ctx, CGFloat(_params.stroke_width)); 251 } 252 253 void CoreGraphicsModule::flush() { 254 CGContextSynchronize(_cg_ctx); 255 } 256 257 void CoreGraphicsModule::after_run() { 258 CGContextRelease(_cg_ctx); 259 CGColorSpaceRelease(_cg_colorspace); 260 261 _cg_ctx = nullptr; 262 _cg_colorspace = nullptr; 263 264 // Free the sprites. 265 for (uint32_t i = 0; i < kBenchNumSprites; i++) { 266 if (_cg_sprites[i]) { 267 CGImageRelease(_cg_sprites[i]); 268 _cg_sprites[i] = nullptr; 269 } 270 } 271 272 flipImage(_surface); 273 } 274 275 CGGradientRef CoreGraphicsModule::create_gradient(StyleKind style) noexcept { 276 BLRgba32 c0 = _rnd_color.next_rgba32(); 277 BLRgba32 c1 = _rnd_color.next_rgba32(); 278 BLRgba32 c2 = _rnd_color.next_rgba32(); 279 280 switch (style) { 281 case StyleKind::kLinearPad: 282 case StyleKind::kLinearRepeat: 283 case StyleKind::kRadialPad: 284 case StyleKind::kRadialRepeat: { 285 CGFloat components[12]; 286 to_cg_color_components(components + 0, c0); 287 to_cg_color_components(components + 4, c1); 288 to_cg_color_components(components + 8, c2); 289 290 CGFloat locations[3] = { 291 CGFloat(0.0), 292 CGFloat(0.5), 293 CGFloat(1.0) 294 }; 295 296 return CGGradientCreateWithColorComponents(_cg_colorspace, components, locations, 3); 297 } 298 299 case StyleKind::kLinearReflect: 300 case StyleKind::kRadialReflect: { 301 302 CGFloat components[20]; 303 to_cg_color_components(components + 0, c0); 304 to_cg_color_components(components + 4, c1); 305 to_cg_color_components(components + 8, c2); 306 to_cg_color_components(components + 12, c1); 307 to_cg_color_components(components + 16, c0); 308 309 CGFloat locations[5] = { 310 CGFloat(0.0), 311 CGFloat(0.25), 312 CGFloat(0.5), 313 CGFloat(0.75), 314 CGFloat(1.0) 315 }; 316 317 return CGGradientCreateWithColorComponents(_cg_colorspace, components, locations, 5); 318 } 319 320 case StyleKind::kConic: { 321 BLRgba32 c0 = _rnd_color.next_rgba32(); 322 BLRgba32 c1 = _rnd_color.next_rgba32(); 323 BLRgba32 c2 = _rnd_color.next_rgba32(); 324 325 CGFloat components[16]; 326 to_cg_color_components(components + 0, c0); 327 to_cg_color_components(components + 4, c1); 328 to_cg_color_components(components + 8, c2); 329 to_cg_color_components(components + 12, c0); 330 331 CGFloat locations[4] = { 332 CGFloat(0.0), 333 CGFloat(0.33), 334 CGFloat(0.66), 335 CGFloat(1.0) 336 }; 337 338 return CGGradientCreateWithColorComponents(_cg_colorspace, components, locations, 4); 339 } 340 341 default: 342 return CGGradientRef{}; 343 } 344 } 345 346 BL_INLINE void CoreGraphicsModule::render_solid_path(RenderOp op) noexcept { 347 CGFloat color[4]; 348 to_cg_color_components(color, _rnd_color.next_rgba32()); 349 350 if (op == RenderOp::kStroke) { 351 CGContextSetStrokeColor(_cg_ctx, color); 352 CGContextStrokePath(_cg_ctx); 353 } 354 else { 355 CGContextSetFillColor(_cg_ctx, color); 356 if (op == RenderOp::kFillNonZero) 357 CGContextFillPath(_cg_ctx); 358 else 359 CGContextEOFillPath(_cg_ctx); 360 } 361 } 362 363 template<typename RectT> 364 BL_INLINE void CoreGraphicsModule::render_solid_rect(const RectT& rect, RenderOp op) noexcept { 365 CGFloat color[4]; 366 to_cg_color_components(color, _rnd_color.next_rgba32()); 367 368 if (op == RenderOp::kStroke) { 369 CGContextSetStrokeColor(_cg_ctx, color); 370 CGContextStrokeRect(_cg_ctx, to_cg_rect(rect)); 371 } 372 else { 373 CGContextSetFillColor(_cg_ctx, color); 374 CGContextFillRect(_cg_ctx, to_cg_rect(rect)); 375 } 376 } 377 378 template<bool kSaveGState, typename RectT> 379 BL_INLINE void CoreGraphicsModule::render_styled_path(const RectT& rect, StyleKind style, RenderOp op) noexcept { 380 if (kSaveGState) 381 CGContextSaveGState(_cg_ctx); 382 383 if (op == RenderOp::kStroke) { 384 CGContextReplacePathWithStrokedPath(_cg_ctx); 385 } 386 387 if (op == RenderOp::kFillEvenOdd) { 388 CGContextEOClip(_cg_ctx); 389 } 390 else { 391 CGContextClip(_cg_ctx); 392 } 393 394 switch (style) { 395 case StyleKind::kSolid: 396 // Not reached (the caller must use render_solid_path() instead). 397 break; 398 399 case StyleKind::kLinearPad: 400 case StyleKind::kLinearRepeat: 401 case StyleKind::kLinearReflect: { 402 CGFloat reflectScale = style == StyleKind::kLinearReflect ? 1.0 : 2.0; 403 CGFloat w = rect.w * reflectScale; 404 CGFloat h = rect.h * reflectScale; 405 406 CGFloat x0 = CGFloat(rect.x) + w * CGFloat(0.2); 407 CGFloat y0 = CGFloat(rect.y) + h * CGFloat(0.2); 408 CGFloat x1 = CGFloat(rect.x) + w * CGFloat(0.8); 409 CGFloat y1 = CGFloat(rect.y) + h * CGFloat(0.8); 410 411 CGGradientRef gradient = create_gradient(style); 412 CGGradientDrawingOptions options = kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation; 413 CGContextDrawLinearGradient(_cg_ctx, gradient, CGPointMake(x0, y0), CGPointMake(x1, y1), options); 414 CGGradientRelease(gradient); 415 break; 416 } 417 418 case StyleKind::kRadialPad: 419 case StyleKind::kRadialRepeat: 420 case StyleKind::kRadialReflect: { 421 CGFloat cx = CGFloat(rect.x + rect.w / 2); 422 CGFloat cy = CGFloat(rect.y + rect.h / 2); 423 CGFloat cr = CGFloat((rect.w + rect.h) / 4); 424 CGFloat fx = CGFloat(cx - cr / 2); 425 CGFloat fy = CGFloat(cy - cr / 2); 426 427 CGGradientRef gradient = create_gradient(style); 428 CGGradientDrawingOptions options = kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation; 429 CGContextDrawRadialGradient(_cg_ctx, gradient, CGPointMake(cx, cy), cr, CGPointMake(fx, fy), CGFloat(0.0), options); 430 CGGradientRelease(gradient); 431 break; 432 } 433 434 case StyleKind::kConic: { 435 double cx = rect.x + rect.w / 2; 436 double cy = rect.y + rect.h / 2; 437 double angle = 0.0; 438 439 CGGradientRef gradient = create_gradient(style); 440 CGContextDrawConicGradient(_cg_ctx, gradient, CGPointMake(cx, cy), CGFloat(angle)); 441 CGGradientRelease(gradient); 442 break; 443 } 444 445 case StyleKind::kPatternNN: 446 case StyleKind::kPatternBI: { 447 uint32_t spriteId = nextSpriteId(); 448 449 CGContextDrawImage(_cg_ctx, to_cg_rect(rect), _cg_sprites[spriteId]); 450 break; 451 } 452 } 453 454 if (kSaveGState) 455 CGContextRestoreGState(_cg_ctx); 456 } 457 458 template<bool kSaveGState, typename RectT> 459 BL_INLINE void CoreGraphicsModule::render_styled_rect(const RectT& rect, StyleKind style, RenderOp op) noexcept { 460 CGContextAddRect(_cg_ctx, to_cg_rect(rect)); 461 render_styled_path<kSaveGState>(rect, style, op); 462 } 463 464 void CoreGraphicsModule::render_rect_a(RenderOp op) { 465 BLSizeI bounds(_params.screen_w, _params.screen_h); 466 StyleKind style = _params.style; 467 int wh = _params.shape_size; 468 469 if (style == StyleKind::kSolid) { 470 for (uint32_t i = 0, quantity = _params.quantity; i < quantity; i++) { 471 render_solid_rect(_rnd_coord.next_rect_i(bounds, wh, wh), op); 472 } 473 } 474 else if ((style == StyleKind::kPatternNN || style == StyleKind::kPatternBI) && op != RenderOp::kStroke) { 475 CGFloat wh_f = CGFloat(wh); 476 for (uint32_t i = 0, quantity = _params.quantity; i < quantity; i++) { 477 BLRectI r = _rnd_coord.next_rect_i(bounds, wh, wh); 478 uint32_t spriteId = nextSpriteId(); 479 480 CGContextDrawImage(_cg_ctx, CGRectMake(CGFloat(r.x), CGFloat(r.y), wh_f, wh_f), _cg_sprites[spriteId]); 481 } 482 } 483 else { 484 for (uint32_t i = 0, quantity = _params.quantity; i < quantity; i++) { 485 render_styled_rect<true>(_rnd_coord.next_rect_i(bounds, wh, wh), style, op); 486 } 487 } 488 } 489 490 void CoreGraphicsModule::render_rect_f(RenderOp op) { 491 BLSize bounds(_params.screen_w, _params.screen_h); 492 StyleKind style = _params.style; 493 double wh = _params.shape_size; 494 495 if (style == StyleKind::kSolid) { 496 for (uint32_t i = 0, quantity = _params.quantity; i < quantity; i++) { 497 render_solid_rect(_rnd_coord.next_rect(bounds, wh, wh), op); 498 } 499 } 500 else { 501 for (uint32_t i = 0, quantity = _params.quantity; i < quantity; i++) { 502 render_styled_rect<true>(_rnd_coord.next_rect(bounds, wh, wh), style, op); 503 } 504 } 505 } 506 507 void CoreGraphicsModule::render_rect_rotated(RenderOp op) { 508 BLSize bounds(_params.screen_w, _params.screen_h); 509 StyleKind style = _params.style; 510 511 double cx = double(_params.screen_w) * 0.5; 512 double cy = double(_params.screen_h) * 0.5; 513 double wh = _params.shape_size; 514 double angle = 0.0; 515 516 for (uint32_t i = 0, quantity = _params.quantity; i < quantity; i++, angle += 0.01) { 517 BLRect rect(_rnd_coord.next_rect(bounds, wh, wh)); 518 519 CGContextSaveGState(_cg_ctx); 520 CGContextTranslateCTM(_cg_ctx, CGFloat(cx), CGFloat(cy)); 521 CGContextRotateCTM(_cg_ctx, CGFloat(angle)); 522 CGContextTranslateCTM(_cg_ctx, CGFloat(-cx), CGFloat(-cy)); 523 524 if (style == StyleKind::kSolid) { 525 render_solid_rect(rect, op); 526 } 527 else { 528 render_styled_rect<false>(rect, style, op); 529 } 530 531 CGContextRestoreGState(_cg_ctx); 532 } 533 } 534 535 void CoreGraphicsModule::render_round_f(RenderOp op) { 536 BLSize bounds(_params.screen_w, _params.screen_h); 537 StyleKind style = _params.style; 538 double wh = _params.shape_size; 539 540 for (uint32_t i = 0, quantity = _params.quantity; i < quantity; i++) { 541 BLRect rect(_rnd_coord.next_rect(bounds, wh, wh)); 542 double radius = _rnd_extra.next_double(4.0, 40.0); 543 544 CGPathRef path = CGPathCreateWithRoundedRect( 545 CGRectMake(rect.x, rect.y, rect.w, rect.h), 546 std::min(rect.w * 0.5, radius), 547 std::min(rect.h * 0.5, radius), 548 nullptr); 549 550 CGContextAddPath(_cg_ctx, path); 551 552 if (style == StyleKind::kSolid) { 553 render_solid_path(op); 554 } 555 else { 556 render_styled_path<true>(rect, style, op); 557 } 558 559 CGPathRelease(path); 560 } 561 } 562 563 void CoreGraphicsModule::render_round_rotated(RenderOp op) { 564 BLSize bounds(_params.screen_w, _params.screen_h); 565 StyleKind style = _params.style; 566 567 double cx = double(_params.screen_w) * 0.5; 568 double cy = double(_params.screen_h) * 0.5; 569 double wh = _params.shape_size; 570 double angle = 0.0; 571 572 for (uint32_t i = 0, quantity = _params.quantity; i < quantity; i++, angle += 0.01) { 573 BLRect rect(_rnd_coord.next_rect(bounds, wh, wh)); 574 double radius = _rnd_extra.next_double(4.0, 40.0); 575 576 CGContextSaveGState(_cg_ctx); 577 CGContextTranslateCTM(_cg_ctx, CGFloat(cx), CGFloat(cy)); 578 CGContextRotateCTM(_cg_ctx, CGFloat(angle)); 579 CGContextTranslateCTM(_cg_ctx, CGFloat(-cx), CGFloat(-cy)); 580 581 CGPathRef path = CGPathCreateWithRoundedRect( 582 CGRectMake(rect.x, rect.y, rect.w, rect.h), 583 std::min(rect.w * 0.5, radius), 584 std::min(rect.h * 0.5, radius), 585 nullptr); 586 587 CGContextAddPath(_cg_ctx, path); 588 589 if (style == StyleKind::kSolid) { 590 render_solid_path(op); 591 } 592 else { 593 render_styled_path<false>(rect, style, op); 594 } 595 596 CGPathRelease(path); 597 CGContextRestoreGState(_cg_ctx); 598 } 599 } 600 601 void CoreGraphicsModule::render_polygon(RenderOp op, uint32_t complexity) { 602 BLSizeI bounds(_params.screen_w - _params.shape_size, 603 _params.screen_h - _params.shape_size); 604 StyleKind style = _params.style; 605 double wh = double(_params.shape_size); 606 607 for (uint32_t i = 0, quantity = _params.quantity; i < quantity; i++) { 608 BLPoint base(_rnd_coord.nextPoint(bounds)); 609 610 double x = _rnd_coord.next_double(base.x, base.x + wh); 611 double y = _rnd_coord.next_double(base.y, base.y + wh); 612 613 CGContextMoveToPoint(_cg_ctx, CGFloat(x), CGFloat(y)); 614 for (uint32_t p = 1; p < complexity; p++) { 615 x = _rnd_coord.next_double(base.x, base.x + wh); 616 y = _rnd_coord.next_double(base.y, base.y + wh); 617 CGContextAddLineToPoint(_cg_ctx, CGFloat(x), CGFloat(y)); 618 } 619 CGContextClosePath(_cg_ctx); 620 621 if (style == StyleKind::kSolid) { 622 render_solid_path(op); 623 } 624 else { 625 render_styled_path<true>(BLRect(x, y, wh, wh), style, op); 626 } 627 } 628 } 629 630 void CoreGraphicsModule::render_shape(RenderOp op, ShapeData shape) { 631 BLSizeI bounds(_params.screen_w - _params.shape_size, 632 _params.screen_h - _params.shape_size); 633 StyleKind style = _params.style; 634 double wh = double(_params.shape_size); 635 636 CGMutablePathRef path = CGPathCreateMutable(); 637 ShapeIterator it(shape); 638 639 while (it.has_command()) { 640 if (it.is_move_to()) { 641 CGPathMoveToPoint( 642 path, 643 nullptr, 644 it.x(0) * wh, it.y(0) * wh); 645 } 646 else if (it.is_line_to()) { 647 CGPathAddLineToPoint( 648 path, 649 nullptr, 650 it.x(0) * wh, it.y(0) * wh); 651 } 652 else if (it.is_quad_to()) { 653 CGPathAddQuadCurveToPoint( 654 path, 655 nullptr, 656 it.x(0) * wh, it.y(0) * wh, 657 it.x(1) * wh, it.y(1) * wh); 658 } 659 else if (it.is_cubic_to()) { 660 CGPathAddCurveToPoint( 661 path, 662 nullptr, 663 it.x(0) * wh, it.y(0) * wh, 664 it.x(1) * wh, it.y(1) * wh, 665 it.x(2) * wh, it.y(2) * wh); 666 } 667 else { 668 CGPathCloseSubpath(path); 669 } 670 it.next(); 671 } 672 673 for (uint32_t i = 0, quantity = _params.quantity; i < quantity; i++) { 674 BLPoint base(_rnd_coord.nextPoint(bounds)); 675 676 CGContextSaveGState(_cg_ctx); 677 CGContextTranslateCTM(_cg_ctx, CGFloat(base.x), CGFloat(base.y)); 678 CGContextAddPath(_cg_ctx, path); 679 680 if (style == StyleKind::kSolid) { 681 render_solid_path(op); 682 } 683 else { 684 render_styled_path<false>(BLRect(base.x, base.y, wh, wh), style, op); 685 } 686 687 CGContextRestoreGState(_cg_ctx); 688 } 689 690 CGPathRelease(path); 691 } 692 693 Backend* create_cg_backend() { 694 return new CoreGraphicsModule(); 695 } 696 697 } // {blbench} 698 699 #endif // BL_BENCH_ENABLE_COREGRAPHICS