1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // Description: Implements the Graphite interfaces with access to the
32 // platform's font and graphics systems.
34 // MARKER(update_precomp.py): autogen include statement, do not remove
35 #include "precompiled_vcl.hxx"
37 // We need this to enable namespace support in libgrengine headers.
46 #include <rtl/string.hxx>
47 #include <rtl/ustring.hxx>
48 #include <i18npool/mslangid.hxx>
51 #include <saldisp.hxx>
53 #include <vcl/salgdi.hxx>
55 #include <freetype/ftsynth.h>
58 #include "gcach_ftyp.hxx"
60 #include <vcl/graphite_features.hxx>
61 #include <vcl/graphite_adaptors.hxx>
63 // Module private type definitions and forward declarations.
68 inline float from_hinted(const int x
) {
69 return static_cast<float>(x
+ 32) / 64.0;
71 typedef std::hash_map
<long,bool> SilfMap
;
75 // class CharacterRenderProperties implentation.
77 FontProperties::FontProperties(const FreetypeServerFont
&font
) throw()
79 clrFore
= gr::kclrBlack
;
80 clrBack
= gr::kclrTransparent
;
82 pixHeight
= from_hinted(font
.GetMetricsFT().height
);
84 switch (font
.GetFontSelData().meWeight
)
86 case WEIGHT_SEMIBOLD
: case WEIGHT_BOLD
:
87 case WEIGHT_ULTRABOLD
: case WEIGHT_BLACK
:
94 switch (font
.GetFontSelData().meItalic
)
96 case ITALIC_NORMAL
: case ITALIC_OBLIQUE
:
103 // Get the font name.
104 const sal_Unicode
* name
= font
.GetFontSelData().maName
.GetBuffer();
105 const size_t name_sz
= std::min(sizeof szFaceName
/sizeof(wchar_t)-1,
106 size_t(font
.GetFontSelData().maName
.Len()));
108 std::copy(name
, name
+ name_sz
, szFaceName
);
109 szFaceName
[name_sz
] = '\0';
112 // class GraphiteFontAdaptor implementaion.
114 GraphiteFontAdaptor::GraphiteFontAdaptor(ServerFont
& sfont
, const sal_Int32 dpiX
, const sal_Int32 dpiY
)
115 : mrFont(static_cast<FreetypeServerFont
&>(sfont
)),
116 maFontProperties(static_cast<FreetypeServerFont
&>(sfont
)),
119 mfAscent(from_hinted(static_cast<FreetypeServerFont
&>(sfont
).GetMetricsFT().ascender
)),
120 mfDescent(from_hinted(static_cast<FreetypeServerFont
&>(sfont
).GetMetricsFT().descender
)),
121 mfEmUnits(static_cast<FreetypeServerFont
&>(sfont
).GetMetricsFT().y_ppem
),
124 //std::wstring face_name(maFontProperties.szFaceName);
125 const rtl::OString aLang
= MsLangId::convertLanguageToIsoByteString( sfont
.GetFontSelData().meLanguage
);
127 printf("GraphiteFontAdaptor %lx\n", (long)this);
129 rtl::OString name
= rtl::OUStringToOString(
130 sfont
.GetFontSelData().maTargetName
, RTL_TEXTENCODING_UTF8
);
131 sal_Int32 nFeat
= name
.indexOf(grutils::GrFeatureParser::FEAT_PREFIX
) + 1;
134 rtl::OString aFeat
= name
.copy(nFeat
, name
.getLength() - nFeat
);
135 mpFeatures
= new grutils::GrFeatureParser(*this, aFeat
.getStr(), aLang
.getStr());
137 printf("GraphiteFontAdaptor %s/%s/%s %x language %d features %d errors\n",
138 rtl::OUStringToOString( sfont
.GetFontSelData().maName
,
139 RTL_TEXTENCODING_UTF8
).getStr(),
140 rtl::OUStringToOString( sfont
.GetFontSelData().maTargetName
,
141 RTL_TEXTENCODING_UTF8
).getStr(),
142 rtl::OUStringToOString( sfont
.GetFontSelData().maSearchName
,
143 RTL_TEXTENCODING_UTF8
).getStr(),
144 sfont
.GetFontSelData().meLanguage
,
145 (int)mpFeatures
->getFontFeatures(NULL
), mpFeatures
->parseErrors());
150 mpFeatures
= new grutils::GrFeatureParser(*this, aLang
.getStr());
154 GraphiteFontAdaptor::GraphiteFontAdaptor(const GraphiteFontAdaptor
&rhs
) throw()
156 mrFont (rhs
.mrFont
), maFontProperties(rhs
.maFontProperties
),
157 mnDpiX(rhs
.mnDpiX
), mnDpiY(rhs
.mnDpiY
),
158 mfAscent(rhs
.mfAscent
), mfDescent(rhs
.mfDescent
), mfEmUnits(rhs
.mfEmUnits
),
161 if (rhs
.mpFeatures
) mpFeatures
= new grutils::GrFeatureParser(*(rhs
.mpFeatures
));
165 GraphiteFontAdaptor::~GraphiteFontAdaptor() throw()
167 maGlyphMetricMap
.clear();
168 if (mpFeatures
) delete mpFeatures
;
172 void GraphiteFontAdaptor::UniqueCacheInfo(std::wstring
& face_name_out
, bool & bold_out
, bool & italic_out
)
174 face_name_out
= maFontProperties
.szFaceName
;
175 bold_out
= maFontProperties
.fBold
;
176 italic_out
= maFontProperties
.fItalic
;
179 bool GraphiteFontAdaptor::IsGraphiteEnabledFont(ServerFont
& font
) throw()
181 // NOTE: this assumes that the same FTFace pointer won't be reused,
182 // so FtFontInfo::ReleaseFaceFT must only be called at shutdown.
183 FreetypeServerFont
& aFtFont
= dynamic_cast<FreetypeServerFont
&>(font
);
184 FT_Face aFace
= reinterpret_cast<FT_FaceRec_
*>(aFtFont
.GetFtFace());
185 SilfMap::iterator i
= sSilfMap
.find(reinterpret_cast<long>(aFace
));
186 if (i
!= sSilfMap
.end())
189 if (static_cast<bool>(aFtFont
.GetTable("Silf", 0)) != (*i
).second
)
190 printf("Silf cache font mismatch\n");
194 bool bHasSilf
= aFtFont
.GetTable("Silf", 0);
195 sSilfMap
[reinterpret_cast<long>(aFace
)] = bHasSilf
;
200 gr::Font
* GraphiteFontAdaptor::copyThis() {
201 return new GraphiteFontAdaptor(*this);
205 unsigned int GraphiteFontAdaptor::getDPIx() {
210 unsigned int GraphiteFontAdaptor::getDPIy() {
215 float GraphiteFontAdaptor::ascent() {
220 float GraphiteFontAdaptor::descent() {
225 bool GraphiteFontAdaptor::bold() {
226 return maFontProperties
.fBold
;
230 bool GraphiteFontAdaptor::italic() {
231 return maFontProperties
.fItalic
;
235 float GraphiteFontAdaptor::height() {
236 return maFontProperties
.pixHeight
;
240 void GraphiteFontAdaptor::getFontMetrics(float * ascent_out
, float * descent_out
, float * em_square_out
) {
241 if (ascent_out
) *ascent_out
= mfAscent
;
242 if (descent_out
) *descent_out
= mfDescent
;
243 if (em_square_out
) *em_square_out
= mfEmUnits
;
247 const void * GraphiteFontAdaptor::getTable(gr::fontTableId32 table_id
, size_t * buffer_sz
)
249 char tag_name
[5] = {char(table_id
>> 24), char(table_id
>> 16), char(table_id
>> 8), char(table_id
), 0};
250 ULONG temp
= *buffer_sz
;
252 const void * const tbl_buf
= static_cast<FreetypeServerFont
&>(mrFont
).GetTable(tag_name
, &temp
);
258 #define fix26_6(x) (x >> 6) + (x & 32 ? (x > 0 ? 1 : 0) : (x < 0 ? -1 : 0))
260 // Return the glyph's metrics in pixels.
261 void GraphiteFontAdaptor::getGlyphMetrics(gr::gid16 nGlyphId
, gr::Rect
& aBounding
, gr::Point
& advances
)
263 // Graphite gets really confused if the glyphs have been transformed, so
264 // if orientation has been set we can't use the font's glyph cache
265 // unfortunately the font selection data, doesn't always have the orientation
266 // set, even if it was when the glyphs were cached, so we use our own cache.
268 // const GlyphMetric & metric = mrFont.GetGlyphMetric(nGlyphId);
270 // aBounding.right = aBounding.left = metric.GetOffset().X();
271 // aBounding.bottom = aBounding.top = -metric.GetOffset().Y();
272 // aBounding.right += metric.GetSize().Width();
273 // aBounding.bottom -= metric.GetSize().Height();
275 // advances.x = metric.GetDelta().X();
276 // advances.y = -metric.GetDelta().Y();
278 GlyphMetricMap::const_iterator gm_itr
= maGlyphMetricMap
.find(nGlyphId
);
279 if (gm_itr
!= maGlyphMetricMap
.end())
281 // We've cached the results from last time.
282 aBounding
= gm_itr
->second
.first
;
283 advances
= gm_itr
->second
.second
;
287 // We need to look up the glyph.
288 FT_Int nLoadFlags
= mrFont
.GetLoadFlags();
290 FT_Face aFace
= reinterpret_cast<FT_Face
>(mrFont
.GetFtFace());
293 aBounding
.top
= aBounding
.bottom
= aBounding
.left
= aBounding
.right
= 0;
294 advances
.x
= advances
.y
= 0;
297 FT_Error aStatus
= -1;
298 aStatus
= FT_Load_Glyph(aFace
, nGlyphId
, nLoadFlags
);
299 if( aStatus
!= FT_Err_Ok
|| (!aFace
->glyph
))
301 aBounding
.top
= aBounding
.bottom
= aBounding
.left
= aBounding
.right
= 0;
302 advances
.x
= advances
.y
= 0;
305 // check whether we need synthetic bold/italic otherwise metric is wrong
306 if (mrFont
.NeedsArtificialBold())
307 FT_GlyphSlot_Embolden(aFace
->glyph
);
309 if (mrFont
.NeedsArtificialItalic())
310 FT_GlyphSlot_Oblique(aFace
->glyph
);
312 const FT_Glyph_Metrics
&gm
= aFace
->glyph
->metrics
;
314 // Fill out the bounding box an advances.
315 aBounding
.top
= aBounding
.bottom
= fix26_6(gm
.horiBearingY
);
316 aBounding
.bottom
-= fix26_6(gm
.height
);
317 aBounding
.left
= aBounding
.right
= fix26_6(gm
.horiBearingX
);
318 aBounding
.right
+= fix26_6(gm
.width
);
319 advances
.x
= fix26_6(gm
.horiAdvance
);
322 // Now add an entry to our metrics map.
323 maGlyphMetricMap
[nGlyphId
] = std::make_pair(aBounding
, advances
);