LCOV - code coverage report
Current view: top level - xenolith/font - XLFontLabelBase.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 550 565 97.3 %
Date: 2024-05-12 00:16:13 Functions: 123 125 98.4 %

          Line data    Source code
       1             : /**
       2             :  Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
       3             : 
       4             :  Permission is hereby granted, free of charge, to any person obtaining a copy
       5             :  of this software and associated documentation files (the "Software"), to deal
       6             :  in the Software without restriction, including without limitation the rights
       7             :  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       8             :  copies of the Software, and to permit persons to whom the Software is
       9             :  furnished to do so, subject to the following conditions:
      10             : 
      11             :  The above copyright notice and this permission notice shall be included in
      12             :  all copies or substantial portions of the Software.
      13             : 
      14             :  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      15             :  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      16             :  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      17             :  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      18             :  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      19             :  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      20             :  THE SOFTWARE.
      21             :  **/
      22             : 
      23             : #include "XLFontLabelBase.h"
      24             : #include "XLFontLocale.h"
      25             : 
      26             : namespace STAPPLER_VERSIONIZED stappler::xenolith::font {
      27             : 
      28       16448 : TextLayout::~TextLayout() { }
      29             : 
      30        8224 : TextLayout::TextLayout(FontController *h, size_t nchars, size_t nranges)
      31        8224 : : _handle(h) {
      32        8224 :         if (nchars) {
      33        8094 :                 _data.chars.reserve(nchars);
      34        8094 :                 _data.lines.reserve(nchars / 60);
      35             :         }
      36        8224 :         if (nranges) {
      37        8094 :                 _data.ranges.reserve(nranges);
      38             :         }
      39        8224 : }
      40             : 
      41         260 : void TextLayout::reserve(size_t nchars, size_t nranges) {
      42         260 :         _data.reserve(nchars, nranges);
      43         260 : }
      44             : 
      45        8094 : void TextLayout::clear() {
      46        8094 :         _data.chars.clear();
      47        8094 :         _data.lines.clear();
      48        8094 :         _data.ranges.clear();
      49        8094 :         _data.overflow = false;
      50        8094 : }
      51             : 
      52        8848 : Rc<FontFaceSet> TextLayout::getLayout(const FontParameters &f) {
      53        8848 :         auto font = _handle->getLayout(f);
      54        8848 :         if (font) {
      55        8824 :                 _fonts.emplace(font);
      56             :         }
      57        8848 :         return font;
      58           0 : }
      59             : 
      60         130 : RangeLineIterator TextLayout::begin() const {
      61         130 :         return _data.begin();
      62             : }
      63             : 
      64        1153 : RangeLineIterator TextLayout::end() const {
      65        1153 :         return _data.end();
      66             : }
      67             : 
      68         130 : auto TextLayout::str(bool filter) const -> WideString {
      69         130 :         WideString ret; ret.reserve(_data.chars.size());
      70         130 :         _data.str([&] (char16_t ch) {
      71       11390 :                 ret.push_back(ch);
      72       11390 :         }, filter);
      73         130 :         return ret;
      74           0 : }
      75             : 
      76         130 : auto TextLayout::str(uint32_t s_start, uint32_t s_end, size_t maxWords, bool ellipsis, bool filter) const -> WideString {
      77         130 :         WideString ret; ret.reserve(s_end - s_start + 2);
      78         130 :         _data.str([&] (char16_t ch) {
      79          55 :                 ret.push_back(ch);
      80          55 :         }, s_start, s_end, maxWords, ellipsis, filter);
      81         130 :         return ret;
      82           0 : }
      83             : 
      84         532 : Pair<uint32_t, CharSelectMode> TextLayout::getChar(int32_t x, int32_t y, CharSelectMode m) const {
      85         532 :         return _data.getChar(x, y, m);
      86             : }
      87             : 
      88          60 : const LineLayoutData *TextLayout::getLine(uint32_t charIndex) const {
      89          60 :         return _data.getLine(charIndex);
      90             : }
      91             : 
      92         130 : uint32_t TextLayout::getLineForChar(uint32_t charIndex) const {
      93         130 :         return _data.getLineForChar(charIndex);
      94             : }
      95             : 
      96         142 : Pair<uint32_t, uint32_t> TextLayout::selectWord(uint32_t origin) const {
      97         142 :         return _data.selectWord(origin);
      98             : }
      99             : 
     100         130 : geom::Rect TextLayout::getLineRect(uint32_t lineId, float density, const geom::Vec2 &origin) const {
     101         130 :         return _data.getLineRect(lineId, density, origin);
     102             : }
     103             : 
     104        1023 : geom::Rect TextLayout::getLineRect(const LineLayoutData &line, float density, const geom::Vec2 &origin) const {
     105        1023 :         return _data.getLineRect(line, density, origin);
     106             : }
     107             : 
     108          12 : auto TextLayout::getLabelRects(uint32_t firstCharId, uint32_t lastCharId, float density, const geom::Vec2 &origin, const geom::Padding &p) const -> Vector<geom::Rect> {
     109          12 :         Vector<geom::Rect> ret;
     110          12 :         getLabelRects(ret, firstCharId, lastCharId, density, origin, p);
     111          12 :         return ret;
     112           0 : }
     113             : 
     114          12 : void TextLayout::getLabelRects(Vector<geom::Rect> &ret, uint32_t firstCharId, uint32_t lastCharId, float density, const geom::Vec2 &origin, const geom::Padding &p) const {
     115          12 :         _data.getLabelRects([&] (const geom::Rect &rect) {
     116          12 :                 ret.push_back(rect);
     117          12 :         }, firstCharId, lastCharId, density, origin, p);
     118          12 : }
     119             : 
     120        3898 : LabelBase::DescriptionStyle::DescriptionStyle() {
     121        3898 :         font.fontFamily = StringView("default");
     122        3898 :         font.fontSize = FontSize(14);
     123        3898 :         text.opacity = 222;
     124        3898 :         text.color = Color3B::BLACK;
     125        3898 :         text.whiteSpace = font::WhiteSpace::PreWrap;
     126        3898 : }
     127             : 
     128         130 : String LabelBase::DescriptionStyle::getConfigName(bool caps) const {
     129         130 :         return font.getConfigName<Interface>(caps);
     130             : }
     131             : 
     132       10148 : LabelBase::DescriptionStyle LabelBase::DescriptionStyle::merge(
     133             :                 const Rc<font::FontController> &source, const Style &style) const {
     134       10148 :         DescriptionStyle ret(*this);
     135       12204 :         for (auto &it : style.params) {
     136        2056 :                 switch (it.name) {
     137         130 :                 case Style::Name::TextTransform: ret.text.textTransform = it.value.textTransform; break;
     138         254 :                 case Style::Name::TextDecoration: ret.text.textDecoration = it.value.textDecoration; break;
     139         130 :                 case Style::Name::Hyphens: ret.text.hyphens = it.value.hyphens; break;
     140         130 :                 case Style::Name::VerticalAlign: ret.text.verticalAlign = it.value.verticalAlign; break;
     141         130 :                 case Style::Name::Color: ret.text.color = it.value.color; ret.colorDirty = true; break;
     142         130 :                 case Style::Name::Opacity: ret.text.opacity = it.value.opacity; ret.opacityDirty = true; break;
     143         254 :                 case Style::Name::FontSize: ret.font.fontSize = it.value.fontSize; break;
     144         130 :                 case Style::Name::FontStyle: ret.font.fontStyle = it.value.fontStyle; break;
     145         254 :                 case Style::Name::FontWeight: ret.font.fontWeight = it.value.fontWeight; break;
     146         254 :                 case Style::Name::FontStretch: ret.font.fontStretch = it.value.fontStretch; break;
     147         130 :                 case Style::Name::FontFamily: ret.font.fontFamily = source->getFamilyName(it.value.fontFamily); break;
     148         130 :                 case Style::Name::FontGrade: ret.font.fontGrade = it.value.fontGrade; break;
     149             :                 }
     150             :         }
     151       10148 :         return ret;
     152             : }
     153             : 
     154         260 : bool LabelBase::DescriptionStyle::operator == (const DescriptionStyle &style) const {
     155         260 :         return font == style.font && text == style.text && colorDirty == style.colorDirty && opacityDirty == style.opacityDirty;
     156             : }
     157         130 : bool LabelBase::DescriptionStyle::operator != (const DescriptionStyle &style) const {
     158         130 :         return !((*this) == style);
     159             : }
     160             : 
     161        1858 : LabelBase::Style::Value::Value() {
     162        1858 :         memset(this, 0, sizeof(Value));
     163        1858 : }
     164             : 
     165         754 : void LabelBase::Style::set(const Param &p, bool force) {
     166         754 :         if (force) {
     167         754 :                 auto it = params.begin();
     168        1007 :                 while(it != params.end()) {
     169         253 :                         if (it->name == p.name) {
     170         129 :                                 it = params.erase(it);
     171             :                         } else {
     172         124 :                                 it ++;
     173             :                         }
     174             :                 }
     175             :         }
     176         754 :         params.push_back(p);
     177         754 : }
     178             : 
     179         496 : void LabelBase::Style::merge(const Style &style) {
     180         992 :         for (auto &it : style.params) {
     181         496 :                 set(it, true);
     182             :         }
     183         496 : }
     184             : 
     185         496 : void LabelBase::Style::clear() {
     186         496 :         params.clear();
     187         496 : }
     188             : 
     189         130 : LabelBase::ExternalFormatter::~ExternalFormatter() { }
     190             : 
     191         259 : bool LabelBase::ExternalFormatter::init(font::FontController *s, float w, float density) {
     192         259 :         if (!s) {
     193         129 :                 return false;
     194             :         }
     195             : 
     196         130 :         _density = density;
     197         130 :         _spec = Rc<TextLayout>::alloc(s);
     198         130 :         _formatter.setFontCallback([this] (const FontParameters &f) {
     199         260 :                 return _spec->getLayout(f);
     200             :         });
     201         130 :         _formatter.reset(_spec->getData());
     202         130 :         if (w > 0.0f) {
     203         130 :                 _formatter.setWidth(static_cast<uint16_t>(roundf(w * _density)));
     204             :         }
     205         130 :         return true;
     206             : }
     207             : 
     208         130 : void LabelBase::ExternalFormatter::setLineHeightAbsolute(float value) {
     209         130 :         _formatter.setLineHeightAbsolute(static_cast<uint16_t>(value * _density));
     210         130 : }
     211             : 
     212         130 : void LabelBase::ExternalFormatter::setLineHeightRelative(float value) {
     213         130 :         _formatter.setLineHeightRelative(value);
     214         130 : }
     215             : 
     216         130 : void LabelBase::ExternalFormatter::reserve(size_t chars, size_t ranges) {
     217         130 :         if (_spec) {
     218         130 :                 _spec->reserve(chars, ranges);
     219             :         }
     220         130 : }
     221             : 
     222         130 : void LabelBase::ExternalFormatter::addString(const DescriptionStyle &style, const StringView &str, bool localized) {
     223         130 :         addString(style, string::toUtf16<Interface>(str), localized);
     224         130 : }
     225         260 : void LabelBase::ExternalFormatter::addString(const DescriptionStyle &style, const WideStringView &str, bool localized) {
     226         260 :         if (!begin) {
     227         130 :                 _formatter.begin(0, 0);
     228         130 :                 begin = true;
     229             :         }
     230         260 :         if (localized && locale::hasLocaleTags(str)) {
     231         129 :                 auto u16str = locale::resolveLocaleTags(str);
     232         129 :                 _formatter.read(style.font, style.text, u16str.data(), u16str.size());
     233         129 :         } else {
     234         131 :                 _formatter.read(style.font, style.text, str.data(), str.size());
     235             :         }
     236         260 : }
     237             : 
     238         259 : Size2 LabelBase::ExternalFormatter::finalize() {
     239         259 :         if (_spec) {
     240         130 :                 _formatter.finalize();
     241         130 :                 return Size2(_spec->getWidth() / _density, _spec->getHeight() / _density);
     242             :         }
     243         129 :         return Size2();
     244             : }
     245             : 
     246         258 : WideString LabelBase::getLocalizedString(const StringView &s) {
     247         258 :         return getLocalizedString(string::toUtf16<Interface>(s));
     248             : }
     249         258 : WideString LabelBase::getLocalizedString(const WideStringView &s) {
     250         258 :         if (locale::hasLocaleTags(s)) {
     251         129 :                 return locale::resolveLocaleTags(s);
     252             :         }
     253         129 :         return s.str<Interface>();
     254             : }
     255             : 
     256         393 : float LabelBase::getStringWidth(font::FontController *source, const DescriptionStyle &style,
     257             :                 const StringView &str, bool localized) {
     258         393 :         return getStringWidth(source, style, string::toUtf16<Interface>(str), localized);
     259             : }
     260             : 
     261         393 : float LabelBase::getStringWidth(font::FontController *source, const DescriptionStyle &style,
     262             :                 const WideStringView &str, bool localized) {
     263         393 :         if (!source) {
     264         129 :                 return 0.0f;
     265             :         }
     266             : 
     267         264 :         TextLayoutData<Interface> spec;
     268             : 
     269         264 :         font::Formatter fmt([source = Rc<font::FontController>(source)] (const FontParameters &f) {
     270         264 :                 return source->getLayout(f);
     271         528 :         }, &spec);
     272         264 :         fmt.begin(0, 0);
     273             : 
     274         264 :         if (localized && locale::hasLocaleTags(str)) {
     275         129 :                 auto u16str = locale::resolveLocaleTags(str);
     276         129 :                 spec.reserve(u16str.size());
     277         129 :                 fmt.read(style.font, style.text, u16str.data(), u16str.size());
     278         129 :         } else {
     279         135 :                 spec.reserve(str.size());
     280         135 :                 fmt.read(style.font, style.text, str.data(), str.size());
     281             :         }
     282             : 
     283         264 :         fmt.finalize();
     284         264 :         return spec.width / style.font.density;
     285         264 : }
     286             : 
     287         516 : Size2 LabelBase::getLabelSize(font::FontController *source, const DescriptionStyle &style,
     288             :                 const StringView &s, float w, bool localized) {
     289         516 :         return getLabelSize(source, style, string::toUtf16<Interface>(s), w, localized);
     290             : }
     291             : 
     292         516 : Size2 LabelBase::getLabelSize(font::FontController *source, const DescriptionStyle &style,
     293             :                 const WideStringView &str, float w, bool localized) {
     294         516 :         if (str.empty()) {
     295         129 :                 return Size2(0.0f, 0.0f);
     296             :         }
     297             : 
     298         387 :         if (!source) {
     299         129 :                 return Size2(0.0f, 0.0f);
     300             :         }
     301             : 
     302         258 :         TextLayoutData<Interface> spec;
     303             : 
     304         258 :         font::Formatter fmt([source = Rc<font::FontController>(source)] (const FontParameters &f) {
     305         258 :                 return source->getLayout(f);
     306         516 :         }, &spec);
     307         258 :         fmt.setWidth(static_cast<uint16_t>(roundf(w * style.font.density)));
     308         258 :         fmt.begin(0, 0);
     309             : 
     310         258 :         if (localized && locale::hasLocaleTags(str)) {
     311         129 :                 auto u16str = locale::resolveLocaleTags(str);
     312         129 :                 spec.reserve(u16str.size());
     313         129 :                 fmt.read(style.font, style.text, u16str.data(), u16str.size());
     314         129 :         } else {
     315         129 :                 spec.reserve(str.size());
     316         129 :                 fmt.read(style.font, style.text, str.data(), str.size());
     317             :         }
     318             : 
     319         258 :         fmt.finalize();
     320         258 :         return Size2(spec.maxAdvance / style.font.density, spec.height / style.font.density);
     321         258 : }
     322             : 
     323        2135 : void LabelBase::setAlignment(TextAlign alignment) {
     324        2135 :         if (_alignment != alignment) {
     325         324 :                 _alignment = alignment;
     326         324 :                 setLabelDirty();
     327             :         }
     328        2135 : }
     329             : 
     330         129 : TextAlign LabelBase::getAlignment() const {
     331         129 :         return _alignment;
     332             : }
     333             : 
     334        2147 : void LabelBase::setWidth(float width) {
     335        2147 :         if (_width != width) {
     336         288 :                 _width = width;
     337         288 :                 setLabelDirty();
     338             :         }
     339        2147 : }
     340             : 
     341         129 : float LabelBase::getWidth() const {
     342         129 :         return _width;
     343             : }
     344             : 
     345           8 : void LabelBase::setTextIndent(float value) {
     346           8 :         if (_textIndent != value) {
     347           8 :                 _textIndent = value;
     348           8 :                 setLabelDirty();
     349             :         }
     350           8 : }
     351         129 : float LabelBase::getTextIndent() const {
     352         129 :         return _textIndent;
     353             : }
     354             : 
     355         158 : void LabelBase::setTextTransform(const TextTransform &value) {
     356         158 :         if (value != _style.text.textTransform) {
     357          62 :                 _style.text.textTransform = value;
     358          62 :                 setLabelDirty();
     359             :         }
     360         158 : }
     361             : 
     362         129 : TextTransform LabelBase::getTextTransform() const {
     363         129 :         return _style.text.textTransform;
     364             : }
     365             : 
     366           7 : void LabelBase::setTextDecoration(const TextDecoration &value) {
     367           7 :         if (value != _style.text.textDecoration) {
     368           7 :                 _style.text.textDecoration = value;
     369           7 :                 setLabelDirty();
     370             :         }
     371           7 : }
     372          14 : TextDecoration LabelBase::getTextDecoration() const {
     373          14 :         return _style.text.textDecoration;
     374             : }
     375             : 
     376           8 : void LabelBase::setHyphens(const Hyphens &value) {
     377           8 :         if (value != _style.text.hyphens) {
     378           8 :                 _style.text.hyphens = value;
     379           8 :                 setLabelDirty();
     380             :         }
     381           8 : }
     382         129 : Hyphens LabelBase::getHyphens() const {
     383         129 :         return _style.text.hyphens;
     384             : }
     385             : 
     386           8 : void LabelBase::setVerticalAlign(const VerticalAlign &value) {
     387           8 :         if (value != _style.text.verticalAlign) {
     388           8 :                 _style.text.verticalAlign = value;
     389           8 :                 setLabelDirty();
     390             :         }
     391           8 : }
     392         129 : VerticalAlign LabelBase::getVerticalAlign() const {
     393         129 :         return _style.text.verticalAlign;
     394             : }
     395             : 
     396        1557 : void LabelBase::setFontSize(const uint16_t &value) {
     397        1557 :         setFontSize(FontSize(value));
     398        1557 : }
     399             : 
     400        2373 : void LabelBase::setFontSize(const FontSize &value) {
     401        2373 :         auto realTargetValue = value.scale(_labelDensity).get();
     402        2373 :         auto realSourceValue = _style.font.fontSize.scale(_labelDensity).get();
     403             : 
     404        2373 :         if (realTargetValue != realSourceValue) {
     405        1019 :                 _style.font.fontSize = value;
     406        1019 :                 setLabelDirty();
     407             :         }
     408        2373 : }
     409          12 : FontSize LabelBase::getFontSize() const {
     410          12 :         return _style.font.fontSize;
     411             : }
     412             : 
     413         393 : void LabelBase::setFontStyle(const FontStyle &value) {
     414         393 :         if (value != _style.font.fontStyle) {
     415         369 :                 _style.font.fontStyle = value;
     416         369 :                 setLabelDirty();
     417             :         }
     418         393 : }
     419         129 : FontStyle LabelBase::getFontStyle() const {
     420         129 :         return _style.font.fontStyle;
     421             : }
     422             : 
     423        1035 : void LabelBase::setFontWeight(const FontWeight &value) {
     424        1035 :         if (value != _style.font.fontWeight) {
     425         843 :                 _style.font.fontWeight = value;
     426         843 :                 setLabelDirty();
     427             :         }
     428        1035 : }
     429         129 : FontWeight LabelBase::getFontWeight() const {
     430         129 :         return _style.font.fontWeight;
     431             : }
     432             : 
     433         381 : void LabelBase::setFontStretch(const FontStretch &value) {
     434         381 :         if (value != _style.font.fontStretch) {
     435         381 :                 _style.font.fontStretch = value;
     436         381 :                 setLabelDirty();
     437             :         }
     438         381 : }
     439         129 : FontStretch LabelBase::getFontStretch() const {
     440         129 :         return _style.font.fontStretch;
     441             : }
     442             : 
     443         381 : void LabelBase::setFontGrade(const FontGrade &value) {
     444         381 :         if (value != _style.font.fontGrade) {
     445         381 :                 _style.font.fontGrade = value;
     446         381 :                 setLabelDirty();
     447             :         }
     448         381 : }
     449             : 
     450         129 : FontGrade LabelBase::getFontGrade() const {
     451         129 :         return _style.font.fontGrade;
     452             : }
     453             : 
     454         648 : void LabelBase::setFontFamily(const StringView &value) {
     455         648 :         if (value != _style.font.fontFamily) {
     456         648 :                 _fontFamilyStorage = value.str<Interface>();
     457         648 :                 _style.font.fontFamily = _fontFamilyStorage;
     458         648 :                 setLabelDirty();
     459             :         }
     460         648 : }
     461         129 : StringView LabelBase::getFontFamily() const {
     462         129 :         return _style.font.fontFamily;
     463             : }
     464             : 
     465           8 : void LabelBase::setLineHeightAbsolute(float value) {
     466           8 :         if (!_isLineHeightAbsolute || _lineHeight != value) {
     467           8 :                 _isLineHeightAbsolute = true;
     468           8 :                 _lineHeight = value;
     469           8 :                 setLabelDirty();
     470             :         }
     471           8 : }
     472           8 : void LabelBase::setLineHeightRelative(float value) {
     473           8 :         if (_isLineHeightAbsolute || _lineHeight != value) {
     474           8 :                 _isLineHeightAbsolute = false;
     475           8 :                 _lineHeight = value;
     476           8 :                 setLabelDirty();
     477             :         }
     478           8 : }
     479         129 : float LabelBase::getLineHeight() const {
     480         129 :         return _lineHeight;
     481             : }
     482         129 : bool LabelBase::isLineHeightAbsolute() const {
     483         129 :         return _isLineHeightAbsolute;
     484             : }
     485             : 
     486          36 : void LabelBase::setMaxWidth(float value) {
     487          36 :         if (_maxWidth != value) {
     488          12 :                 _maxWidth = value;
     489          12 :                 setLabelDirty();
     490             :         }
     491          36 : }
     492         129 : float LabelBase::getMaxWidth() const {
     493         129 :         return _maxWidth;
     494             : }
     495             : 
     496         192 : void LabelBase::setMaxLines(size_t value) {
     497         192 :         if (_maxLines != value) {
     498         168 :                 _maxLines = value;
     499         168 :                 setLabelDirty();
     500             :         }
     501         192 : }
     502         129 : size_t LabelBase::getMaxLines() const {
     503         129 :         return _maxLines;
     504             : }
     505             : 
     506           8 : void LabelBase::setMaxChars(size_t value) {
     507           8 :         if (_maxChars != value) {
     508           8 :                 _maxChars = value;
     509           8 :                 setLabelDirty();
     510             :         }
     511           8 : }
     512         396 : size_t LabelBase::getMaxChars() const {
     513         396 :         return _maxChars;
     514             : }
     515             : 
     516           8 : void LabelBase::setOpticalAlignment(bool value) {
     517           8 :         if (_opticalAlignment != value) {
     518           8 :                 _opticalAlignment = value;
     519           8 :                 setLabelDirty();
     520             :         }
     521           8 : }
     522         129 : bool LabelBase::isOpticallyAligned() const {
     523         129 :         return _opticalAlignment;
     524             : }
     525             : 
     526           8 : void LabelBase::setFillerChar(char16_t c) {
     527           8 :         if (c != _fillerChar) {
     528           8 :                 _fillerChar = c;
     529           8 :                 setLabelDirty();
     530             :         }
     531           8 : }
     532         129 : char16_t LabelBase::getFillerChar() const {
     533         129 :         return _fillerChar;
     534             : }
     535             : 
     536         492 : void LabelBase::setLocaleEnabled(bool value) {
     537         492 :         if (_localeEnabled != value) {
     538         471 :                 _localeEnabled = value;
     539         471 :                 setLabelDirty();
     540             :         }
     541         492 : }
     542         129 : bool LabelBase::isLocaleEnabled() const {
     543         129 :         return _localeEnabled;
     544             : }
     545             : 
     546          48 : void LabelBase::setPersistentLayout(bool value) {
     547          48 :         if (_persistentLayout != value) {
     548          48 :                 _persistentLayout = value;
     549          48 :                 setLabelDirty();
     550             :         }
     551          48 : }
     552             : 
     553         129 : bool LabelBase::isPersistentLayout() const {
     554         129 :         return _persistentLayout;
     555             : }
     556             : 
     557      117609 : void LabelBase::setString(const StringView &newString) {
     558      117609 :         if (newString == _string8) {
     559      109129 :                 return;
     560             :         }
     561             : 
     562        8480 :         _string8 = newString.str<Interface>();
     563        8480 :         _string16 = string::toUtf16<Interface>(newString);
     564        8480 :         if (!_localeEnabled && locale::hasLocaleTagsFast(_string16)) {
     565           8 :                 setLocaleEnabled(true);
     566             :         }
     567        8480 :         setLabelDirty();
     568        8480 :         clearStyles();
     569             : }
     570             : 
     571         417 : void LabelBase::setString(const WideStringView &newString) {
     572         417 :         if (newString == _string16) {
     573          14 :                 return;
     574             :         }
     575             : 
     576         403 :         _string8 = string::toUtf8<Interface>(newString);
     577         403 :         _string16 = newString.str<Interface>();
     578         403 :         if (!_localeEnabled && locale::hasLocaleTagsFast(_string16)) {
     579           7 :                 setLocaleEnabled(true);
     580             :         }
     581         403 :         setLabelDirty();
     582         403 :         clearStyles();
     583             : }
     584             : 
     585           7 : void LabelBase::setLocalizedString(size_t idx) {
     586           7 :         setString(localeIndex(idx));
     587           7 :         setLocaleEnabled(true);
     588           7 : }
     589             : 
     590         129 : WideStringView LabelBase::getString() const {
     591         129 :         return _string16;
     592             : }
     593             : 
     594         129 : StringView LabelBase::getString8() const {
     595         129 :         return _string8;
     596             : }
     597             : 
     598           7 : void LabelBase::erase16(size_t start, size_t len) {
     599           7 :         if (start >= _string16.length()) {
     600           0 :                 return;
     601             :         }
     602             : 
     603           7 :         _string16.erase(start, len);
     604           7 :         _string8 = string::toUtf8<Interface>(_string16);
     605           7 :         setLabelDirty();
     606             : }
     607             : 
     608           7 : void LabelBase::erase8(size_t start, size_t len) {
     609           7 :         if (start >= _string8.length()) {
     610           0 :                 return;
     611             :         }
     612             : 
     613           7 :         _string8.erase(start, len);
     614           7 :         _string16 = string::toUtf16<Interface>(_string8);
     615           7 :         setLabelDirty();
     616             : }
     617             : 
     618          10 : void LabelBase::append(const StringView &value) {
     619          10 :         _string8.append(value.str<Interface>());
     620          10 :         _string16 = string::toUtf16<Interface>(_string8);
     621          10 :         setLabelDirty();
     622          10 : }
     623          18 : void LabelBase::append(const WideStringView &value) {
     624          18 :         _string16.append(value.str<Interface>());
     625          18 :         _string8 = string::toUtf8<Interface>(_string16);
     626          18 :         setLabelDirty();
     627          18 : }
     628             : 
     629          10 : void LabelBase::prepend(const StringView &value) {
     630          10 :         _string8 = toString(value, _string8);
     631          10 :         _string16 = string::toUtf16<Interface>(_string8);
     632          10 :         setLabelDirty();
     633          10 : }
     634          10 : void LabelBase::prepend(const WideStringView &value) {
     635          10 :         _string16 = value.str<Interface>() + _string16;
     636          10 :         _string8 = string::toUtf8<Interface>(_string16);
     637          10 :         setLabelDirty();
     638          10 : }
     639             : 
     640          40 : void LabelBase::setTextRangeStyle(size_t start, size_t length, Style &&style) {
     641          40 :         if (length > 0) {
     642          40 :                 _styles.emplace_back(start, length, std::move(style));
     643          40 :                 setLabelDirty();
     644             :         }
     645          40 : }
     646             : 
     647          10 : void LabelBase::appendTextWithStyle(const StringView &str, Style &&style) {
     648          10 :         auto start = _string16.length();
     649          10 :         append(str);
     650          10 :         setTextRangeStyle(start, _string16.length() - start, std::move(style));
     651          10 : }
     652             : 
     653          10 : void LabelBase::appendTextWithStyle(const WideStringView &str, Style &&style) {
     654          10 :         auto start = _string16.length();
     655          10 :         append(str);
     656          10 :         setTextRangeStyle(start, str.size(), std::move(style));
     657          10 : }
     658             : 
     659          10 : void LabelBase::prependTextWithStyle(const StringView &str, Style &&style) {
     660          10 :         auto len = _string16.length();
     661          10 :         prepend(str);
     662          10 :         setTextRangeStyle(0, _string16.length() - len, std::move(style));
     663          10 : }
     664          10 : void LabelBase::prependTextWithStyle(const WideStringView &str, Style &&style) {
     665          10 :         prepend(str);
     666          10 :         setTextRangeStyle(0, str.size(), std::move(style));
     667          10 : }
     668             : 
     669        8883 : void LabelBase::clearStyles() {
     670        8883 :         _styles.clear();
     671        8883 :         setLabelDirty();
     672        8883 : }
     673             : 
     674         136 : const LabelBase::StyleVec &LabelBase::getStyles() const {
     675         136 :         return _styles;
     676             : }
     677             : 
     678         129 : const LabelBase::StyleVec &LabelBase::getCompiledStyles() const {
     679         129 :         return _compiledStyles;
     680             : }
     681             : 
     682           7 : void LabelBase::setStyles(StyleVec &&vec) {
     683           7 :         _styles = std::move(vec);
     684           7 :         setLabelDirty();
     685           7 : }
     686           7 : void LabelBase::setStyles(const StyleVec &vec) {
     687           7 :         _styles = vec;
     688           7 :         setLabelDirty();
     689           7 : }
     690             : 
     691        8094 : bool LabelBase::updateFormatSpec(TextLayout *format, const StyleVec &compiledStyles, float density, uint8_t _adjustValue) {
     692        8094 :         bool success = true;
     693        8094 :         uint16_t adjustValue = maxOf<uint16_t>();
     694             : 
     695             :         do {
     696        8094 :                 if (adjustValue == maxOf<uint16_t>()) {
     697        8094 :                         adjustValue = 0;
     698             :                 } else {
     699           0 :                         adjustValue += 1;
     700             :                 }
     701             : 
     702        8094 :                 format->clear();
     703             : 
     704        8588 :                 font::Formatter formatter([format] (const FontParameters &f) {
     705        8588 :                         return format->getLayout(f);
     706        8094 :                 }, format->getData());
     707        8094 :                 formatter.setWidth(static_cast<uint16_t>(roundf(_width * density)));
     708        8094 :                 formatter.setTextAlignment(_alignment);
     709        8094 :                 formatter.setMaxWidth(static_cast<uint16_t>(roundf(_maxWidth * density)));
     710        8094 :                 formatter.setMaxLines(_maxLines);
     711        8094 :                 formatter.setOpticalAlignment(_opticalAlignment);
     712        8094 :                 formatter.setFillerChar(_fillerChar);
     713        8094 :                 formatter.setEmplaceAllChars(_emplaceAllChars);
     714             : 
     715        8094 :                 if (_lineHeight != 0.0f) {
     716         129 :                         if (_isLineHeightAbsolute) {
     717           0 :                                 formatter.setLineHeightAbsolute(static_cast<uint16_t>(_lineHeight * density));
     718             :                         } else {
     719         129 :                                 formatter.setLineHeightRelative(_lineHeight);
     720             :                         }
     721             :                 }
     722             : 
     723        8094 :                 formatter.begin(static_cast<uint16_t>(roundf(_textIndent * density)));
     724             : 
     725        8094 :                 size_t drawedChars = 0;
     726       16658 :                 for (auto &it : compiledStyles) {
     727        8588 :                         DescriptionStyle params = _style.merge(dynamic_cast<font::FontController *>(format->getController()), it.style);
     728        8588 :                         specializeStyle(params, density);
     729        8588 :                         if (adjustValue > 0) {
     730           0 :                                 params.font.fontSize -= FontSize(adjustValue);
     731             :                         }
     732             : 
     733        8588 :                         auto start = _string16.c_str() + it.start;
     734        8588 :                         auto len = it.length;
     735             : 
     736        8588 :                         if (_localeEnabled && hasLocaleTags(WideStringView(start, len))) {
     737         136 :                                 WideString str(resolveLocaleTags(WideStringView(start, len)));
     738             : 
     739         136 :                                 start = str.c_str();
     740         136 :                                 len = str.length();
     741             : 
     742         136 :                                 if (_maxChars > 0 && drawedChars + len > _maxChars) {
     743           0 :                                         len = _maxChars - drawedChars;
     744             :                                 }
     745         136 :                                 if (!formatter.read(params.font, params.text, start, len)) {
     746           0 :                                         drawedChars += len;
     747           0 :                                         success = false;
     748           0 :                                         break;
     749             :                                 }
     750         136 :                         } else {
     751        8452 :                                 if (_maxChars > 0 && drawedChars + len > _maxChars) {
     752           0 :                                         len = _maxChars - drawedChars;
     753             :                                 }
     754        8452 :                                 if (!formatter.read(params.font, params.text, start, len)) {
     755          24 :                                         drawedChars += len;
     756          24 :                                         success = false;
     757          24 :                                         break;
     758             :                                 }
     759             :                         }
     760             : 
     761        8564 :                         if (!format->getData()->ranges.empty()) {
     762        8564 :                                 format->getData()->ranges.back().colorDirty = params.colorDirty;
     763        8564 :                                 format->getData()->ranges.back().opacityDirty = params.opacityDirty;
     764             :                         }
     765             :                 }
     766        8094 :                 formatter.finalize();
     767        8094 :         } while (format->isOverflow() && adjustValue < _adjustValue);
     768             : 
     769        8094 :         return success;
     770             : }
     771             : 
     772        1751 : LabelBase::~LabelBase() { }
     773             : 
     774         129 : bool LabelBase::isLabelDirty() const {
     775         129 :         return _labelDirty;
     776             : }
     777             : 
     778        8712 : static void LabelBase_dumpStyle(LabelBase::StyleVec &ret, size_t pos, size_t len, const LabelBase::Style &style) {
     779        8712 :         if (len > 0) {
     780        8588 :                 ret.emplace_back(pos, len, style);
     781             :         }
     782        8712 : }
     783             : 
     784        8094 : LabelBase::StyleVec LabelBase::compileStyle() const {
     785        8094 :         size_t pos = 0;
     786        8094 :         size_t max = _string16.length();
     787             : 
     788        8094 :         StyleVec ret;
     789        8094 :         StyleVec vec = _styles;
     790             : 
     791        8094 :         Style compiledStyle;
     792             : 
     793        8094 :         size_t dumpPos = 0;
     794             : 
     795      441657 :         for (pos = 0; pos < max; pos ++) {
     796      433563 :                 auto it = vec.begin();
     797             : 
     798      433563 :                 bool cleaned = false;
     799             :                 // check for endings
     800      451569 :                 while(it != vec.end()) {
     801       18006 :                         if (it->start + it->length <= pos) {
     802         496 :                                 LabelBase_dumpStyle(ret, dumpPos, pos - dumpPos, compiledStyle);
     803         496 :                                 compiledStyle.clear();
     804         496 :                                 cleaned = true;
     805         496 :                                 dumpPos = pos;
     806         496 :                                 it = vec.erase(it);
     807             :                         } else {
     808       17510 :                                 it ++;
     809             :                         }
     810             :                 }
     811             : 
     812             :                 // checks for continuations and starts
     813      433563 :                 it = vec.begin();
     814      451073 :                 while(it != vec.end()) {
     815       17510 :                         if (it->start == pos) {
     816         496 :                                 if (dumpPos != pos) {
     817         122 :                                         LabelBase_dumpStyle(ret, dumpPos, pos - dumpPos, compiledStyle);
     818         122 :                                         dumpPos = pos;
     819             :                                 }
     820         496 :                                 compiledStyle.merge(it->style);
     821       17014 :                         } else if (it->start <= pos && it->start + it->length > pos) {
     822        4960 :                                 if (cleaned) {
     823           0 :                                         compiledStyle.merge(it->style);
     824             :                                 }
     825             :                         }
     826       17510 :                         it ++;
     827             :                 }
     828             :         }
     829             : 
     830        8094 :         LabelBase_dumpStyle(ret, dumpPos, pos - dumpPos, compiledStyle);
     831             : 
     832       16188 :         return ret;
     833        8094 : }
     834             : 
     835         786 : bool LabelBase::hasLocaleTags(const WideStringView &str) const {
     836         786 :         return locale::hasLocaleTags(str);
     837             : }
     838             : 
     839         265 : WideString LabelBase::resolveLocaleTags(const WideStringView &str) const {
     840         265 :         return locale::resolveLocaleTags(str);
     841             : }
     842             : 
     843        8588 : void LabelBase::specializeStyle(DescriptionStyle &style, float density) const {
     844        8588 :         style.font.density = density;
     845        8588 :         style.font.persistent = _persistentLayout;
     846        8588 : }
     847             : 
     848       23425 : void LabelBase::setLabelDirty() {
     849       23425 :         _labelDirty = true;
     850       23425 : }
     851             : 
     852             : }

Generated by: LCOV version 1.14