1 | use super::{FontArguments, FontFamilies, TextBaseline, TextShadow}; |
2 | use crate::{ |
3 | interop::{self, AsStr, FromStrs, SetStr}, |
4 | prelude::*, |
5 | scalar, |
6 | textlayout::{RangeExtensions, EMPTY_INDEX, EMPTY_RANGE}, |
7 | Color, FontMetrics, FontStyle, Paint, Typeface, |
8 | }; |
9 | use skia_bindings as sb; |
10 | use std::{fmt, ops::Range}; |
11 | |
12 | bitflags! { |
13 | /// Multiple decorations can be applied at once. Ex: Underline and overline is |
14 | /// (0x1 | 0x2) |
15 | #[derive (Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] |
16 | pub struct TextDecoration: u32 { |
17 | const NO_DECORATION = sb::skia_textlayout_TextDecoration::kNoDecoration as _; |
18 | const UNDERLINE = sb::skia_textlayout_TextDecoration::kUnderline as _; |
19 | const OVERLINE = sb::skia_textlayout_TextDecoration::kOverline as _; |
20 | const LINE_THROUGH = sb::skia_textlayout_TextDecoration::kLineThrough as _; |
21 | } |
22 | } |
23 | |
24 | pub const ALL_TEXT_DECORATIONS: TextDecoration = TextDecoration::ALL; |
25 | |
26 | impl Default for TextDecoration { |
27 | fn default() -> Self { |
28 | TextDecoration::NO_DECORATION |
29 | } |
30 | } |
31 | |
32 | impl TextDecoration { |
33 | pub const ALL: TextDecoration = TextDecoration::all(); |
34 | } |
35 | |
36 | pub use sb::skia_textlayout_TextDecorationStyle as TextDecorationStyle; |
37 | #[test ] |
38 | fn text_decoration_style_naming() { |
39 | let _ = TextDecorationStyle::Solid; |
40 | } |
41 | |
42 | pub use sb::skia_textlayout_TextDecorationMode as TextDecorationMode; |
43 | #[test ] |
44 | fn text_decoration_mode_naming() { |
45 | let _ = TextDecorationMode::Gaps; |
46 | } |
47 | |
48 | pub use sb::skia_textlayout_StyleType as StyleType; |
49 | #[test ] |
50 | fn style_type_member_naming() { |
51 | let _ = StyleType::Foreground; |
52 | let _ = StyleType::LetterSpacing; |
53 | } |
54 | |
55 | #[repr (C)] |
56 | #[derive (Copy, Clone, PartialEq, Debug)] |
57 | pub struct Decoration { |
58 | pub ty: TextDecoration, |
59 | pub mode: TextDecorationMode, |
60 | pub color: Color, |
61 | pub style: TextDecorationStyle, |
62 | pub thickness_multiplier: scalar, |
63 | } |
64 | |
65 | impl Default for Decoration { |
66 | fn default() -> Self { |
67 | Self { |
68 | ty: TextDecoration::default(), |
69 | mode: TextDecorationMode::default(), |
70 | color: Color::TRANSPARENT, |
71 | style: TextDecorationStyle::default(), |
72 | thickness_multiplier: 1.0, |
73 | } |
74 | } |
75 | } |
76 | |
77 | native_transmutable!( |
78 | sb::skia_textlayout_Decoration, |
79 | Decoration, |
80 | decoration_layout |
81 | ); |
82 | |
83 | /// Where to vertically align the placeholder relative to the surrounding text. |
84 | #[repr (i32)] |
85 | #[derive (Debug, Copy, Clone, Hash, PartialEq, Eq, Default)] |
86 | pub enum PlaceholderAlignment { |
87 | /// Match the baseline of the placeholder with the baseline. |
88 | #[default] |
89 | Baseline, |
90 | |
91 | /// Align the bottom edge of the placeholder with the baseline such that the |
92 | /// placeholder sits on top of the baseline. |
93 | AboveBaseline, |
94 | |
95 | /// Align the top edge of the placeholder with the baseline specified in |
96 | /// such that the placeholder hangs below the baseline. |
97 | BelowBaseline, |
98 | |
99 | /// Align the top edge of the placeholder with the top edge of the font. |
100 | /// When the placeholder is very tall, the extra space will hang from |
101 | /// the top and extend through the bottom of the line. |
102 | Top, |
103 | |
104 | /// Align the bottom edge of the placeholder with the top edge of the font. |
105 | /// When the placeholder is very tall, the extra space will rise from |
106 | /// the bottom and extend through the top of the line. |
107 | Bottom, |
108 | |
109 | /// Align the middle of the placeholder with the middle of the text. When the |
110 | /// placeholder is very tall, the extra space will grow equally from |
111 | /// the top and bottom of the line. |
112 | Middle, |
113 | } |
114 | native_transmutable!( |
115 | sb::skia_textlayout_PlaceholderAlignment, |
116 | PlaceholderAlignment, |
117 | placeholder_alignment_layout |
118 | ); |
119 | |
120 | pub type FontFeature = Handle<sb::skia_textlayout_FontFeature>; |
121 | unsafe_send_sync!(FontFeature); |
122 | |
123 | impl NativeDrop for sb::skia_textlayout_FontFeature { |
124 | fn drop(&mut self) { |
125 | unsafe { sb::C_FontFeature_destruct(self) } |
126 | } |
127 | } |
128 | |
129 | impl NativeClone for sb::skia_textlayout_FontFeature { |
130 | fn clone(&self) -> Self { |
131 | construct(|ts: *mut skia_textlayout_FontFeature| unsafe { sb::C_FontFeature_CopyConstruct(uninitialized:ts, self) }) |
132 | } |
133 | } |
134 | |
135 | impl PartialEq for FontFeature { |
136 | fn eq(&self, other: &Self) -> bool { |
137 | self.name() == other.name() && self.value() == other.value() |
138 | } |
139 | } |
140 | |
141 | impl fmt::Debug for FontFeature { |
142 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
143 | f&mut DebugTuple<'_, '_>.debug_tuple(name:"FontFeature" ) |
144 | .field(&self.name()) |
145 | .field(&self.value()) |
146 | .finish() |
147 | } |
148 | } |
149 | |
150 | impl FontFeature { |
151 | pub fn name(&self) -> &str { |
152 | self.native().fName.as_str() |
153 | } |
154 | |
155 | pub fn value(&self) -> i32 { |
156 | self.native().fValue |
157 | } |
158 | } |
159 | |
160 | #[repr (C)] |
161 | #[derive (Clone, Default, Debug)] |
162 | pub struct PlaceholderStyle { |
163 | pub width: scalar, |
164 | pub height: scalar, |
165 | pub alignment: PlaceholderAlignment, |
166 | pub baseline: TextBaseline, |
167 | /// Distance from the top edge of the rect to the baseline position. This |
168 | /// baseline will be aligned against the alphabetic baseline of the surrounding |
169 | /// text. |
170 | /// |
171 | /// Positive values drop the baseline lower (positions the rect higher) and |
172 | /// small or negative values will cause the rect to be positioned underneath |
173 | /// the line. When baseline == height, the bottom edge of the rect will rest on |
174 | /// the alphabetic baseline. |
175 | pub baseline_offset: scalar, |
176 | } |
177 | |
178 | native_transmutable!( |
179 | sb::skia_textlayout_PlaceholderStyle, |
180 | PlaceholderStyle, |
181 | placeholder_style_layout |
182 | ); |
183 | |
184 | impl PartialEq for PlaceholderStyle { |
185 | fn eq(&self, other: &Self) -> bool { |
186 | unsafe { self.native().equals(arg1:other.native()) } |
187 | } |
188 | } |
189 | |
190 | impl PlaceholderStyle { |
191 | pub fn new( |
192 | width: scalar, |
193 | height: scalar, |
194 | alignment: PlaceholderAlignment, |
195 | baseline: TextBaseline, |
196 | offset: scalar, |
197 | ) -> Self { |
198 | Self { |
199 | width, |
200 | height, |
201 | alignment, |
202 | baseline, |
203 | baseline_offset: offset, |
204 | } |
205 | } |
206 | } |
207 | |
208 | pub type TextStyle = Handle<sb::skia_textlayout_TextStyle>; |
209 | unsafe_send_sync!(TextStyle); |
210 | |
211 | impl NativeDrop for sb::skia_textlayout_TextStyle { |
212 | fn drop(&mut self) { |
213 | unsafe { sb::C_TextStyle_destruct(self) } |
214 | } |
215 | } |
216 | |
217 | impl NativeClone for sb::skia_textlayout_TextStyle { |
218 | fn clone(&self) -> Self { |
219 | construct(|ts: *mut skia_textlayout_TextStyle| unsafe { sb::C_TextStyle_CopyConstruct(uninitialized:ts, self) }) |
220 | } |
221 | } |
222 | |
223 | impl NativePartialEq for sb::skia_textlayout_TextStyle { |
224 | fn eq(&self, rhs: &Self) -> bool { |
225 | unsafe { self.equals(rhs) } |
226 | } |
227 | } |
228 | |
229 | impl Default for TextStyle { |
230 | fn default() -> Self { |
231 | Self::new() |
232 | } |
233 | } |
234 | |
235 | impl fmt::Debug for TextStyle { |
236 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
237 | f.debug_struct("TextStyle" ) |
238 | .field("color" , &self.color()) |
239 | .field("has_foreground" , &self.has_foreground()) |
240 | .field("foreground" , &self.foreground()) |
241 | .field("has_background" , &self.has_background()) |
242 | .field("background" , &self.background()) |
243 | .field("decoration" , &self.decoration()) |
244 | .field("font_style" , &self.font_style()) |
245 | .field("shadows" , &self.shadows()) |
246 | .field("font_features" , &self.font_features()) |
247 | .field("font_size" , &self.font_size()) |
248 | .field("font_families" , &self.font_families()) |
249 | .field("baseline_shift" , &self.baseline_shift()) |
250 | .field("height" , &self.height()) |
251 | .field("height_override" , &self.height_override()) |
252 | .field("half_leading" , &self.half_leading()) |
253 | .field("letter_spacing" , &self.letter_spacing()) |
254 | .field("word_spacing" , &self.word_spacing()) |
255 | .field("typeface" , &self.typeface()) |
256 | .field("locale" , &self.locale()) |
257 | .field("text_baseline" , &self.text_baseline()) |
258 | .field("is_placeholder" , &self.is_placeholder()) |
259 | .finish() |
260 | } |
261 | } |
262 | |
263 | impl TextStyle { |
264 | pub fn new() -> Self { |
265 | TextStyle::construct(|ts| unsafe { sb::C_TextStyle_Construct(ts) }) |
266 | } |
267 | |
268 | #[deprecated (since = "0.51.0" , note = "Use clone_for_placeholder" )] |
269 | #[must_use ] |
270 | pub fn to_placeholder(&self) -> Self { |
271 | self.clone_for_placeholder() |
272 | } |
273 | |
274 | #[must_use ] |
275 | pub fn clone_for_placeholder(&self) -> Self { |
276 | Self::construct(|ts| unsafe { sb::C_TextStyle_cloneForPlaceholder(self.native(), ts) }) |
277 | } |
278 | |
279 | pub fn equals(&self, other: &TextStyle) -> bool { |
280 | *self == *other |
281 | } |
282 | |
283 | pub fn equals_by_fonts(&self, that: &TextStyle) -> bool { |
284 | unsafe { self.native().equalsByFonts(that.native()) } |
285 | } |
286 | |
287 | pub fn match_one_attribute(&self, style_type: StyleType, other: &TextStyle) -> bool { |
288 | unsafe { self.native().matchOneAttribute(style_type, other.native()) } |
289 | } |
290 | |
291 | pub fn color(&self) -> Color { |
292 | Color::from_native_c(self.native().fColor) |
293 | } |
294 | |
295 | pub fn set_color(&mut self, color: impl Into<Color>) -> &mut Self { |
296 | self.native_mut().fColor = color.into().into_native(); |
297 | self |
298 | } |
299 | |
300 | pub fn has_foreground(&self) -> bool { |
301 | self.native().fHasForeground |
302 | } |
303 | |
304 | pub fn foreground(&self) -> Paint { |
305 | Paint::construct(|p| unsafe { sb::C_TextStyle_getForeground(self.native(), p) }) |
306 | } |
307 | |
308 | pub fn set_foreground_paint(&mut self, paint: &Paint) -> &mut Self { |
309 | unsafe { sb::C_TextStyle_setForegroundPaint(self.native_mut(), paint.native()) }; |
310 | self |
311 | } |
312 | |
313 | #[deprecated (since = "0.64.0" , note = "use set_foreground_paint()" )] |
314 | pub fn set_foreground_color(&mut self, paint: &Paint) -> &mut Self { |
315 | self.set_foreground_paint(paint) |
316 | } |
317 | |
318 | pub fn clear_foreground_color(&mut self) -> &mut Self { |
319 | self.native_mut().fHasForeground = false; |
320 | self |
321 | } |
322 | |
323 | pub fn has_background(&self) -> bool { |
324 | self.native().fHasBackground |
325 | } |
326 | |
327 | pub fn background(&self) -> Paint { |
328 | Paint::construct(|p| unsafe { sb::C_TextStyle_getBackground(self.native(), p) }) |
329 | } |
330 | |
331 | pub fn set_background_paint(&mut self, paint: &Paint) -> &mut Self { |
332 | unsafe { sb::C_TextStyle_setBackgroundPaint(self.native_mut(), paint.native()) }; |
333 | self |
334 | } |
335 | |
336 | #[deprecated (since = "0.64.0" , note = "use set_background_paint()" )] |
337 | pub fn set_background_color(&mut self, paint: &Paint) -> &mut Self { |
338 | self.set_background_paint(paint) |
339 | } |
340 | |
341 | pub fn clear_background_color(&mut self) -> &mut Self { |
342 | self.native_mut().fHasBackground = false; |
343 | self |
344 | } |
345 | |
346 | pub fn decoration(&self) -> &Decoration { |
347 | Decoration::from_native_ref(&self.native().fDecoration) |
348 | } |
349 | |
350 | pub fn decoration_type(&self) -> TextDecoration { |
351 | self.decoration().ty |
352 | } |
353 | |
354 | pub fn decoration_mode(&self) -> TextDecorationMode { |
355 | self.decoration().mode |
356 | } |
357 | |
358 | pub fn decoration_color(&self) -> Color { |
359 | self.decoration().color |
360 | } |
361 | |
362 | pub fn decoration_style(&self) -> TextDecorationStyle { |
363 | self.decoration().style |
364 | } |
365 | |
366 | pub fn decoration_thickness_multiplier(&self) -> scalar { |
367 | self.decoration().thickness_multiplier |
368 | } |
369 | |
370 | pub fn set_decoration(&mut self, decoration: &Decoration) { |
371 | *self.decoration_mut_internal() = *decoration; |
372 | } |
373 | |
374 | pub fn set_decoration_type(&mut self, decoration: TextDecoration) { |
375 | self.decoration_mut_internal().ty = decoration; |
376 | } |
377 | |
378 | pub fn set_decoration_mode(&mut self, mode: TextDecorationMode) { |
379 | self.decoration_mut_internal().mode = mode; |
380 | } |
381 | |
382 | pub fn set_decoration_style(&mut self, style: TextDecorationStyle) { |
383 | self.decoration_mut_internal().style = style; |
384 | } |
385 | |
386 | pub fn set_decoration_color(&mut self, color: impl Into<Color>) { |
387 | self.decoration_mut_internal().color = color.into(); |
388 | } |
389 | |
390 | pub fn set_decoration_thickness_multiplier(&mut self, multiplier: scalar) { |
391 | self.decoration_mut_internal().thickness_multiplier = multiplier; |
392 | } |
393 | |
394 | #[deprecated (since = "0.63.1" , note = "use set_decoration()" )] |
395 | pub fn decoration_mut(&mut self) -> &mut Decoration { |
396 | self.decoration_mut_internal() |
397 | } |
398 | |
399 | fn decoration_mut_internal(&mut self) -> &mut Decoration { |
400 | Decoration::from_native_ref_mut(&mut self.native_mut().fDecoration) |
401 | } |
402 | |
403 | pub fn font_style(&self) -> FontStyle { |
404 | FontStyle::from_native_c(self.native().fFontStyle) |
405 | } |
406 | |
407 | pub fn set_font_style(&mut self, font_style: FontStyle) -> &mut Self { |
408 | self.native_mut().fFontStyle = font_style.into_native(); |
409 | self |
410 | } |
411 | |
412 | pub fn shadows(&self) -> &[TextShadow] { |
413 | unsafe { |
414 | let mut count = 0; |
415 | let ptr = sb::C_TextStyle_getShadows(&self.native().fTextShadows, &mut count); |
416 | safer::from_raw_parts(TextShadow::from_native_ptr(ptr), count) |
417 | } |
418 | } |
419 | |
420 | pub fn add_shadow(&mut self, shadow: TextShadow) -> &mut Self { |
421 | unsafe { sb::C_TextStyle_addShadow(self.native_mut(), shadow.native()) } |
422 | self |
423 | } |
424 | |
425 | pub fn reset_shadows(&mut self) -> &mut Self { |
426 | unsafe { sb::C_TextStyle_resetShadows(self.native_mut()) } |
427 | self |
428 | } |
429 | |
430 | pub fn font_features(&self) -> &[FontFeature] { |
431 | unsafe { |
432 | let mut count = 0; |
433 | let ptr = sb::C_TextStyle_getFontFeatures(&self.native().fFontFeatures, &mut count); |
434 | safer::from_raw_parts(FontFeature::from_native_ptr(ptr), count) |
435 | } |
436 | } |
437 | |
438 | pub fn add_font_feature(&mut self, font_feature: impl AsRef<str>, value: i32) { |
439 | let font_feature = interop::String::from_str(font_feature); |
440 | unsafe { sb::C_TextStyle_addFontFeature(self.native_mut(), font_feature.native(), value) } |
441 | } |
442 | |
443 | pub fn reset_font_features(&mut self) { |
444 | unsafe { sb::C_TextStyle_resetFontFeatures(self.native_mut()) } |
445 | } |
446 | |
447 | pub fn font_arguments(&self) -> Option<&FontArguments> { |
448 | unsafe { sb::C_TextStyle_getFontArguments(self.native()) } |
449 | .into_option() |
450 | .map(|ptr| FontArguments::from_native_ref(unsafe { &*ptr })) |
451 | } |
452 | |
453 | /// The contents of the [`crate::FontArguments`] will be copied into the [`TextStyle`]. |
454 | pub fn set_font_arguments<'fa>( |
455 | &mut self, |
456 | arguments: impl Into<Option<&'fa crate::FontArguments<'fa, 'fa>>>, |
457 | ) { |
458 | unsafe { |
459 | sb::C_TextStyle_setFontArguments( |
460 | self.native_mut(), |
461 | arguments.into().native_ptr_or_null(), |
462 | ) |
463 | } |
464 | } |
465 | |
466 | pub fn font_size(&self) -> scalar { |
467 | self.native().fFontSize |
468 | } |
469 | |
470 | pub fn set_font_size(&mut self, size: scalar) -> &mut Self { |
471 | self.native_mut().fFontSize = size; |
472 | self |
473 | } |
474 | |
475 | pub fn font_families(&self) -> FontFamilies { |
476 | unsafe { |
477 | let mut count = 0; |
478 | let ptr = sb::C_TextStyle_getFontFamilies(self.native(), &mut count); |
479 | FontFamilies(safer::from_raw_parts(ptr, count)) |
480 | } |
481 | } |
482 | |
483 | pub fn set_font_families(&mut self, families: &[impl AsRef<str>]) -> &mut Self { |
484 | let families: Vec<interop::String> = FromStrs::from_strs(families); |
485 | let families = families.native(); |
486 | unsafe { |
487 | sb::C_TextStyle_setFontFamilies(self.native_mut(), families.as_ptr(), families.len()) |
488 | } |
489 | self |
490 | } |
491 | |
492 | pub fn baseline_shift(&self) -> scalar { |
493 | self.native().fBaselineShift |
494 | } |
495 | |
496 | pub fn set_baseline_shift(&mut self, baseline_shift: scalar) -> &mut Self { |
497 | self.native_mut().fBaselineShift = baseline_shift; |
498 | self |
499 | } |
500 | |
501 | pub fn set_height(&mut self, height: scalar) -> &mut Self { |
502 | self.native_mut().fHeight = height; |
503 | self |
504 | } |
505 | |
506 | pub fn height(&self) -> scalar { |
507 | let n = self.native(); |
508 | if n.fHeightOverride { |
509 | n.fHeight |
510 | } else { |
511 | 0.0 |
512 | } |
513 | } |
514 | |
515 | pub fn set_height_override(&mut self, height_override: bool) -> &mut Self { |
516 | self.native_mut().fHeightOverride = height_override; |
517 | self |
518 | } |
519 | |
520 | pub fn height_override(&self) -> bool { |
521 | self.native().fHeightOverride |
522 | } |
523 | |
524 | pub fn set_half_leading(&mut self, half_leading: bool) -> &mut Self { |
525 | self.native_mut().fHalfLeading = half_leading; |
526 | self |
527 | } |
528 | |
529 | pub fn half_leading(&self) -> bool { |
530 | self.native().fHalfLeading |
531 | } |
532 | |
533 | pub fn set_letter_spacing(&mut self, letter_spacing: scalar) -> &mut Self { |
534 | self.native_mut().fLetterSpacing = letter_spacing; |
535 | self |
536 | } |
537 | |
538 | pub fn letter_spacing(&self) -> scalar { |
539 | self.native().fLetterSpacing |
540 | } |
541 | |
542 | pub fn set_word_spacing(&mut self, word_spacing: scalar) -> &mut Self { |
543 | self.native_mut().fWordSpacing = word_spacing; |
544 | self |
545 | } |
546 | |
547 | pub fn word_spacing(&self) -> scalar { |
548 | self.native().fWordSpacing |
549 | } |
550 | |
551 | pub fn typeface(&self) -> Option<Typeface> { |
552 | Typeface::from_unshared_ptr(self.native().fTypeface.fPtr) |
553 | } |
554 | |
555 | pub fn set_typeface(&mut self, typeface: impl Into<Option<Typeface>>) -> &mut Self { |
556 | unsafe { |
557 | sb::C_TextStyle_setTypeface(self.native_mut(), typeface.into().into_ptr_or_null()) |
558 | } |
559 | self |
560 | } |
561 | |
562 | pub fn locale(&self) -> &str { |
563 | self.native().fLocale.as_str() |
564 | } |
565 | |
566 | pub fn set_locale(&mut self, locale: impl AsRef<str>) -> &mut Self { |
567 | self.native_mut().fLocale.set_str(locale); |
568 | self |
569 | } |
570 | |
571 | pub fn text_baseline(&self) -> TextBaseline { |
572 | self.native().fTextBaseline |
573 | } |
574 | |
575 | pub fn set_text_baseline(&mut self, baseline: TextBaseline) -> &mut Self { |
576 | self.native_mut().fTextBaseline = baseline; |
577 | self |
578 | } |
579 | |
580 | pub fn font_metrics(&self) -> FontMetrics { |
581 | FontMetrics::construct(|fm| unsafe { self.native().getFontMetrics(fm) }) |
582 | } |
583 | |
584 | pub fn is_placeholder(&self) -> bool { |
585 | self.native().fIsPlaceholder |
586 | } |
587 | |
588 | pub fn set_placeholder(&mut self) -> &mut Self { |
589 | self.native_mut().fIsPlaceholder = true; |
590 | self |
591 | } |
592 | } |
593 | |
594 | pub type TextIndex = usize; |
595 | pub type TextRange = Range<usize>; |
596 | pub const EMPTY_TEXT: TextRange = EMPTY_RANGE; |
597 | |
598 | #[repr (C)] |
599 | #[derive (Clone, PartialEq, Debug)] |
600 | pub struct Block { |
601 | pub range: TextRange, |
602 | pub style: TextStyle, |
603 | } |
604 | |
605 | native_transmutable!(sb::skia_textlayout_Block, Block, block_layout); |
606 | |
607 | impl Default for Block { |
608 | fn default() -> Self { |
609 | Self { |
610 | range: EMPTY_RANGE, |
611 | style: Default::default(), |
612 | } |
613 | } |
614 | } |
615 | |
616 | impl Block { |
617 | pub fn new(text_range: TextRange, style: TextStyle) -> Self { |
618 | Self { |
619 | range: text_range, |
620 | style, |
621 | } |
622 | } |
623 | |
624 | pub fn add(&mut self, tail: TextRange) -> &mut Self { |
625 | debug_assert!(self.range.end == tail.start); |
626 | self.range = self.range.start..self.range.start + self.range.width() + tail.width(); |
627 | self |
628 | } |
629 | } |
630 | |
631 | pub type BlockIndex = usize; |
632 | pub type BlockRange = Range<usize>; |
633 | |
634 | pub const EMPTY_BLOCK: usize = EMPTY_INDEX; |
635 | pub const EMPTY_BLOCKS: Range<usize> = EMPTY_RANGE; |
636 | |
637 | #[repr (C)] |
638 | #[derive (Clone, PartialEq, Debug)] |
639 | pub struct Placeholder { |
640 | pub range: TextRange, |
641 | pub style: PlaceholderStyle, |
642 | pub text_style: TextStyle, |
643 | pub blocks_before: BlockRange, |
644 | pub text_before: TextRange, |
645 | } |
646 | |
647 | native_transmutable!( |
648 | sb::skia_textlayout_Placeholder, |
649 | Placeholder, |
650 | placeholder_layout |
651 | ); |
652 | |
653 | impl Default for Placeholder { |
654 | fn default() -> Self { |
655 | #[allow (clippy::reversed_empty_ranges)] |
656 | Self { |
657 | range: EMPTY_RANGE, |
658 | style: Default::default(), |
659 | text_style: Default::default(), |
660 | blocks_before: 0..0, |
661 | text_before: 0..0, |
662 | } |
663 | } |
664 | } |
665 | |
666 | impl Placeholder { |
667 | pub fn new( |
668 | range: Range<usize>, |
669 | style: PlaceholderStyle, |
670 | text_style: TextStyle, |
671 | blocks_before: BlockRange, |
672 | text_before: TextRange, |
673 | ) -> Self { |
674 | Self { |
675 | range, |
676 | style, |
677 | text_style, |
678 | blocks_before, |
679 | text_before, |
680 | } |
681 | } |
682 | } |
683 | |
684 | #[cfg (test)] |
685 | mod tests { |
686 | use super::*; |
687 | |
688 | #[test ] |
689 | fn getting_setting_comparing_font_arguments() { |
690 | let mut ts = TextStyle::new(); |
691 | let mut fa = crate::FontArguments::default(); |
692 | fa.set_collection_index(100); |
693 | ts.set_font_arguments(&fa); |
694 | let tl_fa: FontArguments = fa.into(); |
695 | let fa = ts.font_arguments().unwrap(); |
696 | assert_eq!(tl_fa, *fa); |
697 | let default_fa: FontArguments = crate::FontArguments::default().into(); |
698 | assert_ne!(default_fa, *fa); |
699 | } |
700 | } |
701 | |