2019-01-23 14:13:57 +08:00
|
|
|
|
// (C) Copyright 2017, Google Inc.
|
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
|
// limitations under the License.
|
2018-08-24 21:07:48 +08:00
|
|
|
|
|
2019-01-23 14:13:57 +08:00
|
|
|
|
#include <memory>
|
|
|
|
|
#include <string>
|
2018-08-24 21:07:48 +08:00
|
|
|
|
|
2019-03-25 16:33:56 +08:00
|
|
|
|
#include "absl/strings/str_split.h" // for absl::StrSplit
|
2018-08-24 21:07:48 +08:00
|
|
|
|
|
2019-01-23 14:13:57 +08:00
|
|
|
|
#include "allheaders.h"
|
|
|
|
|
#include "boxchar.h"
|
|
|
|
|
#include "boxread.h"
|
|
|
|
|
#include "commandlineflags.h"
|
|
|
|
|
#include "genericvector.h"
|
2019-03-25 16:33:56 +08:00
|
|
|
|
#include "include_gunit.h"
|
2019-01-23 14:13:57 +08:00
|
|
|
|
#include "stringrenderer.h"
|
|
|
|
|
#include "strngs.h"
|
2018-08-24 21:07:48 +08:00
|
|
|
|
|
2019-01-23 14:13:57 +08:00
|
|
|
|
BOOL_PARAM_FLAG(display, false, "Display image for inspection");
|
2018-08-24 21:07:48 +08:00
|
|
|
|
|
|
|
|
|
// Flags defined in pango_font_info.cpp
|
|
|
|
|
DECLARE_BOOL_PARAM_FLAG(use_only_legacy_fonts);
|
|
|
|
|
DECLARE_STRING_PARAM_FLAG(fonts_dir);
|
|
|
|
|
DECLARE_STRING_PARAM_FLAG(fontconfig_tmpdir);
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
|
|
const char kEngText[] = "the quick brown fox jumps over the lazy dog";
|
|
|
|
|
const char kHinText[] = "पिताने विवाह की | हो गई उद्विग्न वह सोचा";
|
|
|
|
|
|
2018-09-29 15:19:13 +08:00
|
|
|
|
const char kKorText[] = "이는 것으로 다시 넣을 1234 수는 있지만 선택의 의미는";
|
|
|
|
|
const char kArabicText[] =
|
|
|
|
|
"والفكر والصراع ، بالتأمل والفهم والتحليل ، "
|
2018-08-24 21:07:48 +08:00
|
|
|
|
"بالعلم والفن ، وأخيرا بالضحك أوبالبكاء ، ";
|
|
|
|
|
const char kMixedText[] = "والفكر 123 والصراع abc";
|
|
|
|
|
|
|
|
|
|
const char kEngNonLigatureText[] = "fidelity";
|
|
|
|
|
// Same as kEngNonLigatureText, but with "fi" replaced with its ligature.
|
|
|
|
|
const char kEngLigatureText[] = "fidelity";
|
|
|
|
|
|
|
|
|
|
using tesseract::BoxChar;
|
|
|
|
|
using tesseract::StringRenderer;
|
|
|
|
|
|
|
|
|
|
class StringRendererTest : public ::testing::Test {
|
|
|
|
|
protected:
|
2019-05-18 13:58:33 +08:00
|
|
|
|
void SetUp() override {
|
|
|
|
|
static std::locale system_locale("");
|
|
|
|
|
std::locale::global(system_locale);
|
2019-05-17 00:12:06 +08:00
|
|
|
|
}
|
|
|
|
|
|
2018-08-24 21:07:48 +08:00
|
|
|
|
static void SetUpTestCase() {
|
|
|
|
|
l_chooseDisplayProg(L_DISPLAY_WITH_XZGV);
|
2019-01-23 14:13:57 +08:00
|
|
|
|
FLAGS_fonts_dir = TESTING_DIR;
|
2018-08-24 21:07:48 +08:00
|
|
|
|
FLAGS_fontconfig_tmpdir = FLAGS_test_tmpdir;
|
2019-01-23 14:13:57 +08:00
|
|
|
|
#ifdef GOOGLE_TESSERACT
|
2018-08-24 21:07:48 +08:00
|
|
|
|
FLAGS_use_only_legacy_fonts = false;
|
|
|
|
|
// Needed for reliable heapchecking of pango layout structures.
|
|
|
|
|
FLAGS_heap_check_max_pointer_offset = -1;
|
2019-01-23 14:13:57 +08:00
|
|
|
|
#endif
|
2018-08-24 21:07:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DisplayClusterBoxes(Pix* pix) {
|
|
|
|
|
if (!FLAGS_display) return;
|
|
|
|
|
const std::vector<BoxChar*>& boxchars = renderer_->GetBoxes();
|
|
|
|
|
Boxa* boxes = boxaCreate(0);
|
2019-03-25 16:33:56 +08:00
|
|
|
|
for (const auto& boxchar : boxchars) {
|
|
|
|
|
if (boxchar->box())
|
|
|
|
|
boxaAddBox(boxes, const_cast<Box*>(boxchar->box()), L_CLONE);
|
2018-08-24 21:07:48 +08:00
|
|
|
|
}
|
|
|
|
|
Pix* box_pix = pixDrawBoxaRandom(pix, boxes, 1);
|
|
|
|
|
boxaDestroy(&boxes);
|
|
|
|
|
pixDisplay(box_pix, 0, 0);
|
|
|
|
|
pixDestroy(&box_pix);
|
|
|
|
|
}
|
|
|
|
|
std::unique_ptr<StringRenderer> renderer_;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
TEST_F(StringRendererTest, DoesRenderToImage) {
|
|
|
|
|
renderer_.reset(new StringRenderer("Verdana 10", 600, 600));
|
2018-09-29 15:27:12 +08:00
|
|
|
|
Pix* pix = nullptr;
|
2018-08-24 21:07:48 +08:00
|
|
|
|
EXPECT_EQ(strlen(kEngText),
|
|
|
|
|
renderer_->RenderToImage(kEngText, strlen(kEngText), &pix));
|
2018-09-29 15:27:12 +08:00
|
|
|
|
EXPECT_TRUE(pix != nullptr);
|
2018-08-24 21:07:48 +08:00
|
|
|
|
EXPECT_GT(renderer_->GetBoxes().size(), 0);
|
|
|
|
|
DisplayClusterBoxes(pix);
|
|
|
|
|
pixDestroy(&pix);
|
|
|
|
|
|
|
|
|
|
renderer_.reset(new StringRenderer("UnBatang 10", 600, 600));
|
|
|
|
|
EXPECT_EQ(strlen(kKorText),
|
|
|
|
|
renderer_->RenderToImage(kKorText, strlen(kKorText), &pix));
|
|
|
|
|
EXPECT_GT(renderer_->GetBoxes().size(), 0);
|
|
|
|
|
DisplayClusterBoxes(pix);
|
|
|
|
|
pixDestroy(&pix);
|
|
|
|
|
|
|
|
|
|
renderer_.reset(new StringRenderer("Lohit Hindi 10", 600, 600));
|
|
|
|
|
EXPECT_EQ(strlen(kHinText),
|
|
|
|
|
renderer_->RenderToImage(kHinText, strlen(kHinText), &pix));
|
|
|
|
|
EXPECT_GT(renderer_->GetBoxes().size(), 0);
|
|
|
|
|
DisplayClusterBoxes(pix);
|
|
|
|
|
pixDestroy(&pix);
|
|
|
|
|
|
|
|
|
|
// RTL text
|
|
|
|
|
renderer_.reset(new StringRenderer("Arab 10", 600, 600));
|
|
|
|
|
EXPECT_EQ(strlen(kArabicText),
|
|
|
|
|
renderer_->RenderToImage(kArabicText, strlen(kArabicText), &pix));
|
2018-09-29 15:27:12 +08:00
|
|
|
|
EXPECT_TRUE(pix != nullptr);
|
2018-08-24 21:07:48 +08:00
|
|
|
|
EXPECT_GT(renderer_->GetBoxes().size(), 0);
|
|
|
|
|
DisplayClusterBoxes(pix);
|
|
|
|
|
pixDestroy(&pix);
|
|
|
|
|
|
|
|
|
|
// Mixed direction Arabic + english text
|
|
|
|
|
renderer_.reset(new StringRenderer("Arab 10", 600, 600));
|
|
|
|
|
EXPECT_EQ(strlen(kMixedText),
|
|
|
|
|
renderer_->RenderToImage(kMixedText, strlen(kMixedText), &pix));
|
2018-09-29 15:27:12 +08:00
|
|
|
|
EXPECT_TRUE(pix != nullptr);
|
2018-08-24 21:07:48 +08:00
|
|
|
|
EXPECT_GT(renderer_->GetBoxes().size(), 0);
|
|
|
|
|
DisplayClusterBoxes(pix);
|
|
|
|
|
pixDestroy(&pix);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(StringRendererTest, DoesRenderToImageWithUnderline) {
|
|
|
|
|
renderer_.reset(new StringRenderer("Verdana 10", 600, 600));
|
|
|
|
|
// Underline all words but NOT intervening spaces.
|
|
|
|
|
renderer_->set_underline_start_prob(1.0);
|
|
|
|
|
renderer_->set_underline_continuation_prob(0);
|
2018-09-29 15:27:12 +08:00
|
|
|
|
Pix* pix = nullptr;
|
2018-08-24 21:07:48 +08:00
|
|
|
|
EXPECT_EQ(strlen(kEngText),
|
|
|
|
|
renderer_->RenderToImage(kEngText, strlen(kEngText), &pix));
|
2018-09-29 15:27:12 +08:00
|
|
|
|
EXPECT_TRUE(pix != nullptr);
|
2018-08-24 21:07:48 +08:00
|
|
|
|
EXPECT_GT(renderer_->GetBoxes().size(), 0);
|
|
|
|
|
DisplayClusterBoxes(pix);
|
|
|
|
|
pixDestroy(&pix);
|
|
|
|
|
renderer_->ClearBoxes();
|
|
|
|
|
|
|
|
|
|
// Underline all words AND intervening spaces.
|
|
|
|
|
renderer_->set_underline_start_prob(1.0);
|
|
|
|
|
renderer_->set_underline_continuation_prob(1.0);
|
|
|
|
|
EXPECT_EQ(strlen(kEngText),
|
|
|
|
|
renderer_->RenderToImage(kEngText, strlen(kEngText), &pix));
|
2018-09-29 15:27:12 +08:00
|
|
|
|
EXPECT_TRUE(pix != nullptr);
|
2018-08-24 21:07:48 +08:00
|
|
|
|
EXPECT_GT(renderer_->GetBoxes().size(), 0);
|
|
|
|
|
DisplayClusterBoxes(pix);
|
|
|
|
|
pixDestroy(&pix);
|
|
|
|
|
renderer_->ClearBoxes();
|
|
|
|
|
|
|
|
|
|
// Underline words and intervening spaces with 0.5 prob.
|
|
|
|
|
renderer_->set_underline_start_prob(0.5);
|
|
|
|
|
renderer_->set_underline_continuation_prob(0.5);
|
|
|
|
|
EXPECT_EQ(strlen(kEngText),
|
|
|
|
|
renderer_->RenderToImage(kEngText, strlen(kEngText), &pix));
|
2018-09-29 15:27:12 +08:00
|
|
|
|
EXPECT_TRUE(pix != nullptr);
|
2018-08-24 21:07:48 +08:00
|
|
|
|
EXPECT_GT(renderer_->GetBoxes().size(), 0);
|
|
|
|
|
DisplayClusterBoxes(pix);
|
|
|
|
|
pixDestroy(&pix);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(StringRendererTest, DoesHandleNewlineCharacters) {
|
|
|
|
|
const char kRawText[] = "\n\n\n A \nB \nC \n\n\n";
|
|
|
|
|
const char kStrippedText[] = " A B C "; // text with newline chars removed
|
|
|
|
|
renderer_.reset(new StringRenderer("Verdana 10", 600, 600));
|
2018-09-29 15:27:12 +08:00
|
|
|
|
Pix* pix = nullptr;
|
2018-08-24 21:07:48 +08:00
|
|
|
|
EXPECT_EQ(strlen(kRawText),
|
|
|
|
|
renderer_->RenderToImage(kRawText, strlen(kRawText), &pix));
|
2018-09-29 15:27:12 +08:00
|
|
|
|
EXPECT_TRUE(pix != nullptr);
|
2018-08-24 21:07:48 +08:00
|
|
|
|
const std::vector<BoxChar*>& boxchars = renderer_->GetBoxes();
|
2019-01-23 14:13:57 +08:00
|
|
|
|
// 3 characters + 4 spaces => 7 boxes
|
|
|
|
|
EXPECT_EQ(7, boxchars.size());
|
|
|
|
|
if (boxchars.size() == 7) {
|
|
|
|
|
// Verify the text content of the boxchars
|
|
|
|
|
for (size_t i = 0; i < boxchars.size(); ++i) {
|
|
|
|
|
EXPECT_EQ(std::string(1, kStrippedText[i]), boxchars[i]->ch());
|
|
|
|
|
}
|
2018-08-24 21:07:48 +08:00
|
|
|
|
}
|
|
|
|
|
DisplayClusterBoxes(pix);
|
|
|
|
|
pixDestroy(&pix);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(StringRendererTest, DoesRenderLigatures) {
|
|
|
|
|
renderer_.reset(new StringRenderer("Arab 12", 600, 250));
|
|
|
|
|
const char kArabicLigature[] = "لا";
|
|
|
|
|
|
2018-09-29 15:27:12 +08:00
|
|
|
|
Pix* pix = nullptr;
|
2018-09-29 15:19:13 +08:00
|
|
|
|
EXPECT_EQ(
|
|
|
|
|
strlen(kArabicLigature),
|
|
|
|
|
renderer_->RenderToImage(kArabicLigature, strlen(kArabicLigature), &pix));
|
2018-09-29 15:27:12 +08:00
|
|
|
|
EXPECT_TRUE(pix != nullptr);
|
2018-08-24 21:07:48 +08:00
|
|
|
|
EXPECT_GT(renderer_->GetBoxes().size(), 0);
|
|
|
|
|
const std::vector<BoxChar*>& boxes = renderer_->GetBoxes();
|
|
|
|
|
EXPECT_EQ(1, boxes.size());
|
2018-09-29 15:27:12 +08:00
|
|
|
|
EXPECT_TRUE(boxes[0]->box() != nullptr);
|
2018-08-24 21:07:48 +08:00
|
|
|
|
EXPECT_STREQ(kArabicLigature, boxes[0]->ch().c_str());
|
|
|
|
|
DisplayClusterBoxes(pix);
|
|
|
|
|
pixDestroy(&pix);
|
|
|
|
|
|
|
|
|
|
renderer_.reset(new StringRenderer("Arab 12", 600, 250));
|
|
|
|
|
const char kArabicMixedText[] = "والفكر والصراع 1234,\nوالفكر لا والصراع";
|
|
|
|
|
renderer_->RenderToImage(kArabicMixedText, strlen(kArabicMixedText), &pix);
|
|
|
|
|
DisplayClusterBoxes(pix);
|
|
|
|
|
pixDestroy(&pix);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int FindBoxCharXCoord(const std::vector<BoxChar*>& boxchars,
|
2019-01-23 14:13:57 +08:00
|
|
|
|
const std::string& ch) {
|
2019-03-25 16:33:56 +08:00
|
|
|
|
for (const auto& boxchar : boxchars) {
|
|
|
|
|
if (boxchar->ch() == ch) return boxchar->box()->x;
|
2018-08-24 21:07:48 +08:00
|
|
|
|
}
|
2019-01-23 14:13:57 +08:00
|
|
|
|
return INT_MAX;
|
2018-08-24 21:07:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(StringRendererTest, ArabicBoxcharsInLTROrder) {
|
|
|
|
|
renderer_.reset(new StringRenderer("Arab 10", 600, 600));
|
2018-09-29 15:27:12 +08:00
|
|
|
|
Pix* pix = nullptr;
|
2018-08-24 21:07:48 +08:00
|
|
|
|
// Arabic letters should be in decreasing x-coordinates
|
|
|
|
|
const char kArabicWord[] = "\u0644\u0627\u0641\u0643\u0631";
|
2019-01-23 14:13:57 +08:00
|
|
|
|
const std::string kRevWord = "\u0631\u0643\u0641\u0627\u0644";
|
2018-08-24 21:07:48 +08:00
|
|
|
|
renderer_->RenderToImage(kArabicWord, strlen(kArabicWord), &pix);
|
2019-01-23 14:13:57 +08:00
|
|
|
|
std::string boxes_str = renderer_->GetBoxesStr();
|
2018-08-24 21:07:48 +08:00
|
|
|
|
// Decode to get the box text strings.
|
|
|
|
|
EXPECT_FALSE(boxes_str.empty());
|
|
|
|
|
GenericVector<STRING> texts;
|
2019-01-23 14:13:57 +08:00
|
|
|
|
EXPECT_TRUE(ReadMemBoxes(0, false, boxes_str.c_str(), false, nullptr, &texts,
|
2018-08-24 21:07:48 +08:00
|
|
|
|
nullptr, nullptr));
|
2019-01-23 14:13:57 +08:00
|
|
|
|
std::string ltr_str;
|
2019-03-25 16:33:56 +08:00
|
|
|
|
for (int i = 0; i < texts.size(); ++i) ltr_str += texts[i].string();
|
2018-08-24 21:07:48 +08:00
|
|
|
|
// The string should come out perfectly reversed, despite there being a
|
|
|
|
|
// ligature.
|
|
|
|
|
EXPECT_EQ(ltr_str, kRevWord);
|
|
|
|
|
// Just to prove there was a ligature, the number of texts is less than the
|
|
|
|
|
// number of unicodes.
|
|
|
|
|
EXPECT_LT(texts.size(), 5);
|
|
|
|
|
pixDestroy(&pix);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(StringRendererTest, DoesOutputBoxcharsInReadingOrder) {
|
|
|
|
|
renderer_.reset(new StringRenderer("Arab 10", 600, 600));
|
2018-09-29 15:27:12 +08:00
|
|
|
|
Pix* pix = nullptr;
|
2018-08-24 21:07:48 +08:00
|
|
|
|
// Arabic letters should be in decreasing x-coordinates
|
|
|
|
|
const char kArabicWord[] = "والفكر";
|
|
|
|
|
renderer_->RenderToImage(kArabicWord, strlen(kArabicWord), &pix);
|
|
|
|
|
EXPECT_GT(renderer_->GetBoxes().size(), 0);
|
|
|
|
|
const std::vector<BoxChar*>& boxchars = renderer_->GetBoxes();
|
2019-01-23 14:13:57 +08:00
|
|
|
|
for (size_t i = 1; i < boxchars.size(); ++i) {
|
|
|
|
|
EXPECT_GT(boxchars[i - 1]->box()->x, boxchars[i]->box()->x)
|
|
|
|
|
<< boxchars[i - 1]->ch();
|
2018-08-24 21:07:48 +08:00
|
|
|
|
}
|
|
|
|
|
pixDestroy(&pix);
|
|
|
|
|
|
|
|
|
|
// English letters should be in increasing x-coordinates
|
|
|
|
|
const char kEnglishWord[] = "Google";
|
|
|
|
|
renderer_->ClearBoxes();
|
|
|
|
|
renderer_->RenderToImage(kEnglishWord, strlen(kEnglishWord), &pix);
|
|
|
|
|
EXPECT_EQ(boxchars.size(), strlen(kEnglishWord));
|
2019-01-23 14:13:57 +08:00
|
|
|
|
for (size_t i = 1; i < boxchars.size(); ++i) {
|
|
|
|
|
EXPECT_LT(boxchars[i - 1]->box()->x, boxchars[i]->box()->x)
|
|
|
|
|
<< boxchars[i - 1]->ch();
|
2018-08-24 21:07:48 +08:00
|
|
|
|
}
|
|
|
|
|
pixDestroy(&pix);
|
|
|
|
|
|
|
|
|
|
// Mixed text should satisfy both.
|
|
|
|
|
renderer_->ClearBoxes();
|
|
|
|
|
renderer_->RenderToImage(kMixedText, strlen(kMixedText), &pix);
|
2019-01-23 14:13:57 +08:00
|
|
|
|
EXPECT_LT(FindBoxCharXCoord(boxchars, "a"), FindBoxCharXCoord(boxchars, "b"));
|
|
|
|
|
EXPECT_LT(FindBoxCharXCoord(boxchars, "1"), FindBoxCharXCoord(boxchars, "2"));
|
|
|
|
|
EXPECT_GT(FindBoxCharXCoord(boxchars, "و"), FindBoxCharXCoord(boxchars, "ر"));
|
2018-08-24 21:07:48 +08:00
|
|
|
|
pixDestroy(&pix);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(StringRendererTest, DoesRenderVerticalText) {
|
2018-09-29 15:27:12 +08:00
|
|
|
|
Pix* pix = nullptr;
|
2018-08-24 21:07:48 +08:00
|
|
|
|
renderer_.reset(new StringRenderer("UnBatang 10", 600, 600));
|
|
|
|
|
renderer_->set_vertical_text(true);
|
|
|
|
|
EXPECT_EQ(strlen(kKorText),
|
|
|
|
|
renderer_->RenderToImage(kKorText, strlen(kKorText), &pix));
|
|
|
|
|
EXPECT_GT(renderer_->GetBoxes().size(), 0);
|
|
|
|
|
DisplayClusterBoxes(pix);
|
|
|
|
|
pixDestroy(&pix);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Checks that we preserve charboxes across RenderToImage calls, with
|
|
|
|
|
// appropriate page numbers.
|
|
|
|
|
TEST_F(StringRendererTest, DoesKeepAllImageBoxes) {
|
|
|
|
|
renderer_.reset(new StringRenderer("Verdana 10", 600, 600));
|
2018-09-29 15:27:12 +08:00
|
|
|
|
Pix* pix = nullptr;
|
2018-08-24 21:07:48 +08:00
|
|
|
|
int num_boxes_per_page = 0;
|
|
|
|
|
const int kNumTrials = 2;
|
|
|
|
|
for (int i = 0; i < kNumTrials; ++i) {
|
|
|
|
|
EXPECT_EQ(strlen(kEngText),
|
|
|
|
|
renderer_->RenderToImage(kEngText, strlen(kEngText), &pix));
|
2018-09-29 15:27:12 +08:00
|
|
|
|
EXPECT_TRUE(pix != nullptr);
|
2018-08-24 21:07:48 +08:00
|
|
|
|
pixDestroy(&pix);
|
|
|
|
|
EXPECT_GT(renderer_->GetBoxes().size(), 0);
|
|
|
|
|
if (!num_boxes_per_page) {
|
|
|
|
|
num_boxes_per_page = renderer_->GetBoxes().size();
|
|
|
|
|
} else {
|
2018-09-29 15:19:13 +08:00
|
|
|
|
EXPECT_EQ((i + 1) * num_boxes_per_page, renderer_->GetBoxes().size());
|
2018-08-24 21:07:48 +08:00
|
|
|
|
}
|
2018-09-29 15:19:13 +08:00
|
|
|
|
for (int j = i * num_boxes_per_page; j < (i + 1) * num_boxes_per_page;
|
|
|
|
|
++j) {
|
2018-08-24 21:07:48 +08:00
|
|
|
|
EXPECT_EQ(i, renderer_->GetBoxes()[j]->page());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(StringRendererTest, DoesClearBoxes) {
|
|
|
|
|
renderer_.reset(new StringRenderer("Verdana 10", 600, 600));
|
2018-09-29 15:27:12 +08:00
|
|
|
|
Pix* pix = nullptr;
|
2018-08-24 21:07:48 +08:00
|
|
|
|
EXPECT_EQ(strlen(kEngText),
|
|
|
|
|
renderer_->RenderToImage(kEngText, strlen(kEngText), &pix));
|
|
|
|
|
pixDestroy(&pix);
|
|
|
|
|
EXPECT_GT(renderer_->GetBoxes().size(), 0);
|
|
|
|
|
const int num_boxes_per_page = renderer_->GetBoxes().size();
|
|
|
|
|
|
|
|
|
|
renderer_->ClearBoxes();
|
|
|
|
|
EXPECT_EQ(strlen(kEngText),
|
|
|
|
|
renderer_->RenderToImage(kEngText, strlen(kEngText), &pix));
|
|
|
|
|
pixDestroy(&pix);
|
|
|
|
|
EXPECT_EQ(num_boxes_per_page, renderer_->GetBoxes().size());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(StringRendererTest, DoesLigatureTextForRendering) {
|
|
|
|
|
renderer_.reset(new StringRenderer("Verdana 10", 600, 600));
|
|
|
|
|
renderer_->set_add_ligatures(true);
|
2018-09-29 15:27:12 +08:00
|
|
|
|
Pix* pix = nullptr;
|
2018-08-24 21:07:48 +08:00
|
|
|
|
EXPECT_EQ(strlen(kEngNonLigatureText),
|
|
|
|
|
renderer_->RenderToImage(kEngNonLigatureText,
|
|
|
|
|
strlen(kEngNonLigatureText), &pix));
|
|
|
|
|
pixDestroy(&pix);
|
|
|
|
|
// There should be one less box than letters due to the 'fi' ligature.
|
|
|
|
|
EXPECT_EQ(strlen(kEngNonLigatureText) - 1, renderer_->GetBoxes().size());
|
|
|
|
|
// The output box text should be ligatured.
|
|
|
|
|
EXPECT_STREQ("fi", renderer_->GetBoxes()[0]->ch().c_str());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(StringRendererTest, DoesRetainInputLigatureForRendering) {
|
|
|
|
|
renderer_.reset(new StringRenderer("Verdana 10", 600, 600));
|
2018-09-29 15:27:12 +08:00
|
|
|
|
Pix* pix = nullptr;
|
2018-08-24 21:07:48 +08:00
|
|
|
|
EXPECT_EQ(strlen(kEngLigatureText),
|
|
|
|
|
renderer_->RenderToImage(kEngLigatureText, strlen(kEngLigatureText),
|
|
|
|
|
&pix));
|
|
|
|
|
pixDestroy(&pix);
|
|
|
|
|
// There should be one less box than letters due to the 'fi' ligature.
|
|
|
|
|
EXPECT_EQ(strlen(kEngNonLigatureText) - 1, renderer_->GetBoxes().size());
|
|
|
|
|
// The output box text should be ligatured.
|
|
|
|
|
EXPECT_STREQ("\uFB01", renderer_->GetBoxes()[0]->ch().c_str());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(StringRendererTest, DoesStripUnrenderableWords) {
|
|
|
|
|
// Verdana should only be able to render the english letters and numbers in
|
|
|
|
|
// the mixed text.
|
|
|
|
|
renderer_.reset(new StringRenderer("Verdana 10", 600, 600));
|
2019-01-23 14:13:57 +08:00
|
|
|
|
std::string text(kMixedText);
|
2018-08-24 21:07:48 +08:00
|
|
|
|
EXPECT_GT(renderer_->StripUnrenderableWords(&text), 0);
|
|
|
|
|
EXPECT_EQ(" 123 abc", text);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(StringRendererTest, DoesRenderWordBoxes) {
|
|
|
|
|
renderer_.reset(new StringRenderer("Verdana 10", 600, 600));
|
|
|
|
|
renderer_->set_output_word_boxes(true);
|
2018-09-29 15:27:12 +08:00
|
|
|
|
Pix* pix = nullptr;
|
2018-08-24 21:07:48 +08:00
|
|
|
|
EXPECT_EQ(strlen(kEngText),
|
|
|
|
|
renderer_->RenderToImage(kEngText, strlen(kEngText), &pix));
|
|
|
|
|
pixDestroy(&pix);
|
|
|
|
|
// Verify #boxchars = #words + #spaces
|
2019-03-25 16:33:56 +08:00
|
|
|
|
std::vector<std::string> words =
|
|
|
|
|
absl::StrSplit(kEngText, ' ', absl::SkipEmpty());
|
2018-08-24 21:07:48 +08:00
|
|
|
|
const int kNumSpaces = words.size() - 1;
|
|
|
|
|
const int kExpectedNumBoxes = words.size() + kNumSpaces;
|
|
|
|
|
const std::vector<BoxChar*>& boxchars = renderer_->GetBoxes();
|
|
|
|
|
EXPECT_EQ(kExpectedNumBoxes, boxchars.size());
|
|
|
|
|
// Verify content of words and spaces
|
2019-01-23 14:13:57 +08:00
|
|
|
|
for (size_t i = 0; i < boxchars.size(); i += 2) {
|
2018-08-24 21:07:48 +08:00
|
|
|
|
EXPECT_EQ(words[i / 2], boxchars[i]->ch());
|
|
|
|
|
if (i < boxchars.size() - 1) {
|
|
|
|
|
EXPECT_EQ(" ", boxchars[i + 1]->ch());
|
2018-09-29 15:27:12 +08:00
|
|
|
|
EXPECT_TRUE(boxchars[i + 1]->box() == nullptr);
|
2018-08-24 21:07:48 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(StringRendererTest, DoesRenderWordBoxesFromMultiLineText) {
|
|
|
|
|
renderer_.reset(new StringRenderer("Verdana 10", 600, 600));
|
|
|
|
|
renderer_->set_output_word_boxes(true);
|
2018-09-29 15:27:12 +08:00
|
|
|
|
Pix* pix = nullptr;
|
2018-08-24 21:07:48 +08:00
|
|
|
|
const char kMultlineText[] = "the quick brown fox\njumps over the lazy dog";
|
|
|
|
|
EXPECT_EQ(strlen(kMultlineText),
|
|
|
|
|
renderer_->RenderToImage(kMultlineText, strlen(kEngText), &pix));
|
|
|
|
|
pixDestroy(&pix);
|
|
|
|
|
// Verify #boxchars = #words + #spaces + #newlines
|
2019-01-23 14:13:57 +08:00
|
|
|
|
std::vector<std::string> words =
|
2018-08-24 21:07:48 +08:00
|
|
|
|
absl::StrSplit(kMultlineText, absl::ByAnyChar(" \n"), absl::SkipEmpty());
|
|
|
|
|
const int kNumSeparators = words.size() - 1;
|
|
|
|
|
const int kExpectedNumBoxes = words.size() + kNumSeparators;
|
|
|
|
|
const std::vector<BoxChar*>& boxchars = renderer_->GetBoxes();
|
|
|
|
|
EXPECT_EQ(kExpectedNumBoxes, boxchars.size());
|
|
|
|
|
// Verify content of words and spaces
|
2019-01-23 14:13:57 +08:00
|
|
|
|
for (size_t i = 0; i < boxchars.size(); i += 2) {
|
2018-08-24 21:07:48 +08:00
|
|
|
|
EXPECT_EQ(words[i / 2], boxchars[i]->ch());
|
2019-01-23 14:13:57 +08:00
|
|
|
|
if (i + 1 < boxchars.size()) {
|
2018-08-24 21:07:48 +08:00
|
|
|
|
EXPECT_EQ(" ", boxchars[i + 1]->ch());
|
2018-09-29 15:27:12 +08:00
|
|
|
|
EXPECT_TRUE(boxchars[i + 1]->box() == nullptr);
|
2018-08-24 21:07:48 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(StringRendererTest, DoesRenderAllFontsToImage) {
|
|
|
|
|
renderer_.reset(new StringRenderer("Verdana 10", 1200, 1200));
|
2019-01-23 14:13:57 +08:00
|
|
|
|
size_t offset = 0;
|
|
|
|
|
std::string font_used;
|
2018-08-24 21:07:48 +08:00
|
|
|
|
do {
|
2018-09-29 15:27:12 +08:00
|
|
|
|
Pix* pix = nullptr;
|
2018-08-24 21:07:48 +08:00
|
|
|
|
font_used.clear();
|
2018-09-29 15:19:13 +08:00
|
|
|
|
offset += renderer_->RenderAllFontsToImage(
|
|
|
|
|
1.0, kEngText + offset, strlen(kEngText + offset), &font_used, &pix);
|
2018-08-24 21:07:48 +08:00
|
|
|
|
if (offset < strlen(kEngText)) {
|
2018-09-29 15:27:12 +08:00
|
|
|
|
EXPECT_TRUE(pix != nullptr);
|
2018-08-24 21:07:48 +08:00
|
|
|
|
EXPECT_STRNE("", font_used.c_str());
|
|
|
|
|
}
|
|
|
|
|
if (FLAGS_display) pixDisplay(pix, 0, 0);
|
|
|
|
|
pixDestroy(&pix);
|
|
|
|
|
} while (offset < strlen(kEngText));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(StringRendererTest, DoesNotRenderWordJoiner) {
|
|
|
|
|
renderer_.reset(new StringRenderer("Verdana 10", 500, 200));
|
2019-01-23 14:13:57 +08:00
|
|
|
|
const std::string word = "A- -B C-D A BC";
|
|
|
|
|
const std::string joined_word = StringRenderer::InsertWordJoiners(word);
|
2018-09-29 15:27:12 +08:00
|
|
|
|
Pix* pix = nullptr;
|
2018-08-24 21:07:48 +08:00
|
|
|
|
renderer_->RenderToImage(joined_word.c_str(), joined_word.length(), &pix);
|
|
|
|
|
pixDestroy(&pix);
|
|
|
|
|
const std::vector<BoxChar*>& boxchars = renderer_->GetBoxes();
|
2019-01-23 14:13:57 +08:00
|
|
|
|
const std::string kWordJoinerUTF8 = "\u2060";
|
2018-08-24 21:07:48 +08:00
|
|
|
|
ASSERT_EQ(word.length(), boxchars.size());
|
2019-01-23 14:13:57 +08:00
|
|
|
|
for (size_t i = 0; i < boxchars.size(); ++i) {
|
2018-08-24 21:07:48 +08:00
|
|
|
|
EXPECT_NE(kWordJoinerUTF8, boxchars[i]->ch());
|
|
|
|
|
EXPECT_EQ(word.substr(i, 1), boxchars[i]->ch());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-25 02:51:33 +08:00
|
|
|
|
TEST_F(StringRendererTest, DISABLED_DoesDropUncoveredChars) {
|
2018-08-24 21:07:48 +08:00
|
|
|
|
renderer_.reset(new StringRenderer("Verdana 10", 500, 200));
|
|
|
|
|
renderer_->set_drop_uncovered_chars(true);
|
2019-01-23 14:13:57 +08:00
|
|
|
|
const std::string kWord = "office";
|
|
|
|
|
const std::string kCleanWord = "oice";
|
2018-09-29 15:27:12 +08:00
|
|
|
|
Pix* pix = nullptr;
|
2018-09-29 15:19:13 +08:00
|
|
|
|
EXPECT_FALSE(
|
|
|
|
|
renderer_->font().CanRenderString(kWord.c_str(), kWord.length()));
|
2018-08-24 21:07:48 +08:00
|
|
|
|
EXPECT_FALSE(renderer_->font().CoversUTF8Text(kWord.c_str(), kWord.length()));
|
|
|
|
|
int offset = renderer_->RenderToImage(kWord.c_str(), kWord.length(), &pix);
|
|
|
|
|
pixDestroy(&pix);
|
|
|
|
|
const std::vector<BoxChar*>& boxchars = renderer_->GetBoxes();
|
|
|
|
|
EXPECT_EQ(kWord.length(), offset);
|
|
|
|
|
ASSERT_EQ(kCleanWord.length(), boxchars.size());
|
2019-01-23 14:13:57 +08:00
|
|
|
|
for (size_t i = 0; i < boxchars.size(); ++i) {
|
2018-08-24 21:07:48 +08:00
|
|
|
|
EXPECT_EQ(kCleanWord.substr(i, 1), boxchars[i]->ch());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ------------ StringRenderer::ConvertBasicLatinToFullwidthLatin() ------------
|
|
|
|
|
|
|
|
|
|
TEST(ConvertBasicLatinToFullwidthLatinTest, DoesConvertBasicLatin) {
|
2019-01-23 14:13:57 +08:00
|
|
|
|
const std::string kHalfAlpha = "ABCD";
|
|
|
|
|
const std::string kFullAlpha = "ABCD";
|
2018-08-24 21:07:48 +08:00
|
|
|
|
EXPECT_EQ(kFullAlpha,
|
|
|
|
|
StringRenderer::ConvertBasicLatinToFullwidthLatin(kHalfAlpha));
|
|
|
|
|
|
2019-01-23 14:13:57 +08:00
|
|
|
|
const std::string kHalfDigit = "0123";
|
|
|
|
|
const std::string kFullDigit = "0123";
|
2018-08-24 21:07:48 +08:00
|
|
|
|
EXPECT_EQ(kFullDigit,
|
|
|
|
|
StringRenderer::ConvertBasicLatinToFullwidthLatin(kHalfDigit));
|
|
|
|
|
|
2019-01-23 14:13:57 +08:00
|
|
|
|
const std::string kHalfSym = "()[]:;!?";
|
|
|
|
|
const std::string kFullSym = "()[]:;!?";
|
2018-08-24 21:07:48 +08:00
|
|
|
|
EXPECT_EQ(kFullSym,
|
|
|
|
|
StringRenderer::ConvertBasicLatinToFullwidthLatin(kHalfSym));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(ConvertBasicLatinToFullwidthLatinTest, DoesNotConvertFullwidthLatin) {
|
2019-01-23 14:13:57 +08:00
|
|
|
|
const std::string kFullAlpha = "ABCD";
|
2018-08-24 21:07:48 +08:00
|
|
|
|
EXPECT_EQ(kFullAlpha,
|
|
|
|
|
StringRenderer::ConvertBasicLatinToFullwidthLatin(kFullAlpha));
|
|
|
|
|
|
2019-01-23 14:13:57 +08:00
|
|
|
|
const std::string kFullDigit = "0123";
|
2018-08-24 21:07:48 +08:00
|
|
|
|
EXPECT_EQ(kFullDigit,
|
|
|
|
|
StringRenderer::ConvertBasicLatinToFullwidthLatin(kFullDigit));
|
|
|
|
|
|
2019-01-23 14:13:57 +08:00
|
|
|
|
const std::string kFullSym = "()[]:;!?";
|
2018-08-24 21:07:48 +08:00
|
|
|
|
EXPECT_EQ(kFullSym,
|
|
|
|
|
StringRenderer::ConvertBasicLatinToFullwidthLatin(kFullSym));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(ConvertBasicLatinToFullwidthLatinTest, DoesNotConvertNonLatin) {
|
2019-01-23 14:13:57 +08:00
|
|
|
|
const std::string kHalfKana = "アイウエオ";
|
|
|
|
|
const std::string kFullKana = "アイウエオ";
|
2018-08-24 21:07:48 +08:00
|
|
|
|
EXPECT_EQ(kHalfKana,
|
|
|
|
|
StringRenderer::ConvertBasicLatinToFullwidthLatin(kHalfKana));
|
|
|
|
|
EXPECT_EQ(kFullKana,
|
|
|
|
|
StringRenderer::ConvertBasicLatinToFullwidthLatin(kFullKana));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(ConvertBasicLatinToFullwidthLatinTest, DoesNotConvertSpace) {
|
2019-01-23 14:13:57 +08:00
|
|
|
|
const std::string kHalfSpace = " ";
|
|
|
|
|
const std::string kFullSpace = " ";
|
2018-08-24 21:07:48 +08:00
|
|
|
|
EXPECT_EQ(kHalfSpace,
|
|
|
|
|
StringRenderer::ConvertBasicLatinToFullwidthLatin(kHalfSpace));
|
|
|
|
|
EXPECT_EQ(kFullSpace,
|
|
|
|
|
StringRenderer::ConvertBasicLatinToFullwidthLatin(kFullSpace));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ------------ StringRenderer::ConvertFullwidthLatinToBasicLatin() ------------
|
|
|
|
|
|
|
|
|
|
TEST(ConvertFullwidthLatinToBasicLatinTest, DoesConvertFullwidthLatin) {
|
2019-01-23 14:13:57 +08:00
|
|
|
|
const std::string kHalfAlpha = "ABCD";
|
|
|
|
|
const std::string kFullAlpha = "ABCD";
|
2018-08-24 21:07:48 +08:00
|
|
|
|
EXPECT_EQ(kHalfAlpha,
|
|
|
|
|
StringRenderer::ConvertFullwidthLatinToBasicLatin(kFullAlpha));
|
|
|
|
|
|
2019-01-23 14:13:57 +08:00
|
|
|
|
const std::string kHalfDigit = "0123";
|
|
|
|
|
const std::string kFullDigit = "0123";
|
2018-08-24 21:07:48 +08:00
|
|
|
|
EXPECT_EQ(kHalfDigit,
|
|
|
|
|
StringRenderer::ConvertFullwidthLatinToBasicLatin(kFullDigit));
|
|
|
|
|
|
2019-01-23 14:13:57 +08:00
|
|
|
|
const std::string kHalfSym = "()[]:;!?";
|
|
|
|
|
const std::string kFullSym = "()[]:;!?";
|
2018-08-24 21:07:48 +08:00
|
|
|
|
EXPECT_EQ(kHalfSym,
|
|
|
|
|
StringRenderer::ConvertFullwidthLatinToBasicLatin(kFullSym));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(ConvertFullwidthLatinToBasicLatinTest, DoesNotConvertBasicLatin) {
|
2019-01-23 14:13:57 +08:00
|
|
|
|
const std::string kHalfAlpha = "ABCD";
|
2018-08-24 21:07:48 +08:00
|
|
|
|
EXPECT_EQ(kHalfAlpha,
|
|
|
|
|
StringRenderer::ConvertFullwidthLatinToBasicLatin(kHalfAlpha));
|
|
|
|
|
|
2019-01-23 14:13:57 +08:00
|
|
|
|
const std::string kHalfDigit = "0123";
|
2018-08-24 21:07:48 +08:00
|
|
|
|
EXPECT_EQ(kHalfDigit,
|
|
|
|
|
StringRenderer::ConvertFullwidthLatinToBasicLatin(kHalfDigit));
|
|
|
|
|
|
2019-01-23 14:13:57 +08:00
|
|
|
|
const std::string kHalfSym = "()[]:;!?";
|
2018-08-24 21:07:48 +08:00
|
|
|
|
EXPECT_EQ(kHalfSym,
|
|
|
|
|
StringRenderer::ConvertFullwidthLatinToBasicLatin(kHalfSym));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(ConvertFullwidthLatinToBasicLatinTest, DoesNotConvertNonLatin) {
|
2019-01-23 14:13:57 +08:00
|
|
|
|
const std::string kHalfKana = "アイウエオ";
|
|
|
|
|
const std::string kFullKana = "アイウエオ";
|
2018-08-24 21:07:48 +08:00
|
|
|
|
EXPECT_EQ(kHalfKana,
|
|
|
|
|
StringRenderer::ConvertFullwidthLatinToBasicLatin(kHalfKana));
|
|
|
|
|
EXPECT_EQ(kFullKana,
|
|
|
|
|
StringRenderer::ConvertFullwidthLatinToBasicLatin(kFullKana));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(ConvertFullwidthLatinToBasicLatinTest, DoesNotConvertSpace) {
|
2019-01-23 14:13:57 +08:00
|
|
|
|
const std::string kHalfSpace = " ";
|
|
|
|
|
const std::string kFullSpace = " ";
|
2018-08-24 21:07:48 +08:00
|
|
|
|
EXPECT_EQ(kHalfSpace,
|
|
|
|
|
StringRenderer::ConvertFullwidthLatinToBasicLatin(kHalfSpace));
|
|
|
|
|
EXPECT_EQ(kFullSpace,
|
|
|
|
|
StringRenderer::ConvertFullwidthLatinToBasicLatin(kFullSpace));
|
|
|
|
|
}
|
|
|
|
|
} // namespace
|