// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "flutter/sky/engine/platform/fonts/GlyphPageTreeNode.h" #include #include "flutter/sky/engine/platform/fonts/SegmentedFontData.h" #include "flutter/sky/engine/platform/fonts/SimpleFontData.h" namespace blink { class TestCustomFontData : public CustomFontData { public: static PassRefPtr create() { return adoptRef(new TestCustomFontData()); } private: TestCustomFontData() {} virtual bool isLoadingFallback() const override { return true; } }; class TestSimpleFontData : public SimpleFontData { public: static PassRefPtr create(UChar32 from, UChar32 to) { return adoptRef(new TestSimpleFontData(nullptr, from, to)); } static PassRefPtr createUnloaded(UChar32 from, UChar32 to) { return adoptRef( new TestSimpleFontData(TestCustomFontData::create(), from, to)); } private: TestSimpleFontData(PassRefPtr customData, UChar32 from, UChar32 to) : SimpleFontData(customData, 10, false, false), m_from(from), m_to(to) {} bool fillGlyphPage(GlyphPage* pageToFill, unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength) const override { const Glyph kGlyph = 1; String bufferString(buffer, bufferLength); unsigned bufferIndex = 0; bool hasGlyphs = false; for (unsigned i = 0; i < length; i++) { UChar32 c = bufferString.characterStartingAt(bufferIndex); bufferIndex += U16_LENGTH(c); if (m_from <= c && c <= m_to) { pageToFill->setGlyphDataForIndex(offset + i, kGlyph, this); hasGlyphs = true; } } return hasGlyphs; } UChar32 m_from; UChar32 m_to; }; TEST(GlyphPageTreeNode, rootChild) { const unsigned kPageNumber = 0; size_t pageCountBeforeTest = GlyphPageTreeNode::treeGlyphPageCount(); { RefPtr data = TestSimpleFontData::create('a', 'z'); GlyphPageTreeNode* node = GlyphPageTreeNode::getRootChild(data.get(), kPageNumber); EXPECT_EQ(pageCountBeforeTest + 1, GlyphPageTreeNode::treeGlyphPageCount()); EXPECT_TRUE(node->page()->glyphAt('a')); EXPECT_FALSE(node->page()->glyphAt('A')); EXPECT_FALSE(node->isSystemFallback()); EXPECT_EQ(1u, node->level()); EXPECT_EQ(node, node->page()->owner()); } EXPECT_EQ(pageCountBeforeTest, GlyphPageTreeNode::treeGlyphPageCount()); } TEST(GlyphPageTreeNode, level2) { const unsigned kPageNumber = 0; size_t pageCountBeforeTest = GlyphPageTreeNode::treeGlyphPageCount(); { RefPtr dataAtoC = TestSimpleFontData::create('A', 'C'); RefPtr dataCtoE = TestSimpleFontData::create('C', 'E'); GlyphPageTreeNode* node1 = GlyphPageTreeNode::getRootChild(dataAtoC.get(), kPageNumber); GlyphPageTreeNode* node2 = node1->getChild(dataCtoE.get(), kPageNumber); EXPECT_EQ(pageCountBeforeTest + 3, GlyphPageTreeNode::treeGlyphPageCount()); EXPECT_EQ(2u, node2->level()); EXPECT_EQ(dataAtoC, node2->page()->glyphDataForCharacter('A').fontData); EXPECT_EQ(dataAtoC, node2->page()->glyphDataForCharacter('C').fontData); EXPECT_EQ(dataCtoE, node2->page()->glyphDataForCharacter('E').fontData); } EXPECT_EQ(pageCountBeforeTest, GlyphPageTreeNode::treeGlyphPageCount()); } TEST(GlyphPageTreeNode, segmentedData) { const unsigned kPageNumber = 0; size_t pageCountBeforeTest = GlyphPageTreeNode::treeGlyphPageCount(); { RefPtr dataBtoC = TestSimpleFontData::create('B', 'C'); RefPtr dataCtoE = TestSimpleFontData::create('C', 'E'); RefPtr segmentedData = SegmentedFontData::create(); segmentedData->appendRange(FontDataRange('A', 'C', dataBtoC)); segmentedData->appendRange(FontDataRange('C', 'D', dataCtoE)); GlyphPageTreeNode* node = GlyphPageTreeNode::getRootChild(segmentedData.get(), kPageNumber); EXPECT_EQ(0, node->page()->glyphDataForCharacter('A').fontData); EXPECT_EQ(dataBtoC, node->page()->glyphDataForCharacter('B').fontData); EXPECT_EQ(dataBtoC, node->page()->glyphDataForCharacter('C').fontData); EXPECT_EQ(dataCtoE, node->page()->glyphDataForCharacter('D').fontData); EXPECT_EQ(0, node->page()->glyphDataForCharacter('E').fontData); } EXPECT_EQ(pageCountBeforeTest, GlyphPageTreeNode::treeGlyphPageCount()); } TEST(GlyphPageTreeNode, outsideBMP) { const unsigned kPageNumber = 0x1f300 / GlyphPage::size; size_t pageCountBeforeTest = GlyphPageTreeNode::treeGlyphPageCount(); { RefPtr data = TestSimpleFontData::create(0x1f310, 0x1f320); GlyphPageTreeNode* node = GlyphPageTreeNode::getRootChild(data.get(), kPageNumber); EXPECT_EQ(pageCountBeforeTest + 1, GlyphPageTreeNode::treeGlyphPageCount()); EXPECT_FALSE(node->page()->glyphForCharacter(0x1f30f)); EXPECT_TRUE(node->page()->glyphForCharacter(0x1f310)); EXPECT_TRUE(node->page()->glyphForCharacter(0x1f320)); EXPECT_FALSE(node->page()->glyphForCharacter(0x1f321)); } EXPECT_EQ(pageCountBeforeTest, GlyphPageTreeNode::treeGlyphPageCount()); } TEST(GlyphPageTreeNode, customData) { const unsigned kPageNumber = 0; size_t pageCountBeforeTest = GlyphPageTreeNode::treeGlyphPageCount(); { RefPtr dataAtoC = TestSimpleFontData::createUnloaded('A', 'C'); RefPtr dataBtoD = TestSimpleFontData::create('B', 'D'); RefPtr dataCtoE = TestSimpleFontData::createUnloaded('C', 'E'); RefPtr segmentedData = SegmentedFontData::create(); segmentedData->appendRange(FontDataRange('A', 'C', dataAtoC)); segmentedData->appendRange(FontDataRange('B', 'D', dataBtoD)); segmentedData->appendRange(FontDataRange('C', 'E', dataCtoE)); GlyphPageTreeNode* node = GlyphPageTreeNode::getRootChild(segmentedData.get(), kPageNumber); EXPECT_EQ(0, node->page()->glyphDataForCharacter('A').fontData); EXPECT_EQ(dataBtoD, node->page()->glyphDataForCharacter('B').fontData); EXPECT_EQ(dataBtoD, node->page()->glyphDataForCharacter('C').fontData); EXPECT_EQ(dataBtoD, node->page()->glyphDataForCharacter('D').fontData); EXPECT_EQ(0, node->page()->glyphDataForCharacter('E').fontData); EXPECT_EQ(dataAtoC->customFontData(), node->page()->customFontToLoadAt('A')); EXPECT_EQ(dataAtoC->customFontData(), node->page()->customFontToLoadAt('B')); EXPECT_EQ(dataAtoC->customFontData(), node->page()->customFontToLoadAt('C')); EXPECT_EQ(0, node->page()->customFontToLoadAt('D')); EXPECT_EQ(dataCtoE->customFontData(), node->page()->customFontToLoadAt('E')); } EXPECT_EQ(pageCountBeforeTest, GlyphPageTreeNode::treeGlyphPageCount()); } TEST(GlyphPageTreeNode, customDataWithMultiplePages) { const unsigned kPageNumber = 0; size_t pageCountBeforeTest = GlyphPageTreeNode::treeGlyphPageCount(); { RefPtr dataAtoC = TestSimpleFontData::createUnloaded('A', 'C'); RefPtr dataBtoD = TestSimpleFontData::create('B', 'D'); RefPtr dataCtoE = TestSimpleFontData::createUnloaded('C', 'E'); RefPtr segmentedData1 = SegmentedFontData::create(); RefPtr segmentedData2 = SegmentedFontData::create(); RefPtr segmentedData3 = SegmentedFontData::create(); segmentedData1->appendRange(FontDataRange('A', 'C', dataAtoC)); segmentedData2->appendRange(FontDataRange('B', 'D', dataBtoD)); segmentedData3->appendRange(FontDataRange('C', 'E', dataCtoE)); GlyphPageTreeNode* node1 = GlyphPageTreeNode::getRootChild(segmentedData1.get(), kPageNumber); GlyphPageTreeNode* node2 = node1->getChild(segmentedData2.get(), kPageNumber); GlyphPageTreeNode* node3 = node2->getChild(segmentedData3.get(), kPageNumber); EXPECT_EQ(0, node3->page()->glyphDataForCharacter('A').fontData); EXPECT_EQ(dataBtoD, node3->page()->glyphDataForCharacter('B').fontData); EXPECT_EQ(dataBtoD, node3->page()->glyphDataForCharacter('C').fontData); EXPECT_EQ(dataBtoD, node3->page()->glyphDataForCharacter('D').fontData); EXPECT_EQ(0, node3->page()->glyphDataForCharacter('E').fontData); EXPECT_EQ(dataAtoC->customFontData(), node3->page()->customFontToLoadAt('A')); EXPECT_EQ(dataAtoC->customFontData(), node3->page()->customFontToLoadAt('B')); EXPECT_EQ(dataAtoC->customFontData(), node3->page()->customFontToLoadAt('C')); EXPECT_EQ(0, node3->page()->customFontToLoadAt('D')); EXPECT_EQ(dataCtoE->customFontData(), node3->page()->customFontToLoadAt('E')); } EXPECT_EQ(pageCountBeforeTest, GlyphPageTreeNode::treeGlyphPageCount()); } TEST(GlyphPageTreeNode, systemFallback) { const unsigned kPageNumber = 0; size_t pageCountBeforeTest = GlyphPageTreeNode::treeGlyphPageCount(); { RefPtr dataAtoC = TestSimpleFontData::createUnloaded('A', 'C'); RefPtr dataBtoD = TestSimpleFontData::create('B', 'D'); RefPtr segmentedData = SegmentedFontData::create(); segmentedData->appendRange(FontDataRange('A', 'C', dataAtoC)); GlyphPageTreeNode* node1 = GlyphPageTreeNode::getRootChild(segmentedData.get(), kPageNumber); GlyphPageTreeNode* node2 = node1->getChild(dataBtoD.get(), kPageNumber); GlyphPageTreeNode* node3 = node2->getChild(0, kPageNumber); EXPECT_TRUE(node3->isSystemFallback()); EXPECT_EQ(0, node3->page()->glyphDataForCharacter('A').fontData); EXPECT_EQ(dataBtoD, node3->page()->glyphDataForCharacter('B').fontData); EXPECT_EQ(dataBtoD, node3->page()->glyphDataForCharacter('C').fontData); EXPECT_EQ(dataBtoD, node3->page()->glyphDataForCharacter('D').fontData); EXPECT_EQ(dataAtoC->customFontData(), node3->page()->customFontToLoadAt('A')); EXPECT_EQ(dataAtoC->customFontData(), node3->page()->customFontToLoadAt('B')); EXPECT_EQ(dataAtoC->customFontData(), node3->page()->customFontToLoadAt('C')); EXPECT_EQ(0, node3->page()->customFontToLoadAt('D')); } EXPECT_EQ(pageCountBeforeTest, GlyphPageTreeNode::treeGlyphPageCount()); } } // namespace blink