Mike Reed | 235cb7f | 2018-12-03 10:57:53 -0500 | [diff] [blame] | 1 | #Topic Text_Blob
|
| 2 | #Alias Text_Blob_Reference ##
|
| 3 |
|
| 4 | #Class SkTextBlob
|
| 5 |
|
| 6 | #Code
|
| 7 | #Populate
|
| 8 | ##
|
| 9 |
|
| 10 | SkTextBlob combines multiple text runs into an immutable container. Each text
|
| 11 | run consists of Glyphs, Paint, and position. Only parts of Paint related to
|
| 12 | fonts and text rendering are used by run.
|
| 13 |
|
| 14 | # ------------------------------------------------------------------------------
|
| 15 |
|
| 16 | #Method const SkRect& bounds() const
|
| 17 | #In Property
|
| 18 | #Line # returns conservative bounding box ##
|
| 19 | #Populate
|
| 20 |
|
| 21 | #Example
|
| 22 | #Height 70
|
Cary Clark | fc93eb0 | 2018-11-24 22:32:31 -0500 | [diff] [blame] | 23 | SkTextBlobBuilder textBlobBuilder;
|
| 24 | const char bunny[] = "/(^x^)\\";
|
| 25 | const int len = sizeof(bunny) - 1;
|
| 26 | uint16_t glyphs[len];
|
| 27 | SkPaint paint;
|
| 28 | paint.textToGlyphs(bunny, len, glyphs);
|
Mike Reed | c86ec97 | 2018-12-05 15:09:24 -0500 | [diff] [blame] | 29 | paint.setTextEncoding(kGlyphID_SkTextEncoding);
|
Cary Clark | fc93eb0 | 2018-11-24 22:32:31 -0500 | [diff] [blame] | 30 | SkFont font;
|
| 31 | int runs[] = { 3, 1, 3 };
|
| 32 | SkPoint textPos = { 20, 50 };
|
| 33 | int glyphIndex = 0;
|
| 34 | for (auto runLen : runs) {
|
| 35 | font.setSize(1 == runLen ? 20 : 50);
|
| 36 | paint.setTextSize(1 == runLen ? 20 : 50);
|
| 37 | const SkTextBlobBuilder::RunBuffer& run =
|
| 38 | textBlobBuilder.allocRun(font, runLen, textPos.fX, textPos.fY);
|
| 39 | memcpy(run.glyphs, &glyphs[glyphIndex], sizeof(glyphs[0]) * runLen);
|
| 40 | textPos.fX += paint.measureText(&glyphs[glyphIndex], sizeof(glyphs[0]) * runLen, nullptr);
|
| 41 | glyphIndex += runLen;
|
| 42 | }
|
| 43 | sk_sp<const SkTextBlob> blob = textBlobBuilder.make();
|
| 44 | canvas->drawTextBlob(blob.get(), 0, 0, paint);
|
| 45 | paint.setStyle(SkPaint::kStroke_Style);
|
| 46 | canvas->drawRect(blob->bounds(), paint);
|
Mike Reed | 235cb7f | 2018-12-03 10:57:53 -0500 | [diff] [blame] | 47 | ##
|
| 48 |
|
| 49 | #SeeAlso SkPath::getBounds
|
| 50 |
|
| 51 | #Method ##
|
| 52 |
|
| 53 | # ------------------------------------------------------------------------------
|
| 54 |
|
| 55 | #Method uint32_t uniqueID() const
|
| 56 | #In Property
|
| 57 | #Line # returns identifier for Text_Blob ##
|
| 58 | #Populate
|
| 59 |
|
| 60 | #Example
|
Cary Clark | fc93eb0 | 2018-11-24 22:32:31 -0500 | [diff] [blame] | 61 | for (int index = 0; index < 2; ++index) {
|
| 62 | SkTextBlobBuilder textBlobBuilder;
|
| 63 | const char bunny[] = "/(^x^)\\";
|
| 64 | const int len = sizeof(bunny) - 1;
|
| 65 | uint16_t glyphs[len];
|
| 66 | SkPaint paint;
|
| 67 | paint.textToGlyphs(bunny, len, glyphs);
|
Mike Reed | c86ec97 | 2018-12-05 15:09:24 -0500 | [diff] [blame] | 68 | paint.setTextEncoding(kGlyphID_SkTextEncoding);
|
Cary Clark | fc93eb0 | 2018-11-24 22:32:31 -0500 | [diff] [blame] | 69 | paint.setTextScaleX(0.5);
|
| 70 | SkFont font;
|
| 71 | font.setScaleX(0.5);
|
| 72 | int runs[] = { 3, 1, 3 };
|
| 73 | SkPoint textPos = { 20, 50 };
|
| 74 | int glyphIndex = 0;
|
| 75 | for (auto runLen : runs) {
|
| 76 | font.setSize(1 == runLen ? 20 : 50);
|
| 77 | paint.setTextSize(1 == runLen ? 20 : 50);
|
| 78 | const SkTextBlobBuilder::RunBuffer& run =
|
| 79 | textBlobBuilder.allocRun(font, runLen, textPos.fX, textPos.fY);
|
| 80 | memcpy(run.glyphs, &glyphs[glyphIndex], sizeof(glyphs[0]) * runLen);
|
| 81 | textPos.fX += paint.measureText(&glyphs[glyphIndex], sizeof(glyphs[0]) * runLen, nullptr);
|
| 82 | glyphIndex += runLen;
|
| 83 | }
|
| 84 | sk_sp<const SkTextBlob> blob = textBlobBuilder.make();
|
| 85 | paint.reset();
|
| 86 | canvas->drawTextBlob(blob.get(), 0, 0, paint);
|
| 87 | std::string id = "unique ID:" + std::to_string(blob->uniqueID());
|
| 88 | canvas->drawString(id.c_str(), 30, blob->bounds().fBottom + 15, paint);
|
| 89 | canvas->translate(blob->bounds().fRight + 10, 0);
|
| 90 | }
|
Mike Reed | 235cb7f | 2018-12-03 10:57:53 -0500 | [diff] [blame] | 91 | ##
|
| 92 |
|
| 93 | #SeeAlso SkRefCnt
|
| 94 |
|
| 95 | #Method ##
|
| 96 |
|
| 97 | # ------------------------------------------------------------------------------
|
| 98 |
|
Cary Clark | 4f73883 | 2018-12-11 08:41:11 -0500 | [diff] [blame^] | 99 | #Method int getIntercepts(const SkScalar bounds[2], SkScalar intervals[], |
| 100 | const SkPaint* paint = nullptr) const; |
| 101 | #In Utility |
| 102 | #Line # returns where lines intersect Text_Blob; underlines ## |
| 103 | #Populate |
| 104 | |
| 105 | #Example |
| 106 | #Height 143 |
| 107 | void draw(SkCanvas* canvas) { |
| 108 | SkFont font; |
| 109 | font.setSize(120); |
| 110 | SkPoint textPos = { 20, 110 }; |
| 111 | int len = 3; |
| 112 | SkTextBlobBuilder textBlobBuilder; |
| 113 | const SkTextBlobBuilder::RunBuffer& run = |
| 114 | textBlobBuilder.allocRun(font, len, textPos.fX, textPos.fY); |
| 115 | run.glyphs[0] = 10; |
| 116 | run.glyphs[1] = 20; |
| 117 | run.glyphs[2] = 30; |
| 118 | sk_sp<const SkTextBlob> blob = textBlobBuilder.make(); |
| 119 | SkPaint paint; |
| 120 | SkScalar bounds[] = { 116, 134 }; |
| 121 | int count = blob->getIntercepts(bounds, nullptr); |
| 122 | std::vector<SkScalar> intervals; |
| 123 | intervals.resize(count); |
| 124 | (void) paint.getTextBlobIntercepts(blob.get(), bounds, &intervals.front()); |
| 125 | canvas->drawTextBlob(blob.get(), 0, 0, paint); |
| 126 | paint.setColor(0xFFFF7777); |
| 127 | SkScalar x = textPos.fX; |
| 128 | for (int i = 0; i < count; i+= 2) { |
| 129 | canvas->drawRect({x, bounds[0], intervals[i], bounds[1]}, paint); |
| 130 | x = intervals[i + 1]; |
| 131 | } |
| 132 | canvas->drawRect({intervals[count - 1], bounds[0], 180, bounds[1]}, paint); |
| 133 | } |
| 134 | ## |
| 135 |
|
| 136 | #Method ##
|
| 137 |
|
| 138 | # ------------------------------------------------------------------------------
|
| 139 |
|
Mike Reed | 235cb7f | 2018-12-03 10:57:53 -0500 | [diff] [blame] | 140 | #Method static sk_sp<SkTextBlob> MakeFromText(const void* text, size_t byteLength, const SkFont& font,
|
| 141 | SkTextEncoding encoding = kUTF8_SkTextEncoding)
|
| 142 | #In Constructors
|
| 143 | #Line # constructs Text_Blob with one run ##
|
| 144 |
|
Mike Reed | c86ec97 | 2018-12-05 15:09:24 -0500 | [diff] [blame] | 145 | Creates Text_Blob with a single run. text meaning depends on Text_Encoding;
|
Mike Reed | 235cb7f | 2018-12-03 10:57:53 -0500 | [diff] [blame] | 146 | by default, text is encoded as UTF-8.
|
| 147 |
|
Cary Clark | 3e73dcf | 2018-12-06 08:41:14 -0500 | [diff] [blame] | 148 | font contains attributes used to define the run text: #font_metrics#.
|
Mike Reed | 235cb7f | 2018-12-03 10:57:53 -0500 | [diff] [blame] | 149 |
|
| 150 | #Param text character code points or Glyphs drawn ##
|
| 151 | #Param byteLength byte length of text array ##
|
| 152 | #Param font text size, typeface, text scale, and so on, used to draw ##
|
| 153 | #Param encoding one of: kUTF8_SkTextEncoding, kUTF16_SkTextEncoding,
|
| 154 | kUTF32_SkTextEncoding, kGlyphID_SkTextEncoding
|
| 155 | ##
|
| 156 |
|
| 157 | #Return Text_Blob constructed from one run ##
|
| 158 |
|
| 159 | #Example
|
| 160 | #Height 24
|
| 161 | SkFont font;
|
| 162 | font.setSize(24);
|
| 163 | SkPaint canvasPaint;
|
| 164 | canvasPaint.setColor(SK_ColorBLUE); // respected
|
| 165 | canvasPaint.setTextSize(2); // ignored
|
| 166 | sk_sp<SkTextBlob> blob = SkTextBlob::MakeFromText("Hello World", 11, font);
|
| 167 | canvas->drawTextBlob(blob, 20, 20, canvasPaint);
|
| 168 | ##
|
| 169 |
|
| 170 | #SeeAlso MakeFromString SkTextBlobBuilder
|
| 171 |
|
| 172 | ##
|
| 173 |
|
| 174 | # ------------------------------------------------------------------------------
|
| 175 |
|
| 176 | #Method static sk_sp<SkTextBlob> MakeFromString(const char* string, const SkFont& font,
|
| 177 | SkTextEncoding encoding = kUTF8_SkTextEncoding)
|
| 178 | #In Constructors
|
| 179 | #Line # constructs Text_Blob with one run ##
|
| 180 |
|
Cary Clark | 3e73dcf | 2018-12-06 08:41:14 -0500 | [diff] [blame] | 181 | Creates Text_Blob with a single run. string meaning depends on Text_Encoding;
|
Mike Reed | 235cb7f | 2018-12-03 10:57:53 -0500 | [diff] [blame] | 182 | by default, string is encoded as UTF-8.
|
| 183 |
|
Cary Clark | 3e73dcf | 2018-12-06 08:41:14 -0500 | [diff] [blame] | 184 | font contains Font_Metrics used to define the run text: #font_metrics#.
|
Mike Reed | 235cb7f | 2018-12-03 10:57:53 -0500 | [diff] [blame] | 185 |
|
| 186 | #Param string character code points or Glyphs drawn ##
|
| 187 | #Param font text size, typeface, text scale, and so on, used to draw ##
|
| 188 | #Param encoding one of: kUTF8_SkTextEncoding, kUTF16_SkTextEncoding,
|
| 189 | kUTF32_SkTextEncoding, kGlyphID_SkTextEncoding
|
| 190 | ##
|
| 191 |
|
| 192 | #Return Text_Blob constructed from one run ##
|
| 193 |
|
| 194 | #Example
|
| 195 | #Height 24
|
| 196 | SkFont font;
|
| 197 | font.setSize(24);
|
| 198 | SkPaint canvasPaint;
|
| 199 | canvasPaint.setColor(SK_ColorBLUE); // respected
|
| 200 | canvasPaint.setTextSize(2); // ignored
|
| 201 | sk_sp<SkTextBlob> blob = SkTextBlob::MakeFromString("Hello World", font);
|
| 202 | canvas->drawTextBlob(blob, 20, 20, canvasPaint);
|
| 203 | ##
|
| 204 |
|
| 205 | #SeeAlso MakeFromText SkTextBlobBuilder
|
| 206 |
|
| 207 | ##
|
| 208 |
|
| 209 | # ------------------------------------------------------------------------------
|
| 210 |
|
| 211 | #Method size_t serialize(const SkSerialProcs& procs, void* memory, size_t memory_size) const
|
| 212 | #In Utility
|
| 213 | #Line # writes Text_Blob to memory ##
|
| 214 | #Populate
|
| 215 |
|
| 216 | #Example
|
| 217 | #Height 64
|
| 218 | ###$
|
| 219 | $Function
|
| 220 | #include "SkSerialProcs.h"
|
| 221 | $$
|
| 222 | $$$#
|
| 223 | SkFont blobFont;
|
| 224 | blobFont.setSize(24);
|
| 225 | sk_sp<SkTextBlob> blob = SkTextBlob::MakeFromText("Hello World", 11, blobFont);
|
| 226 | char storage[2048];
|
| 227 | size_t used = blob->serialize(SkSerialProcs(), storage, sizeof(storage));
|
| 228 | sk_sp<SkTextBlob> copy = SkTextBlob::Deserialize(storage, used, SkDeserialProcs());
|
| 229 | canvas->drawTextBlob(copy, 20, 20, SkPaint());
|
| 230 | std::string usage = "size=" + std::to_string(sizeof(storage)) + " used=" + std::to_string(used);
|
| 231 | canvas->drawString(usage.c_str(), 20, 40, SkPaint());
|
| 232 | ##
|
| 233 |
|
| 234 | #SeeAlso Deserialize SkSerialProcs
|
| 235 |
|
| 236 | #Method ##
|
| 237 |
|
| 238 | # ------------------------------------------------------------------------------
|
| 239 |
|
| 240 | #Method sk_sp<SkData> serialize(const SkSerialProcs& procs) const
|
| 241 | #In Utility
|
| 242 | #Line # writes Text_Blob to Data ##
|
| 243 | #Populate
|
| 244 |
|
| 245 | #Example
|
| 246 | #Height 24
|
| 247 | ###$
|
| 248 | $Function
|
| 249 | #include "SkSerialProcs.h"
|
| 250 | $$
|
| 251 | $$$#
|
| 252 | SkFont blobFont;
|
| 253 | blobFont.setSize(24);
|
| 254 | sk_sp<SkTextBlob> blob = SkTextBlob::MakeFromText("Hello World", 11, blobFont);
|
| 255 | sk_sp<SkData> data = blob->serialize(SkSerialProcs());
|
| 256 | sk_sp<SkTextBlob> copy = SkTextBlob::Deserialize(data->data(), data->size(), SkDeserialProcs());
|
| 257 | canvas->drawTextBlob(copy, 20, 20, SkPaint());
|
| 258 | ##
|
| 259 |
|
| 260 | #SeeAlso Deserialize SkData SkSerialProcs
|
| 261 |
|
| 262 | #Method ##
|
| 263 |
|
| 264 | # ------------------------------------------------------------------------------
|
| 265 |
|
| 266 | #Method static sk_sp<SkTextBlob> Deserialize(const void* data, size_t size, const SkDeserialProcs& procs)
|
| 267 | #In Constructors
|
| 268 | #Line # constructs Text_Blob from memory ##
|
| 269 | #Populate
|
| 270 |
|
| 271 | #Example
|
| 272 | #Height 24
|
| 273 | #Description
|
| 274 | Text "Hacker" replaces "World!", but does not update its metrics.
|
| 275 | When drawn, "Hacker" uses the spacing computed for "World!".
|
| 276 | ##
|
| 277 | ###$
|
| 278 | $Function
|
| 279 | #include "SkSerialProcs.h"
|
| 280 | $$
|
| 281 | $$$#
|
| 282 | SkFont blobFont;
|
| 283 | blobFont.setSize(24);
|
| 284 | sk_sp<SkTextBlob> blob = SkTextBlob::MakeFromText("Hello World!", 12, blobFont);
|
| 285 | sk_sp<SkData> data = blob->serialize(SkSerialProcs());
|
| 286 | uint16_t glyphs[6];
|
| 287 | SkPaint blobPaint;
|
| 288 | blobPaint.textToGlyphs("Hacker", 6, glyphs);
|
| 289 | memcpy((char*)data->writable_data() + 0x54, glyphs, sizeof(glyphs));
|
| 290 | sk_sp<SkTextBlob> copy = SkTextBlob::Deserialize(data->data(), data->size(), SkDeserialProcs());
|
| 291 | canvas->drawTextBlob(copy, 20, 20, SkPaint());
|
| 292 | ##
|
| 293 |
|
| 294 | #SeeAlso serialize SkDeserialProcs
|
| 295 |
|
| 296 | #Method ##
|
| 297 |
|
| 298 | #Class SkTextBlob ##
|
| 299 |
|
| 300 | #Topic Text_Blob ##
|