Backed out changeset b88172246b66 due to Win32 debug failures.
[mozilla-central.git] / gfx / thebes / gfxQtPlatform.cpp
blobdc074dccf395dec38b3714f174d7ac724a0fcf25
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is Mozilla Foundation code.
17 * The Initial Developer of the Original Code is Mozilla Foundation.
18 * Portions created by the Initial Developer are Copyright (C) 2005
19 * the Initial Developer. All Rights Reserved.
21 * Contributor(s):
22 * Vladimir Vukicevic <vladimir@pobox.com>
23 * Masayuki Nakano <masayuki@d-toybox.com>
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
39 #include <QPixmap>
40 #include <QX11Info>
41 #include <QApplication>
42 #include <QDesktopWidget>
43 #include <QPaintEngine>
45 #include "gfxQtPlatform.h"
47 #include "gfxFontconfigUtils.h"
49 #include "cairo.h"
51 #include "gfxImageSurface.h"
52 #include "gfxQPainterSurface.h"
54 #ifdef MOZ_PANGO
55 #include "gfxPangoFonts.h"
56 #include "gfxContext.h"
57 #include "gfxUserFontSet.h"
58 #else
59 #include "gfxFT2Fonts.h"
60 #endif
62 #include "nsUnicharUtils.h"
64 #include <fontconfig/fontconfig.h>
66 #include "nsMathUtils.h"
67 #include "nsTArray.h"
68 #ifdef MOZ_X11
69 #include "gfxXlibSurface.h"
70 #endif
72 #include "qcms.h"
74 #ifndef MOZ_PANGO
75 #include <ft2build.h>
76 #include FT_FREETYPE_H
77 #endif
79 #include "nsIPrefBranch.h"
80 #include "nsIPrefService.h"
82 #define DEFAULT_RENDER_MODE RENDER_DIRECT
84 static QPaintEngine::Type sDefaultQtPaintEngineType = QPaintEngine::X11;
85 gfxFontconfigUtils *gfxQtPlatform::sFontconfigUtils = nsnull;
86 static cairo_user_data_key_t cairo_qt_pixmap_key;
87 static void do_qt_pixmap_unref (void *data)
89 QPixmap *pmap = (QPixmap*)data;
90 delete pmap;
93 #ifndef MOZ_PANGO
94 typedef nsDataHashtable<nsStringHashKey, nsRefPtr<FontFamily> > FontTable;
95 typedef nsDataHashtable<nsCStringHashKey, nsTArray<nsRefPtr<FontEntry> > > PrefFontTable;
96 static FontTable *gPlatformFonts = NULL;
97 static FontTable *gPlatformFontAliases = NULL;
98 static PrefFontTable *gPrefFonts = NULL;
99 static gfxSparseBitSet *gCodepointsWithNoFonts = NULL;
100 static FT_Library gPlatformFTLibrary = NULL;
101 #endif
103 gfxQtPlatform::gfxQtPlatform()
105 mPrefFonts.Init(50);
107 if (!sFontconfigUtils)
108 sFontconfigUtils = gfxFontconfigUtils::GetFontconfigUtils();
110 #ifdef MOZ_PANGO
111 g_type_init();
112 #else
113 FT_Init_FreeType(&gPlatformFTLibrary);
115 gPlatformFonts = new FontTable();
116 gPlatformFonts->Init(100);
117 gPlatformFontAliases = new FontTable();
118 gPlatformFontAliases->Init(100);
119 gPrefFonts = new PrefFontTable();
120 gPrefFonts->Init(100);
121 gCodepointsWithNoFonts = new gfxSparseBitSet();
122 UpdateFontList();
123 #endif
125 nsresult rv;
126 PRInt32 ival;
127 // 0 - default gfxQPainterSurface
128 // 1 - gfxImageSurface
129 nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
130 if (prefs) {
131 rv = prefs->GetIntPref("mozilla.widget-qt.render-mode", &ival);
132 if (NS_FAILED(rv))
133 ival = DEFAULT_RENDER_MODE;
136 const char *envTypeOverride = getenv("MOZ_QT_RENDER_TYPE");
137 if (envTypeOverride)
138 ival = atoi(envTypeOverride);
140 switch (ival) {
141 case 0:
142 mRenderMode = RENDER_QPAINTER;
143 break;
144 case 1:
145 mRenderMode = RENDER_BUFFERED;
146 break;
147 case 2:
148 mRenderMode = RENDER_DIRECT;
149 break;
150 default:
151 mRenderMode = RENDER_QPAINTER;
154 // Qt doesn't provide a public API to detect the graphicssystem type. We hack
155 // around this by checking what type of graphicssystem a test QPixmap uses.
156 QPixmap pixmap(1, 1);
157 sDefaultQtPaintEngineType = pixmap.paintEngine()->type();
160 gfxQtPlatform::~gfxQtPlatform()
162 gfxFontconfigUtils::Shutdown();
163 sFontconfigUtils = nsnull;
165 #ifdef MOZ_PANGO
166 gfxPangoFontGroup::Shutdown();
167 #else
168 delete gPlatformFonts;
169 gPlatformFonts = NULL;
170 delete gPlatformFontAliases;
171 gPlatformFontAliases = NULL;
172 delete gPrefFonts;
173 gPrefFonts = NULL;
174 delete gCodepointsWithNoFonts;
175 gCodepointsWithNoFonts = NULL;
177 cairo_debug_reset_static_data();
179 FT_Done_FreeType(gPlatformFTLibrary);
180 gPlatformFTLibrary = NULL;
181 #endif
183 #if 0
184 // It would be nice to do this (although it might need to be after
185 // the cairo shutdown that happens in ~gfxPlatform). It even looks
186 // idempotent. But it has fatal assertions that fire if stuff is
187 // leaked, and we hit them.
188 FcFini();
189 #endif
192 already_AddRefed<gfxASurface>
193 gfxQtPlatform::CreateOffscreenSurface(const gfxIntSize& size,
194 gfxASurface::gfxContentType contentType)
196 nsRefPtr<gfxASurface> newSurface = nsnull;
198 // try to optimize it for 16bpp screen
199 gfxASurface::gfxImageFormat imageFormat = gfxASurface::FormatFromContent(contentType);
200 if (gfxASurface::CONTENT_COLOR == contentType) {
201 imageFormat = GetOffscreenFormat();
204 #ifdef CAIRO_HAS_QT_SURFACE
205 if (mRenderMode == RENDER_QPAINTER) {
206 newSurface = new gfxQPainterSurface(size, imageFormat);
207 return newSurface.forget();
209 #endif
211 if ((mRenderMode == RENDER_BUFFERED || mRenderMode == RENDER_DIRECT) &&
212 sDefaultQtPaintEngineType != QPaintEngine::X11) {
213 newSurface = new gfxImageSurface(size, imageFormat);
214 return newSurface.forget();
217 #ifdef MOZ_X11
218 XRenderPictFormat* xrenderFormat =
219 gfxXlibSurface::FindRenderFormat(QX11Info().display(), imageFormat);
221 Screen* screen = ScreenOfDisplay(QX11Info().display(), QX11Info().screen());
222 newSurface = gfxXlibSurface::Create(screen, xrenderFormat, size);
223 #endif
225 if (newSurface) {
226 gfxContext ctx(newSurface);
227 ctx.SetOperator(gfxContext::OPERATOR_CLEAR);
228 ctx.Paint();
231 return newSurface.forget();
234 nsresult
235 gfxQtPlatform::GetFontList(nsIAtom *aLangGroup,
236 const nsACString& aGenericFamily,
237 nsTArray<nsString>& aListOfFonts)
239 return sFontconfigUtils->GetFontList(aLangGroup, aGenericFamily,
240 aListOfFonts);
243 nsresult
244 gfxQtPlatform::UpdateFontList()
246 #ifndef MOZ_PANGO
247 FcPattern *pat = NULL;
248 FcObjectSet *os = NULL;
249 FcFontSet *fs = NULL;
251 pat = FcPatternCreate();
252 os = FcObjectSetBuild(FC_FAMILY, FC_FILE, FC_INDEX, FC_WEIGHT, FC_SLANT, FC_WIDTH, NULL);
254 fs = FcFontList(NULL, pat, os);
257 for (int i = 0; i < fs->nfont; i++) {
258 char *str;
260 if (FcPatternGetString(fs->fonts[i], FC_FAMILY, 0, (FcChar8 **) &str) != FcResultMatch)
261 continue;
263 nsAutoString name(NS_ConvertUTF8toUTF16(nsDependentCString(str)).get());
264 nsAutoString key(name);
265 ToLowerCase(key);
266 nsRefPtr<FontFamily> ff;
267 if (!gPlatformFonts->Get(key, &ff)) {
268 ff = new FontFamily(name);
269 gPlatformFonts->Put(key, ff);
272 FontEntry *fe = new FontEntry(ff->Name());
273 ff->AddFontEntry(fe);
275 if (FcPatternGetString(fs->fonts[i], FC_FILE, 0, (FcChar8 **) &str) == FcResultMatch) {
276 fe->mFilename = nsDependentCString(str);
279 int x;
280 if (FcPatternGetInteger(fs->fonts[i], FC_INDEX, 0, &x) == FcResultMatch) {
281 fe->mFTFontIndex = x;
282 } else {
283 fe->mFTFontIndex = 0;
286 if (FcPatternGetInteger(fs->fonts[i], FC_WEIGHT, 0, &x) == FcResultMatch) {
287 switch(x) {
288 case 0:
289 fe->mWeight = 100;
290 break;
291 case 40:
292 fe->mWeight = 200;
293 break;
294 case 50:
295 fe->mWeight = 300;
296 break;
297 case 75:
298 case 80:
299 fe->mWeight = 400;
300 break;
301 case 100:
302 fe->mWeight = 500;
303 break;
304 case 180:
305 fe->mWeight = 600;
306 break;
307 case 200:
308 fe->mWeight = 700;
309 break;
310 case 205:
311 fe->mWeight = 800;
312 break;
313 case 210:
314 fe->mWeight = 900;
315 break;
316 default:
317 // rough estimate
318 fe->mWeight = (((x * 4) + 100) / 100) * 100;
319 break;
323 fe->mItalic = PR_FALSE;
324 if (FcPatternGetInteger(fs->fonts[i], FC_SLANT, 0, &x) == FcResultMatch) {
325 switch (x) {
326 case FC_SLANT_ITALIC:
327 case FC_SLANT_OBLIQUE:
328 fe->mItalic = PR_TRUE;
332 // XXX deal with font-stretch (FC_WIDTH) stuff later
335 if (pat)
336 FcPatternDestroy(pat);
337 if (os)
338 FcObjectSetDestroy(os);
339 if (fs)
340 FcFontSetDestroy(fs);
341 #endif
343 return sFontconfigUtils->UpdateFontList();
346 nsresult
347 gfxQtPlatform::ResolveFontName(const nsAString& aFontName,
348 FontResolverCallback aCallback,
349 void *aClosure,
350 PRBool& aAborted)
352 #ifdef MOZ_PANGO
353 return sFontconfigUtils->ResolveFontName(aFontName, aCallback,
354 aClosure, aAborted);
355 #else
356 nsAutoString name(aFontName);
357 ToLowerCase(name);
359 nsRefPtr<FontFamily> ff;
360 if (gPlatformFonts->Get(name, &ff) ||
361 gPlatformFontAliases->Get(name, &ff)) {
362 aAborted = !(*aCallback)(ff->Name(), aClosure);
363 return NS_OK;
366 nsCAutoString utf8Name = NS_ConvertUTF16toUTF8(aFontName);
368 FcPattern *npat = FcPatternCreate();
369 FcPatternAddString(npat, FC_FAMILY, (FcChar8*)utf8Name.get());
370 FcObjectSet *nos = FcObjectSetBuild(FC_FAMILY, NULL);
371 FcFontSet *nfs = FcFontList(NULL, npat, nos);
373 for (int k = 0; k < nfs->nfont; k++) {
374 FcChar8 *str;
375 if (FcPatternGetString(nfs->fonts[k], FC_FAMILY, 0, (FcChar8 **) &str) != FcResultMatch)
376 continue;
377 nsAutoString altName = NS_ConvertUTF8toUTF16(nsDependentCString(reinterpret_cast<char*>(str)));
378 ToLowerCase(altName);
379 if (gPlatformFonts->Get(altName, &ff)) {
380 gPlatformFontAliases->Put(name, ff);
381 aAborted = !(*aCallback)(NS_ConvertUTF8toUTF16(nsDependentCString(reinterpret_cast<char*>(str))), aClosure);
382 goto DONE;
386 FcPatternDestroy(npat);
387 FcObjectSetDestroy(nos);
388 FcFontSetDestroy(nfs);
391 npat = FcPatternCreate();
392 FcPatternAddString(npat, FC_FAMILY, (FcChar8*)utf8Name.get());
393 FcPatternDel(npat, FC_LANG);
394 FcConfigSubstitute(NULL, npat, FcMatchPattern);
395 FcDefaultSubstitute(npat);
397 nos = FcObjectSetBuild(FC_FAMILY, NULL);
398 nfs = FcFontList(NULL, npat, nos);
400 FcResult fresult;
402 FcPattern *match = FcFontMatch(NULL, npat, &fresult);
403 if (match)
404 FcFontSetAdd(nfs, match);
406 for (int k = 0; k < nfs->nfont; k++) {
407 FcChar8 *str;
408 if (FcPatternGetString(nfs->fonts[k], FC_FAMILY, 0, (FcChar8 **) &str) != FcResultMatch)
409 continue;
410 nsAutoString altName = NS_ConvertUTF8toUTF16(nsDependentCString(reinterpret_cast<char*>(str)));
411 ToLowerCase(altName);
412 if (gPlatformFonts->Get(altName, &ff)) {
413 gPlatformFontAliases->Put(name, ff);
414 aAborted = !(*aCallback)(NS_ConvertUTF8toUTF16(nsDependentCString(reinterpret_cast<char*>(str))), aClosure);
415 goto DONE;
419 DONE:
420 FcPatternDestroy(npat);
421 FcObjectSetDestroy(nos);
422 FcFontSetDestroy(nfs);
424 return NS_OK;
425 #endif
428 nsresult
429 gfxQtPlatform::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
431 return sFontconfigUtils->GetStandardFamilyName(aFontName, aFamilyName);
434 gfxFontGroup *
435 gfxQtPlatform::CreateFontGroup(const nsAString &aFamilies,
436 const gfxFontStyle *aStyle,
437 gfxUserFontSet* aUserFontSet)
439 #ifdef MOZ_PANGO
440 return new gfxPangoFontGroup(aFamilies, aStyle, aUserFontSet);
441 #else
442 return new gfxFT2FontGroup(aFamilies, aStyle);
443 #endif
446 #ifdef MOZ_PANGO
447 gfxFontEntry*
448 gfxQtPlatform::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
449 const nsAString& aFontName)
451 return gfxPangoFontGroup::NewFontEntry(*aProxyEntry, aFontName);
454 gfxFontEntry*
455 gfxQtPlatform::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
456 const PRUint8 *aFontData, PRUint32 aLength)
458 // passing ownership of the font data to the new font entry
459 return gfxPangoFontGroup::NewFontEntry(*aProxyEntry,
460 aFontData, aLength);
463 PRBool
464 gfxQtPlatform::IsFontFormatSupported(nsIURI *aFontURI, PRUint32 aFormatFlags)
466 // check for strange format flags
467 NS_ASSERTION(!(aFormatFlags & gfxUserFontSet::FLAG_FORMAT_NOT_USED),
468 "strange font format hint set");
470 // accept supported formats
471 // Pango doesn't apply features from AAT TrueType extensions.
472 // Assume that if this is the only SFNT format specified,
473 // then AAT extensions are required for complex script support.
474 if (aFormatFlags & (gfxUserFontSet::FLAG_FORMAT_WOFF |
475 gfxUserFontSet::FLAG_FORMAT_OPENTYPE |
476 gfxUserFontSet::FLAG_FORMAT_TRUETYPE)) {
477 return PR_TRUE;
480 // reject all other formats, known and unknown
481 if (aFormatFlags != 0) {
482 return PR_FALSE;
485 // no format hint set, need to look at data
486 return PR_TRUE;
488 #endif
490 qcms_profile*
491 gfxQtPlatform::GetPlatformCMSOutputProfile()
493 return nsnull;
496 #ifndef MOZ_PANGO
497 FT_Library
498 gfxQtPlatform::GetFTLibrary()
500 return gPlatformFTLibrary;
503 FontFamily *
504 gfxQtPlatform::FindFontFamily(const nsAString& aName)
506 nsAutoString name(aName);
507 ToLowerCase(name);
509 nsRefPtr<FontFamily> ff;
510 if (!gPlatformFonts->Get(name, &ff)) {
511 return nsnull;
513 return ff.get();
516 FontEntry *
517 gfxQtPlatform::FindFontEntry(const nsAString& aName, const gfxFontStyle& aFontStyle)
519 nsRefPtr<FontFamily> ff = FindFontFamily(aName);
520 if (!ff)
521 return nsnull;
523 return ff->FindFontEntry(aFontStyle);
526 static PLDHashOperator
527 FindFontForCharProc(nsStringHashKey::KeyType aKey,
528 nsRefPtr<FontFamily>& aFontFamily,
529 void* aUserArg)
531 FontSearch *data = (FontSearch*)aUserArg;
532 aFontFamily->FindFontForChar(data);
533 return PL_DHASH_NEXT;
536 already_AddRefed<gfxFont>
537 gfxQtPlatform::FindFontForChar(PRUint32 aCh, gfxFont *aFont)
539 if (!gPlatformFonts || !gCodepointsWithNoFonts)
540 return nsnull;
542 // is codepoint with no matching font? return null immediately
543 if (gCodepointsWithNoFonts->test(aCh)) {
544 return nsnull;
547 FontSearch data(aCh, aFont);
549 // find fonts that support the character
550 gPlatformFonts->Enumerate(FindFontForCharProc, &data);
552 if (data.mBestMatch) {
553 nsRefPtr<gfxFT2Font> font =
554 gfxFT2Font::GetOrMakeFont(static_cast<FontEntry*>(data.mBestMatch.get()),
555 aFont->GetStyle());
556 gfxFont* ret = font.forget().get();
557 return already_AddRefed<gfxFont>(ret);
560 // no match? add to set of non-matching codepoints
561 gCodepointsWithNoFonts->set(aCh);
563 return nsnull;
566 PRBool
567 gfxQtPlatform::GetPrefFontEntries(const nsCString& aKey, nsTArray<nsRefPtr<gfxFontEntry> > *array)
569 return mPrefFonts.Get(aKey, array);
572 void
573 gfxQtPlatform::SetPrefFontEntries(const nsCString& aKey, nsTArray<nsRefPtr<gfxFontEntry> >& array)
575 mPrefFonts.Put(aKey, array);
578 #endif
580 PRInt32
581 gfxQtPlatform::GetDPI()
583 QDesktopWidget* rootWindow = qApp->desktop();
584 PRInt32 dpi = rootWindow->logicalDpiY(); // y-axis DPI for fonts
585 return dpi <= 0 ? 96 : dpi;
588 gfxImageFormat
589 gfxQtPlatform::GetOffscreenFormat()
591 if (QX11Info::appDepth() == 16) {
592 return gfxASurface::ImageFormatRGB16_565;
595 return gfxASurface::ImageFormatRGB24;