|
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
|
2 * This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 #include "gtest/gtest.h" |
|
7 |
|
8 #include "nsCOMPtr.h" |
|
9 #include "nsTArray.h" |
|
10 #include "nsString.h" |
|
11 #include "nsDependentString.h" |
|
12 |
|
13 #include "prinrval.h" |
|
14 |
|
15 #include "gfxContext.h" |
|
16 #include "gfxFont.h" |
|
17 #include "gfxPlatform.h" |
|
18 |
|
19 #include "gfxFontTest.h" |
|
20 #include "mozilla/Attributes.h" |
|
21 |
|
22 class FrameTextRunCache; |
|
23 |
|
24 static FrameTextRunCache *gTextRuns = nullptr; |
|
25 |
|
26 /* |
|
27 * Cache textruns and expire them after 3*10 seconds of no use. |
|
28 */ |
|
29 class FrameTextRunCache MOZ_FINAL : public nsExpirationTracker<gfxTextRun,3> { |
|
30 public: |
|
31 enum { TIMEOUT_SECONDS = 10 }; |
|
32 FrameTextRunCache() |
|
33 : nsExpirationTracker<gfxTextRun,3>(TIMEOUT_SECONDS*1000) {} |
|
34 ~FrameTextRunCache() { |
|
35 AgeAllGenerations(); |
|
36 } |
|
37 |
|
38 void RemoveFromCache(gfxTextRun* aTextRun) { |
|
39 if (aTextRun->GetExpirationState()->IsTracked()) { |
|
40 RemoveObject(aTextRun); |
|
41 } |
|
42 } |
|
43 |
|
44 // This gets called when the timeout has expired on a gfxTextRun |
|
45 virtual void NotifyExpired(gfxTextRun* aTextRun) { |
|
46 RemoveFromCache(aTextRun); |
|
47 delete aTextRun; |
|
48 } |
|
49 }; |
|
50 |
|
51 static gfxTextRun * |
|
52 MakeTextRun(const char16_t *aText, uint32_t aLength, |
|
53 gfxFontGroup *aFontGroup, const gfxFontGroup::Parameters* aParams, |
|
54 uint32_t aFlags) |
|
55 { |
|
56 nsAutoPtr<gfxTextRun> textRun; |
|
57 if (aLength == 0) { |
|
58 abort(); |
|
59 //textRun = aFontGroup->MakeEmptyTextRun(aParams, aFlags); |
|
60 } else if (aLength == 1 && aText[0] == ' ') { |
|
61 abort(); |
|
62 //textRun = aFontGroup->MakeSpaceTextRun(aParams, aFlags); |
|
63 } else { |
|
64 textRun = aFontGroup->MakeTextRun(aText, aLength, aParams, aFlags); |
|
65 } |
|
66 if (!textRun) |
|
67 return nullptr; |
|
68 nsresult rv = gTextRuns->AddObject(textRun); |
|
69 if (NS_FAILED(rv)) { |
|
70 gTextRuns->RemoveFromCache(textRun); |
|
71 return nullptr; |
|
72 } |
|
73 return textRun.forget(); |
|
74 } |
|
75 |
|
76 static already_AddRefed<gfxContext> |
|
77 MakeContext () |
|
78 { |
|
79 const int size = 200; |
|
80 |
|
81 nsRefPtr<gfxASurface> surface; |
|
82 |
|
83 surface = gfxPlatform::GetPlatform()-> |
|
84 CreateOffscreenSurface(IntSize(size, size), |
|
85 gfxASurface::ContentFromFormat(gfxImageFormat::RGB24)); |
|
86 nsRefPtr<gfxContext> ctx = new gfxContext(surface); |
|
87 return ctx.forget(); |
|
88 } |
|
89 |
|
90 TEST(Gfx, WordCache) { |
|
91 gTextRuns = new FrameTextRunCache(); |
|
92 |
|
93 nsRefPtr<gfxContext> ctx = MakeContext(); |
|
94 { |
|
95 gfxFontStyle style (mozilla::gfx::FontStyle::NORMAL, |
|
96 139, |
|
97 10.0, |
|
98 0, |
|
99 NS_NewPermanentAtom(NS_LITERAL_STRING("en")), |
|
100 0.0, |
|
101 false, false, |
|
102 NS_LITERAL_STRING("")); |
|
103 |
|
104 nsRefPtr<gfxFontGroup> fontGroup = |
|
105 gfxPlatform::GetPlatform()->CreateFontGroup(NS_LITERAL_STRING("Geneva, MS Sans Serif, Helvetica,serif"), &style, nullptr); |
|
106 |
|
107 gfxTextRunFactory::Parameters params = { |
|
108 ctx, nullptr, nullptr, nullptr, 0, 60 |
|
109 }; |
|
110 |
|
111 uint32_t flags = gfxTextRunFactory::TEXT_IS_PERSISTENT; |
|
112 |
|
113 // First load an Arabic word into the cache |
|
114 const char cString[] = "\xd8\xaa\xd9\x85"; |
|
115 nsDependentCString cStr(cString); |
|
116 NS_ConvertUTF8toUTF16 str(cStr); |
|
117 gfxTextRun *tr = MakeTextRun(str.get(), str.Length(), fontGroup, ¶ms, flags); |
|
118 tr->GetAdvanceWidth(0, str.Length(), nullptr); |
|
119 |
|
120 // Now try to trigger an assertion with a word cache bug. The first |
|
121 // word is in the cache so it gets added to the new textrun directly. |
|
122 // The second word is not in the cache |
|
123 const char cString2[] = "\xd8\xaa\xd9\x85\n\xd8\xaa\xd8\x85 "; |
|
124 nsDependentCString cStr2(cString2); |
|
125 NS_ConvertUTF8toUTF16 str2(cStr2); |
|
126 gfxTextRun *tr2 = MakeTextRun(str2.get(), str2.Length(), fontGroup, ¶ms, flags); |
|
127 tr2->GetAdvanceWidth(0, str2.Length(), nullptr); |
|
128 } |
|
129 |
|
130 delete gTextRuns; |
|
131 gTextRuns = nullptr; |
|
132 |
|
133 } |