void glyphTraverse(const std::string& text, std::function<void(stbtt_packedchar*)> fn) { auto cp_str = utils::utf8_to_codepoint(text); std::vector<char32_t> glyphs_to_add; for(char32_t cp : cp_str) { auto it = packed_char_.find(UnicodeRange(cp)); if(it == packed_char_.end()) { glyphs_to_add.emplace_back(cp); } } if(!glyphs_to_add.empty()) { addGlyphsToTexture(glyphs_to_add); } for(char32_t cp : cp_str) { auto it = packed_char_.find(UnicodeRange(cp)); if(it == packed_char_.end()) { cp = 0xfffd; it = packed_char_.find(UnicodeRange(0xfffd)); if(it == packed_char_.end()) { continue; } } stbtt_packedchar* b = it->second.data() + cp - it->first.first; fn(b); } }
TEST(UnicodeRangeSet, Overlap) { Vector<UnicodeRange> ranges; ranges.append(UnicodeRange('0', '2')); ranges.append(UnicodeRange('1', '1')); ranges.append(UnicodeRange('3', '5')); ranges.append(UnicodeRange('4', '6')); RefPtr<UnicodeRangeSet> set = adoptRef(new UnicodeRangeSet(ranges)); ASSERT_EQ(1u, set->size()); EXPECT_EQ('0', set->rangeAt(0).from()); EXPECT_EQ('6', set->rangeAt(0).to()); }
void addGlyphsToTexture(const std::vector<char32_t>& codepoints) override { if(codepoints.empty()) { LOG_WARN("stb_impl::addGlyphsToTexture: no codepoints."); return; } int old_size = packed_char_.size(); auto ttf_buffer = reinterpret_cast<const unsigned char*>(font_data_.c_str()); if(font_size_ < 20.0f) { stbtt_PackSetOversampling(&pc_, 2, 2); } std::vector<stbtt_pack_range> ranges; char32_t last_cp = codepoints.front(); char32_t first_cp = codepoints.front(); int num_chars = 1; for(auto it = codepoints.begin() + 1; it != codepoints.end(); ++it) { char32_t cp = *it; if(cp == last_cp+1) { ++num_chars; } else { auto& packed_data = packed_char_[UnicodeRange(first_cp, first_cp+num_chars-1)]; packed_data.resize(num_chars); stbtt_pack_range range; range.num_chars_in_range = num_chars; range.chardata_for_range = packed_data.data(); range.font_size = font_size_; range.first_unicode_char_in_range = first_cp; ranges.emplace_back(range); num_chars = 1; first_cp = cp; } last_cp = cp; } auto& packed_data = packed_char_[UnicodeRange(first_cp, first_cp+num_chars-1)]; packed_data.resize(num_chars); stbtt_pack_range range; range.num_chars_in_range = num_chars; range.chardata_for_range = packed_data.data(); range.font_size = font_size_; range.first_unicode_char_in_range = first_cp; ranges.emplace_back(range); stbtt_PackFontRanges(&pc_, ttf_buffer, 0, ranges.data(), ranges.size()); font_texture_->update2D(0, 0, 0, surface_width, surface_height, surface_width, pixels_.data()); }
TEST(UnicodeRangeSet, Non8Bit) { Vector<UnicodeRange> ranges; ranges.append(UnicodeRange(0x3042, 0x3042)); RefPtr<UnicodeRangeSet> set = adoptRef(new UnicodeRangeSet(ranges)); ASSERT_EQ(1u, set->size()); EXPECT_EQ(0x3042, set->rangeAt(0).from()); EXPECT_EQ(0x3042, set->rangeAt(0).to()); EXPECT_FALSE(set->intersectsWith(String("a"))); EXPECT_TRUE(set->intersectsWith(String(hiraganaA))); }
TEST(UnicodeRangeSet, TwoRanges) { Vector<UnicodeRange> ranges; ranges.append(UnicodeRange('6', '7')); ranges.append(UnicodeRange('2', '4')); RefPtr<UnicodeRangeSet> set = adoptRef(new UnicodeRangeSet(ranges)); EXPECT_FALSE(set->isEntireRange()); EXPECT_FALSE(set->intersectsWith(String())); EXPECT_FALSE(set->intersectsWith(String("1"))); EXPECT_TRUE(set->intersectsWith(String("2"))); EXPECT_TRUE(set->intersectsWith(String("3"))); EXPECT_TRUE(set->intersectsWith(String("4"))); EXPECT_FALSE(set->intersectsWith(String("5"))); EXPECT_TRUE(set->intersectsWith(String("6"))); EXPECT_TRUE(set->intersectsWith(String("7"))); EXPECT_FALSE(set->intersectsWith(String("8"))); ASSERT_EQ(2u, set->size()); EXPECT_EQ('2', set->rangeAt(0).from()); EXPECT_EQ('4', set->rangeAt(0).to()); EXPECT_EQ('6', set->rangeAt(1).from()); EXPECT_EQ('7', set->rangeAt(1).to()); }
QString MainWindow::refineString2(QString s) { QString result = ""; for (int i = 0; i < s.length(); ++i) { if (UnicodeRange(s.at(i)) != NON_JAPANESE) { result.append(s.at(i)); } } return result; }
const std::vector<point>& getGlyphPath(const std::string& text) override { auto it = glyph_path_cache_.find(text); if(it != glyph_path_cache_.end()) { return it->second; } std::vector<point>& path = glyph_path_cache_[text]; auto cp_str = utils::utf8_to_codepoint(text); std::vector<char32_t> glyphs_to_add; for(char32_t cp : cp_str) { auto it = packed_char_.find(UnicodeRange(cp)); if(it == packed_char_.end()) { glyphs_to_add.emplace_back(cp); } } if(!glyphs_to_add.empty()) { addGlyphsToTexture(glyphs_to_add); } point pen; for(char32_t cp : cp_str) { path.emplace_back(pen); auto it = packed_char_.find(UnicodeRange(cp)); if(it == packed_char_.end()) { cp = 0xfffd; it = packed_char_.find(UnicodeRange(0xfffd)); if(it == packed_char_.end()) { continue; } } stbtt_packedchar *b = it->second.data() + cp - it->first.first; pen.x += static_cast<int>(b->xadvance * 65536.0f); } path.emplace_back(pen); return path; }
static CSSFontFace* createCSSFontFace(FontFace* fontFace, CSSValue* unicodeRange) { Vector<UnicodeRange> ranges; if (CSSValueList* rangeList = toCSSValueList(unicodeRange)) { unsigned numRanges = rangeList->length(); for (unsigned i = 0; i < numRanges; i++) { CSSUnicodeRangeValue* range = toCSSUnicodeRangeValue(rangeList->item(i)); ranges.append(UnicodeRange(range->from(), range->to())); } } return new CSSFontFace(fontFace, ranges); }
TEST(UnicodeRangeSet, SingleCharacter) { Vector<UnicodeRange> ranges; ranges.append(UnicodeRange('b', 'b')); RefPtr<UnicodeRangeSet> set = adoptRef(new UnicodeRangeSet(ranges)); EXPECT_FALSE(set->isEntireRange()); EXPECT_FALSE(set->intersectsWith(String())); EXPECT_FALSE(set->intersectsWith(String("a"))); EXPECT_TRUE(set->intersectsWith(String("b"))); EXPECT_FALSE(set->intersectsWith(String("c"))); EXPECT_TRUE(set->intersectsWith(String("abc"))); EXPECT_FALSE(set->intersectsWith(String(hiraganaA))); ASSERT_EQ(1u, set->size()); EXPECT_EQ('b', set->rangeAt(0).from()); EXPECT_EQ('b', set->rangeAt(0).to()); }
CSSFontFace::UnicodeRangeSet::UnicodeRangeSet(const Vector<UnicodeRange>& ranges) : m_ranges(ranges) { if (m_ranges.isEmpty()) return; std::sort(m_ranges.begin(), m_ranges.end()); // Unify overlapping ranges. UChar32 from = m_ranges[0].from(); UChar32 to = m_ranges[0].to(); size_t targetIndex = 0; for (size_t i = 1; i < m_ranges.size(); i++) { if (to + 1 >= m_ranges[i].from()) { to = std::max(to, m_ranges[i].to()); } else { m_ranges[targetIndex++] = UnicodeRange(from, to); from = m_ranges[i].from(); to = m_ranges[i].to(); } } m_ranges[targetIndex++] = UnicodeRange(from, to); m_ranges.shrink(targetIndex); }
long calculateCharAdvance(char32_t cp) override { //int advance = 0; //int bearing = 0; //stbtt_GetCodepointHMetrics(&font_handle_, cp, &advance, &bearing); //return static_cast<int>(advance * scale_ * 65536.0f); auto it = packed_char_.find(UnicodeRange(cp)); if(it == packed_char_.end()) { int advance = 0; int bearing = 0; stbtt_GetCodepointHMetrics(&font_handle_, cp, &advance, &bearing); return static_cast<int>(advance * scale_ * 65536.0f); } stbtt_packedchar *b = it->second.data() + cp - it->first.first; return static_cast<int>(b->xadvance * 65536.0f); }
// Joins this range with another that it is contiguous with. UnicodeRange UnicodeRange::Join(const UnicodeRange& rhs) { return UnicodeRange(Math::Min(min_codepoint, rhs.min_codepoint), Math::Max(max_codepoint, rhs.max_codepoint)); }
ColoredFontRenderablePtr createColoredRenderableFromPath(ColoredFontRenderablePtr font_renderable, const std::string& text, const std::vector<point>& path, const std::vector<KRE::Color>& colors) override { auto cp_string = utils::utf8_to_codepoint(text); int glyphs_in_text = 0; std::vector<char32_t> glyphs_to_add; for(char32_t cp : cp_string) { ++glyphs_in_text; auto it = packed_char_.find(UnicodeRange(cp)); if(it == packed_char_.end()) { glyphs_to_add.emplace_back(cp); } } if(!glyphs_to_add.empty()) { addGlyphsToTexture(glyphs_to_add); } ASSERT_LOG(glyphs_in_text == colors.size(), "Not enough/Too many colors for the text."); if(font_renderable == nullptr) { font_renderable = std::make_shared<ColoredFontRenderable>(); font_renderable->setTexture(font_texture_); } int width = font_renderable->getWidth(); int height = font_renderable->getHeight(); int max_height = 0; std::vector<font_coord> coords; coords.reserve(glyphs_in_text * 6); int n = 0; for(char32_t cp : cp_string) { ASSERT_LOG(n < static_cast<int>(path.size()), "Insufficient points were supplied to create a path from the string '" << text << "'"); auto& pt =path[n]; auto it = packed_char_.find(UnicodeRange(cp)); if(it == packed_char_.end()) { it = packed_char_.find(UnicodeRange(0xfffd)); if(it == packed_char_.end()) { continue; } } stbtt_packedchar *b = it->second.data() + cp - it->first.first; //width += pt.x >> 16; //width += static_cast<int>(b->xoff2 - b->xoff); max_height = std::max(max_height, static_cast<int>(b->yoff2 - b->yoff)); const float u1 = font_texture_->getTextureCoordW(0, b->x0); const float v1 = font_texture_->getTextureCoordH(0, b->y0); const float u2 = font_texture_->getTextureCoordW(0, b->x1); const float v2 = font_texture_->getTextureCoordH(0, b->y1); const float x1 = static_cast<float>(pt.x) / 65536.0f + b->xoff; const float y1 = static_cast<float>(pt.y) / 65536.0f + b->yoff; const float x2 = x1 + b->xoff2 - b->xoff; const float y2 = static_cast<float>(pt.y) / 65536.0f + b->yoff2; coords.emplace_back(glm::vec2(x1, y2), glm::vec2(u1, v2)); coords.emplace_back(glm::vec2(x1, y1), glm::vec2(u1, v1)); coords.emplace_back(glm::vec2(x2, y1), glm::vec2(u2, v1)); coords.emplace_back(glm::vec2(x2, y1), glm::vec2(u2, v1)); coords.emplace_back(glm::vec2(x1, y2), glm::vec2(u1, v2)); coords.emplace_back(glm::vec2(x2, y2), glm::vec2(u2, v2)); ++n; } height += max_height; width = std::max(width, path.back().x >> 16); font_renderable->setWidth(width); font_renderable->setHeight(height); font_renderable->update(&coords); font_renderable->setVerticesPerColor(6); font_renderable->updateColors(colors); return font_renderable; }