TextFragment subText(const TextFragment& frag, int start, int end) { // this impl does an unneccesary copy, to keep TextFragment very simple for now. if(!frag) return TextFragment(); if(start >= end) return TextFragment(); // we won't know the output fragment size in bytes until iterating the code points. int len = frag.lengthInBytes(); SmallStackBuffer<char> temp(len); char* buf = temp.data(); char* pb = buf; auto first = codepoint_iterator<const char*>(frag.getText()); auto it = first; for(int i=0; i<start; ++i) { ++it; } for (int i=0; i<end - start; ++i) { // write the codepoint as UTF-8 to the buffer if(!utf::internal::validate_codepoint(*it)) return TextFragment(); pb = utf::internal::utf_traits<utf::utf8>::encode(*it, pb); ++it; } return TextFragment(buf, pb - buf); }
TextFragmentIterator::TextFragment TextFragmentIterator::findNextTextFragment(float xPosition) { // A fragment can either be // 1. line break when <br> is present or preserveNewline is on (not considered as whitespace) or // 2. whitespace (collasped, non-collapsed multi or single) or // 3. non-whitespace characters. // 4. content end. ASSERT(m_currentSegment != m_flowContents.end()); unsigned startPosition = m_position; if (m_atEndOfSegment) ++m_currentSegment; if (m_currentSegment == m_flowContents.end()) return TextFragment(startPosition, startPosition, 0, TextFragment::ContentEnd); if (isHardLineBreak(m_currentSegment)) return TextFragment(startPosition, startPosition, 0, TextFragment::HardLineBreak); if (isSoftLineBreak(startPosition)) { unsigned endPosition = ++m_position; return TextFragment(startPosition, endPosition, 0, TextFragment::SoftLineBreak); } float width = 0; bool overlappingFragment = false; unsigned endPosition = skipToNextPosition(PositionType::NonWhitespace, startPosition, width, xPosition, overlappingFragment); unsigned segmentEndPosition = m_currentSegment->end; ASSERT(startPosition <= endPosition); if (startPosition < endPosition) { bool multipleWhitespace = startPosition + 1 < endPosition; bool isCollapsed = multipleWhitespace && m_style.collapseWhitespace; m_position = endPosition; return TextFragment(startPosition, endPosition, width, TextFragment::Whitespace, endPosition == segmentEndPosition, false, isCollapsed, m_style.collapseWhitespace); } endPosition = skipToNextPosition(PositionType::Breakable, startPosition, width, xPosition, overlappingFragment); m_position = endPosition; return TextFragment(startPosition, endPosition, width, TextFragment::NonWhitespace, endPosition == segmentEndPosition, overlappingFragment, false, false); }
int SymbolTable::getSymbolID(const HashedCharArray& hsl) { int r = 0; // get the vector of symbol IDs matching this hash. It probably has one entry but may have more. const std::vector<int>& bin = mHashTable[hsl.hash].mIDVector; { bool found = false; std::unique_lock<std::mutex> lock(mHashTable[hsl.hash].mMutex); for(int ID : bin) { // there should be few collisions, so probably the first ID in the hash bin // will be the symbol we are looking for. Unfortunately to test for equality we may have to // compare the entire string. TextFragment* binFragment = &mSymbolTextsByID[ID]; if(compareSizedCharArrays(binFragment->getText(), binFragment->lengthInBytes(), hsl.pChars, hsl.len)) { r = ID; found = true; break; } } if(!found) { mSymbolTextsByID.emplace_back(TextFragment(hsl.pChars, static_cast<int>(hsl.len))); r = mSize++; mHashTable[hsl.hash].mIDVector.emplace_back(r); } } return r; }
// add an entry to the table. The entry must not already exist in the table. // this must be the only way of modifying the symbol table. int SymbolTable::addEntry(const HashedCharArray& hsl) { mSymbolTextsByID.emplace_back(TextFragment(hsl.pChars, static_cast<int>(hsl.len))); int newID = mSize++; mHashTable[hsl.hash].mIDVector.emplace_back(newID); return newID; }
void TextParser::ReadText (OptionalType<TextFragment>& result, const TCHAR delimiters[]) { uint32 marker = ForwardSkip (_T("\t ")); uint32 endPoint = ReadText(delimiters, marker); if ( (endPoint != marker) && (endPoint < Length()) ) { result = TextFragment(*this, marker, endPoint - marker); Forward(endPoint); } }
void PathParser::Parse (const TextFragment& input) { TextParser parser (input); OptionalType<TextFragment> info; parser.ReadText(info, _T(":")); if ((info.IsSet()) && (info.Value().Length() == 1)) { m_Drive = *(info.Value().Data()); parser.Skip(1); } // Find the last '/ or \ from the back, after the drive uint32 index = parser.ReverseFind(_T("\\/")); if (index != NUMBER_MAX_UNSIGNED(uint32)) { m_Path = TextFragment(parser, 0, index); parser.Skip(index+1); } // Now we are ate the complete filename m_FileName = TextFragment (parser, 0, NUMBER_MAX_UNSIGNED(uint32)); // Find the extension from the current parser... index = parser.ReverseFind(_T(".")); if (index == NUMBER_MAX_UNSIGNED(uint32)) { // oops there is no extension, BaseFileName == Filename m_BaseFileName = m_FileName; } else { m_BaseFileName = TextFragment (parser, 0, index); m_Extension = TextFragment(parser, index + 1, NUMBER_MAX_UNSIGNED(uint32)); } }
bool gfxr_font_calculate_size(Common::Array<TextFragment> &fragments, gfx_bitmap_font_t *font, int max_width, const char *text, int *width, int *height, int *line_height_p, int *last_offset_p, int flags) { int maxheight = font->line_height; int last_breakpoint = 0; int last_break_width = 0; int maxwidth = 0, localmaxwidth = 0; const char *breakpoint_ptr = NULL; unsigned char curChar; if (line_height_p) *line_height_p = font->line_height; fragments.push_back(TextFragment(text)); while ((curChar = *text++)) { if (curChar >= font->chars_nr) { error("Invalid char 0x%02x (max. 0x%02x) encountered in text string '%s', font %04x", curChar, font->chars_nr, text, font->ID); if (font->chars_nr > ' ') curChar = ' '; else { return false; } } if (((curChar == '\n') || (curChar == 0x0d)) && !(flags & kFontNoNewlines)) { fragments.back().length = text - 1 - fragments.back().offset; if (*text) maxheight += font->line_height; if (curChar == 0x0d && *text == '\n') text++; // Interpret DOS-style CR LF as single NL fragments.push_back(TextFragment(text)); if (localmaxwidth > maxwidth) maxwidth = localmaxwidth; localmaxwidth = 0; } else { // curChar != '\n' localmaxwidth += font->widths[curChar]; if (localmaxwidth > max_width) { int blank_break = 1; // break is at a blank char, i.e. not within a word maxheight += font->line_height; if (last_breakpoint == 0) { // Text block too long and without whitespace? last_breakpoint = localmaxwidth - font->widths[curChar]; last_break_width = 0; --text; blank_break = 0; // non-blank break } else { text = breakpoint_ptr + 1; assert(breakpoint_ptr); } if (last_breakpoint == 0) { warning("[GFX] maxsize %d too small for '%s'", max_width, text); } if (last_breakpoint > maxwidth) maxwidth = last_breakpoint; fragments.back().length = text - blank_break - fragments.back().offset; fragments.push_back(TextFragment(text)); localmaxwidth = localmaxwidth - last_breakpoint; if (!(flags & kFontCountWhitespace)) localmaxwidth -= last_break_width; last_breakpoint = localmaxwidth = 0; } else if (*text == ' ') { last_breakpoint = localmaxwidth; last_break_width = font->widths[curChar]; breakpoint_ptr = text; } } } if (localmaxwidth > maxwidth) *width = localmaxwidth; else *width = maxwidth; if (last_offset_p) *last_offset_p = localmaxwidth; if (height) *height = maxheight; fragments.back().length = text - fragments.back().offset - 1; return true; }