Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* vim: set ts=8 sts=4 et sw=4 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "base/basictypes.h"
9 #include "gfxAndroidPlatform.h"
10 #include "mozilla/gfx/2D.h"
11 #include "mozilla/Preferences.h"
13 #include "gfx2DGlue.h"
14 #include "gfxFT2FontList.h"
15 #include "gfxImageSurface.h"
16 #include "mozilla/dom/ContentChild.h"
17 #include "nsXULAppAPI.h"
18 #include "nsIScreen.h"
19 #include "nsIScreenManager.h"
20 #include "nsILocaleService.h"
21 #include "nsServiceManagerUtils.h"
22 #include "gfxPrefs.h"
23 #include "cairo.h"
25 #ifdef MOZ_WIDGET_ANDROID
26 #include "AndroidBridge.h"
27 #endif
29 #ifdef MOZ_WIDGET_GONK
30 #include <cutils/properties.h>
31 #endif
33 #include "ft2build.h"
34 #include FT_FREETYPE_H
35 #include FT_MODULE_H
37 using namespace mozilla;
38 using namespace mozilla::dom;
39 using namespace mozilla::gfx;
41 static FT_Library gPlatformFTLibrary = nullptr;
43 class FreetypeReporter MOZ_FINAL : public nsIMemoryReporter,
44 public CountingAllocatorBase<FreetypeReporter>
45 {
46 public:
47 NS_DECL_ISUPPORTS
49 static void* Malloc(FT_Memory, long size)
50 {
51 return CountingMalloc(size);
52 }
54 static void Free(FT_Memory, void* p)
55 {
56 return CountingFree(p);
57 }
59 static void*
60 Realloc(FT_Memory, long cur_size, long new_size, void* p)
61 {
62 return CountingRealloc(p, new_size);
63 }
65 NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
66 nsISupports* aData)
67 {
68 return MOZ_COLLECT_REPORT(
69 "explicit/freetype", KIND_HEAP, UNITS_BYTES, MemoryAllocated(),
70 "Memory used by Freetype.");
71 }
72 };
74 NS_IMPL_ISUPPORTS(FreetypeReporter, nsIMemoryReporter)
76 template<> Atomic<size_t> CountingAllocatorBase<FreetypeReporter>::sAmount(0);
78 static FT_MemoryRec_ sFreetypeMemoryRecord;
80 gfxAndroidPlatform::gfxAndroidPlatform()
81 {
82 // A custom allocator. It counts allocations, enabling memory reporting.
83 sFreetypeMemoryRecord.user = nullptr;
84 sFreetypeMemoryRecord.alloc = FreetypeReporter::Malloc;
85 sFreetypeMemoryRecord.free = FreetypeReporter::Free;
86 sFreetypeMemoryRecord.realloc = FreetypeReporter::Realloc;
88 // These two calls are equivalent to FT_Init_FreeType(), but allow us to
89 // provide a custom memory allocator.
90 FT_New_Library(&sFreetypeMemoryRecord, &gPlatformFTLibrary);
91 FT_Add_Default_Modules(gPlatformFTLibrary);
93 RegisterStrongMemoryReporter(new FreetypeReporter());
95 nsCOMPtr<nsIScreenManager> screenMgr = do_GetService("@mozilla.org/gfx/screenmanager;1");
96 nsCOMPtr<nsIScreen> screen;
97 screenMgr->GetPrimaryScreen(getter_AddRefs(screen));
98 mScreenDepth = 24;
99 screen->GetColorDepth(&mScreenDepth);
101 mOffscreenFormat = mScreenDepth == 16
102 ? gfxImageFormat::RGB16_565
103 : gfxImageFormat::RGB24;
105 if (gfxPrefs::AndroidRGB16Force()) {
106 mOffscreenFormat = gfxImageFormat::RGB16_565;
107 }
109 #ifdef MOZ_WIDGET_GONK
110 char propQemu[PROPERTY_VALUE_MAX];
111 property_get("ro.kernel.qemu", propQemu, "");
112 mIsInGonkEmulator = !strncmp(propQemu, "1", 1);
113 #endif
114 }
116 gfxAndroidPlatform::~gfxAndroidPlatform()
117 {
118 FT_Done_Library(gPlatformFTLibrary);
119 gPlatformFTLibrary = nullptr;
120 }
122 already_AddRefed<gfxASurface>
123 gfxAndroidPlatform::CreateOffscreenSurface(const IntSize& size,
124 gfxContentType contentType)
125 {
126 nsRefPtr<gfxASurface> newSurface;
127 newSurface = new gfxImageSurface(ThebesIntSize(size),
128 OptimalFormatForContent(contentType));
130 return newSurface.forget();
131 }
133 static bool
134 IsJapaneseLocale()
135 {
136 static bool sInitialized = false;
137 static bool sIsJapanese = false;
139 if (!sInitialized) {
140 sInitialized = true;
142 do { // to allow 'break' to abandon this block if a call fails
143 nsresult rv;
144 nsCOMPtr<nsILocaleService> ls =
145 do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv);
146 if (NS_FAILED(rv)) {
147 break;
148 }
149 nsCOMPtr<nsILocale> appLocale;
150 rv = ls->GetApplicationLocale(getter_AddRefs(appLocale));
151 if (NS_FAILED(rv)) {
152 break;
153 }
154 nsString localeStr;
155 rv = appLocale->
156 GetCategory(NS_LITERAL_STRING(NSILOCALE_MESSAGE), localeStr);
157 if (NS_FAILED(rv)) {
158 break;
159 }
160 const nsAString& lang = nsDependentSubstring(localeStr, 0, 2);
161 if (lang.EqualsLiteral("ja")) {
162 sIsJapanese = true;
163 }
164 } while (false);
165 }
167 return sIsJapanese;
168 }
170 void
171 gfxAndroidPlatform::GetCommonFallbackFonts(const uint32_t aCh,
172 int32_t aRunScript,
173 nsTArray<const char*>& aFontList)
174 {
175 static const char kDroidSansJapanese[] = "Droid Sans Japanese";
176 static const char kMotoyaLMaru[] = "MotoyaLMaru";
178 if (IS_IN_BMP(aCh)) {
179 // try language-specific "Droid Sans *" fonts for certain blocks,
180 // as most devices probably have these
181 uint8_t block = (aCh >> 8) & 0xff;
182 switch (block) {
183 case 0x05:
184 aFontList.AppendElement("Droid Sans Hebrew");
185 aFontList.AppendElement("Droid Sans Armenian");
186 break;
187 case 0x06:
188 aFontList.AppendElement("Droid Sans Arabic");
189 break;
190 case 0x09:
191 aFontList.AppendElement("Droid Sans Devanagari");
192 break;
193 case 0x0b:
194 aFontList.AppendElement("Droid Sans Tamil");
195 break;
196 case 0x0e:
197 aFontList.AppendElement("Droid Sans Thai");
198 break;
199 case 0x10: case 0x2d:
200 aFontList.AppendElement("Droid Sans Georgian");
201 break;
202 case 0x12: case 0x13:
203 aFontList.AppendElement("Droid Sans Ethiopic");
204 break;
205 case 0xf9: case 0xfa:
206 if (IsJapaneseLocale()) {
207 aFontList.AppendElement(kMotoyaLMaru);
208 aFontList.AppendElement(kDroidSansJapanese);
209 }
210 break;
211 default:
212 if (block >= 0x2e && block <= 0x9f && IsJapaneseLocale()) {
213 aFontList.AppendElement(kMotoyaLMaru);
214 aFontList.AppendElement(kDroidSansJapanese);
215 }
216 break;
217 }
218 }
219 // and try Droid Sans Fallback as a last resort
220 aFontList.AppendElement("Droid Sans Fallback");
221 }
223 nsresult
224 gfxAndroidPlatform::GetFontList(nsIAtom *aLangGroup,
225 const nsACString& aGenericFamily,
226 nsTArray<nsString>& aListOfFonts)
227 {
228 gfxPlatformFontList::PlatformFontList()->GetFontList(aLangGroup,
229 aGenericFamily,
230 aListOfFonts);
231 return NS_OK;
232 }
234 void
235 gfxAndroidPlatform::GetFontList(InfallibleTArray<FontListEntry>* retValue)
236 {
237 gfxFT2FontList::PlatformFontList()->GetFontList(retValue);
238 }
240 nsresult
241 gfxAndroidPlatform::UpdateFontList()
242 {
243 gfxPlatformFontList::PlatformFontList()->UpdateFontList();
244 return NS_OK;
245 }
247 nsresult
248 gfxAndroidPlatform::ResolveFontName(const nsAString& aFontName,
249 FontResolverCallback aCallback,
250 void *aClosure,
251 bool& aAborted)
252 {
253 nsAutoString resolvedName;
254 if (!gfxPlatformFontList::PlatformFontList()->
255 ResolveFontName(aFontName, resolvedName)) {
256 aAborted = false;
257 return NS_OK;
258 }
259 aAborted = !(*aCallback)(resolvedName, aClosure);
260 return NS_OK;
261 }
263 nsresult
264 gfxAndroidPlatform::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
265 {
266 gfxPlatformFontList::PlatformFontList()->GetStandardFamilyName(aFontName, aFamilyName);
267 return NS_OK;
268 }
270 gfxPlatformFontList*
271 gfxAndroidPlatform::CreatePlatformFontList()
272 {
273 gfxPlatformFontList* list = new gfxFT2FontList();
274 if (NS_SUCCEEDED(list->InitFontList())) {
275 return list;
276 }
277 gfxPlatformFontList::Shutdown();
278 return nullptr;
279 }
281 bool
282 gfxAndroidPlatform::IsFontFormatSupported(nsIURI *aFontURI, uint32_t aFormatFlags)
283 {
284 // check for strange format flags
285 NS_ASSERTION(!(aFormatFlags & gfxUserFontSet::FLAG_FORMAT_NOT_USED),
286 "strange font format hint set");
288 // accept supported formats
289 if (aFormatFlags & (gfxUserFontSet::FLAG_FORMAT_OPENTYPE |
290 gfxUserFontSet::FLAG_FORMAT_WOFF |
291 gfxUserFontSet::FLAG_FORMAT_TRUETYPE)) {
292 return true;
293 }
295 // reject all other formats, known and unknown
296 if (aFormatFlags != 0) {
297 return false;
298 }
300 // no format hint set, need to look at data
301 return true;
302 }
304 gfxFontGroup *
305 gfxAndroidPlatform::CreateFontGroup(const nsAString &aFamilies,
306 const gfxFontStyle *aStyle,
307 gfxUserFontSet* aUserFontSet)
308 {
309 return new gfxFontGroup(aFamilies, aStyle, aUserFontSet);
310 }
312 FT_Library
313 gfxAndroidPlatform::GetFTLibrary()
314 {
315 return gPlatformFTLibrary;
316 }
318 gfxFontEntry*
319 gfxAndroidPlatform::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
320 const uint8_t *aFontData, uint32_t aLength)
321 {
322 return gfxPlatformFontList::PlatformFontList()->MakePlatformFont(aProxyEntry,
323 aFontData,
324 aLength);
325 }
327 gfxFontEntry*
328 gfxAndroidPlatform::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
329 const nsAString& aFontName)
330 {
331 return gfxPlatformFontList::PlatformFontList()->LookupLocalFont(aProxyEntry,
332 aFontName);
333 }
335 TemporaryRef<ScaledFont>
336 gfxAndroidPlatform::GetScaledFontForFont(DrawTarget* aTarget, gfxFont *aFont)
337 {
338 return GetScaledFontForFontWithCairoSkia(aTarget, aFont);
339 }
341 bool
342 gfxAndroidPlatform::FontHintingEnabled()
343 {
344 // In "mobile" builds, we sometimes use non-reflow-zoom, so we
345 // might not want hinting. Let's see.
347 #ifdef MOZ_USING_ANDROID_JAVA_WIDGETS
348 // On android-java, we currently only use gecko to render web
349 // content that can always be be non-reflow-zoomed. So turn off
350 // hinting.
351 //
352 // XXX when gecko-android-java is used as an "app runtime", we may
353 // want to re-enable hinting for non-browser processes there.
354 return false;
355 #endif // MOZ_USING_ANDROID_JAVA_WIDGETS
357 #ifdef MOZ_WIDGET_GONK
358 // On B2G, the UX preference is currently to keep hinting disabled
359 // for all text (see bug 829523).
360 return false;
361 #endif
363 // Currently, we don't have any other targets, but if/when we do,
364 // decide how to handle them here.
366 NS_NOTREACHED("oops, what platform is this?");
367 return gfxPlatform::FontHintingEnabled();
368 }
370 bool
371 gfxAndroidPlatform::RequiresLinearZoom()
372 {
373 #ifdef MOZ_USING_ANDROID_JAVA_WIDGETS
374 // On android-java, we currently only use gecko to render web
375 // content that can always be be non-reflow-zoomed.
376 //
377 // XXX when gecko-android-java is used as an "app runtime", we may
378 // want to treat it like B2G and use linear zoom only for the web
379 // browser process, not other apps.
380 return true;
381 #endif
383 #ifdef MOZ_WIDGET_GONK
384 // On B2G, we need linear zoom for the browser, but otherwise prefer
385 // the improved glyph spacing that results from respecting the device
386 // pixel resolution for glyph layout (see bug 816614).
387 return XRE_GetProcessType() == GeckoProcessType_Content &&
388 ContentChild::GetSingleton()->IsForBrowser();
389 #endif
391 NS_NOTREACHED("oops, what platform is this?");
392 return gfxPlatform::RequiresLinearZoom();
393 }
395 int
396 gfxAndroidPlatform::GetScreenDepth() const
397 {
398 return mScreenDepth;
399 }
401 bool
402 gfxAndroidPlatform::UseAcceleratedSkiaCanvas()
403 {
404 #ifdef MOZ_WIDGET_ANDROID
405 if (AndroidBridge::Bridge()->GetAPIVersion() < 11) {
406 // It's slower than software due to not having a compositing fast path
407 return false;
408 }
409 #endif
411 return gfxPlatform::UseAcceleratedSkiaCanvas();
412 }