Flutter Engine
paragraph_builder.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter 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 #include "flutter/lib/ui/text/paragraph_builder.h"
6 
7 #include <cstring>
8 
9 #include "flutter/common/settings.h"
10 #include "flutter/common/task_runners.h"
11 #include "flutter/fml/logging.h"
12 #include "flutter/fml/task_runner.h"
13 #include "flutter/lib/ui/text/font_collection.h"
14 #include "flutter/lib/ui/ui_dart_state.h"
15 #include "flutter/lib/ui/window/platform_configuration.h"
16 #include "flutter/third_party/txt/src/txt/font_style.h"
17 #include "flutter/third_party/txt/src/txt/font_weight.h"
18 #include "flutter/third_party/txt/src/txt/paragraph_style.h"
19 #include "flutter/third_party/txt/src/txt/text_baseline.h"
20 #include "flutter/third_party/txt/src/txt/text_decoration.h"
21 #include "flutter/third_party/txt/src/txt/text_style.h"
22 #include "third_party/icu/source/common/unicode/ustring.h"
23 #include "third_party/skia/include/core/SkColor.h"
29 
30 namespace flutter {
31 namespace {
32 
33 // TextStyle
34 
35 const int tsLeadingDistributionIndex = 0;
36 const int tsColorIndex = 1;
37 const int tsTextDecorationIndex = 2;
38 const int tsTextDecorationColorIndex = 3;
39 const int tsTextDecorationStyleIndex = 4;
40 const int tsFontWeightIndex = 5;
41 const int tsFontStyleIndex = 6;
42 const int tsTextBaselineIndex = 7;
43 const int tsTextDecorationThicknessIndex = 8;
44 const int tsFontFamilyIndex = 9;
45 const int tsFontSizeIndex = 10;
46 const int tsLetterSpacingIndex = 11;
47 const int tsWordSpacingIndex = 12;
48 const int tsHeightIndex = 13;
49 const int tsLocaleIndex = 14;
50 const int tsBackgroundIndex = 15;
51 const int tsForegroundIndex = 16;
52 const int tsTextShadowsIndex = 17;
53 const int tsFontFeaturesIndex = 18;
54 
55 const int tsLeadingDistributionMask = 1 << tsLeadingDistributionIndex;
56 const int tsColorMask = 1 << tsColorIndex;
57 const int tsTextDecorationMask = 1 << tsTextDecorationIndex;
58 const int tsTextDecorationColorMask = 1 << tsTextDecorationColorIndex;
59 const int tsTextDecorationStyleMask = 1 << tsTextDecorationStyleIndex;
60 const int tsTextDecorationThicknessMask = 1 << tsTextDecorationThicknessIndex;
61 const int tsFontWeightMask = 1 << tsFontWeightIndex;
62 const int tsFontStyleMask = 1 << tsFontStyleIndex;
63 const int tsTextBaselineMask = 1 << tsTextBaselineIndex;
64 const int tsFontFamilyMask = 1 << tsFontFamilyIndex;
65 const int tsFontSizeMask = 1 << tsFontSizeIndex;
66 const int tsLetterSpacingMask = 1 << tsLetterSpacingIndex;
67 const int tsWordSpacingMask = 1 << tsWordSpacingIndex;
68 const int tsHeightMask = 1 << tsHeightIndex;
69 const int tsLocaleMask = 1 << tsLocaleIndex;
70 const int tsBackgroundMask = 1 << tsBackgroundIndex;
71 const int tsForegroundMask = 1 << tsForegroundIndex;
72 const int tsTextShadowsMask = 1 << tsTextShadowsIndex;
73 const int tsFontFeaturesMask = 1 << tsFontFeaturesIndex;
74 
75 // ParagraphStyle
76 
77 const int psTextAlignIndex = 1;
78 const int psTextDirectionIndex = 2;
79 const int psFontWeightIndex = 3;
80 const int psFontStyleIndex = 4;
81 const int psMaxLinesIndex = 5;
82 const int psTextHeightBehaviorIndex = 6;
83 const int psFontFamilyIndex = 7;
84 const int psFontSizeIndex = 8;
85 const int psHeightIndex = 9;
86 const int psStrutStyleIndex = 10;
87 const int psEllipsisIndex = 11;
88 const int psLocaleIndex = 12;
89 
90 const int psTextAlignMask = 1 << psTextAlignIndex;
91 const int psTextDirectionMask = 1 << psTextDirectionIndex;
92 const int psFontWeightMask = 1 << psFontWeightIndex;
93 const int psFontStyleMask = 1 << psFontStyleIndex;
94 const int psMaxLinesMask = 1 << psMaxLinesIndex;
95 const int psFontFamilyMask = 1 << psFontFamilyIndex;
96 const int psFontSizeMask = 1 << psFontSizeIndex;
97 const int psHeightMask = 1 << psHeightIndex;
98 const int psTextHeightBehaviorMask = 1 << psTextHeightBehaviorIndex;
99 const int psStrutStyleMask = 1 << psStrutStyleIndex;
100 const int psEllipsisMask = 1 << psEllipsisIndex;
101 const int psLocaleMask = 1 << psLocaleIndex;
102 
103 // TextShadows decoding
104 
105 constexpr uint32_t kColorDefault = 0xFF000000;
106 constexpr uint32_t kBytesPerShadow = 16;
107 constexpr uint32_t kShadowPropertiesCount = 4;
108 constexpr uint32_t kColorOffset = 0;
109 constexpr uint32_t kXOffset = 1;
110 constexpr uint32_t kYOffset = 2;
111 constexpr uint32_t kBlurOffset = 3;
112 
113 // FontFeature decoding
114 constexpr uint32_t kBytesPerFontFeature = 8;
115 constexpr uint32_t kFontFeatureTagLength = 4;
116 
117 // Strut decoding
118 const int sFontWeightIndex = 0;
119 const int sFontStyleIndex = 1;
120 const int sFontFamilyIndex = 2;
121 const int sLeadingDistributionIndex = 3;
122 const int sFontSizeIndex = 4;
123 const int sHeightIndex = 5;
124 const int sLeadingIndex = 6;
125 const int sForceStrutHeightIndex = 7;
126 
127 const int sFontWeightMask = 1 << sFontWeightIndex;
128 const int sFontStyleMask = 1 << sFontStyleIndex;
129 const int sFontFamilyMask = 1 << sFontFamilyIndex;
130 const int sLeadingDistributionMask = 1 << sLeadingDistributionIndex;
131 const int sFontSizeMask = 1 << sFontSizeIndex;
132 const int sHeightMask = 1 << sHeightIndex;
133 const int sLeadingMask = 1 << sLeadingIndex;
134 const int sForceStrutHeightMask = 1 << sForceStrutHeightIndex;
135 
136 } // namespace
137 
138 static void ParagraphBuilder_constructor(Dart_NativeArguments args) {
141 }
142 
144 
145 #define FOR_EACH_BINDING(V) \
146  V(ParagraphBuilder, pushStyle) \
147  V(ParagraphBuilder, pop) \
148  V(ParagraphBuilder, addText) \
149  V(ParagraphBuilder, addPlaceholder) \
150  V(ParagraphBuilder, build)
151 
153 
154 void ParagraphBuilder::RegisterNatives(tonic::DartLibraryNatives* natives) {
155  natives->Register(
156  {{"ParagraphBuilder_constructor", ParagraphBuilder_constructor, 9, true},
158 }
159 
161  tonic::Int32List& encoded,
162  Dart_Handle strutData,
163  const std::string& fontFamily,
164  const std::vector<std::string>& strutFontFamilies,
165  double fontSize,
166  double height,
167  const std::u16string& ellipsis,
168  const std::string& locale) {
169  return fml::MakeRefCounted<ParagraphBuilder>(encoded, strutData, fontFamily,
170  strutFontFamilies, fontSize,
171  height, ellipsis, locale);
172 }
173 
174 // returns true if there is a font family defined. Font family is the only
175 // parameter passed directly.
176 void decodeStrut(Dart_Handle strut_data,
177  const std::vector<std::string>& strut_font_families,
178  txt::ParagraphStyle& paragraph_style) { // NOLINT
179  if (strut_data == Dart_Null()) {
180  return;
181  }
182 
183  tonic::DartByteData byte_data(strut_data);
184  if (byte_data.length_in_bytes() == 0) {
185  return;
186  }
187  paragraph_style.strut_enabled = true;
188 
189  const uint8_t* uint8_data = static_cast<const uint8_t*>(byte_data.data());
190  uint8_t mask = uint8_data[0];
191 
192  // Data is stored in order of increasing size, eg, 8 bit ints will be before
193  // any 32 bit ints. In addition, the order of decoding is the same order
194  // as it is encoded, and the order is used to maintain consistency.
195  size_t byte_count = 1;
196  if (mask & sFontWeightMask) {
197  paragraph_style.strut_font_weight =
198  static_cast<txt::FontWeight>(uint8_data[byte_count++]);
199  }
200  if (mask & sFontStyleMask) {
201  paragraph_style.strut_font_style =
202  static_cast<txt::FontStyle>(uint8_data[byte_count++]);
203  }
204 
205  paragraph_style.strut_half_leading = mask & sLeadingDistributionMask;
206 
207  std::vector<float> float_data;
208  float_data.resize((byte_data.length_in_bytes() - byte_count) / 4);
209  memcpy(float_data.data(),
210  static_cast<const char*>(byte_data.data()) + byte_count,
211  byte_data.length_in_bytes() - byte_count);
212  size_t float_count = 0;
213  if (mask & sFontSizeMask) {
214  paragraph_style.strut_font_size = float_data[float_count++];
215  }
216  if (mask & sHeightMask) {
217  paragraph_style.strut_height = float_data[float_count++];
218  paragraph_style.strut_has_height_override = true;
219  }
220  if (mask & sLeadingMask) {
221  paragraph_style.strut_leading = float_data[float_count++];
222  }
223 
224  // The boolean is stored as the last bit in the bitmask, as null
225  // and false have the same behavior.
226  paragraph_style.force_strut_height = mask & sForceStrutHeightMask;
227 
228  if (mask & sFontFamilyMask) {
229  paragraph_style.strut_font_families = strut_font_families;
230  } else {
231  // Provide an empty font name so that the platform default font will be
232  // used.
233  paragraph_style.strut_font_families.push_back("");
234  }
235 }
236 
237 ParagraphBuilder::ParagraphBuilder(
238  tonic::Int32List& encoded,
239  Dart_Handle strutData,
240  const std::string& fontFamily,
241  const std::vector<std::string>& strutFontFamilies,
242  double fontSize,
243  double height,
244  const std::u16string& ellipsis,
245  const std::string& locale) {
246  int32_t mask = encoded[0];
247  txt::ParagraphStyle style;
248 
249  if (mask & psTextAlignMask) {
250  style.text_align = txt::TextAlign(encoded[psTextAlignIndex]);
251  }
252 
253  if (mask & psTextDirectionMask) {
254  style.text_direction = txt::TextDirection(encoded[psTextDirectionIndex]);
255  }
256 
257  if (mask & psFontWeightMask) {
258  style.font_weight =
259  static_cast<txt::FontWeight>(encoded[psFontWeightIndex]);
260  }
261 
262  if (mask & psFontStyleMask) {
263  style.font_style = static_cast<txt::FontStyle>(encoded[psFontStyleIndex]);
264  }
265 
266  if (mask & psFontFamilyMask) {
267  style.font_family = fontFamily;
268  }
269 
270  if (mask & psFontSizeMask) {
271  style.font_size = fontSize;
272  }
273 
274  if (mask & psHeightMask) {
275  style.height = height;
276  style.has_height_override = true;
277  }
278 
279  if (mask & psTextHeightBehaviorMask) {
280  style.text_height_behavior = encoded[psTextHeightBehaviorIndex];
281  }
282 
283  if (mask & psStrutStyleMask) {
284  decodeStrut(strutData, strutFontFamilies, style);
285  }
286 
287  if (mask & psMaxLinesMask) {
288  style.max_lines = encoded[psMaxLinesIndex];
289  }
290 
291  if (mask & psEllipsisMask) {
292  style.ellipsis = ellipsis;
293  }
294 
295  if (mask & psLocaleMask) {
296  style.locale = locale;
297  }
298 
299  FontCollection& font_collection = UIDartState::Current()
301  ->client()
302  ->GetFontCollection();
303 
304  typedef std::unique_ptr<txt::ParagraphBuilder> (*ParagraphBuilderFactory)(
305  const txt::ParagraphStyle& style,
306  std::shared_ptr<txt::FontCollection> font_collection);
307  ParagraphBuilderFactory factory = txt::ParagraphBuilder::CreateTxtBuilder;
308 
309 #if FLUTTER_ENABLE_SKSHAPER
310 #if FLUTTER_ALWAYS_USE_SKSHAPER
311  bool enable_skparagraph = true;
312 #else
313  bool enable_skparagraph = UIDartState::Current()->enable_skparagraph();
314 #endif
315  if (enable_skparagraph) {
316  factory = txt::ParagraphBuilder::CreateSkiaBuilder;
317  }
318 #endif // FLUTTER_ENABLE_SKSHAPER
319 
320  m_paragraphBuilder = factory(style, font_collection.GetFontCollection());
321 }
322 
324 
326  Dart_Handle shadows_data,
327  std::vector<txt::TextShadow>& decoded_shadows) { // NOLINT
328  decoded_shadows.clear();
329 
330  tonic::DartByteData byte_data(shadows_data);
331  FML_CHECK(byte_data.length_in_bytes() % kBytesPerShadow == 0);
332 
333  const uint32_t* uint_data = static_cast<const uint32_t*>(byte_data.data());
334  const float* float_data = static_cast<const float*>(byte_data.data());
335 
336  size_t shadow_count = byte_data.length_in_bytes() / kBytesPerShadow;
337  size_t shadow_count_offset = 0;
338  for (size_t shadow_index = 0; shadow_index < shadow_count; ++shadow_index) {
339  shadow_count_offset = shadow_index * kShadowPropertiesCount;
340  SkColor color =
341  uint_data[shadow_count_offset + kColorOffset] ^ kColorDefault;
342  decoded_shadows.emplace_back(
343  color,
344  SkPoint::Make(float_data[shadow_count_offset + kXOffset],
345  float_data[shadow_count_offset + kYOffset]),
346  float_data[shadow_count_offset + kBlurOffset]);
347  }
348 }
349 
350 void decodeFontFeatures(Dart_Handle font_features_data,
351  txt::FontFeatures& font_features) { // NOLINT
352  tonic::DartByteData byte_data(font_features_data);
353  FML_CHECK(byte_data.length_in_bytes() % kBytesPerFontFeature == 0);
354 
355  size_t feature_count = byte_data.length_in_bytes() / kBytesPerFontFeature;
356  for (size_t feature_index = 0; feature_index < feature_count;
357  ++feature_index) {
358  size_t feature_offset = feature_index * kBytesPerFontFeature;
359  const char* feature_bytes =
360  static_cast<const char*>(byte_data.data()) + feature_offset;
361  std::string tag(feature_bytes, kFontFeatureTagLength);
362  int32_t value = *(reinterpret_cast<const int32_t*>(feature_bytes +
363  kFontFeatureTagLength));
364  font_features.SetFeature(tag, value);
365  }
366 }
367 
368 void ParagraphBuilder::pushStyle(tonic::Int32List& encoded,
369  const std::vector<std::string>& fontFamilies,
370  double fontSize,
371  double letterSpacing,
372  double wordSpacing,
373  double height,
374  double decorationThickness,
375  const std::string& locale,
376  Dart_Handle background_objects,
377  Dart_Handle background_data,
378  Dart_Handle foreground_objects,
379  Dart_Handle foreground_data,
380  Dart_Handle shadows_data,
381  Dart_Handle font_features_data) {
382  FML_DCHECK(encoded.num_elements() == 9);
383 
384  int32_t mask = encoded[0];
385 
386  // Set to use the properties of the previous style if the property is not
387  // explicitly given.
388  txt::TextStyle style = m_paragraphBuilder->PeekStyle();
389 
390  style.half_leading = mask & tsLeadingDistributionMask;
391  // Only change the style property from the previous value if a new explicitly
392  // set value is available
393  if (mask & tsColorMask) {
394  style.color = encoded[tsColorIndex];
395  }
396 
397  if (mask & tsTextDecorationMask) {
398  style.decoration =
399  static_cast<txt::TextDecoration>(encoded[tsTextDecorationIndex]);
400  }
401 
402  if (mask & tsTextDecorationColorMask) {
403  style.decoration_color = encoded[tsTextDecorationColorIndex];
404  }
405 
406  if (mask & tsTextDecorationStyleMask) {
407  style.decoration_style = static_cast<txt::TextDecorationStyle>(
408  encoded[tsTextDecorationStyleIndex]);
409  }
410 
411  if (mask & tsTextDecorationThicknessMask) {
412  style.decoration_thickness_multiplier = decorationThickness;
413  }
414 
415  if (mask & tsTextBaselineMask) {
416  // TODO(abarth): Implement TextBaseline. The CSS version of this
417  // property wasn't wired up either.
418  }
419 
420  if (mask & (tsFontWeightMask | tsFontStyleMask | tsFontSizeMask |
421  tsLetterSpacingMask | tsWordSpacingMask)) {
422  if (mask & tsFontWeightMask) {
423  style.font_weight =
424  static_cast<txt::FontWeight>(encoded[tsFontWeightIndex]);
425  }
426 
427  if (mask & tsFontStyleMask) {
428  style.font_style = static_cast<txt::FontStyle>(encoded[tsFontStyleIndex]);
429  }
430 
431  if (mask & tsFontSizeMask) {
432  style.font_size = fontSize;
433  }
434 
435  if (mask & tsLetterSpacingMask) {
436  style.letter_spacing = letterSpacing;
437  }
438 
439  if (mask & tsWordSpacingMask) {
440  style.word_spacing = wordSpacing;
441  }
442  }
443 
444  if (mask & tsHeightMask) {
445  style.height = height;
446  style.has_height_override = true;
447  }
448 
449  if (mask & tsLocaleMask) {
450  style.locale = locale;
451  }
452 
453  if (mask & tsBackgroundMask) {
454  Paint background(background_objects, background_data);
455  if (background.paint()) {
456  style.has_background = true;
457  style.background = *background.paint();
458  }
459  }
460 
461  if (mask & tsForegroundMask) {
462  Paint foreground(foreground_objects, foreground_data);
463  if (foreground.paint()) {
464  style.has_foreground = true;
465  style.foreground = *foreground.paint();
466  }
467  }
468 
469  if (mask & tsTextShadowsMask) {
470  decodeTextShadows(shadows_data, style.text_shadows);
471  }
472 
473  if (mask & tsFontFamilyMask) {
474  // The child style's font families override the parent's font families.
475  // If the child's fonts are not available, then the font collection will
476  // use the system fallback fonts (not the parent's fonts).
477  style.font_families = fontFamilies;
478  }
479 
480  if (mask & tsFontFeaturesMask) {
481  decodeFontFeatures(font_features_data, style.font_features);
482  }
483 
484  m_paragraphBuilder->PushStyle(style);
485 }
486 
488  m_paragraphBuilder->Pop();
489 }
490 
491 Dart_Handle ParagraphBuilder::addText(const std::u16string& text) {
492  if (text.empty()) {
493  return Dart_Null();
494  }
495 
496  // Use ICU to validate the UTF-16 input. Calling u_strToUTF8 with a null
497  // output buffer will return U_BUFFER_OVERFLOW_ERROR if the input is well
498  // formed.
499  const UChar* text_ptr = reinterpret_cast<const UChar*>(text.data());
500  UErrorCode error_code = U_ZERO_ERROR;
501  u_strToUTF8(nullptr, 0, nullptr, text_ptr, text.size(), &error_code);
502  if (error_code != U_BUFFER_OVERFLOW_ERROR) {
503  return tonic::ToDart("string is not well-formed UTF-16");
504  }
505 
506  m_paragraphBuilder->AddText(text);
507 
508  return Dart_Null();
509 }
510 
512  double height,
513  unsigned alignment,
514  double baseline_offset,
515  unsigned baseline) {
516  txt::PlaceholderRun placeholder_run(
517  width, height, static_cast<txt::PlaceholderAlignment>(alignment),
518  static_cast<txt::TextBaseline>(baseline), baseline_offset);
519 
520  m_paragraphBuilder->AddPlaceholder(placeholder_run);
521 
522  return Dart_Null();
523 }
524 
525 void ParagraphBuilder::build(Dart_Handle paragraph_handle) {
526  Paragraph::Create(paragraph_handle, m_paragraphBuilder->Build());
527 }
528 
529 } // namespace flutter
PlatformConfigurationClient * client() const
Access to the platform configuration client (which typically is implemented by the RuntimeController)...
constexpr uint32_t kColorDefault
Definition: paint.cc:45
#define FOR_EACH_BINDING(V)
G_BEGIN_DECLS FlValue * args
bool has_background
Definition: text_style.h:57
FontStyle
Definition: font_style.h:22
virtual FontCollection & GetFontCollection()=0
Returns the current collection of fonts available on the platform.
std::vector< std::string > strut_font_families
const void * data() const
Dart_Handle addPlaceholder(double width, double height, unsigned alignment, double baseline_offset, unsigned baseline)
std::vector< TextShadow > text_shadows
Definition: text_style.h:63
TextDecorationStyle
#define FML_DCHECK(condition)
Definition: logging.h:86
void build(Dart_Handle paragraph_handle)
void DartCallConstructor(Sig func, Dart_NativeArguments args)
Definition: dart_args.h:218
bool has_height_override
Definition: text_style.h:55
double height
Definition: text_style.h:54
double decoration_thickness_multiplier
Definition: text_style.h:43
FontStyle font_style
Definition: text_style.h:45
FontWeight strut_font_weight
FontWeight
Definition: font_weight.h:22
double letter_spacing
Definition: text_style.h:52
std::string locale
Definition: text_style.h:56
double font_size
Definition: text_style.h:51
std::u16string ellipsis
std::shared_ptr< txt::FontCollection > GetFontCollection() const
const SkPaint * paint() const
Definition: paint.h:18
#define DART_NATIVE_CALLBACK(CLASS, METHOD)
void decodeTextShadows(Dart_Handle shadows_data, std::vector< txt::TextShadow > &decoded_shadows)
std::string font_family
FontStyle strut_font_style
bool enable_skparagraph() const
FontFeatures font_features
Definition: text_style.h:64
double word_spacing
Definition: text_style.h:53
uint8_t value
bool half_leading
Definition: text_style.h:47
SkColor decoration_color
Definition: text_style.h:40
IMPLEMENT_WRAPPERTYPEINFO(ui, Scene)
size_t length_in_bytes() const
void pushStyle(tonic::Int32List &encoded, const std::vector< std::string > &fontFamilies, double fontSize, double letterSpacing, double wordSpacing, double height, double decorationThickness, const std::string &locale, Dart_Handle background_objects, Dart_Handle background_data, Dart_Handle foreground_objects, Dart_Handle foreground_data, Dart_Handle shadows_data, Dart_Handle font_features_data)
TextDecorationStyle decoration_style
Definition: text_style.h:41
std::vector< std::string > font_families
Definition: text_style.h:50
SkColor color
Definition: text_style.h:36
bool has_foreground
Definition: text_style.h:59
static void ThrowIfUIOperationsProhibited()
int32_t width
PlatformConfiguration * platform_configuration() const
void SetFeature(std::string tag, int value)
SkPaint foreground
Definition: text_style.h:60
int32_t height
void decodeFontFeatures(Dart_Handle font_features_data, txt::FontFeatures &font_features)
static std::unique_ptr< ParagraphBuilder > CreateTxtBuilder(const ParagraphStyle &style, std::shared_ptr< FontCollection > font_collection)
static fml::RefPtr< ParagraphBuilder > create(tonic::Int32List &encoded, Dart_Handle strutData, const std::string &fontFamily, const std::vector< std::string > &strutFontFamilies, double fontSize, double height, const std::u16string &ellipsis, const std::string &locale)
FontWeight font_weight
Definition: text_style.h:44
static void Create(Dart_Handle paragraph_handle, std::unique_ptr< txt::Paragraph > txt_paragraph)
Definition: paragraph.h:26
#define FML_CHECK(condition)
Definition: logging.h:68
std::u16string text
SkPaint background
Definition: text_style.h:58
#define DART_REGISTER_NATIVE(CLASS, METHOD)
Dart_Handle addText(const std::u16string &text)
TextDirection text_direction
Dart_Handle ToDart(const T &object)
static void ParagraphBuilder_constructor(Dart_NativeArguments args)
void decodeStrut(Dart_Handle strut_data, const std::vector< std::string > &strut_font_families, txt::ParagraphStyle &paragraph_style)
TextDecoration
static UIDartState * Current()