1*9f62ea84SAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
3*9f62ea84SAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
4*9f62ea84SAndrew Rist  * or more contributor license agreements.  See the NOTICE file
5*9f62ea84SAndrew Rist  * distributed with this work for additional information
6*9f62ea84SAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
7*9f62ea84SAndrew Rist  * to you under the Apache License, Version 2.0 (the
8*9f62ea84SAndrew Rist  * "License"); you may not use this file except in compliance
9*9f62ea84SAndrew Rist  * with the License.  You may obtain a copy of the License at
10*9f62ea84SAndrew Rist  *
11*9f62ea84SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12*9f62ea84SAndrew Rist  *
13*9f62ea84SAndrew Rist  * Unless required by applicable law or agreed to in writing,
14*9f62ea84SAndrew Rist  * software distributed under the License is distributed on an
15*9f62ea84SAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*9f62ea84SAndrew Rist  * KIND, either express or implied.  See the License for the
17*9f62ea84SAndrew Rist  * specific language governing permissions and limitations
18*9f62ea84SAndrew Rist  * under the License.
19*9f62ea84SAndrew Rist  *
20*9f62ea84SAndrew Rist  *************************************************************/
21*9f62ea84SAndrew Rist 
22*9f62ea84SAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir // Description: Implements the Graphite interfaces with access to the
25cdf0e10cSrcweir //              platform's font and graphics systems.
26cdf0e10cSrcweir 
27cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
28cdf0e10cSrcweir #include "precompiled_vcl.hxx"
29cdf0e10cSrcweir 
30cdf0e10cSrcweir // We need this to enable namespace support in libgrengine headers.
31cdf0e10cSrcweir #define GR_NAMESPACE
32cdf0e10cSrcweir 
33cdf0e10cSrcweir // Header files
34cdf0e10cSrcweir //
35cdf0e10cSrcweir // Standard Library
36cdf0e10cSrcweir #include <string>
37cdf0e10cSrcweir #include <cassert>
38cdf0e10cSrcweir // Libraries
39cdf0e10cSrcweir #include <rtl/string.hxx>
40cdf0e10cSrcweir #include <rtl/ustring.hxx>
41cdf0e10cSrcweir #include <i18npool/mslangid.hxx>
42cdf0e10cSrcweir // Platform
43cdf0e10cSrcweir #ifndef WNT
44cdf0e10cSrcweir #include <unx/saldisp.hxx>
45cdf0e10cSrcweir 
46cdf0e10cSrcweir #include <salgdi.hxx>
47cdf0e10cSrcweir 
48cdf0e10cSrcweir #include <freetype/ftsynth.h>
49cdf0e10cSrcweir 
50cdf0e10cSrcweir // Module
51cdf0e10cSrcweir #include "gcach_ftyp.hxx"
52cdf0e10cSrcweir 
53cdf0e10cSrcweir #include <graphite_features.hxx>
54cdf0e10cSrcweir #include <graphite_adaptors.hxx>
55cdf0e10cSrcweir 
56cdf0e10cSrcweir // Module private type definitions and forward declarations.
57cdf0e10cSrcweir //
58cdf0e10cSrcweir using gr::GrResult;
59cdf0e10cSrcweir namespace
60cdf0e10cSrcweir {
61cdf0e10cSrcweir     inline float from_hinted(const int x) {
62cdf0e10cSrcweir         return static_cast<float>(x + 32) / 64.0;
63cdf0e10cSrcweir     }
64cdf0e10cSrcweir     typedef std::hash_map<long,bool> SilfMap;
65cdf0e10cSrcweir     SilfMap sSilfMap;
66cdf0e10cSrcweir }
67cdf0e10cSrcweir extern FT_Error (*pFTEmbolden)(FT_GlyphSlot);
68cdf0e10cSrcweir extern FT_Error (*pFTOblique)(FT_GlyphSlot);
69cdf0e10cSrcweir 
70cdf0e10cSrcweir // class CharacterRenderProperties implentation.
71cdf0e10cSrcweir //
72cdf0e10cSrcweir FontProperties::FontProperties(const FreetypeServerFont &font) throw()
73cdf0e10cSrcweir {
74cdf0e10cSrcweir     clrFore = gr::kclrBlack;
75cdf0e10cSrcweir     clrBack = gr::kclrTransparent;
76cdf0e10cSrcweir 
77cdf0e10cSrcweir     pixHeight = from_hinted(font.GetMetricsFT().height);
78cdf0e10cSrcweir 
79cdf0e10cSrcweir     switch (font.GetFontSelData().meWeight)
80cdf0e10cSrcweir     {
81cdf0e10cSrcweir         case WEIGHT_SEMIBOLD: case WEIGHT_BOLD:
82cdf0e10cSrcweir         case WEIGHT_ULTRABOLD: case WEIGHT_BLACK:
83cdf0e10cSrcweir             fBold = true;
84cdf0e10cSrcweir             break;
85cdf0e10cSrcweir         default :
86cdf0e10cSrcweir             fBold = false;
87cdf0e10cSrcweir     }
88cdf0e10cSrcweir 
89cdf0e10cSrcweir     switch (font.GetFontSelData().meItalic)
90cdf0e10cSrcweir     {
91cdf0e10cSrcweir         case ITALIC_NORMAL: case ITALIC_OBLIQUE:
92cdf0e10cSrcweir             fItalic = true;
93cdf0e10cSrcweir             break;
94cdf0e10cSrcweir         default :
95cdf0e10cSrcweir             fItalic = false;
96cdf0e10cSrcweir     }
97cdf0e10cSrcweir 
98cdf0e10cSrcweir     // Get the font name, but prefix with file name hash in case
99cdf0e10cSrcweir     // there are 2 fonts on the system with the same face name
100cdf0e10cSrcweir     sal_Int32 nHashCode = font.GetFontFileName()->hashCode();
101cdf0e10cSrcweir     ::rtl::OUStringBuffer nHashFaceName;
102cdf0e10cSrcweir     nHashFaceName.append(nHashCode, 16);
103cdf0e10cSrcweir     const sal_Unicode    * name = font.GetFontSelData().maName.GetBuffer();
104cdf0e10cSrcweir     nHashFaceName.append(name);
105cdf0e10cSrcweir 
106cdf0e10cSrcweir     const size_t name_sz = std::min(sizeof szFaceName/sizeof(wchar_t)-1,
107cdf0e10cSrcweir                     static_cast<size_t>(nHashFaceName.getLength()));
108cdf0e10cSrcweir 
109cdf0e10cSrcweir     std::copy(nHashFaceName.getStr(), nHashFaceName.getStr() + name_sz, szFaceName);
110cdf0e10cSrcweir     szFaceName[name_sz] = '\0';
111cdf0e10cSrcweir }
112cdf0e10cSrcweir 
113cdf0e10cSrcweir // class GraphiteFontAdaptor implementaion.
114cdf0e10cSrcweir //
115cdf0e10cSrcweir GraphiteFontAdaptor::GraphiteFontAdaptor(ServerFont & sfont, const sal_Int32 dpiX, const sal_Int32 dpiY)
116cdf0e10cSrcweir   :    mrFont(static_cast<FreetypeServerFont &>(sfont)),
117cdf0e10cSrcweir     maFontProperties(static_cast<FreetypeServerFont &>(sfont)),
118cdf0e10cSrcweir     mnDpiX(dpiX),
119cdf0e10cSrcweir     mnDpiY(dpiY),
120cdf0e10cSrcweir     mfAscent(from_hinted(static_cast<FreetypeServerFont &>(sfont).GetMetricsFT().ascender)),
121cdf0e10cSrcweir     mfDescent(from_hinted(static_cast<FreetypeServerFont &>(sfont).GetMetricsFT().descender)),
122cdf0e10cSrcweir     mfEmUnits(static_cast<FreetypeServerFont &>(sfont).GetMetricsFT().y_ppem),
123cdf0e10cSrcweir     mpFeatures(NULL)
124cdf0e10cSrcweir {
125cdf0e10cSrcweir     const rtl::OString aLang = MsLangId::convertLanguageToIsoByteString( sfont.GetFontSelData().meLanguage );
126cdf0e10cSrcweir     rtl::OString name = rtl::OUStringToOString(
127cdf0e10cSrcweir         sfont.GetFontSelData().maTargetName, RTL_TEXTENCODING_UTF8 );
128cdf0e10cSrcweir #ifdef DEBUG
129cdf0e10cSrcweir     printf("GraphiteFontAdaptor %lx %s italic=%u bold=%u\n", (long)this, name.getStr(),
130cdf0e10cSrcweir            maFontProperties.fItalic, maFontProperties.fBold);
131cdf0e10cSrcweir #endif
132cdf0e10cSrcweir     sal_Int32 nFeat = name.indexOf(grutils::GrFeatureParser::FEAT_PREFIX) + 1;
133cdf0e10cSrcweir     if (nFeat > 0)
134cdf0e10cSrcweir     {
135cdf0e10cSrcweir         rtl::OString aFeat = name.copy(nFeat, name.getLength() - nFeat);
136cdf0e10cSrcweir         mpFeatures = new grutils::GrFeatureParser(*this, aFeat.getStr(), aLang.getStr());
137cdf0e10cSrcweir #ifdef DEBUG
138cdf0e10cSrcweir         printf("GraphiteFontAdaptor %s/%s/%s %x language %d features %d errors\n",
139cdf0e10cSrcweir             rtl::OUStringToOString( sfont.GetFontSelData().maName,
140cdf0e10cSrcweir             RTL_TEXTENCODING_UTF8 ).getStr(),
141cdf0e10cSrcweir             rtl::OUStringToOString( sfont.GetFontSelData().maTargetName,
142cdf0e10cSrcweir             RTL_TEXTENCODING_UTF8 ).getStr(),
143cdf0e10cSrcweir             rtl::OUStringToOString( sfont.GetFontSelData().maSearchName,
144cdf0e10cSrcweir             RTL_TEXTENCODING_UTF8 ).getStr(),
145cdf0e10cSrcweir             sfont.GetFontSelData().meLanguage,
146cdf0e10cSrcweir             (int)mpFeatures->getFontFeatures(NULL), mpFeatures->parseErrors());
147cdf0e10cSrcweir #endif
148cdf0e10cSrcweir     }
149cdf0e10cSrcweir     else
150cdf0e10cSrcweir     {
151cdf0e10cSrcweir         mpFeatures = new grutils::GrFeatureParser(*this, aLang.getStr());
152cdf0e10cSrcweir     }
153cdf0e10cSrcweir }
154cdf0e10cSrcweir 
155cdf0e10cSrcweir GraphiteFontAdaptor::GraphiteFontAdaptor(const GraphiteFontAdaptor &rhs) throw()
156cdf0e10cSrcweir  :    Font(rhs),
157cdf0e10cSrcweir      mrFont (rhs.mrFont), maFontProperties(rhs.maFontProperties),
158cdf0e10cSrcweir     mnDpiX(rhs.mnDpiX), mnDpiY(rhs.mnDpiY),
159cdf0e10cSrcweir     mfAscent(rhs.mfAscent), mfDescent(rhs.mfDescent), mfEmUnits(rhs.mfEmUnits),
160cdf0e10cSrcweir     mpFeatures(NULL)
161cdf0e10cSrcweir {
162cdf0e10cSrcweir     if (rhs.mpFeatures) mpFeatures = new grutils::GrFeatureParser(*(rhs.mpFeatures));
163cdf0e10cSrcweir }
164cdf0e10cSrcweir 
165cdf0e10cSrcweir 
166cdf0e10cSrcweir GraphiteFontAdaptor::~GraphiteFontAdaptor() throw()
167cdf0e10cSrcweir {
168cdf0e10cSrcweir     maGlyphMetricMap.clear();
169cdf0e10cSrcweir     if (mpFeatures) delete mpFeatures;
170cdf0e10cSrcweir     mpFeatures = NULL;
171cdf0e10cSrcweir }
172cdf0e10cSrcweir 
173cdf0e10cSrcweir void GraphiteFontAdaptor::UniqueCacheInfo(ext_std::wstring & face_name_out, bool & bold_out, bool & italic_out)
174cdf0e10cSrcweir {
175cdf0e10cSrcweir     face_name_out = maFontProperties.szFaceName;
176cdf0e10cSrcweir     bold_out = maFontProperties.fBold;
177cdf0e10cSrcweir     italic_out = maFontProperties.fItalic;
178cdf0e10cSrcweir }
179cdf0e10cSrcweir 
180cdf0e10cSrcweir bool GraphiteFontAdaptor::IsGraphiteEnabledFont(ServerFont & font) throw()
181cdf0e10cSrcweir {
182cdf0e10cSrcweir     // NOTE: this assumes that the same FTFace pointer won't be reused,
183cdf0e10cSrcweir     // so FtFontInfo::ReleaseFaceFT must only be called at shutdown.
184cdf0e10cSrcweir     FreetypeServerFont & aFtFont = dynamic_cast<FreetypeServerFont &>(font);
185cdf0e10cSrcweir     FT_Face aFace = reinterpret_cast<FT_FaceRec_*>(aFtFont.GetFtFace());
186cdf0e10cSrcweir     SilfMap::iterator i = sSilfMap.find(reinterpret_cast<long>(aFace));
187cdf0e10cSrcweir     if (i != sSilfMap.end())
188cdf0e10cSrcweir     {
189cdf0e10cSrcweir #ifdef DEBUG
190cdf0e10cSrcweir         if (static_cast<bool>(aFtFont.GetTable("Silf", 0)) != (*i).second)
191cdf0e10cSrcweir             printf("Silf cache font mismatch\n");
192cdf0e10cSrcweir #endif
193cdf0e10cSrcweir         return (*i).second;
194cdf0e10cSrcweir     }
195cdf0e10cSrcweir     bool bHasSilf = aFtFont.GetTable("Silf", 0);
196cdf0e10cSrcweir     sSilfMap[reinterpret_cast<long>(aFace)] = bHasSilf;
197cdf0e10cSrcweir     return bHasSilf;
198cdf0e10cSrcweir }
199cdf0e10cSrcweir 
200cdf0e10cSrcweir 
201cdf0e10cSrcweir gr::Font * GraphiteFontAdaptor::copyThis() {
202cdf0e10cSrcweir     return new GraphiteFontAdaptor(*this);
203cdf0e10cSrcweir }
204cdf0e10cSrcweir 
205cdf0e10cSrcweir 
206cdf0e10cSrcweir unsigned int GraphiteFontAdaptor::getDPIx() {
207cdf0e10cSrcweir     return mnDpiX;
208cdf0e10cSrcweir }
209cdf0e10cSrcweir 
210cdf0e10cSrcweir 
211cdf0e10cSrcweir unsigned int GraphiteFontAdaptor::getDPIy() {
212cdf0e10cSrcweir     return mnDpiY;
213cdf0e10cSrcweir }
214cdf0e10cSrcweir 
215cdf0e10cSrcweir 
216cdf0e10cSrcweir float GraphiteFontAdaptor::ascent() {
217cdf0e10cSrcweir     return mfAscent;
218cdf0e10cSrcweir }
219cdf0e10cSrcweir 
220cdf0e10cSrcweir 
221cdf0e10cSrcweir float GraphiteFontAdaptor::descent() {
222cdf0e10cSrcweir     return mfDescent;
223cdf0e10cSrcweir }
224cdf0e10cSrcweir 
225cdf0e10cSrcweir 
226cdf0e10cSrcweir bool GraphiteFontAdaptor::bold() {
227cdf0e10cSrcweir     return maFontProperties.fBold;
228cdf0e10cSrcweir }
229cdf0e10cSrcweir 
230cdf0e10cSrcweir 
231cdf0e10cSrcweir bool GraphiteFontAdaptor::italic() {
232cdf0e10cSrcweir     return maFontProperties.fItalic;
233cdf0e10cSrcweir }
234cdf0e10cSrcweir 
235cdf0e10cSrcweir 
236cdf0e10cSrcweir float GraphiteFontAdaptor::height() {
237cdf0e10cSrcweir     return maFontProperties.pixHeight;
238cdf0e10cSrcweir }
239cdf0e10cSrcweir 
240cdf0e10cSrcweir 
241cdf0e10cSrcweir void GraphiteFontAdaptor::getFontMetrics(float * ascent_out, float * descent_out, float * em_square_out) {
242cdf0e10cSrcweir     if (ascent_out)        *ascent_out    = mfAscent;
243cdf0e10cSrcweir     if (descent_out)    *descent_out   = mfDescent;
244cdf0e10cSrcweir     if (em_square_out)    *em_square_out = mfEmUnits;
245cdf0e10cSrcweir }
246cdf0e10cSrcweir 
247cdf0e10cSrcweir 
248cdf0e10cSrcweir const void * GraphiteFontAdaptor::getTable(gr::fontTableId32 table_id, size_t * buffer_sz)
249cdf0e10cSrcweir {
250cdf0e10cSrcweir     char tag_name[5] = {char(table_id >> 24), char(table_id >> 16), char(table_id >> 8), char(table_id), 0};
251cdf0e10cSrcweir     sal_uLong temp = *buffer_sz;
252cdf0e10cSrcweir 
253cdf0e10cSrcweir     const void * const tbl_buf = static_cast<FreetypeServerFont &>(mrFont).GetTable(tag_name, &temp);
254cdf0e10cSrcweir     *buffer_sz = temp;
255cdf0e10cSrcweir 
256cdf0e10cSrcweir     return tbl_buf;
257cdf0e10cSrcweir }
258cdf0e10cSrcweir 
259cdf0e10cSrcweir #define fix26_6(x) (x >> 6) + (x & 32 ? (x > 0 ? 1 : 0) : (x < 0 ? -1 : 0))
260cdf0e10cSrcweir 
261cdf0e10cSrcweir // Return the glyph's metrics in pixels.
262cdf0e10cSrcweir void GraphiteFontAdaptor::getGlyphMetrics(gr::gid16 nGlyphId, gr::Rect & aBounding, gr::Point & advances)
263cdf0e10cSrcweir {
264cdf0e10cSrcweir     // There used to be problems when orientation was set however, this no
265cdf0e10cSrcweir     // longer seems to be the case and the Glyph Metric cache in
266cdf0e10cSrcweir     // FreetypeServerFont is more efficient since it lasts between calls to VCL
267cdf0e10cSrcweir #if 1
268cdf0e10cSrcweir     const GlyphMetric & metric = mrFont.GetGlyphMetric(nGlyphId);
269cdf0e10cSrcweir 
270cdf0e10cSrcweir     aBounding.right  = aBounding.left = metric.GetOffset().X();
271cdf0e10cSrcweir     aBounding.bottom = aBounding.top  = -metric.GetOffset().Y();
272cdf0e10cSrcweir     aBounding.right  += metric.GetSize().Width();
273cdf0e10cSrcweir     aBounding.bottom -= metric.GetSize().Height();
274cdf0e10cSrcweir 
275cdf0e10cSrcweir     advances.x = metric.GetDelta().X();
276cdf0e10cSrcweir     advances.y = -metric.GetDelta().Y();
277cdf0e10cSrcweir 
278cdf0e10cSrcweir #else
279cdf0e10cSrcweir     // The problem with the code below is that the cache only lasts
280cdf0e10cSrcweir     // as long as the life time of the GraphiteFontAdaptor, which
281cdf0e10cSrcweir     // is created once per call to X11SalGraphics::GetTextLayout
282cdf0e10cSrcweir     GlyphMetricMap::const_iterator gm_itr = maGlyphMetricMap.find(nGlyphId);
283cdf0e10cSrcweir     if (gm_itr != maGlyphMetricMap.end())
284cdf0e10cSrcweir     {
285cdf0e10cSrcweir         // We've cached the results from last time.
286cdf0e10cSrcweir         aBounding = gm_itr->second.first;
287cdf0e10cSrcweir         advances    = gm_itr->second.second;
288cdf0e10cSrcweir     }
289cdf0e10cSrcweir     else
290cdf0e10cSrcweir     {
291cdf0e10cSrcweir         // We need to look up the glyph.
292cdf0e10cSrcweir         FT_Int nLoadFlags = mrFont.GetLoadFlags();
293cdf0e10cSrcweir 
294cdf0e10cSrcweir         FT_Face aFace = reinterpret_cast<FT_Face>(mrFont.GetFtFace());
295cdf0e10cSrcweir         if (!aFace)
296cdf0e10cSrcweir         {
297cdf0e10cSrcweir             aBounding.top = aBounding.bottom = aBounding.left = aBounding.right = 0;
298cdf0e10cSrcweir             advances.x = advances.y = 0;
299cdf0e10cSrcweir             return;
300cdf0e10cSrcweir         }
301cdf0e10cSrcweir         FT_Error aStatus = -1;
302cdf0e10cSrcweir         aStatus = FT_Load_Glyph(aFace, nGlyphId, nLoadFlags);
303cdf0e10cSrcweir         if( aStatus != FT_Err_Ok || (!aFace->glyph))
304cdf0e10cSrcweir         {
305cdf0e10cSrcweir             aBounding.top = aBounding.bottom = aBounding.left = aBounding.right = 0;
306cdf0e10cSrcweir             advances.x = advances.y = 0;
307cdf0e10cSrcweir             return;
308cdf0e10cSrcweir         }
309cdf0e10cSrcweir         // check whether we need synthetic bold/italic otherwise metric is wrong
310cdf0e10cSrcweir         if (mrFont.NeedsArtificialBold() && pFTEmbolden)
311cdf0e10cSrcweir             (*pFTEmbolden)(aFace->glyph);
312cdf0e10cSrcweir 
313cdf0e10cSrcweir         if (mrFont.NeedsArtificialItalic() && pFTOblique)
314cdf0e10cSrcweir             (*pFTOblique)(aFace->glyph);
315cdf0e10cSrcweir 
316cdf0e10cSrcweir         const FT_Glyph_Metrics &gm = aFace->glyph->metrics;
317cdf0e10cSrcweir 
318cdf0e10cSrcweir         // Fill out the bounding box an advances.
319cdf0e10cSrcweir         aBounding.top = aBounding.bottom = fix26_6(gm.horiBearingY);
320cdf0e10cSrcweir         aBounding.bottom -= fix26_6(gm.height);
321cdf0e10cSrcweir         aBounding.left = aBounding.right = fix26_6(gm.horiBearingX);
322cdf0e10cSrcweir         aBounding.right += fix26_6(gm.width);
323cdf0e10cSrcweir         advances.x = fix26_6(gm.horiAdvance);
324cdf0e10cSrcweir         advances.y = 0;
325cdf0e10cSrcweir 
326cdf0e10cSrcweir         // Now add an entry to our metrics map.
327cdf0e10cSrcweir         maGlyphMetricMap[nGlyphId] = std::make_pair(aBounding, advances);
328cdf0e10cSrcweir     }
329cdf0e10cSrcweir #endif
330cdf0e10cSrcweir }
331cdf0e10cSrcweir 
332cdf0e10cSrcweir #endif
333