1 module skia.SKTextBlob; 2 3 import skia.Exceptions; 4 import skia.SkiaApi; 5 import skia.SKObject; 6 import skia.Util; 7 import skia.SKFont; 8 import skia.Definitions; 9 import skia.MathTypes; 10 import skia.SKPath; 11 import skia.SKPaint; 12 import skia.SKRunBuffer; 13 import skia.SKPathMeasure; 14 15 import std.typecons; 16 import std.experimental.logger; 17 18 /** 19 * 20 */ 21 class SKTextBlob : SKObject, ISKNonVirtualReferenceCounted, ISKSkipObjectRegistration { 22 this(void* x, bool owns) { 23 super(x, owns); 24 } 25 26 void ReferenceNative() { 27 return SkiaApi.sk_textblob_ref(cast(sk_textblob_t*) Handle); 28 } 29 30 void UnreferenceNative() { 31 return SkiaApi.sk_textblob_unref(cast(sk_textblob_t*) Handle); 32 } 33 34 SKRect Bounds() { 35 SKRect bounds; 36 SkiaApi.sk_textblob_get_bounds(cast(sk_textblob_t*) Handle, &bounds); 37 return bounds; 38 } 39 40 uint UniqueId() { 41 return SkiaApi.sk_textblob_get_unique_id(cast(sk_textblob_t*) Handle); 42 } 43 44 // Create 45 46 static SKTextBlob Create(string text, SKFont font, SKPoint origin = SKPoint.Empty) { 47 return Create(cast(const(byte)[]) text, SKTextEncoding.Utf8, font, origin); 48 } 49 50 // static SKTextBlob Create (const(char)[] text, SKFont font, SKPoint origin = SKPoint.Empty) 51 // { 52 // void* t = text.ptr; 53 // return Create (t, text.length * 2, SKTextEncoding.Utf16, font, origin); 54 // } 55 56 // static SKTextBlob Create (void* text, int length, SKTextEncoding encoding, SKFont font, SKPoint origin = SKPoint.Empty) 57 // { 58 // return Create (text.AsReadOnlySpan (length), encoding, font, origin); 59 // } 60 61 static SKTextBlob Create(const(byte)[] text, SKTextEncoding encoding, 62 SKFont font, SKPoint origin = SKPoint.Empty) { 63 void* t = cast(void*) text.ptr; 64 return Create(t, cast(int) text.length, encoding, font, origin); 65 } 66 67 static SKTextBlob Create(void* text, int length, SKTextEncoding encoding, 68 SKFont font, SKPoint origin = SKPoint.Empty) { 69 if (font is null) 70 throw new ArgumentNullException(font.stringof); 71 72 auto count = font.CountGlyphs(text, length, encoding); 73 if (count <= 0) 74 return null; 75 76 SKTextBlobBuilder builder = new SKTextBlobBuilder(); 77 scope (exit) { 78 builder.Dispose(); 79 } 80 81 SKPositionedRunBuffer buffer = builder.AllocatePositionedRun(font, count); 82 font.GetGlyphs(text, length, encoding, buffer.GetGlyphSpan()); 83 font.GetGlyphPositions(buffer.GetGlyphSpan(), buffer.GetPositionSpan(), origin); 84 85 return builder.Build(); 86 } 87 88 // CreateHorizontal 89 90 static SKTextBlob CreateHorizontal(string text, SKFont font, const(float)[] positions, float y) { 91 return CreateHorizontal(cast(const(char)[]) text, font, positions, y); 92 } 93 94 static SKTextBlob CreateHorizontal(const(char)[] text, SKFont font, 95 const(float)[] positions, float y) { 96 void* t = cast(void*) text.ptr; 97 return CreateHorizontal(t, cast(int) text.length, SKTextEncoding.Utf8, font, positions, y); 98 } 99 100 // static SKTextBlob CreateHorizontal (void* text, int length, SKTextEncoding encoding, SKFont font, const(float)[] positions, float y) 101 // { 102 // return CreateHorizontal (text.AsReadOnlySpan (length), encoding, font, positions, y); 103 // } 104 105 static SKTextBlob CreateHorizontal(const(byte)[] text, 106 SKTextEncoding encoding, SKFont font, const(float)[] positions, float y) { 107 void* t = cast(void*) text.ptr; 108 return CreateHorizontal(t, cast(int) text.length, encoding, font, positions, y); 109 } 110 111 static SKTextBlob CreateHorizontal(void* text, int length, 112 SKTextEncoding encoding, SKFont font, const(float)[] positions, float y) { 113 if (font is null) 114 throw new ArgumentNullException(font.stringof); 115 116 auto count = font.CountGlyphs(text, length, encoding); 117 if (count <= 0) 118 return null; 119 120 auto builder = new SKTextBlobBuilder(); 121 scope (exit) { 122 builder.Dispose(); 123 } 124 125 auto buffer = builder.AllocateHorizontalRun(font, count, y); 126 font.GetGlyphs(text, length, encoding, buffer.GetGlyphSpan()); 127 // positions.CopyTo (buffer.GetPositionSpan ()); 128 return builder.Build(); 129 } 130 131 // CreatePositioned 132 133 static SKTextBlob CreatePositioned(string text, SKFont font, const(SKPoint)[] positions) { 134 return CreatePositioned(cast(const(char)[]) text, font, positions); 135 } 136 137 static SKTextBlob CreatePositioned(const(char)[] text, SKFont font, const(SKPoint)[] positions) { 138 void* t = cast(void*) text.ptr; 139 return CreatePositioned(t, cast(int) text.length, SKTextEncoding.Utf8, font, positions); 140 } 141 142 // static SKTextBlob CreatePositioned (void* text, int length, SKTextEncoding encoding, SKFont font, const(SKPoint)[] positions) 143 // { 144 // return CreatePositioned (text.AsReadOnlySpan (length), encoding, font, positions); 145 // } 146 147 static SKTextBlob CreatePositioned(const(byte)[] text, 148 SKTextEncoding encoding, SKFont font, const(SKPoint)[] positions) { 149 void* t = cast(void*) text.ptr; 150 return CreatePositioned(t, cast(int) text.length, encoding, font, positions); 151 } 152 153 static SKTextBlob CreatePositioned(void* text, int length, 154 SKTextEncoding encoding, SKFont font, const(SKPoint)[] positions) { 155 if (font is null) 156 throw new ArgumentNullException(font.stringof); 157 158 auto count = font.CountGlyphs(text, length, encoding); 159 if (count <= 0) 160 return null; 161 162 auto builder = new SKTextBlobBuilder(); 163 scope (exit) { 164 builder.Dispose(); 165 } 166 167 auto buffer = builder.AllocatePositionedRun(font, count); 168 font.GetGlyphs(text, length, encoding, buffer.GetGlyphSpan()); 169 // positions.CopyTo (buffer.GetPositionSpan ()); 170 return builder.Build(); 171 } 172 173 // CreateRotationScale 174 175 static SKTextBlob CreateRotationScale(string text, SKFont font, 176 const(SKRotationScaleMatrix)[] positions) { 177 return CreateRotationScale(cast(const(char)[]) text, font, positions); 178 } 179 180 static SKTextBlob CreateRotationScale(const(char)[] text, SKFont font, 181 const(SKRotationScaleMatrix)[] positions) { 182 void* t = cast(void*) text.ptr; 183 // return CreateRotationScale (t, cast(int)text.length * 2, SKTextEncoding.Utf16, font, positions); 184 return CreateRotationScale(t, cast(int) text.length, SKTextEncoding.Utf8, font, positions); 185 } 186 187 // static SKTextBlob CreateRotationScale (void* text, int length, SKTextEncoding encoding, SKFont font, const(SKRotationScaleMatrix)[] positions) 188 // { 189 // return CreateRotationScale (text.AsReadOnlySpan (length), encoding, font, positions); 190 // } 191 192 static SKTextBlob CreateRotationScale(const(byte)[] text, 193 SKTextEncoding encoding, SKFont font, const(SKRotationScaleMatrix)[] positions) { 194 void* t = cast(void*) text.ptr; 195 return CreateRotationScale(t, cast(int) text.length, encoding, font, positions); 196 } 197 198 static SKTextBlob CreateRotationScale(void* text, int length, 199 SKTextEncoding encoding, SKFont font, const(SKRotationScaleMatrix)[] positions) { 200 if (font is null) 201 throw new ArgumentNullException(font.stringof); 202 203 auto count = font.CountGlyphs(text, length, encoding); 204 if (count <= 0) 205 return null; 206 207 auto builder = new SKTextBlobBuilder(); 208 scope (exit) { 209 builder.Dispose(); 210 } 211 212 auto buffer = builder.AllocateRotationScaleRun(font, count); 213 font.GetGlyphs(text, length, encoding, buffer.GetGlyphSpan()); 214 // positions.CopyTo (buffer.GetRotationScaleSpan ()); 215 return builder.Build(); 216 } 217 218 // CreatePathPositioned 219 220 static SKTextBlob CreatePathPositioned(string text, SKFont font, SKPath path, 221 SKTextAlign textAlign = SKTextAlign.Left, SKPoint origin = SKPoint.Empty) { 222 return CreatePathPositioned(cast(const(char)[]) text, font, path, textAlign, origin); 223 } 224 225 static SKTextBlob CreatePathPositioned(const(char)[] text, SKFont font, SKPath path, 226 SKTextAlign textAlign = SKTextAlign.Left, SKPoint origin = SKPoint.Empty) { 227 void* t = cast(void*) text.ptr; 228 return CreatePathPositioned(t, cast(int) text.length, 229 SKTextEncoding.Utf8, font, path, textAlign, origin); 230 } 231 232 // static SKTextBlob CreatePathPositioned (void* text, int length, SKTextEncoding encoding, SKFont font, SKPath path, SKTextAlign textAlign = SKTextAlign.Left, SKPoint origin = SKPoint.Empty) 233 // { 234 // return CreatePathPositioned (text.AsReadOnlySpan (length), encoding, font, path, textAlign, origin); 235 // } 236 237 static SKTextBlob CreatePathPositioned(const(byte)[] text, SKTextEncoding encoding, SKFont font, 238 SKPath path, SKTextAlign textAlign = SKTextAlign.Left, SKPoint origin = SKPoint.Empty) { 239 void* t = cast(void*) text.ptr; 240 return CreatePathPositioned(t, cast(int) text.length, encoding, font, 241 path, textAlign, origin); 242 } 243 244 static SKTextBlob CreatePathPositioned(void* text, int length, SKTextEncoding encoding, SKFont font, 245 SKPath path, SKTextAlign textAlign = SKTextAlign.Left, SKPoint origin = SKPoint.Empty) { 246 if (font is null) 247 throw new ArgumentNullException(font.stringof); 248 249 auto count = font.CountGlyphs(text, length, encoding); 250 if (count <= 0) 251 return null; 252 253 // we use temporary arrays because we might only use part of the text 254 // Utils.RentArray!(ushort) glyphs = Utils.RentArray!(ushort) (count); 255 ushort[] glyphs = new ushort[count]; 256 // auto glyphWidths = Utils.RentArray!(float) (glyphs.length); 257 float[] glyphWidths = new float[glyphs.length]; 258 // scope(exit) { 259 // glyphWidths.Dispose(); 260 // } 261 262 // auto glyphOffsets = Utils.RentArray!SKPoint (glyphs.length); 263 SKPoint[] glyphOffsets = new SKPoint[glyphs.length]; 264 // scope(exit) { 265 // glyphOffsets.Dispose(); 266 // } 267 268 font.GetGlyphs(text, length, encoding, glyphs); 269 font.GetGlyphWidths(glyphs, glyphWidths, null); 270 font.GetGlyphPositions(glyphs, glyphOffsets, origin); 271 272 auto builder = new SKTextBlobBuilder(); 273 scope (exit) { 274 builder.Dispose(); 275 } 276 277 builder.AddPathPositionedRun(glyphs, font, glyphWidths, glyphOffsets, path, textAlign); 278 return builder.Build(); 279 } 280 281 // GetIntercepts 282 283 float[] GetIntercepts(float upperBounds, float lowerBounds, SKPaint paint = null) { 284 int n = CountIntercepts(upperBounds, lowerBounds, paint); 285 auto intervals = new float[n]; 286 GetIntercepts(upperBounds, lowerBounds, intervals, paint); 287 return intervals; 288 } 289 290 void GetIntercepts(float upperBounds, float lowerBounds, float[] intervals, SKPaint paint = null) { 291 auto bounds = new float[2]; 292 bounds[0] = upperBounds; 293 bounds[1] = lowerBounds; 294 float* i = intervals.ptr; 295 void* handle = null; 296 if (paint !is null && paint.Handle !is null) { 297 handle = paint.Handle; 298 } 299 SkiaApi.sk_textblob_get_intercepts(cast(sk_textblob_t*) Handle, 300 bounds.ptr, i, cast(sk_paint_t*) handle); 301 } 302 303 // CountIntercepts 304 305 int CountIntercepts(float upperBounds, float lowerBounds, SKPaint paint = null) { 306 auto bounds = new float[2]; 307 bounds[0] = upperBounds; 308 bounds[1] = lowerBounds; 309 void* handle = null; 310 if (paint !is null && paint.Handle !is null) { 311 handle = paint.Handle; 312 } 313 return SkiaApi.sk_textblob_get_intercepts(cast(sk_textblob_t*) Handle, 314 bounds.ptr, null, cast(sk_paint_t*) handle); 315 } 316 317 // 318 319 static SKTextBlob GetObject(void* handle) { 320 return handle is null ? null : new SKTextBlob(handle, true); 321 } 322 } 323 324 /** 325 * 326 */ 327 class SKTextBlobBuilder : SKObject, ISKSkipObjectRegistration { 328 this(void* x, bool owns) { 329 super(x, owns); 330 } 331 332 this() { 333 this(SkiaApi.sk_textblob_builder_new(), true); 334 } 335 336 // protected override void Dispose(bool disposing) { 337 // return super.Dispose(disposing); 338 // } 339 340 protected override void DisposeNative() { 341 return SkiaApi.sk_textblob_builder_delete(cast(sk_textblob_builder_t*) Handle); 342 } 343 344 // override void Dispose() { 345 // return super.Dispose(); 346 // } 347 348 // Build 349 350 SKTextBlob Build() { 351 auto blob = SKTextBlob.GetObject( 352 SkiaApi.sk_textblob_builder_make(cast(sk_textblob_builder_t*) Handle)); 353 // GC.KeepAlive (this); 354 return blob; 355 } 356 357 // AddRun 358 359 void AddRun(const(ushort)[] glyphs, SKFont font, SKPoint origin = SKPoint.Empty) { 360 if (font is null) 361 throw new ArgumentNullException(font.stringof); 362 363 auto buffer = AllocatePositionedRun(font, cast(int) glyphs.length); 364 // glyphs.CopyTo (buffer.GetGlyphSpan ()); 365 font.GetGlyphPositions(buffer.GetGlyphSpan(), buffer.GetPositionSpan(), origin); 366 } 367 368 // AddHorizontalRun 369 370 void AddHorizontalRun(const(ushort)[] glyphs, SKFont font, const(float)[] positions, float y) { 371 if (font is null) 372 throw new ArgumentNullException(font.stringof); 373 374 auto buffer = AllocateHorizontalRun(font, cast(int) glyphs.length, y); 375 // glyphs.CopyTo (buffer.GetGlyphSpan ()); 376 // positions.CopyTo (buffer.GetPositionSpan ()); 377 } 378 379 // AddPositionedRun 380 381 void AddPositionedRun(const(ushort)[] glyphs, SKFont font, const(SKPoint)[] positions) { 382 if (font is null) 383 throw new ArgumentNullException(font.stringof); 384 385 auto buffer = AllocatePositionedRun(font, cast(int) glyphs.length); 386 // glyphs.CopyTo (buffer.GetGlyphSpan ()); 387 // positions.CopyTo (buffer.GetPositionSpan ()); 388 } 389 390 // AddRotationScaleRun 391 392 void AddRotationScaleRun(const(ushort)[] glyphs, SKFont font, 393 const(SKRotationScaleMatrix)[] positions) { 394 if (font is null) 395 throw new ArgumentNullException(font.stringof); 396 397 auto buffer = AllocateRotationScaleRun(font, cast(int) glyphs.length); 398 // glyphs.CopyTo (buffer.GetGlyphSpan ()); 399 // positions.CopyTo (buffer.GetRotationScaleSpan ()); 400 } 401 402 // AddPathPositionedRun 403 404 void AddPathPositionedRun(const(ushort)[] glyphs, SKFont font, const(float)[] glyphWidths, 405 SKPoint[] glyphOffsets, SKPath path, SKTextAlign textAlign = SKTextAlign.Left) { 406 auto pathMeasure = new SKPathMeasure(path); 407 scope (exit) { 408 pathMeasure.Dispose(); 409 } 410 411 auto contourLength = pathMeasure.Length(); 412 413 auto textLength = glyphOffsets[glyphs.length - 1].X + glyphWidths[glyphs.length - 1]; 414 auto alignment = cast(int) textAlign * 0.5f; 415 auto startOffset = glyphOffsets[0].X + (contourLength - textLength) * alignment; 416 417 auto firstGlyphIndex = 0; 418 auto pathGlyphCount = 0; 419 420 // auto glyphTransforms = Utils.RentArray<SKRotationScaleMatrix> (glyphs.length); 421 // scope(exit) { 422 // glyphTransforms.Dispose(); 423 // } 424 SKRotationScaleMatrix[] glyphTransforms = new SKRotationScaleMatrix[glyphs.length]; 425 426 // TODO: deal with multiple contours? 427 for (int index = 0; index < glyphOffsets.length; index++) { 428 auto glyphOffset = glyphOffsets[index]; 429 auto halfWidth = glyphWidths[index] * 0.5f; 430 auto pathOffset = startOffset + glyphOffset.X + halfWidth; 431 432 // TODO: clip glyphs on both ends of paths 433 SKPoint position; 434 SKPoint tangent; 435 436 if (pathOffset >= 0 && pathOffset < contourLength 437 && pathMeasure.GetPositionAndTangent(pathOffset, position, tangent)) { 438 if (pathGlyphCount == 0) 439 firstGlyphIndex = index; 440 441 auto tx = tangent.X; 442 auto ty = tangent.Y; 443 444 auto px = position.X; 445 auto py = position.Y; 446 447 // horizontally offset the position using the tangent vector 448 px -= tx * halfWidth; 449 py -= ty * halfWidth; 450 451 // vertically offset the position using the normal vector (-ty, tx) 452 auto dy = glyphOffset.Y; 453 px -= dy * ty; 454 py += dy * tx; 455 456 glyphTransforms[pathGlyphCount++] = SKRotationScaleMatrix(tx, ty, px, py); 457 } 458 } 459 460 auto glyphSubset = glyphs[firstGlyphIndex .. firstGlyphIndex + pathGlyphCount]; 461 auto positions = glyphTransforms[0 .. pathGlyphCount]; 462 463 AddRotationScaleRun(glyphSubset, font, positions); 464 } 465 466 // AllocateRun 467 468 SKRunBuffer AllocateRun(SKFont font, int count, float x, float y, Nullable!SKRect bounds) { 469 if (font is null) 470 throw new ArgumentNullException(font.stringof); 471 472 SKRunBufferInternal runbuffer; 473 474 if (!bounds.isNull) { 475 SKRect b = bounds.get(); 476 SkiaApi.sk_textblob_builder_alloc_run(cast(sk_textblob_builder_t*) Handle, 477 cast(sk_font_t*) font.Handle, count, x, y, &b, &runbuffer); 478 } else { 479 SkiaApi.sk_textblob_builder_alloc_run(cast(sk_textblob_builder_t*) Handle, 480 cast(sk_font_t*) font.Handle, count, x, y, null, &runbuffer); 481 } 482 483 return new SKRunBuffer(runbuffer, count); 484 } 485 486 // AllocateHorizontalRun 487 SKHorizontalRunBuffer AllocateHorizontalRun(SKFont font, int count, float y) { 488 // return AllocateHorizontalRun ( font, count, y, SKRect()); 489 return null; 490 } 491 492 SKHorizontalRunBuffer AllocateHorizontalRun(SKFont font, int count, float y, 493 Nullable!SKRect bounds) { 494 if (font is null) 495 throw new ArgumentNullException(font.stringof); 496 497 SKRunBufferInternal runbuffer; 498 499 if (!bounds.isNull) { 500 SKRect b = bounds.get(); 501 SkiaApi.sk_textblob_builder_alloc_run_pos_h(cast(sk_textblob_builder_t*) Handle, 502 cast(sk_font_t*) font.Handle, count, y, &b, &runbuffer); 503 } else { 504 SkiaApi.sk_textblob_builder_alloc_run_pos_h(cast(sk_textblob_builder_t*) Handle, 505 cast(sk_font_t*) font.Handle, count, y, null, &runbuffer); 506 } 507 508 return new SKHorizontalRunBuffer(runbuffer, count); 509 } 510 511 // AllocatePositionedRun 512 513 SKPositionedRunBuffer AllocatePositionedRun(SKFont font, int count, 514 Nullable!SKRect bounds = Nullable!SKRect.init) { 515 if (font is null) 516 throw new ArgumentNullException(font.stringof); 517 518 SKRunBufferInternal runbuffer; 519 520 if (bounds.isNull) { 521 SkiaApi.sk_textblob_builder_alloc_run_pos(cast(sk_textblob_builder_t*) Handle, 522 cast(sk_font_t*) font.Handle, count, null, &runbuffer); 523 } else { 524 warning("22"); 525 SKRect b = bounds.get(); 526 SkiaApi.sk_textblob_builder_alloc_run_pos(cast(sk_textblob_builder_t*) Handle, 527 cast(sk_font_t*) font.Handle, count, &b, &runbuffer); 528 } 529 530 return new SKPositionedRunBuffer(runbuffer, count); 531 } 532 533 // AllocateRotationScaleRun 534 535 SKRotationScaleRunBuffer AllocateRotationScaleRun(SKFont font, int count) { 536 if (font is null) 537 throw new ArgumentNullException(font.stringof); 538 539 SKRunBufferInternal runbuffer; 540 SkiaApi.sk_textblob_builder_alloc_run_rsxform(cast(sk_textblob_builder_t*) Handle, 541 cast(sk_font_t*) font.Handle, count, &runbuffer); 542 543 return new SKRotationScaleRunBuffer(runbuffer, count); 544 } 545 546 // OBSOLETE OVERLOADS 547 548 // AddRun 549 550 void AddRun(SKPaint font, float x, float y, ushort[] glyphs, string text, uint[] clusters) { 551 auto utf8Text = StringUtilities.GetEncodedText(text, SKTextEncoding.Utf8); 552 AddRun(font, x, y, glyphs, utf8Text, clusters); 553 } 554 555 void AddRun(SKPaint font, float x, float y, ushort[] glyphs, string text, 556 uint[] clusters, SKRect bounds) { 557 auto utf8Text = StringUtilities.GetEncodedText(text, SKTextEncoding.Utf8); 558 AddRun(font, x, y, glyphs, utf8Text, clusters, bounds); 559 } 560 561 void AddRun(SKPaint font, float x, float y, ushort[] glyphs) { 562 // return AddRun (font, x, y, glyphs, const(byte)[].Empty, null, null); 563 564 // return AddRun (font, x, y, glyphs, (const(byte)[]).init, null, null); 565 } 566 567 void AddRun(SKPaint font, float x, float y, ushort[] glyphs, SKRect bounds) { 568 AddRun(font, x, y, glyphs, (const(byte)[]).init, null, bounds); 569 } 570 571 void AddRun(SKPaint font, float x, float y, ushort[] glyphs, byte[] text, uint[] clusters) { 572 // AddRun (font, x, y, glyphs, text, clusters, null); 573 } 574 575 void AddRun(SKPaint font, float x, float y, ushort[] glyphs, byte[] text, 576 uint[] clusters, SKRect bounds) { 577 AddRun(font, x, y, glyphs, text, clusters, bounds); 578 } 579 580 // AddRun (spans) 581 582 void AddRun(SKPaint font, float x, float y, const(ushort)[] glyphs) { 583 // AddRun (font, x, y, glyphs, (const(byte)[]).init, null, null); 584 } 585 586 // void AddRun (SKPaint font, float x, float y, const(ushort)[] glyphs1 Nullable!SKRect bounds) 587 // { 588 // return AddRun (font, x, y, glyphs, (const(byte)[]).init, null, bounds); 589 // } 590 591 void AddRun(SKPaint font, float x, float y, const(ushort)[] glyphs, 592 const(byte)[] text, const(uint)[] clusters) { 593 // AddRun (font, x, y, glyphs, text, clusters, null); 594 } 595 596 // void AddRun (SKPaint font, float x, float y, const(ushort)[] glyphs, const(byte)[] text, const(uint)[] clusters1 Nullable!SKRect bounds) 597 // { 598 // if (font is null) 599 // throw new ArgumentNullException (font.stringof); 600 // if (glyphs.empty()) 601 // throw new ArgumentNullException (glyphs.stringof); 602 603 // if (!text.empty()) { 604 // if (clusters.empty()) 605 // throw new ArgumentNullException (clusters.stringof); 606 // if (glyphs.length != clusters.length) 607 // throw new ArgumentException ("The number of glyphs and clusters must be the same."); 608 // } 609 610 // auto run = AllocateRun (font, glyphs.length, x, y, text.empty() ? 0 : text.length, bounds); 611 // run.SetGlyphs (glyphs); 612 613 // if (!text.empty()) { 614 // run.SetText (text); 615 // run.SetClusters (clusters); 616 // } 617 // } 618 619 // AddHorizontalRun 620 621 void AddHorizontalRun(SKPaint font, float y, ushort[] glyphs, 622 float[] positions, string text, uint[] clusters) { 623 auto utf8Text = StringUtilities.GetEncodedText(text, SKTextEncoding.Utf8); 624 AddHorizontalRun(font, y, glyphs, positions, utf8Text, clusters); 625 } 626 627 void AddHorizontalRun(SKPaint font, float y, ushort[] glyphs, 628 float[] positions, string text, uint[] clusters, SKRect bounds) { 629 auto utf8Text = StringUtilities.GetEncodedText(text, SKTextEncoding.Utf8); 630 AddHorizontalRun(font, y, glyphs, positions, utf8Text, clusters, bounds); 631 } 632 633 void AddHorizontalRun(SKPaint font, float y, ushort[] glyphs, float[] positions) { 634 // AddHorizontalRun (font, y, glyphs, positions, (const(byte)[]).init, null, null); 635 } 636 637 void AddHorizontalRun(SKPaint font, float y, ushort[] glyphs, float[] positions, SKRect bounds) { 638 AddHorizontalRun(font, y, glyphs, positions, (const(byte)[]).init, null, bounds); 639 } 640 641 void AddHorizontalRun(SKPaint font, float y, ushort[] glyphs, 642 float[] positions, byte[] text, uint[] clusters) { 643 // AddHorizontalRun (font, y, glyphs, positions, text, clusters, null); 644 } 645 646 void AddHorizontalRun(SKPaint font, float y, ushort[] glyphs, 647 float[] positions, byte[] text, uint[] clusters, SKRect bounds) { 648 AddHorizontalRun(font, y, glyphs, positions, text, clusters, bounds); 649 } 650 651 // AddHorizontalRun (spans) 652 653 void AddHorizontalRun(SKPaint font, float y, const(ushort)[] glyphs, const(float)[] positions) { 654 // AddHorizontalRun (font, y, glyphs, positions, (const(byte)[]).init, null, null); 655 } 656 657 // void AddHorizontalRun (SKPaint font, float y, const(ushort)[] glyphs, const(float)[] positions1, Nullable!SKRect bounds) 658 // { 659 // return AddHorizontalRun (font, y, glyphs, positions, const(byte)[].Empty, null, bounds); 660 // } 661 662 void AddHorizontalRun(SKPaint font, float y, const(ushort)[] glyphs, 663 const(float)[] positions, const(byte)[] text, const(uint)[] clusters) { 664 // AddHorizontalRun (font, y, glyphs, positions, text, clusters, null); 665 } 666 667 // void AddHorizontalRun (SKPaint font, float y, const(ushort)[] glyphs, const(float)[] positions, const(byte)[] text, const(uint)[] clusters1 Nullable!SKRect bounds) 668 // { 669 // if (font is null) 670 // throw new ArgumentNullException (font.stringof); 671 // if (glyphs.empty()) 672 // throw new ArgumentNullException (glyphs.stringof); 673 // if (positions.empty()) 674 // throw new ArgumentNullException (positions.stringof); 675 // if (glyphs.length != positions.length) 676 // throw new ArgumentException ("The number of glyphs and positions must be the same."); 677 678 // if (!text.empty()) { 679 // if (clusters.empty()) 680 // throw new ArgumentNullException (clusters.stringof); 681 // if (glyphs.length != clusters.length) 682 // throw new ArgumentException ("The number of glyphs and clusters must be the same."); 683 // } 684 685 // auto run = AllocateHorizontalRun (font, glyphs.length, y, text.empty() ? 0 : text.length, bounds); 686 // run.SetGlyphs (glyphs); 687 // run.SetPositions (positions); 688 689 // if (!text.empty()) { 690 // run.SetText (text); 691 // run.SetClusters (clusters); 692 // } 693 // } 694 695 // AddPositionedRun 696 697 void AddPositionedRun(SKPaint font, ushort[] glyphs, SKPoint[] positions, 698 string text, uint[] clusters) { 699 auto utf8Text = StringUtilities.GetEncodedText(text, SKTextEncoding.Utf8); 700 AddPositionedRun(font, glyphs, positions, utf8Text, clusters); 701 } 702 703 void AddPositionedRun(SKPaint font, ushort[] glyphs, SKPoint[] positions, 704 string text, uint[] clusters, SKRect bounds) { 705 auto utf8Text = StringUtilities.GetEncodedText(text, SKTextEncoding.Utf8); 706 AddPositionedRun(font, glyphs, positions, utf8Text, clusters, bounds); 707 } 708 709 void AddPositionedRun(SKPaint font, ushort[] glyphs, SKPoint[] positions) { 710 // AddPositionedRun (font, glyphs, positions, (const(byte)[]).init, null, null); 711 } 712 713 void AddPositionedRun(SKPaint font, ushort[] glyphs, SKPoint[] positions, SKRect bounds) { 714 AddPositionedRun(font, glyphs, positions, (const(byte)[]).init, null, bounds); 715 } 716 717 void AddPositionedRun(SKPaint font, ushort[] glyphs, SKPoint[] positions, 718 byte[] text, uint[] clusters) { 719 // AddPositionedRun (font, glyphs, positions, text, clusters, null); 720 } 721 722 void AddPositionedRun(SKPaint font, ushort[] glyphs, SKPoint[] positions, 723 byte[] text, uint[] clusters, SKRect bounds) { 724 AddPositionedRun(font, glyphs, positions, text, clusters, bounds); 725 } 726 727 // AddPositionedRun (spans) 728 729 void AddPositionedRun(SKPaint font, const(ushort)[] glyphs, const(SKPoint)[] positions) { 730 // AddPositionedRun (font, glyphs, positions, (const(byte)[]).init, null, null); 731 } 732 733 // void AddPositionedRun (SKPaint font, const(ushort)[] glyphs, const(SKPoint)[] positions1 Nullable!SKRect bounds) 734 // { 735 // return AddPositionedRun (font, glyphs, positions, const(byte)[].Empty, null, bounds); 736 // } 737 738 void AddPositionedRun(SKPaint font, const(ushort)[] glyphs, 739 const(SKPoint)[] positions, const(byte)[] text, const(uint)[] clusters) { 740 // AddPositionedRun (font, glyphs, positions, text, clusters, null); 741 } 742 743 // void AddPositionedRun (SKPaint font, const(ushort)[] glyphs, const(SKPoint)[] positions, const(byte)[] text, const(uint)[] clusters1 Nullable!SKRect bounds) 744 // { 745 // if (font is null) 746 // throw new ArgumentNullException (font.stringof); 747 // if (glyphs.empty()) 748 // throw new ArgumentNullException (glyphs.stringof); 749 // if (positions.empty()) 750 // throw new ArgumentNullException (positions.stringof); 751 // if (glyphs.length != positions.length) 752 // throw new ArgumentException ("The number of glyphs and positions must be the same."); 753 754 // if (!text.empty()) { 755 // if (clusters.empty()) 756 // throw new ArgumentNullException (clusters.stringof); 757 // if (glyphs.length != clusters.length) 758 // throw new ArgumentException ("The number of glyphs and clusters must be the same."); 759 // } 760 761 // auto run = AllocatePositionedRun (font, glyphs.length, text.empty() ? 0 : text.length, bounds); 762 // run.SetGlyphs (glyphs); 763 // run.SetPositions (positions); 764 765 // if (!text.empty()) { 766 // run.SetText (text); 767 // run.SetClusters (clusters); 768 // } 769 // } 770 771 // AllocateRun 772 773 SKRunBuffer AllocateRun(SKPaint font, int count, float x, float y) { 774 // return AllocateRun (font, count, x, y, 0, null); 775 return null; 776 } 777 778 // SKRunBuffer AllocateRun (SKPaint font, int count, float x, float y1 Nullable!SKRect bounds) 779 // { 780 // return AllocateRun (font, count, x, y, 0, bounds); 781 // } 782 783 // SKRunBuffer AllocateRun (SKPaint font, int count, float x, float y, int textByteCount) 784 // { 785 // return AllocateRun (font, count, x, y, textByteCount); 786 // } 787 788 // SKRunBuffer AllocateRun (SKPaint font, int count, float x, float y, int textByteCount1 Nullable!SKRect bounds) 789 // { 790 // if (font is null) 791 // throw new ArgumentNullException (font.stringof); 792 793 // auto originalEncoding = font.TextEncoding; 794 // try { 795 // font.TextEncoding = SKTextEncoding.GlyphId; 796 797 // SKRunBufferInternal runbuffer; 798 // if (bounds is SKRect b) { 799 // SkiaApi.sk_textblob_builder_alloc_run_text (Handle, font.GetFont ().Handle, count, x, y, textByteCount, &b, &runbuffer); 800 // } else { 801 // SkiaApi.sk_textblob_builder_alloc_run_text (Handle, font.GetFont ().Handle, count, x, y, textByteCount, null, &runbuffer); 802 // } 803 804 // return new SKRunBuffer (runbuffer, count, textByteCount); 805 806 // } finally { 807 // font.TextEncoding = originalEncoding; 808 // } 809 // } 810 811 // AllocateHorizontalRun 812 813 SKHorizontalRunBuffer AllocateHorizontalRun(SKPaint font, int count, float y) { 814 return AllocateHorizontalRun(font, count, y, 0); 815 } 816 817 // SKHorizontalRunBuffer AllocateHorizontalRun (SKPaint font, int count, float y1 Nullable!SKRect bounds) 818 // { 819 // return AllocateHorizontalRun (font, count, y, 0, bounds); 820 // } 821 822 SKHorizontalRunBuffer AllocateHorizontalRun(SKPaint font, int count, float y, int textByteCount) { 823 return AllocateHorizontalRun(font, count, y, textByteCount); 824 } 825 826 // SKHorizontalRunBuffer AllocateHorizontalRun (SKPaint font, int count, float y, int textByteCount1 Nullable!SKRect bounds) 827 // { 828 // if (font is null) 829 // throw new ArgumentNullException (font.stringof); 830 831 // auto originalEncoding = font.TextEncoding; 832 // try { 833 // font.TextEncoding = SKTextEncoding.GlyphId; 834 835 // SKRunBufferInternal runbuffer; 836 // SKRect b = cast(SKRect)bounds; 837 // if (bounds is SKRect b) { 838 // SkiaApi.sk_textblob_builder_alloc_run_text_pos_h (Handle, font.GetFont ().Handle, count, y, textByteCount, &b, &runbuffer); 839 // } else { 840 // SkiaApi.sk_textblob_builder_alloc_run_text_pos_h (Handle, font.GetFont ().Handle, count, y, textByteCount, null, &runbuffer); 841 // } 842 843 // return new SKHorizontalRunBuffer (runbuffer, count, textByteCount); 844 // } finally { 845 // font.TextEncoding = originalEncoding; 846 // } 847 // } 848 849 // AllocatePositionedRun 850 851 // SKPositionedRunBuffer AllocatePositionedRun (SKPaint font, int count) 852 // { 853 // return AllocatePositionedRun (font, count, 0); 854 // } 855 856 // SKPositionedRunBuffer AllocatePositionedRun (SKPaint font, int count1 Nullable!SKRect bounds) 857 // { 858 // return AllocatePositionedRun (font, count, 0, bounds); 859 // } 860 861 // SKPositionedRunBuffer AllocatePositionedRun (SKPaint font, int count, int textByteCount) 862 // { 863 // return AllocatePositionedRun (font, count, textByteCount); 864 // } 865 866 // SKPositionedRunBuffer AllocatePositionedRun (SKPaint font, int count, int textByteCount1 Nullable!SKRect bounds) 867 // { 868 // if (font is null) 869 // throw new ArgumentNullException (font.stringof); 870 871 // auto originalEncoding = font.TextEncoding; 872 // try { 873 // font.TextEncoding = SKTextEncoding.GlyphId; 874 875 // SKRunBufferInternal runbuffer; 876 // if (bounds is SKRect b) { 877 // SkiaApi.sk_textblob_builder_alloc_run_text_pos (Handle, font.GetFont ().Handle, count, textByteCount, &b, &runbuffer); 878 // } else { 879 // SkiaApi.sk_textblob_builder_alloc_run_text_pos (Handle, font.GetFont ().Handle, count, textByteCount, null, &runbuffer); 880 // } 881 882 // return new SKPositionedRunBuffer (runbuffer, count, textByteCount); 883 // } finally { 884 // font.TextEncoding = originalEncoding; 885 // } 886 // } 887 }