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
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.
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 ***** */
41 #include <QApplication>
42 #include <QDesktopWidget>
43 #include <QPaintEngine>
45 #include "gfxQtPlatform.h"
47 #include "gfxFontconfigUtils.h"
51 #include "gfxImageSurface.h"
52 #include "gfxQPainterSurface.h"
55 #include "gfxPangoFonts.h"
56 #include "gfxContext.h"
57 #include "gfxUserFontSet.h"
59 #include "gfxFT2Fonts.h"
62 #include "nsUnicharUtils.h"
64 #include <fontconfig/fontconfig.h>
66 #include "nsMathUtils.h"
69 #include "gfxXlibSurface.h"
76 #include FT_FREETYPE_H
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
;
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
;
103 gfxQtPlatform::gfxQtPlatform()
107 if (!sFontconfigUtils
)
108 sFontconfigUtils
= gfxFontconfigUtils::GetFontconfigUtils();
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();
127 // 0 - default gfxQPainterSurface
128 // 1 - gfxImageSurface
129 nsCOMPtr
<nsIPrefBranch
> prefs
= do_GetService(NS_PREFSERVICE_CONTRACTID
, &rv
);
131 rv
= prefs
->GetIntPref("mozilla.widget-qt.render-mode", &ival
);
133 ival
= DEFAULT_RENDER_MODE
;
136 const char *envTypeOverride
= getenv("MOZ_QT_RENDER_TYPE");
138 ival
= atoi(envTypeOverride
);
142 mRenderMode
= RENDER_QPAINTER
;
145 mRenderMode
= RENDER_BUFFERED
;
148 mRenderMode
= RENDER_DIRECT
;
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
;
166 gfxPangoFontGroup::Shutdown();
168 delete gPlatformFonts
;
169 gPlatformFonts
= NULL
;
170 delete gPlatformFontAliases
;
171 gPlatformFontAliases
= NULL
;
174 delete gCodepointsWithNoFonts
;
175 gCodepointsWithNoFonts
= NULL
;
177 cairo_debug_reset_static_data();
179 FT_Done_FreeType(gPlatformFTLibrary
);
180 gPlatformFTLibrary
= NULL
;
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.
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();
211 if ((mRenderMode
== RENDER_BUFFERED
|| mRenderMode
== RENDER_DIRECT
) &&
212 sDefaultQtPaintEngineType
!= QPaintEngine::X11
) {
213 newSurface
= new gfxImageSurface(size
, imageFormat
);
214 return newSurface
.forget();
218 XRenderPictFormat
* xrenderFormat
=
219 gfxXlibSurface::FindRenderFormat(QX11Info().display(), imageFormat
);
221 Screen
* screen
= ScreenOfDisplay(QX11Info().display(), QX11Info().screen());
222 newSurface
= gfxXlibSurface::Create(screen
, xrenderFormat
, size
);
226 gfxContext
ctx(newSurface
);
227 ctx
.SetOperator(gfxContext::OPERATOR_CLEAR
);
231 return newSurface
.forget();
235 gfxQtPlatform::GetFontList(nsIAtom
*aLangGroup
,
236 const nsACString
& aGenericFamily
,
237 nsTArray
<nsString
>& aListOfFonts
)
239 return sFontconfigUtils
->GetFontList(aLangGroup
, aGenericFamily
,
244 gfxQtPlatform::UpdateFontList()
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
++) {
260 if (FcPatternGetString(fs
->fonts
[i
], FC_FAMILY
, 0, (FcChar8
**) &str
) != FcResultMatch
)
263 nsAutoString
name(NS_ConvertUTF8toUTF16(nsDependentCString(str
)).get());
264 nsAutoString
key(name
);
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
);
280 if (FcPatternGetInteger(fs
->fonts
[i
], FC_INDEX
, 0, &x
) == FcResultMatch
) {
281 fe
->mFTFontIndex
= x
;
283 fe
->mFTFontIndex
= 0;
286 if (FcPatternGetInteger(fs
->fonts
[i
], FC_WEIGHT
, 0, &x
) == FcResultMatch
) {
318 fe
->mWeight
= (((x
* 4) + 100) / 100) * 100;
323 fe
->mItalic
= PR_FALSE
;
324 if (FcPatternGetInteger(fs
->fonts
[i
], FC_SLANT
, 0, &x
) == FcResultMatch
) {
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
336 FcPatternDestroy(pat
);
338 FcObjectSetDestroy(os
);
340 FcFontSetDestroy(fs
);
343 return sFontconfigUtils
->UpdateFontList();
347 gfxQtPlatform::ResolveFontName(const nsAString
& aFontName
,
348 FontResolverCallback aCallback
,
353 return sFontconfigUtils
->ResolveFontName(aFontName
, aCallback
,
356 nsAutoString
name(aFontName
);
359 nsRefPtr
<FontFamily
> ff
;
360 if (gPlatformFonts
->Get(name
, &ff
) ||
361 gPlatformFontAliases
->Get(name
, &ff
)) {
362 aAborted
= !(*aCallback
)(ff
->Name(), aClosure
);
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
++) {
375 if (FcPatternGetString(nfs
->fonts
[k
], FC_FAMILY
, 0, (FcChar8
**) &str
) != FcResultMatch
)
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
);
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
);
402 FcPattern
*match
= FcFontMatch(NULL
, npat
, &fresult
);
404 FcFontSetAdd(nfs
, match
);
406 for (int k
= 0; k
< nfs
->nfont
; k
++) {
408 if (FcPatternGetString(nfs
->fonts
[k
], FC_FAMILY
, 0, (FcChar8
**) &str
) != FcResultMatch
)
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
);
420 FcPatternDestroy(npat
);
421 FcObjectSetDestroy(nos
);
422 FcFontSetDestroy(nfs
);
429 gfxQtPlatform::GetStandardFamilyName(const nsAString
& aFontName
, nsAString
& aFamilyName
)
431 return sFontconfigUtils
->GetStandardFamilyName(aFontName
, aFamilyName
);
435 gfxQtPlatform::CreateFontGroup(const nsAString
&aFamilies
,
436 const gfxFontStyle
*aStyle
,
437 gfxUserFontSet
* aUserFontSet
)
440 return new gfxPangoFontGroup(aFamilies
, aStyle
, aUserFontSet
);
442 return new gfxFT2FontGroup(aFamilies
, aStyle
);
448 gfxQtPlatform::LookupLocalFont(const gfxProxyFontEntry
*aProxyEntry
,
449 const nsAString
& aFontName
)
451 return gfxPangoFontGroup::NewFontEntry(*aProxyEntry
, aFontName
);
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
,
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
)) {
480 // reject all other formats, known and unknown
481 if (aFormatFlags
!= 0) {
485 // no format hint set, need to look at data
491 gfxQtPlatform::GetPlatformCMSOutputProfile()
498 gfxQtPlatform::GetFTLibrary()
500 return gPlatformFTLibrary
;
504 gfxQtPlatform::FindFontFamily(const nsAString
& aName
)
506 nsAutoString
name(aName
);
509 nsRefPtr
<FontFamily
> ff
;
510 if (!gPlatformFonts
->Get(name
, &ff
)) {
517 gfxQtPlatform::FindFontEntry(const nsAString
& aName
, const gfxFontStyle
& aFontStyle
)
519 nsRefPtr
<FontFamily
> ff
= FindFontFamily(aName
);
523 return ff
->FindFontEntry(aFontStyle
);
526 static PLDHashOperator
527 FindFontForCharProc(nsStringHashKey::KeyType aKey
,
528 nsRefPtr
<FontFamily
>& aFontFamily
,
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
)
542 // is codepoint with no matching font? return null immediately
543 if (gCodepointsWithNoFonts
->test(aCh
)) {
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()),
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
);
567 gfxQtPlatform::GetPrefFontEntries(const nsCString
& aKey
, nsTArray
<nsRefPtr
<gfxFontEntry
> > *array
)
569 return mPrefFonts
.Get(aKey
, array
);
573 gfxQtPlatform::SetPrefFontEntries(const nsCString
& aKey
, nsTArray
<nsRefPtr
<gfxFontEntry
> >& array
)
575 mPrefFonts
.Put(aKey
, array
);
581 gfxQtPlatform::GetDPI()
583 QDesktopWidget
* rootWindow
= qApp
->desktop();
584 PRInt32 dpi
= rootWindow
->logicalDpiY(); // y-axis DPI for fonts
585 return dpi
<= 0 ? 96 : dpi
;
589 gfxQtPlatform::GetOffscreenFormat()
591 if (QX11Info::appDepth() == 16) {
592 return gfxASurface::ImageFormatRGB16_565
;
595 return gfxASurface::ImageFormatRGB24
;