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