michael@0: /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "gtest/gtest.h" michael@0: michael@0: #include "nsCOMPtr.h" michael@0: #include "nsTArray.h" michael@0: #include "nsString.h" michael@0: #include "nsDependentString.h" michael@0: michael@0: #include "mozilla/Preferences.h" michael@0: michael@0: #include "gfxContext.h" michael@0: #include "gfxFont.h" michael@0: #include "gfxPlatform.h" michael@0: michael@0: #include "gfxFontTest.h" michael@0: michael@0: using namespace mozilla; michael@0: michael@0: enum { michael@0: S_UTF8 = 0, michael@0: S_ASCII = 1 michael@0: }; michael@0: michael@0: class FrameTextRunCache; michael@0: michael@0: struct LiteralArray { michael@0: LiteralArray (unsigned long l1) { michael@0: data.AppendElement(l1); michael@0: } michael@0: LiteralArray (unsigned long l1, unsigned long l2) { michael@0: data.AppendElement(l1); michael@0: data.AppendElement(l2); michael@0: } michael@0: LiteralArray (unsigned long l1, unsigned long l2, unsigned long l3) { michael@0: data.AppendElement(l1); michael@0: data.AppendElement(l2); michael@0: data.AppendElement(l3); michael@0: } michael@0: LiteralArray (unsigned long l1, unsigned long l2, unsigned long l3, unsigned long l4) { michael@0: data.AppendElement(l1); michael@0: data.AppendElement(l2); michael@0: data.AppendElement(l3); michael@0: data.AppendElement(l4); michael@0: } michael@0: LiteralArray (unsigned long l1, unsigned long l2, unsigned long l3, unsigned long l4, unsigned long l5) { michael@0: data.AppendElement(l1); michael@0: data.AppendElement(l2); michael@0: data.AppendElement(l3); michael@0: data.AppendElement(l4); michael@0: data.AppendElement(l5); michael@0: } michael@0: michael@0: LiteralArray (const LiteralArray& other) { michael@0: data = other.data; michael@0: } michael@0: michael@0: nsTArray data; michael@0: }; michael@0: michael@0: #define GLYPHS LiteralArray michael@0: michael@0: struct TestEntry { michael@0: TestEntry (const char *aUTF8FamilyString, michael@0: const gfxFontStyle& aFontStyle, michael@0: const char *aString) michael@0: : utf8FamilyString(aUTF8FamilyString), michael@0: fontStyle(aFontStyle), michael@0: stringType(S_ASCII), michael@0: string(aString), michael@0: isRTL(false) michael@0: { michael@0: } michael@0: michael@0: TestEntry (const char *aUTF8FamilyString, michael@0: const gfxFontStyle& aFontStyle, michael@0: int stringType, michael@0: const char *aString) michael@0: : utf8FamilyString(aUTF8FamilyString), michael@0: fontStyle(aFontStyle), michael@0: stringType(stringType), michael@0: string(aString), michael@0: isRTL(false) michael@0: { michael@0: } michael@0: michael@0: struct ExpectItem { michael@0: ExpectItem(const nsCString& aFontName, michael@0: const LiteralArray& aGlyphs) michael@0: : fontName(aFontName), glyphs(aGlyphs) michael@0: { } michael@0: michael@0: bool Compare(const nsCString& aFontName, michael@0: cairo_glyph_t *aGlyphs, michael@0: int num_glyphs) michael@0: { michael@0: // bit that allowed for empty fontname to match all is commented michael@0: // out michael@0: if (/*!fontName.IsEmpty() &&*/ !fontName.Equals(aFontName)) michael@0: return false; michael@0: michael@0: if (num_glyphs != int(glyphs.data.Length())) michael@0: return false; michael@0: michael@0: for (int j = 0; j < num_glyphs; j++) { michael@0: if (glyphs.data[j] != aGlyphs[j].index) michael@0: return false; michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: nsCString fontName; michael@0: LiteralArray glyphs; michael@0: }; michael@0: michael@0: void SetRTL() michael@0: { michael@0: isRTL = true; michael@0: } michael@0: michael@0: // Empty/nullptr fontName means ignore font name michael@0: void Expect (const char *platform, michael@0: const char *fontName, michael@0: const LiteralArray& glyphs) michael@0: { michael@0: if (fontName) michael@0: Expect (platform, nsDependentCString(fontName), glyphs); michael@0: else michael@0: Expect (platform, nsCString(), glyphs); michael@0: } michael@0: michael@0: void Expect (const char *platform, michael@0: const nsCString& fontName, michael@0: const LiteralArray& glyphs) michael@0: { michael@0: #if defined(XP_WIN) michael@0: if (strcmp(platform, "win32")) michael@0: return; michael@0: #elif defined(XP_MACOSX) michael@0: if (strcmp(platform, "macosx")) michael@0: return; michael@0: #elif defined(XP_UNIX) michael@0: if (strcmp(platform, "gtk2-pango")) michael@0: return; michael@0: #else michael@0: return; michael@0: #endif michael@0: michael@0: expectItems.AppendElement(ExpectItem(fontName, glyphs)); michael@0: } michael@0: michael@0: bool Check (gfxFontTestStore *store) { michael@0: if (expectItems.Length() == 0 || michael@0: store->items.Length() != expectItems.Length()) michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: for (uint32_t i = 0; i < expectItems.Length(); i++) { michael@0: if (!expectItems[i].Compare(store->items[i].platformFont, michael@0: store->items[i].glyphs, michael@0: store->items[i].num_glyphs)) michael@0: return false; michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: const char *utf8FamilyString; michael@0: gfxFontStyle fontStyle; michael@0: michael@0: int stringType; michael@0: const char *string; michael@0: bool isRTL; michael@0: michael@0: nsTArray expectItems; michael@0: }; michael@0: michael@0: static already_AddRefed michael@0: MakeContext () michael@0: { michael@0: const int size = 200; michael@0: michael@0: nsRefPtr surface; michael@0: michael@0: surface = gfxPlatform::GetPlatform()-> michael@0: CreateOffscreenSurface(IntSize(size, size), michael@0: gfxASurface::ContentFromFormat(gfxImageFormat::RGB24)); michael@0: nsRefPtr ctx = new gfxContext(surface); michael@0: return ctx.forget(); michael@0: } michael@0: michael@0: TestEntry* michael@0: AddTest (nsTArray& testList, michael@0: const char *utf8FamilyString, michael@0: const gfxFontStyle& fontStyle, michael@0: int stringType, michael@0: const char *string) michael@0: { michael@0: TestEntry te (utf8FamilyString, michael@0: fontStyle, michael@0: stringType, michael@0: string); michael@0: michael@0: testList.AppendElement(te); michael@0: michael@0: return &(testList[testList.Length()-1]); michael@0: } michael@0: michael@0: void michael@0: DumpStore (gfxFontTestStore *store) { michael@0: if (store->items.Length() == 0) { michael@0: printf ("(empty)\n"); michael@0: } michael@0: michael@0: for (uint32_t i = 0; michael@0: i < store->items.Length(); michael@0: i++) michael@0: { michael@0: printf ("Run[% 2d]: '%s' ", i, store->items[i].platformFont.BeginReading()); michael@0: michael@0: for (int j = 0; j < store->items[i].num_glyphs; j++) michael@0: printf ("%d ", int(store->items[i].glyphs[j].index)); michael@0: michael@0: printf ("\n"); michael@0: } michael@0: } michael@0: michael@0: void michael@0: DumpTestExpect (TestEntry *test) { michael@0: for (uint32_t i = 0; i < test->expectItems.Length(); i++) { michael@0: printf ("Run[% 2d]: '%s' ", i, test->expectItems[i].fontName.BeginReading()); michael@0: for (uint32_t j = 0; j < test->expectItems[i].glyphs.data.Length(); j++) michael@0: printf ("%d ", int(test->expectItems[i].glyphs.data[j])); michael@0: michael@0: printf ("\n"); michael@0: } michael@0: } michael@0: michael@0: void SetupTests(nsTArray& testList); michael@0: michael@0: static bool michael@0: RunTest (TestEntry *test, gfxContext *ctx) { michael@0: nsRefPtr fontGroup; michael@0: michael@0: fontGroup = gfxPlatform::GetPlatform()->CreateFontGroup(NS_ConvertUTF8toUTF16(test->utf8FamilyString), &test->fontStyle, nullptr); michael@0: michael@0: nsAutoPtr textRun; michael@0: gfxTextRunFactory::Parameters params = { michael@0: ctx, nullptr, nullptr, nullptr, 0, 60 michael@0: }; michael@0: uint32_t flags = gfxTextRunFactory::TEXT_IS_PERSISTENT; michael@0: if (test->isRTL) { michael@0: flags |= gfxTextRunFactory::TEXT_IS_RTL; michael@0: } michael@0: uint32_t length; michael@0: if (test->stringType == S_ASCII) { michael@0: flags |= gfxTextRunFactory::TEXT_IS_ASCII | gfxTextRunFactory::TEXT_IS_8BIT; michael@0: length = strlen(test->string); michael@0: textRun = fontGroup->MakeTextRun(reinterpret_cast(test->string), length, ¶ms, flags); michael@0: } else { michael@0: NS_ConvertUTF8toUTF16 str(nsDependentCString(test->string)); michael@0: length = str.Length(); michael@0: textRun = fontGroup->MakeTextRun(str.get(), length, ¶ms, flags); michael@0: } michael@0: michael@0: gfxFontTestStore::NewStore(); michael@0: textRun->Draw(ctx, gfxPoint(0,0), DrawMode::GLYPH_FILL, 0, length, nullptr, nullptr, nullptr); michael@0: gfxFontTestStore *s = gfxFontTestStore::CurrentStore(); michael@0: michael@0: if (!test->Check(s)) { michael@0: DumpStore(s); michael@0: printf (" expected:\n"); michael@0: DumpTestExpect(test); michael@0: gfxFontTestStore::DeleteStore(); michael@0: return false; michael@0: } michael@0: michael@0: gfxFontTestStore::DeleteStore(); michael@0: michael@0: return true; michael@0: } michael@0: michael@0: TEST(Gfx, FontSelection) { michael@0: int passed = 0; michael@0: int failed = 0; michael@0: michael@0: // set up the tests michael@0: nsTArray testList; michael@0: SetupTests(testList); michael@0: michael@0: nsRefPtr context = MakeContext(); michael@0: michael@0: for (uint32_t test = 0; michael@0: test < testList.Length(); michael@0: test++) michael@0: { michael@0: bool result = RunTest (&testList[test], context); michael@0: if (result) { michael@0: passed++; michael@0: } else { michael@0: printf ("Test %d failed\n", test); michael@0: failed++; michael@0: } michael@0: } michael@0: } michael@0: michael@0: // The tests themselves michael@0: michael@0: #include "gfxFontSelectionTests.h"