Added Windows support for libtxt in order to build flutter_tester.exe (flutter/engine#4395)

* Added Windows support for libtxt in order to build flutter_tester.exe.

Relatively minor changes were needed to get libtxt building on Windows
(missing/incompatiable headers, the odd syscall, path separators, etc.).
Windows doesn't render text in the same way as other platforms, so some tests
that checked for specific pixel offsets are disabled.
This commit is contained in:
Ben Konyi 2017-11-30 16:35:32 -05:00 committed by GitHub
parent c79fb5a400
commit 3f795be2a2
23 changed files with 160 additions and 27 deletions

View File

@ -49,7 +49,6 @@ group("flutter") {
"$flutter_root/fml:fml_unittests",
"$flutter_root/sky/engine/wtf:wtf_unittests",
"$flutter_root/synchronization:synchronization_unittests",
"$flutter_root/third_party/txt:txt_benchmarks",
"$flutter_root/third_party/txt:txt_unittests",
"//garnet/public/lib/fxl:fxl_unittests",
]

View File

@ -100,6 +100,7 @@ source_set("txt") {
"src/utils/JenkinsHash.h",
"src/utils/LruCache.h",
"src/utils/TypeHelpers.h",
"src/utils/WindowsUtils.h",
]
if (is_mac || is_ios) {
@ -144,8 +145,6 @@ executable("txt_unittests") {
"tests/ICUTestBase.h",
"tests/LayoutUtilsTest.cpp",
"tests/MeasurementTests.cpp",
"tests/MinikinFontForTest.cpp",
"tests/MinikinFontForTest.h",
"tests/SparseBitSetTest.cpp",
"tests/UnicodeUtils.cpp",
"tests/UnicodeUtils.h",
@ -169,6 +168,13 @@ executable("txt_unittests") {
# "tests/LayoutTest.cpp",
]
if (!is_win) {
sources += [
"tests/MinikinFontForTest.cpp",
"tests/MinikinFontForTest.h",
]
}
deps = [
":txt",
"//third_party/gtest",

View File

@ -14,6 +14,7 @@
* limitations under the License.
*/
#include <memory>
#include <string>
#include "lib/fxl/command_line.h"

View File

@ -20,6 +20,11 @@
#include "lib/fxl/logging.h"
#if defined(_WIN32)
// Conflicts with macro on Windows.
#undef ERROR
#endif
#ifndef LOG_ALWAYS_FATAL_IF
#define LOG_ALWAYS_FATAL_IF(cond, ...) \
((cond) ? (FXL_LOG(FATAL) << #cond) : (void)0)

View File

@ -295,7 +295,7 @@ SparseBitSet CmapCoverage::getCoverage(const uint8_t* cmap_data,
} else {
success = getCoverageFormat12(coverageVec, tableData, tableSize);
}
if (success) {
if (success && (coverageVec.size() != 0)) {
return SparseBitSet(&coverageVec.front(), coverageVec.size() >> 1);
} else {
return SparseBitSet();

View File

@ -22,6 +22,7 @@
#include <minikin/Emoji.h>
#include <minikin/GraphemeBreak.h>
#include "MinikinInternal.h"
#include "utils/WindowsUtils.h"
namespace minikin {

View File

@ -27,6 +27,7 @@
#define LOG_TAG "Minikin"
#include "minikin/Hyphenator.h"
#include "utils/WindowsUtils.h"
using std::vector;
@ -375,7 +376,7 @@ HyphenationType Hyphenator::alphabetLookup(uint16_t* alpha_codes,
alpha_codes[0] = 0;
for (size_t i = 0; i < len; i++) {
uint16_t c = word[i];
auto p = std::lower_bound(begin, end, c << 11);
auto p = std::lower_bound<const uint32_t*, uint32_t>(begin, end, c << 11);
if (p == end) {
return HyphenationType::DONT_BREAK;
}

View File

@ -28,6 +28,7 @@
#include <log/log.h>
#include <utils/JenkinsHash.h>
#include <utils/LruCache.h>
#include <utils/WindowsUtils.h>
#include <hb-icu.h>
#include <hb-ot.h>
@ -577,7 +578,8 @@ BidiText::BidiText(const uint16_t* buf,
} else if (bidiFlags == kBidi_Default_RTL) {
bidiReq = UBIDI_DEFAULT_RTL;
}
ubidi_setPara(mBidi, buf, mBufSize, bidiReq, NULL, &status);
ubidi_setPara(mBidi, reinterpret_cast<const UChar*>(buf), mBufSize, bidiReq,
NULL, &status);
if (!U_SUCCESS(status)) {
ALOGE("error calling ubidi_setPara, status = %d", status);
return;

View File

@ -18,12 +18,14 @@
#define LOG_TAG "Minikin"
#include <algorithm>
#include <limits>
#include <log/log.h>
#include <minikin/Layout.h>
#include <minikin/LineBreaker.h>
#include <utils/WindowsUtils.h>
#include "LayoutUtils.h"
using std::vector;

View File

@ -22,6 +22,7 @@
#include <log/log.h>
#include <minikin/SparseBitSet.h>
#include <utils/WindowsUtils.h>
namespace minikin {
@ -106,10 +107,16 @@ void SparseBitSet::initFromRanges(const uint32_t* ranges, size_t nRanges) {
}
}
#if defined(_WIN32)
int SparseBitSet::CountLeadingZeros(element x) {
return sizeof(element) <= sizeof(int) ? clz_win(x) : clzl_win(x);
}
#else
int SparseBitSet::CountLeadingZeros(element x) {
// Note: GCC / clang builtin
return sizeof(element) <= sizeof(int) ? __builtin_clz(x) : __builtin_clzl(x);
}
#endif
uint32_t SparseBitSet::nextSetBit(uint32_t fromIndex) const {
if (fromIndex >= mMaxVal) {

View File

@ -50,7 +50,8 @@ void WordBreaker::setText(const uint16_t* data, size_t size) {
mScanOffset = 0;
mInEmailOrUrl = false;
UErrorCode status = U_ZERO_ERROR;
utext_openUChars(&mUText, data, size, &status);
utext_openUChars(&mUText, reinterpret_cast<const UChar*>(data), size,
&status);
mBreakIterator->setText(&mUText, status);
mBreakIterator->first();
}

View File

@ -25,6 +25,7 @@
#include <memory>
#include "unicode/brkiter.h"
#include "utils/WindowsUtils.h"
namespace minikin {

View File

@ -15,6 +15,7 @@
*/
#include "txt/asset_font_manager.h"
#include <memory>
#include "lib/fxl/logging.h"
namespace txt {

View File

@ -19,6 +19,7 @@
#include <memory>
#include "lib/fxl/macros.h"
#include "third_party/skia/include/core/SkStream.h"
#include "third_party/skia/include/ports/SkFontMgr.h"
#include "txt/asset_data_provider.h"

View File

@ -3,16 +3,44 @@
// found in the LICENSE file.
#include "txt/directory_asset_data_provider.h"
#include <dirent.h>
#include <sstream>
#include "lib/fxl/logging.h"
#include "third_party/skia/include/core/SkStream.h"
#include "third_party/skia/include/core/SkTypeface.h"
#include "utils/WindowsUtils.h"
#if !defined(_WIN32)
#include <dirent.h>
#endif
namespace txt {
DirectoryAssetDataProvider::DirectoryAssetDataProvider(
const std::string& directory_path) {
#if defined(_WIN32)
std::string path = directory_path + "\\*";
WIN32_FIND_DATAA ffd;
HANDLE directory = FindFirstFileA(path.c_str(), &ffd);
if (directory == INVALID_HANDLE_VALUE) {
return;
}
do {
if ((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) {
continue;
}
std::string file_name(ffd.cFileName);
std::stringstream file_path;
file_path << directory_path << "/" << file_name;
RegisterTypeface(SkTypeface::MakeFromFile(file_path.str().c_str()));
} while (FindNextFileA(directory, &ffd) != 0);
// TODO(bkonyi): check for error here?
FindClose(directory);
#else
auto directory_closer = [](DIR* directory) {
if (directory != nullptr) {
::closedir(directory);
@ -39,6 +67,7 @@ DirectoryAssetDataProvider::DirectoryAssetDataProvider(
RegisterTypeface(SkTypeface::MakeFromFile(file_path.str().c_str()));
}
#endif
}
DirectoryAssetDataProvider::~DirectoryAssetDataProvider() = default;

View File

@ -78,6 +78,8 @@ int GetWeight(const FontWeight weight) {
return 8;
case FontWeight::w900:
return 9;
default:
return -1;
}
}
@ -87,10 +89,11 @@ int GetWeight(const TextStyle& style) {
bool GetItalic(const TextStyle& style) {
switch (style.font_style) {
case FontStyle::normal:
return false;
case FontStyle::italic:
return true;
case FontStyle::normal:
default:
return false;
}
}

View File

@ -32,6 +32,7 @@
#include "third_party/skia/include/core/SkPoint.h"
#include "third_party/skia/include/core/SkRect.h"
#include "third_party/skia/include/core/SkTextBlob.h"
#include "utils/WindowsUtils.h"
class SkCanvas;
@ -164,10 +165,10 @@ class Paragraph {
FRIEND_TEST(ParagraphTest, RainbowParagraph);
FRIEND_TEST(ParagraphTest, DefaultStyleParagraph);
FRIEND_TEST(ParagraphTest, BoldParagraph);
FRIEND_TEST(ParagraphTest, LeftAlignParagraph);
FRIEND_TEST(ParagraphTest, RightAlignParagraph);
FRIEND_TEST(ParagraphTest, CenterAlignParagraph);
FRIEND_TEST(ParagraphTest, JustifyAlignParagraph);
FRIEND_TEST_WINDOWS_DISABLED(ParagraphTest, LeftAlignParagraph);
FRIEND_TEST_WINDOWS_DISABLED(ParagraphTest, RightAlignParagraph);
FRIEND_TEST_WINDOWS_DISABLED(ParagraphTest, CenterAlignParagraph);
FRIEND_TEST_WINDOWS_DISABLED(ParagraphTest, JustifyAlignParagraph);
FRIEND_TEST(ParagraphTest, DecorationsParagraph);
FRIEND_TEST(ParagraphTest, ItalicsParagraph);
FRIEND_TEST(ParagraphTest, ChineseParagraph);
@ -175,8 +176,8 @@ class Paragraph {
FRIEND_TEST(ParagraphTest, SpacingParagraph);
FRIEND_TEST(ParagraphTest, LongWordParagraph);
FRIEND_TEST(ParagraphTest, KernScaleParagraph);
FRIEND_TEST(ParagraphTest, NewlineParagraph);
FRIEND_TEST(ParagraphTest, EmojiParagraph);
FRIEND_TEST_WINDOWS_DISABLED(ParagraphTest, NewlineParagraph);
FRIEND_TEST_WINDOWS_DISABLED(ParagraphTest, EmojiParagraph);
FRIEND_TEST(ParagraphTest, HyphenBreakParagraph);
FRIEND_TEST(ParagraphTest, RepeatLayoutParagraph);
FRIEND_TEST(ParagraphTest, Ellipsize);

View File

@ -17,6 +17,7 @@
#include "styled_runs.h"
#include "lib/fxl/logging.h"
#include "utils/WindowsUtils.h"
namespace txt {

View File

@ -22,6 +22,7 @@
#include "text_style.h"
#include "third_party/gtest/include/gtest/gtest_prod.h"
#include "utils/WindowsUtils.h"
namespace txt {
@ -66,10 +67,10 @@ class StyledRuns {
FRIEND_TEST(ParagraphTest, RainbowParagraph);
FRIEND_TEST(ParagraphTest, DefaultStyleParagraph);
FRIEND_TEST(ParagraphTest, BoldParagraph);
FRIEND_TEST(ParagraphTest, LeftAlignParagraph);
FRIEND_TEST(ParagraphTest, RightAlignParagraph);
FRIEND_TEST(ParagraphTest, CenterAlignParagraph);
FRIEND_TEST(ParagraphTest, JustifyAlignParagraph);
FRIEND_TEST_WINDOWS_DISABLED(ParagraphTest, LeftAlignParagraph);
FRIEND_TEST_WINDOWS_DISABLED(ParagraphTest, RightAlignParagraph);
FRIEND_TEST_WINDOWS_DISABLED(ParagraphTest, CenterAlignParagraph);
FRIEND_TEST_WINDOWS_DISABLED(ParagraphTest, JustifyAlignParagraph);
FRIEND_TEST(ParagraphTest, DecorationsParagraph);
FRIEND_TEST(ParagraphTest, ItalicsParagraph);
FRIEND_TEST(ParagraphTest, ChineseParagraph);
@ -84,6 +85,9 @@ class StyledRuns {
size_t style_index = 0;
size_t start = 0;
size_t end = 0;
explicit IndexedRun(size_t style_index, size_t start, size_t end)
: style_index(style_index), start(start), end(end) {}
};
std::vector<TextStyle> styles_;

View File

@ -0,0 +1,59 @@
/*
* 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.
*/
#ifndef WINDOWS_UTILS_H
#define WINDOWS_UTILS_H
#if defined(_WIN32)
#define DISABLE_TEST_WINDOWS(TEST_NAME) DISABLED_##TEST_NAME
#define FRIEND_TEST_WINDOWS_DISABLED_EXPANDED(SUITE, TEST_NAME) \
FRIEND_TEST(SUITE, TEST_NAME)
#define FRIEND_TEST_WINDOWS_DISABLED(SUITE, TEST_NAME) \
FRIEND_TEST_WINDOWS_DISABLED_EXPANDED(SUITE, DISABLE_TEST_WINDOWS(TEST_NAME))
#define NOMINMAX
#include <BaseTsd.h>
#include <intrin.h>
#include <windows.h>
#undef ERROR
inline unsigned int clz_win(unsigned int num) {
unsigned long r = 0;
_BitScanReverse(&r, num);
return r;
}
inline unsigned int clzl_win(unsigned long num) {
unsigned long r = 0;
_BitScanReverse64(&r, num);
return r;
}
inline unsigned int ctz_win(unsigned int num) {
unsigned long r = 0;
_BitScanForward(&r, num);
return r;
}
typedef SSIZE_T ssize_t;
#else
#define DISABLE_TEST_WINDOWS(TEST_NAME) TEST_NAME
#define FRIEND_TEST_WINDOWS_DISABLED(SUITE, TEST_NAME) \
FRIEND_TEST(SUITE, TEST_NAME)
#endif // defined(_WIN32)
#endif // WINDOWS_UTILS_H

View File

@ -20,6 +20,7 @@
#include <log/log.h>
#include <minikin/CmapCoverage.h>
#include <minikin/SparseBitSet.h>
#include <utils/WindowsUtils.h>
namespace minikin {
@ -65,8 +66,12 @@ static std::vector<uint8_t> buildCmapFormat4Table(
head = writeU16(segmentCount * 2, out.data(), head); // segCountX2
head = writeU16(searchRange, out.data(), head); // searchRange
#if defined(_WIN32)
head = writeU16(ctz_win(searchRange) - 1, out.data(), head);
#else
head = writeU16(__builtin_ctz(searchRange) - 1, out.data(),
head); // entrySelector
#endif
head =
writeU16(segmentCount * 2 - searchRange, out.data(), head); // rangeShift

View File

@ -18,6 +18,7 @@
#include <unicode/utf.h>
#include <unicode/utf8.h>
#include <cstdlib>
#include <memory>
#include <string>
#include <vector>

View File

@ -24,6 +24,8 @@
#include "txt/paragraph_builder.h"
#include "utils.h"
#define DISABLE_ON_WINDOWS(TEST) DISABLE_TEST_WINDOWS(TEST)
namespace txt {
using ParagraphTest = RenderTest;
@ -253,7 +255,7 @@ TEST_F(ParagraphTest, BoldParagraph) {
ASSERT_TRUE(Snapshot());
}
TEST_F(ParagraphTest, LeftAlignParagraph) {
TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(LeftAlignParagraph)) {
const char* text =
"This is a very long sentence to test if the text will properly wrap "
"around and go to the next line. Sometimes, short sentence. Longer "
@ -349,7 +351,7 @@ TEST_F(ParagraphTest, LeftAlignParagraph) {
ASSERT_TRUE(Snapshot());
}
TEST_F(ParagraphTest, RightAlignParagraph) {
TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(RightAlignParagraph)) {
const char* text =
"This is a very long sentence to test if the text will properly wrap "
"around and go to the next line. Sometimes, short sentence. Longer "
@ -452,7 +454,7 @@ TEST_F(ParagraphTest, RightAlignParagraph) {
ASSERT_TRUE(Snapshot());
}
TEST_F(ParagraphTest, CenterAlignParagraph) {
TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(CenterAlignParagraph)) {
const char* text =
"This is a very long sentence to test if the text will properly wrap "
"around and go to the next line. Sometimes, short sentence. Longer "
@ -559,7 +561,7 @@ TEST_F(ParagraphTest, CenterAlignParagraph) {
ASSERT_TRUE(Snapshot());
}
TEST_F(ParagraphTest, JustifyAlignParagraph) {
TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(JustifyAlignParagraph)) {
const char* text =
"This is a very long sentence to test if the text will properly wrap "
"around and go to the next line. Sometimes, short sentence. Longer "
@ -913,7 +915,7 @@ TEST_F(ParagraphTest, GetGlyphPositionAtCoordinateParagraph) {
ASSERT_EQ(paragraph->GetGlyphPositionAtCoordinate(85, 10000).position, 74ull);
}
TEST_F(ParagraphTest, GetRectsForRangeParagraph) {
TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(GetRectsForRangeParagraph)) {
const char* text =
"12345, \"67890\" 12345 67890 12345 67890 12345 67890 12345 67890 12345 "
"67890 12345";
@ -1305,7 +1307,7 @@ TEST_F(ParagraphTest, KernScaleParagraph) {
EXPECT_DOUBLE_EQ(paragraph->records_[4].offset().x(), 253.36328125f);
}
TEST_F(ParagraphTest, NewlineParagraph) {
TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(NewlineParagraph)) {
txt::ParagraphStyle paragraph_style;
paragraph_style.break_strategy = minikin::kBreakStrategy_HighQuality;
@ -1344,7 +1346,7 @@ TEST_F(ParagraphTest, NewlineParagraph) {
EXPECT_DOUBLE_EQ(paragraph->records_[6].offset().x(), 0);
}
TEST_F(ParagraphTest, EmojiParagraph) {
TEST_F(ParagraphTest, DISABLE_ON_WINDOWS(EmojiParagraph)) {
const char* text =
"😀😃😄😁😆😅😂🤣☺😇🙂😍😡😟😢😻👽💩👍👎🙏👌👋👄👁👦👼👨‍🚀👨‍🚒🙋‍♂️👳👨‍👨‍👧‍👧\
💼👡👠🐶🐰🐻🐼🐷🐒🐵🐔🐧🐦🐋🐟🐡🕸🐌🐴🐊🐄🐪🐘🌸🌏🔥🌟🌚🌝💦💧\