xref: /aoo4110/main/vcl/unx/generic/gdi/salgdi3.cxx (revision b1cdbd2c)
1*b1cdbd2cSJim Jagielski /**************************************************************
2*b1cdbd2cSJim Jagielski  *
3*b1cdbd2cSJim Jagielski  * Licensed to the Apache Software Foundation (ASF) under one
4*b1cdbd2cSJim Jagielski  * or more contributor license agreements.  See the NOTICE file
5*b1cdbd2cSJim Jagielski  * distributed with this work for additional information
6*b1cdbd2cSJim Jagielski  * regarding copyright ownership.  The ASF licenses this file
7*b1cdbd2cSJim Jagielski  * to you under the Apache License, Version 2.0 (the
8*b1cdbd2cSJim Jagielski  * "License"); you may not use this file except in compliance
9*b1cdbd2cSJim Jagielski  * with the License.  You may obtain a copy of the License at
10*b1cdbd2cSJim Jagielski  *
11*b1cdbd2cSJim Jagielski  *   http://www.apache.org/licenses/LICENSE-2.0
12*b1cdbd2cSJim Jagielski  *
13*b1cdbd2cSJim Jagielski  * Unless required by applicable law or agreed to in writing,
14*b1cdbd2cSJim Jagielski  * software distributed under the License is distributed on an
15*b1cdbd2cSJim Jagielski  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*b1cdbd2cSJim Jagielski  * KIND, either express or implied.  See the License for the
17*b1cdbd2cSJim Jagielski  * specific language governing permissions and limitations
18*b1cdbd2cSJim Jagielski  * under the License.
19*b1cdbd2cSJim Jagielski  *
20*b1cdbd2cSJim Jagielski  *************************************************************/
21*b1cdbd2cSJim Jagielski 
22*b1cdbd2cSJim Jagielski 
23*b1cdbd2cSJim Jagielski 
24*b1cdbd2cSJim Jagielski // MARKER(update_precomp.py): autogen include statement, do not remove
25*b1cdbd2cSJim Jagielski #include "precompiled_vcl.hxx"
26*b1cdbd2cSJim Jagielski 
27*b1cdbd2cSJim Jagielski #include <string.h>
28*b1cdbd2cSJim Jagielski #include <stdio.h>
29*b1cdbd2cSJim Jagielski #include <stdlib.h>
30*b1cdbd2cSJim Jagielski #include <math.h>
31*b1cdbd2cSJim Jagielski #include <unistd.h>
32*b1cdbd2cSJim Jagielski #include <fcntl.h>
33*b1cdbd2cSJim Jagielski #include <sys/mman.h>
34*b1cdbd2cSJim Jagielski #include <sys/stat.h>
35*b1cdbd2cSJim Jagielski #include <sys/types.h>
36*b1cdbd2cSJim Jagielski 
37*b1cdbd2cSJim Jagielski #include "sal/alloca.h"
38*b1cdbd2cSJim Jagielski #include "sal/types.h"
39*b1cdbd2cSJim Jagielski 
40*b1cdbd2cSJim Jagielski #include "rtl/tencinfo.h"
41*b1cdbd2cSJim Jagielski 
42*b1cdbd2cSJim Jagielski #include "osl/file.hxx"
43*b1cdbd2cSJim Jagielski 
44*b1cdbd2cSJim Jagielski #include "tools/string.hxx"
45*b1cdbd2cSJim Jagielski #include "tools/debug.hxx"
46*b1cdbd2cSJim Jagielski #include "tools/stream.hxx"
47*b1cdbd2cSJim Jagielski 
48*b1cdbd2cSJim Jagielski #include "basegfx/polygon/b2dpolypolygon.hxx"
49*b1cdbd2cSJim Jagielski 
50*b1cdbd2cSJim Jagielski #include "i18npool/mslangid.hxx"
51*b1cdbd2cSJim Jagielski 
52*b1cdbd2cSJim Jagielski #include <vcl/sysdata.hxx>
53*b1cdbd2cSJim Jagielski #include "printergfx.hxx"
54*b1cdbd2cSJim Jagielski #include "vcl/fontmanager.hxx"
55*b1cdbd2cSJim Jagielski #include "vcl/jobdata.hxx"
56*b1cdbd2cSJim Jagielski #include "vcl/printerinfomanager.hxx"
57*b1cdbd2cSJim Jagielski #include "vcl/svapp.hxx"
58*b1cdbd2cSJim Jagielski 
59*b1cdbd2cSJim Jagielski #include "unx/salunx.h"
60*b1cdbd2cSJim Jagielski #include "unx/saldata.hxx"
61*b1cdbd2cSJim Jagielski #include "unx/saldisp.hxx"
62*b1cdbd2cSJim Jagielski #include "unx/salgdi.h"
63*b1cdbd2cSJim Jagielski #include "unx/pspgraphics.h"
64*b1cdbd2cSJim Jagielski #include "unx/salvd.h"
65*b1cdbd2cSJim Jagielski 
66*b1cdbd2cSJim Jagielski #include "salcvt.hxx"
67*b1cdbd2cSJim Jagielski #include "gcach_xpeer.hxx"
68*b1cdbd2cSJim Jagielski #include "xrender_peer.hxx"
69*b1cdbd2cSJim Jagielski #include "impfont.hxx"
70*b1cdbd2cSJim Jagielski #include "salframe.hxx"
71*b1cdbd2cSJim Jagielski #include "outdev.h"
72*b1cdbd2cSJim Jagielski 
73*b1cdbd2cSJim Jagielski 
74*b1cdbd2cSJim Jagielski #include <hash_set>
75*b1cdbd2cSJim Jagielski 
76*b1cdbd2cSJim Jagielski #ifdef ENABLE_GRAPHITE
77*b1cdbd2cSJim Jagielski #include <graphite_layout.hxx>
78*b1cdbd2cSJim Jagielski #include <graphite_serverfont.hxx>
79*b1cdbd2cSJim Jagielski #endif
80*b1cdbd2cSJim Jagielski 
81*b1cdbd2cSJim Jagielski struct cairo_surface_t;
82*b1cdbd2cSJim Jagielski struct cairo_t;
83*b1cdbd2cSJim Jagielski struct cairo_font_face_t;
84*b1cdbd2cSJim Jagielski typedef void* FT_Face;
85*b1cdbd2cSJim Jagielski struct cairo_matrix_t {
86*b1cdbd2cSJim Jagielski     double xx; double yx;
87*b1cdbd2cSJim Jagielski     double xy; double yy;
88*b1cdbd2cSJim Jagielski     double x0; double y0;
89*b1cdbd2cSJim Jagielski };
90*b1cdbd2cSJim Jagielski struct cairo_glyph_t
91*b1cdbd2cSJim Jagielski {
92*b1cdbd2cSJim Jagielski     unsigned long index;
93*b1cdbd2cSJim Jagielski     double x;
94*b1cdbd2cSJim Jagielski     double y;
95*b1cdbd2cSJim Jagielski };
96*b1cdbd2cSJim Jagielski struct BOX
97*b1cdbd2cSJim Jagielski {
98*b1cdbd2cSJim Jagielski     short x1, x2, y1, y2;
99*b1cdbd2cSJim Jagielski };
100*b1cdbd2cSJim Jagielski struct _XRegion
101*b1cdbd2cSJim Jagielski {
102*b1cdbd2cSJim Jagielski     long size;
103*b1cdbd2cSJim Jagielski     long numRects;
104*b1cdbd2cSJim Jagielski     BOX *rects;
105*b1cdbd2cSJim Jagielski     BOX extents;
106*b1cdbd2cSJim Jagielski };
107*b1cdbd2cSJim Jagielski using namespace rtl;
108*b1cdbd2cSJim Jagielski 
109*b1cdbd2cSJim Jagielski // ===========================================================================
110*b1cdbd2cSJim Jagielski 
111*b1cdbd2cSJim Jagielski // PspKernInfo allows on-demand-querying of psprint provided kerning info (#i29881#)
112*b1cdbd2cSJim Jagielski class PspKernInfo : public ExtraKernInfo
113*b1cdbd2cSJim Jagielski {
114*b1cdbd2cSJim Jagielski public:
PspKernInfo(int nFontId)115*b1cdbd2cSJim Jagielski     PspKernInfo( int nFontId ) : ExtraKernInfo(nFontId) {}
116*b1cdbd2cSJim Jagielski protected:
117*b1cdbd2cSJim Jagielski     virtual void Initialize() const;
118*b1cdbd2cSJim Jagielski };
119*b1cdbd2cSJim Jagielski 
120*b1cdbd2cSJim Jagielski //--------------------------------------------------------------------------
121*b1cdbd2cSJim Jagielski 
Initialize() const122*b1cdbd2cSJim Jagielski void PspKernInfo::Initialize() const
123*b1cdbd2cSJim Jagielski {
124*b1cdbd2cSJim Jagielski     mbInitialized = true;
125*b1cdbd2cSJim Jagielski 
126*b1cdbd2cSJim Jagielski     // get the kerning pairs from psprint
127*b1cdbd2cSJim Jagielski     const psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
128*b1cdbd2cSJim Jagielski     typedef std::list< psp::KernPair > PspKernPairs;
129*b1cdbd2cSJim Jagielski     const PspKernPairs& rKernPairs = rMgr.getKernPairs( mnFontId );
130*b1cdbd2cSJim Jagielski     if( rKernPairs.empty() )
131*b1cdbd2cSJim Jagielski         return;
132*b1cdbd2cSJim Jagielski 
133*b1cdbd2cSJim Jagielski     // feed psprint's kerning list into a lookup-friendly container
134*b1cdbd2cSJim Jagielski     maUnicodeKernPairs.rehash( rKernPairs.size() );
135*b1cdbd2cSJim Jagielski     PspKernPairs::const_iterator it = rKernPairs.begin();
136*b1cdbd2cSJim Jagielski     for(; it != rKernPairs.end(); ++it )
137*b1cdbd2cSJim Jagielski     {
138*b1cdbd2cSJim Jagielski         ImplKernPairData aKernPair = { it->first, it->second, it->kern_x };
139*b1cdbd2cSJim Jagielski         maUnicodeKernPairs.insert( aKernPair );
140*b1cdbd2cSJim Jagielski     }
141*b1cdbd2cSJim Jagielski }
142*b1cdbd2cSJim Jagielski 
143*b1cdbd2cSJim Jagielski // ----------------------------------------------------------------------------
144*b1cdbd2cSJim Jagielski //
145*b1cdbd2cSJim Jagielski // X11SalGraphics
146*b1cdbd2cSJim Jagielski //
147*b1cdbd2cSJim Jagielski // ----------------------------------------------------------------------------
148*b1cdbd2cSJim Jagielski 
149*b1cdbd2cSJim Jagielski GC
GetFontGC()150*b1cdbd2cSJim Jagielski X11SalGraphics::GetFontGC()
151*b1cdbd2cSJim Jagielski {
152*b1cdbd2cSJim Jagielski 	Display *pDisplay = GetXDisplay();
153*b1cdbd2cSJim Jagielski 
154*b1cdbd2cSJim Jagielski 	if( !pFontGC_ )
155*b1cdbd2cSJim Jagielski 	{
156*b1cdbd2cSJim Jagielski 		XGCValues values;
157*b1cdbd2cSJim Jagielski 		values.subwindow_mode		= ClipByChildren;
158*b1cdbd2cSJim Jagielski 		values.fill_rule			= EvenOddRule;		// Pict import/ Gradient
159*b1cdbd2cSJim Jagielski 		values.graphics_exposures	= False;
160*b1cdbd2cSJim Jagielski 		values.foreground			= nTextPixel_;
161*b1cdbd2cSJim Jagielski         pFontGC_ = XCreateGC( pDisplay, hDrawable_,
162*b1cdbd2cSJim Jagielski                               GCSubwindowMode | GCFillRule
163*b1cdbd2cSJim Jagielski                               | GCGraphicsExposures | GCForeground,
164*b1cdbd2cSJim Jagielski                               &values );
165*b1cdbd2cSJim Jagielski 	}
166*b1cdbd2cSJim Jagielski 	if( !bFontGC_ )
167*b1cdbd2cSJim Jagielski 	{
168*b1cdbd2cSJim Jagielski 		XSetForeground( pDisplay, pFontGC_, nTextPixel_ );
169*b1cdbd2cSJim Jagielski 		SetClipRegion( pFontGC_ );
170*b1cdbd2cSJim Jagielski 		bFontGC_ = sal_True;
171*b1cdbd2cSJim Jagielski 	}
172*b1cdbd2cSJim Jagielski 
173*b1cdbd2cSJim Jagielski 	return pFontGC_;
174*b1cdbd2cSJim Jagielski }
175*b1cdbd2cSJim Jagielski 
176*b1cdbd2cSJim Jagielski //--------------------------------------------------------------------------
177*b1cdbd2cSJim Jagielski 
setFont(const ImplFontSelectData * pEntry,int nFallbackLevel)178*b1cdbd2cSJim Jagielski bool X11SalGraphics::setFont( const ImplFontSelectData *pEntry, int nFallbackLevel )
179*b1cdbd2cSJim Jagielski {
180*b1cdbd2cSJim Jagielski #ifdef HDU_DEBUG
181*b1cdbd2cSJim Jagielski     ByteString aReqName( "NULL" );
182*b1cdbd2cSJim Jagielski     if( pEntry )
183*b1cdbd2cSJim Jagielski         aReqName = ByteString( pEntry->maName, RTL_TEXTENCODING_UTF8 );
184*b1cdbd2cSJim Jagielski     ByteString aUseName( "NULL" );
185*b1cdbd2cSJim Jagielski     if( pEntry && pEntry->mpFontData )
186*b1cdbd2cSJim Jagielski         aUseName = ByteString( pEntry->mpFontData->GetFamilyName(), RTL_TEXTENCODING_UTF8 );
187*b1cdbd2cSJim Jagielski     fprintf( stderr, "SetFont(lvl=%d,\"%s\", %d*%d, naa=%d,b=%d,i=%d) => \"%s\"\n",
188*b1cdbd2cSJim Jagielski         nFallbackLevel, aReqName.GetBuffer(),
189*b1cdbd2cSJim Jagielski 	!pEntry?-1:pEntry->mnWidth, !pEntry?-1:pEntry->mnHeight,
190*b1cdbd2cSJim Jagielski         !pEntry?-1:pEntry->mbNonAntialiased,
191*b1cdbd2cSJim Jagielski 	!pEntry?-1:pEntry->meWeight, !pEntry?-1:pEntry->meItalic,
192*b1cdbd2cSJim Jagielski         aUseName.GetBuffer() );
193*b1cdbd2cSJim Jagielski #endif
194*b1cdbd2cSJim Jagielski 
195*b1cdbd2cSJim Jagielski     // release all no longer needed font resources
196*b1cdbd2cSJim Jagielski     for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i )
197*b1cdbd2cSJim Jagielski     {
198*b1cdbd2cSJim Jagielski         if( mpServerFont[i] != NULL )
199*b1cdbd2cSJim Jagielski         {
200*b1cdbd2cSJim Jagielski             // old server side font is no longer referenced
201*b1cdbd2cSJim Jagielski             GlyphCache::GetInstance().UncacheFont( *mpServerFont[i] );
202*b1cdbd2cSJim Jagielski             mpServerFont[i] = NULL;
203*b1cdbd2cSJim Jagielski         }
204*b1cdbd2cSJim Jagielski     }
205*b1cdbd2cSJim Jagielski 
206*b1cdbd2cSJim Jagielski     // return early if there is no new font
207*b1cdbd2cSJim Jagielski     if( !pEntry )
208*b1cdbd2cSJim Jagielski 	return false;
209*b1cdbd2cSJim Jagielski 
210*b1cdbd2cSJim Jagielski     bFontVertical_ = pEntry->mbVertical;
211*b1cdbd2cSJim Jagielski 
212*b1cdbd2cSJim Jagielski     // return early if this is not a valid font for this graphics
213*b1cdbd2cSJim Jagielski     if( !pEntry->mpFontData )
214*b1cdbd2cSJim Jagielski         return false;
215*b1cdbd2cSJim Jagielski 
216*b1cdbd2cSJim Jagielski     // handle the request for a non-native X11-font => use the GlyphCache
217*b1cdbd2cSJim Jagielski     ServerFont* pServerFont = GlyphCache::GetInstance().CacheFont( *pEntry );
218*b1cdbd2cSJim Jagielski     if( pServerFont != NULL )
219*b1cdbd2cSJim Jagielski     {
220*b1cdbd2cSJim Jagielski         // ignore fonts with e.g. corrupted font files
221*b1cdbd2cSJim Jagielski         if( !pServerFont->TestFont() )
222*b1cdbd2cSJim Jagielski         {
223*b1cdbd2cSJim Jagielski             GlyphCache::GetInstance().UncacheFont( *pServerFont );
224*b1cdbd2cSJim Jagielski             return false;
225*b1cdbd2cSJim Jagielski         }
226*b1cdbd2cSJim Jagielski 
227*b1cdbd2cSJim Jagielski         // register to use the font
228*b1cdbd2cSJim Jagielski         mpServerFont[ nFallbackLevel ] = pServerFont;
229*b1cdbd2cSJim Jagielski 
230*b1cdbd2cSJim Jagielski         // apply font specific-hint settings if needed
231*b1cdbd2cSJim Jagielski         // TODO: also disable it for reference devices
232*b1cdbd2cSJim Jagielski 	if( !bPrinter_ )
233*b1cdbd2cSJim Jagielski 	{
234*b1cdbd2cSJim Jagielski 	    ImplServerFontEntry* pSFE = static_cast<ImplServerFontEntry*>( pEntry->mpFontEntry );
235*b1cdbd2cSJim Jagielski 	    pSFE->HandleFontOptions();
236*b1cdbd2cSJim Jagielski         }
237*b1cdbd2cSJim Jagielski 
238*b1cdbd2cSJim Jagielski         return true;
239*b1cdbd2cSJim Jagielski     }
240*b1cdbd2cSJim Jagielski 
241*b1cdbd2cSJim Jagielski     return false;
242*b1cdbd2cSJim Jagielski }
243*b1cdbd2cSJim Jagielski 
HandleFontOptions(void)244*b1cdbd2cSJim Jagielski void ImplServerFontEntry::HandleFontOptions( void )
245*b1cdbd2cSJim Jagielski {
246*b1cdbd2cSJim Jagielski 	bool GetFCFontOptions( const ImplFontAttributes&, int nSize, ImplFontOptions& );
247*b1cdbd2cSJim Jagielski 
248*b1cdbd2cSJim Jagielski 	if( !mpServerFont )
249*b1cdbd2cSJim Jagielski 		return;
250*b1cdbd2cSJim Jagielski 	if( !mbGotFontOptions )
251*b1cdbd2cSJim Jagielski 	{
252*b1cdbd2cSJim Jagielski 		// get and cache the font options
253*b1cdbd2cSJim Jagielski 		mbGotFontOptions = true;
254*b1cdbd2cSJim Jagielski 		mbValidFontOptions = GetFCFontOptions( *maFontSelData.mpFontData,
255*b1cdbd2cSJim Jagielski 			maFontSelData.mnHeight, maFontOptions );
256*b1cdbd2cSJim Jagielski 	}
257*b1cdbd2cSJim Jagielski 	// apply the font options
258*b1cdbd2cSJim Jagielski 	if( mbValidFontOptions )
259*b1cdbd2cSJim Jagielski 		mpServerFont->SetFontOptions( maFontOptions );
260*b1cdbd2cSJim Jagielski }
261*b1cdbd2cSJim Jagielski 
262*b1cdbd2cSJim Jagielski //--------------------------------------------------------------------------
263*b1cdbd2cSJim Jagielski 
264*b1cdbd2cSJim Jagielski namespace {
265*b1cdbd2cSJim Jagielski 
266*b1cdbd2cSJim Jagielski class CairoWrapper
267*b1cdbd2cSJim Jagielski {
268*b1cdbd2cSJim Jagielski private:
269*b1cdbd2cSJim Jagielski     oslModule mpCairoLib;
270*b1cdbd2cSJim Jagielski 
271*b1cdbd2cSJim Jagielski     cairo_surface_t* (*mp_xlib_surface_create_with_xrender_format)(Display *, Drawable , Screen *, XRenderPictFormat *, int , int );
272*b1cdbd2cSJim Jagielski     void (*mp_surface_destroy)(cairo_surface_t *);
273*b1cdbd2cSJim Jagielski     cairo_t* (*mp_create)(cairo_surface_t *);
274*b1cdbd2cSJim Jagielski     void (*mp_destroy)(cairo_t*);
275*b1cdbd2cSJim Jagielski     void (*mp_clip)(cairo_t*);
276*b1cdbd2cSJim Jagielski     void (*mp_rectangle)(cairo_t*, double, double, double, double);
277*b1cdbd2cSJim Jagielski     cairo_font_face_t * (*mp_ft_font_face_create_for_ft_face)(FT_Face, int);
278*b1cdbd2cSJim Jagielski     void (*mp_set_font_face)(cairo_t *, cairo_font_face_t *);
279*b1cdbd2cSJim Jagielski     void (*mp_font_face_destroy)(cairo_font_face_t *);
280*b1cdbd2cSJim Jagielski     void (*mp_matrix_init_identity)(cairo_matrix_t *);
281*b1cdbd2cSJim Jagielski     void (*mp_matrix_scale)(cairo_matrix_t *, double, double);
282*b1cdbd2cSJim Jagielski     void (*mp_matrix_rotate)(cairo_matrix_t *, double);
283*b1cdbd2cSJim Jagielski     void (*mp_set_font_matrix)(cairo_t *, const cairo_matrix_t *);
284*b1cdbd2cSJim Jagielski     void (*mp_show_glyphs)(cairo_t *, const cairo_glyph_t *, int );
285*b1cdbd2cSJim Jagielski     void (*mp_set_source_rgb)(cairo_t *, double , double , double );
286*b1cdbd2cSJim Jagielski     void (*mp_set_font_options)(cairo_t *, const void *);
287*b1cdbd2cSJim Jagielski     void (*mp_ft_font_options_substitute)(const void*, void*);
288*b1cdbd2cSJim Jagielski 
canEmbolden() const289*b1cdbd2cSJim Jagielski     bool canEmbolden() const { return false; }
290*b1cdbd2cSJim Jagielski 
291*b1cdbd2cSJim Jagielski     CairoWrapper();
292*b1cdbd2cSJim Jagielski public:
293*b1cdbd2cSJim Jagielski     static CairoWrapper& get();
isValid() const294*b1cdbd2cSJim Jagielski     bool isValid() const { return (mpCairoLib != NULL); }
295*b1cdbd2cSJim Jagielski     bool isCairoRenderable(const ServerFont& rFont);
296*b1cdbd2cSJim Jagielski 
xlib_surface_create_with_xrender_format(Display * pDisplay,Drawable drawable,Screen * pScreen,XRenderPictFormat * pFormat,int width,int height)297*b1cdbd2cSJim Jagielski     cairo_surface_t* xlib_surface_create_with_xrender_format(Display *pDisplay, Drawable drawable, Screen *pScreen, XRenderPictFormat *pFormat, int width, int height)
298*b1cdbd2cSJim Jagielski         { return (*mp_xlib_surface_create_with_xrender_format)(pDisplay, drawable, pScreen, pFormat, width, height); }
surface_destroy(cairo_surface_t * surface)299*b1cdbd2cSJim Jagielski     void surface_destroy(cairo_surface_t *surface) { (*mp_surface_destroy)(surface); }
create(cairo_surface_t * surface)300*b1cdbd2cSJim Jagielski     cairo_t* create(cairo_surface_t *surface) { return (*mp_create)(surface); }
destroy(cairo_t * cr)301*b1cdbd2cSJim Jagielski     void destroy(cairo_t *cr) { (*mp_destroy)(cr); }
clip(cairo_t * cr)302*b1cdbd2cSJim Jagielski     void clip(cairo_t *cr) { (*mp_clip)(cr); }
rectangle(cairo_t * cr,double x,double y,double width,double height)303*b1cdbd2cSJim Jagielski     void rectangle(cairo_t *cr, double x, double y, double width, double height)
304*b1cdbd2cSJim Jagielski         { (*mp_rectangle)(cr, x, y, width, height); }
ft_font_face_create_for_ft_face(FT_Face face,int load_flags)305*b1cdbd2cSJim Jagielski     cairo_font_face_t* ft_font_face_create_for_ft_face(FT_Face face, int load_flags)
306*b1cdbd2cSJim Jagielski         { return (*mp_ft_font_face_create_for_ft_face)(face, load_flags); }
set_font_face(cairo_t * cr,cairo_font_face_t * font_face)307*b1cdbd2cSJim Jagielski     void set_font_face(cairo_t *cr, cairo_font_face_t *font_face)
308*b1cdbd2cSJim Jagielski         { (*mp_set_font_face)(cr, font_face); }
font_face_destroy(cairo_font_face_t * font_face)309*b1cdbd2cSJim Jagielski     void font_face_destroy(cairo_font_face_t *font_face)
310*b1cdbd2cSJim Jagielski         { (*mp_font_face_destroy)(font_face); }
matrix_init_identity(cairo_matrix_t * matrix)311*b1cdbd2cSJim Jagielski     void matrix_init_identity(cairo_matrix_t *matrix)
312*b1cdbd2cSJim Jagielski         { (*mp_matrix_init_identity)(matrix); }
matrix_scale(cairo_matrix_t * matrix,double sx,double sy)313*b1cdbd2cSJim Jagielski     void matrix_scale(cairo_matrix_t *matrix, double sx, double sy)
314*b1cdbd2cSJim Jagielski         { (*mp_matrix_scale)(matrix, sx, sy); }
matrix_rotate(cairo_matrix_t * matrix,double radians)315*b1cdbd2cSJim Jagielski     void matrix_rotate(cairo_matrix_t *matrix, double radians)
316*b1cdbd2cSJim Jagielski         { (*mp_matrix_rotate)(matrix, radians); }
set_font_matrix(cairo_t * cr,const cairo_matrix_t * matrix)317*b1cdbd2cSJim Jagielski     void set_font_matrix(cairo_t *cr, const cairo_matrix_t *matrix)
318*b1cdbd2cSJim Jagielski         { (*mp_set_font_matrix)(cr, matrix); }
show_glyphs(cairo_t * cr,const cairo_glyph_t * glyphs,int no_glyphs)319*b1cdbd2cSJim Jagielski     void show_glyphs(cairo_t *cr, const cairo_glyph_t *glyphs, int no_glyphs)
320*b1cdbd2cSJim Jagielski         { (*mp_show_glyphs)(cr, glyphs, no_glyphs); }
set_source_rgb(cairo_t * cr,double red,double green,double blue)321*b1cdbd2cSJim Jagielski     void set_source_rgb(cairo_t *cr, double red, double green, double blue)
322*b1cdbd2cSJim Jagielski         { (*mp_set_source_rgb)(cr, red, green, blue); }
set_font_options(cairo_t * cr,const void * options)323*b1cdbd2cSJim Jagielski     void set_font_options(cairo_t *cr, const void *options)
324*b1cdbd2cSJim Jagielski         { (*mp_set_font_options)(cr, options); }
ft_font_options_substitute(const void * options,void * pattern)325*b1cdbd2cSJim Jagielski     void ft_font_options_substitute(const void *options, void *pattern)
326*b1cdbd2cSJim Jagielski         { (*mp_ft_font_options_substitute)(options, pattern); }
327*b1cdbd2cSJim Jagielski };
328*b1cdbd2cSJim Jagielski 
329*b1cdbd2cSJim Jagielski static CairoWrapper* pCairoInstance = NULL;
330*b1cdbd2cSJim Jagielski 
get()331*b1cdbd2cSJim Jagielski CairoWrapper& CairoWrapper::get()
332*b1cdbd2cSJim Jagielski {
333*b1cdbd2cSJim Jagielski     if( ! pCairoInstance )
334*b1cdbd2cSJim Jagielski         pCairoInstance = new CairoWrapper();
335*b1cdbd2cSJim Jagielski     return *pCairoInstance;
336*b1cdbd2cSJim Jagielski }
337*b1cdbd2cSJim Jagielski 
CairoWrapper()338*b1cdbd2cSJim Jagielski CairoWrapper::CairoWrapper()
339*b1cdbd2cSJim Jagielski :   mpCairoLib( NULL )
340*b1cdbd2cSJim Jagielski {
341*b1cdbd2cSJim Jagielski     static const char* pDisableCairoText = getenv( "SAL_DISABLE_CAIROTEXT" );
342*b1cdbd2cSJim Jagielski     if( pDisableCairoText && (pDisableCairoText[0] != '0') )
343*b1cdbd2cSJim Jagielski         return;
344*b1cdbd2cSJim Jagielski 
345*b1cdbd2cSJim Jagielski     int nDummy;
346*b1cdbd2cSJim Jagielski     if( !XQueryExtension( GetX11SalData()->GetDisplay()->GetDisplay(), "RENDER", &nDummy, &nDummy, &nDummy ) )
347*b1cdbd2cSJim Jagielski         return;
348*b1cdbd2cSJim Jagielski 
349*b1cdbd2cSJim Jagielski     mpCairoLib = osl_loadAsciiModule( "libcairo.so.2", SAL_LOADMODULE_DEFAULT );
350*b1cdbd2cSJim Jagielski     if( !mpCairoLib )
351*b1cdbd2cSJim Jagielski         return;
352*b1cdbd2cSJim Jagielski 
353*b1cdbd2cSJim Jagielski #ifdef DEBUG
354*b1cdbd2cSJim Jagielski     // check cairo version
355*b1cdbd2cSJim Jagielski     int (*p_version)();
356*b1cdbd2cSJim Jagielski     p_version = (int(*)()) osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_version" );
357*b1cdbd2cSJim Jagielski 	const int nVersion = p_version ? (*p_version)() : 0;
358*b1cdbd2cSJim Jagielski     fprintf( stderr, "CAIRO version=%d\n", nVersion );
359*b1cdbd2cSJim Jagielski #endif
360*b1cdbd2cSJim Jagielski 
361*b1cdbd2cSJim Jagielski     mp_xlib_surface_create_with_xrender_format = (cairo_surface_t* (*)(Display *, Drawable , Screen *, XRenderPictFormat *, int , int ))
362*b1cdbd2cSJim Jagielski         osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_xlib_surface_create_with_xrender_format" );
363*b1cdbd2cSJim Jagielski     mp_surface_destroy = (void(*)(cairo_surface_t*))
364*b1cdbd2cSJim Jagielski         osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_surface_destroy" );
365*b1cdbd2cSJim Jagielski     mp_create = (cairo_t*(*)(cairo_surface_t*))
366*b1cdbd2cSJim Jagielski         osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_create" );
367*b1cdbd2cSJim Jagielski     mp_destroy = (void(*)(cairo_t*))
368*b1cdbd2cSJim Jagielski         osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_destroy" );
369*b1cdbd2cSJim Jagielski     mp_clip = (void(*)(cairo_t*))
370*b1cdbd2cSJim Jagielski         osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_clip" );
371*b1cdbd2cSJim Jagielski     mp_rectangle = (void(*)(cairo_t*, double, double, double, double))
372*b1cdbd2cSJim Jagielski         osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_rectangle" );
373*b1cdbd2cSJim Jagielski     mp_ft_font_face_create_for_ft_face = (cairo_font_face_t * (*)(FT_Face, int))
374*b1cdbd2cSJim Jagielski         osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_ft_font_face_create_for_ft_face" );
375*b1cdbd2cSJim Jagielski     mp_set_font_face = (void (*)(cairo_t *, cairo_font_face_t *))
376*b1cdbd2cSJim Jagielski         osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_set_font_face" );
377*b1cdbd2cSJim Jagielski     mp_font_face_destroy = (void (*)(cairo_font_face_t *))
378*b1cdbd2cSJim Jagielski         osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_font_face_destroy" );
379*b1cdbd2cSJim Jagielski     mp_matrix_init_identity = (void (*)(cairo_matrix_t *))
380*b1cdbd2cSJim Jagielski         osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_matrix_init_identity" );
381*b1cdbd2cSJim Jagielski     mp_matrix_scale = (void (*)(cairo_matrix_t *, double, double))
382*b1cdbd2cSJim Jagielski         osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_matrix_scale" );
383*b1cdbd2cSJim Jagielski     mp_matrix_rotate = (void (*)(cairo_matrix_t *, double))
384*b1cdbd2cSJim Jagielski         osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_matrix_rotate" );
385*b1cdbd2cSJim Jagielski     mp_set_font_matrix = (void (*)(cairo_t *, const cairo_matrix_t *))
386*b1cdbd2cSJim Jagielski         osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_set_font_matrix" );
387*b1cdbd2cSJim Jagielski     mp_show_glyphs = (void (*)(cairo_t *, const cairo_glyph_t *, int ))
388*b1cdbd2cSJim Jagielski         osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_show_glyphs" );
389*b1cdbd2cSJim Jagielski     mp_set_source_rgb = (void (*)(cairo_t *, double , double , double ))
390*b1cdbd2cSJim Jagielski         osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_set_source_rgb" );
391*b1cdbd2cSJim Jagielski     mp_set_font_options = (void (*)(cairo_t *, const void *options ))
392*b1cdbd2cSJim Jagielski         osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_set_font_options" );
393*b1cdbd2cSJim Jagielski     mp_ft_font_options_substitute = (void (*)(const void *, void *))
394*b1cdbd2cSJim Jagielski         osl_getAsciiFunctionSymbol( mpCairoLib, "cairo_ft_font_options_substitute" );
395*b1cdbd2cSJim Jagielski 
396*b1cdbd2cSJim Jagielski     if( !(
397*b1cdbd2cSJim Jagielski             mp_xlib_surface_create_with_xrender_format &&
398*b1cdbd2cSJim Jagielski             mp_surface_destroy &&
399*b1cdbd2cSJim Jagielski             mp_create &&
400*b1cdbd2cSJim Jagielski             mp_destroy &&
401*b1cdbd2cSJim Jagielski             mp_clip &&
402*b1cdbd2cSJim Jagielski             mp_rectangle &&
403*b1cdbd2cSJim Jagielski             mp_ft_font_face_create_for_ft_face &&
404*b1cdbd2cSJim Jagielski             mp_set_font_face &&
405*b1cdbd2cSJim Jagielski             mp_font_face_destroy &&
406*b1cdbd2cSJim Jagielski             mp_matrix_init_identity &&
407*b1cdbd2cSJim Jagielski             mp_matrix_scale &&
408*b1cdbd2cSJim Jagielski             mp_matrix_rotate &&
409*b1cdbd2cSJim Jagielski             mp_set_font_matrix &&
410*b1cdbd2cSJim Jagielski             mp_show_glyphs &&
411*b1cdbd2cSJim Jagielski             mp_set_source_rgb &&
412*b1cdbd2cSJim Jagielski             mp_set_font_options &&
413*b1cdbd2cSJim Jagielski             mp_ft_font_options_substitute
414*b1cdbd2cSJim Jagielski         ) )
415*b1cdbd2cSJim Jagielski     {
416*b1cdbd2cSJim Jagielski         osl_unloadModule( mpCairoLib );
417*b1cdbd2cSJim Jagielski 	mpCairoLib = NULL;
418*b1cdbd2cSJim Jagielski #if OSL_DEBUG_LEVEL > 1
419*b1cdbd2cSJim Jagielski         fprintf( stderr, "not all needed symbols were found\n" );
420*b1cdbd2cSJim Jagielski #endif
421*b1cdbd2cSJim Jagielski     }
422*b1cdbd2cSJim Jagielski }
423*b1cdbd2cSJim Jagielski 
isCairoRenderable(const ServerFont & rFont)424*b1cdbd2cSJim Jagielski bool CairoWrapper::isCairoRenderable(const ServerFont& rFont)
425*b1cdbd2cSJim Jagielski {
426*b1cdbd2cSJim Jagielski     return rFont.GetFtFace() && isValid() && rFont.GetAntialiasAdvice() &&
427*b1cdbd2cSJim Jagielski         (rFont.NeedsArtificialBold() ? canEmbolden() : true);
428*b1cdbd2cSJim Jagielski }
429*b1cdbd2cSJim Jagielski 
430*b1cdbd2cSJim Jagielski } //namespace
431*b1cdbd2cSJim Jagielski 
432*b1cdbd2cSJim Jagielski CairoFontsCache::LRUFonts CairoFontsCache::maLRUFonts;
433*b1cdbd2cSJim Jagielski int CairoFontsCache::mnRefCount = 0;
434*b1cdbd2cSJim Jagielski 
CairoFontsCache()435*b1cdbd2cSJim Jagielski CairoFontsCache::CairoFontsCache()
436*b1cdbd2cSJim Jagielski {
437*b1cdbd2cSJim Jagielski     ++mnRefCount;
438*b1cdbd2cSJim Jagielski }
439*b1cdbd2cSJim Jagielski 
~CairoFontsCache()440*b1cdbd2cSJim Jagielski CairoFontsCache::~CairoFontsCache()
441*b1cdbd2cSJim Jagielski {
442*b1cdbd2cSJim Jagielski     --mnRefCount;
443*b1cdbd2cSJim Jagielski     if (!mnRefCount && !maLRUFonts.empty())
444*b1cdbd2cSJim Jagielski     {
445*b1cdbd2cSJim Jagielski         CairoWrapper &rCairo = CairoWrapper::get();
446*b1cdbd2cSJim Jagielski         LRUFonts::iterator aEnd = maLRUFonts.end();
447*b1cdbd2cSJim Jagielski         for (LRUFonts::iterator aI = maLRUFonts.begin(); aI != aEnd; ++aI)
448*b1cdbd2cSJim Jagielski             rCairo.font_face_destroy((cairo_font_face_t*)aI->first);
449*b1cdbd2cSJim Jagielski     }
450*b1cdbd2cSJim Jagielski }
451*b1cdbd2cSJim Jagielski 
CacheFont(void * pFont,void * pId)452*b1cdbd2cSJim Jagielski void CairoFontsCache::CacheFont(void *pFont, void* pId)
453*b1cdbd2cSJim Jagielski {
454*b1cdbd2cSJim Jagielski     maLRUFonts.push_front( std::pair<void*, void *>(pFont, pId) );
455*b1cdbd2cSJim Jagielski     if (maLRUFonts.size() > 8)
456*b1cdbd2cSJim Jagielski     {
457*b1cdbd2cSJim Jagielski         CairoWrapper &rCairo = CairoWrapper::get();
458*b1cdbd2cSJim Jagielski         rCairo.font_face_destroy((cairo_font_face_t*)maLRUFonts.back().first);
459*b1cdbd2cSJim Jagielski         maLRUFonts.pop_back();
460*b1cdbd2cSJim Jagielski     }
461*b1cdbd2cSJim Jagielski }
462*b1cdbd2cSJim Jagielski 
FindCachedFont(void * pId)463*b1cdbd2cSJim Jagielski void* CairoFontsCache::FindCachedFont(void *pId)
464*b1cdbd2cSJim Jagielski {
465*b1cdbd2cSJim Jagielski     LRUFonts::iterator aEnd = maLRUFonts.end();
466*b1cdbd2cSJim Jagielski     for (LRUFonts::iterator aI = maLRUFonts.begin(); aI != aEnd; ++aI)
467*b1cdbd2cSJim Jagielski         if (aI->second == pId)
468*b1cdbd2cSJim Jagielski             return aI->first;
469*b1cdbd2cSJim Jagielski     return NULL;
470*b1cdbd2cSJim Jagielski }
471*b1cdbd2cSJim Jagielski 
DrawCairoAAFontString(const ServerFontLayout & rLayout)472*b1cdbd2cSJim Jagielski void X11SalGraphics::DrawCairoAAFontString( const ServerFontLayout& rLayout )
473*b1cdbd2cSJim Jagielski {
474*b1cdbd2cSJim Jagielski     std::vector<cairo_glyph_t> cairo_glyphs;
475*b1cdbd2cSJim Jagielski     cairo_glyphs.reserve( 256 );
476*b1cdbd2cSJim Jagielski 
477*b1cdbd2cSJim Jagielski     Point aPos;
478*b1cdbd2cSJim Jagielski     sal_GlyphId aGlyphId;
479*b1cdbd2cSJim Jagielski     for( int nStart = 0; rLayout.GetNextGlyphs( 1, &aGlyphId, aPos, nStart ); )
480*b1cdbd2cSJim Jagielski     {
481*b1cdbd2cSJim Jagielski         cairo_glyph_t aGlyph;
482*b1cdbd2cSJim Jagielski         aGlyph.index = aGlyphId & GF_IDXMASK;
483*b1cdbd2cSJim Jagielski         aGlyph.x = aPos.X();
484*b1cdbd2cSJim Jagielski         aGlyph.y = aPos.Y();
485*b1cdbd2cSJim Jagielski         cairo_glyphs.push_back(aGlyph);
486*b1cdbd2cSJim Jagielski     }
487*b1cdbd2cSJim Jagielski 
488*b1cdbd2cSJim Jagielski     if (cairo_glyphs.empty())
489*b1cdbd2cSJim Jagielski         return;
490*b1cdbd2cSJim Jagielski 
491*b1cdbd2cSJim Jagielski     // find a XRenderPictFormat compatible with the Drawable
492*b1cdbd2cSJim Jagielski     XRenderPictFormat* pVisualFormat = static_cast<XRenderPictFormat*>(GetXRenderFormat());
493*b1cdbd2cSJim Jagielski     if( !pVisualFormat )
494*b1cdbd2cSJim Jagielski     {
495*b1cdbd2cSJim Jagielski         Visual* pVisual = GetDisplay()->GetVisual( m_nScreen ).GetVisual();
496*b1cdbd2cSJim Jagielski         pVisualFormat = XRenderPeer::GetInstance().FindVisualFormat( pVisual );
497*b1cdbd2cSJim Jagielski         // cache the XRenderPictFormat
498*b1cdbd2cSJim Jagielski         SetXRenderFormat( static_cast<void*>(pVisualFormat) );
499*b1cdbd2cSJim Jagielski     }
500*b1cdbd2cSJim Jagielski 
501*b1cdbd2cSJim Jagielski     DBG_ASSERT( pVisualFormat!=NULL, "no matching XRenderPictFormat for text" );
502*b1cdbd2cSJim Jagielski     if( !pVisualFormat )
503*b1cdbd2cSJim Jagielski 	    return;
504*b1cdbd2cSJim Jagielski 
505*b1cdbd2cSJim Jagielski     CairoWrapper &rCairo = CairoWrapper::get();
506*b1cdbd2cSJim Jagielski 
507*b1cdbd2cSJim Jagielski     Display* pDisplay = GetXDisplay();
508*b1cdbd2cSJim Jagielski 
509*b1cdbd2cSJim Jagielski     cairo_surface_t *surface = rCairo.xlib_surface_create_with_xrender_format (pDisplay,
510*b1cdbd2cSJim Jagielski         hDrawable_, ScreenOfDisplay(pDisplay, m_nScreen), pVisualFormat, SAL_MAX_INT16, SAL_MAX_INT16);
511*b1cdbd2cSJim Jagielski 
512*b1cdbd2cSJim Jagielski     /*
513*b1cdbd2cSJim Jagielski      * It might be ideal to cache surface and cairo context between calls and
514*b1cdbd2cSJim Jagielski      * only destroy it when the drawable changes, but to do that we need to at
515*b1cdbd2cSJim Jagielski      * least change the SalFrame etc impls to dtor the SalGraphics *before* the
516*b1cdbd2cSJim Jagielski      * destruction of the windows they reference
517*b1cdbd2cSJim Jagielski     */
518*b1cdbd2cSJim Jagielski     cairo_t *cr = rCairo.create(surface);
519*b1cdbd2cSJim Jagielski     rCairo.surface_destroy(surface);
520*b1cdbd2cSJim Jagielski 
521*b1cdbd2cSJim Jagielski     if (const void *pOptions = Application::GetSettings().GetStyleSettings().GetCairoFontOptions())
522*b1cdbd2cSJim Jagielski         rCairo.set_font_options( cr, pOptions);
523*b1cdbd2cSJim Jagielski 
524*b1cdbd2cSJim Jagielski     if( mpClipRegion && !XEmptyRegion( mpClipRegion ) )
525*b1cdbd2cSJim Jagielski     {
526*b1cdbd2cSJim Jagielski         for (long i = 0; i < mpClipRegion->numRects; ++i)
527*b1cdbd2cSJim Jagielski         {
528*b1cdbd2cSJim Jagielski             rCairo.rectangle(cr,
529*b1cdbd2cSJim Jagielski             mpClipRegion->rects[i].x1,
530*b1cdbd2cSJim Jagielski             mpClipRegion->rects[i].y1,
531*b1cdbd2cSJim Jagielski             mpClipRegion->rects[i].x2 - mpClipRegion->rects[i].x1,
532*b1cdbd2cSJim Jagielski             mpClipRegion->rects[i].y2 - mpClipRegion->rects[i].y1);
533*b1cdbd2cSJim Jagielski         }
534*b1cdbd2cSJim Jagielski         rCairo.clip(cr);
535*b1cdbd2cSJim Jagielski     }
536*b1cdbd2cSJim Jagielski 
537*b1cdbd2cSJim Jagielski     rCairo.set_source_rgb(cr,
538*b1cdbd2cSJim Jagielski         SALCOLOR_RED(nTextColor_)/255.0,
539*b1cdbd2cSJim Jagielski         SALCOLOR_GREEN(nTextColor_)/255.0,
540*b1cdbd2cSJim Jagielski         SALCOLOR_BLUE(nTextColor_)/255.0);
541*b1cdbd2cSJim Jagielski 
542*b1cdbd2cSJim Jagielski     ServerFont& rFont = rLayout.GetServerFont();
543*b1cdbd2cSJim Jagielski 
544*b1cdbd2cSJim Jagielski     cairo_font_face_t* font_face = NULL;
545*b1cdbd2cSJim Jagielski 
546*b1cdbd2cSJim Jagielski     void *pId = rFont.GetFtFace();
547*b1cdbd2cSJim Jagielski     font_face = (cairo_font_face_t*)m_aCairoFontsCache.FindCachedFont(pId);
548*b1cdbd2cSJim Jagielski     if (!font_face)
549*b1cdbd2cSJim Jagielski     {
550*b1cdbd2cSJim Jagielski         font_face = rCairo.ft_font_face_create_for_ft_face(pId, rFont.GetLoadFlags());
551*b1cdbd2cSJim Jagielski         m_aCairoFontsCache.CacheFont(font_face, pId);
552*b1cdbd2cSJim Jagielski     }
553*b1cdbd2cSJim Jagielski 
554*b1cdbd2cSJim Jagielski     rCairo.set_font_face(cr, font_face);
555*b1cdbd2cSJim Jagielski 
556*b1cdbd2cSJim Jagielski     cairo_matrix_t m;
557*b1cdbd2cSJim Jagielski     const ImplFontSelectData& rFSD = rFont.GetFontSelData();
558*b1cdbd2cSJim Jagielski     int nWidth = rFSD.mnWidth ? rFSD.mnWidth : rFSD.mnHeight;
559*b1cdbd2cSJim Jagielski 
560*b1cdbd2cSJim Jagielski     rCairo.matrix_init_identity(&m);
561*b1cdbd2cSJim Jagielski 
562*b1cdbd2cSJim Jagielski     if (rLayout.GetOrientation())
563*b1cdbd2cSJim Jagielski         rCairo.matrix_rotate(&m, (3600 - rLayout.GetOrientation()) * M_PI / 1800.0);
564*b1cdbd2cSJim Jagielski 
565*b1cdbd2cSJim Jagielski     rCairo.matrix_scale(&m, nWidth, rFSD.mnHeight);
566*b1cdbd2cSJim Jagielski     if (rFont.NeedsArtificialItalic())
567*b1cdbd2cSJim Jagielski         m.xy = -m.xx * 0x6000L / 0x10000L;
568*b1cdbd2cSJim Jagielski 
569*b1cdbd2cSJim Jagielski     rCairo.set_font_matrix(cr, &m);
570*b1cdbd2cSJim Jagielski     rCairo.show_glyphs(cr, &cairo_glyphs[0], cairo_glyphs.size());
571*b1cdbd2cSJim Jagielski     rCairo.destroy(cr);
572*b1cdbd2cSJim Jagielski }
573*b1cdbd2cSJim Jagielski 
574*b1cdbd2cSJim Jagielski //--------------------------------------------------------------------------
575*b1cdbd2cSJim Jagielski 
DrawServerAAFontString(const ServerFontLayout & rLayout)576*b1cdbd2cSJim Jagielski void X11SalGraphics::DrawServerAAFontString( const ServerFontLayout& rLayout )
577*b1cdbd2cSJim Jagielski {
578*b1cdbd2cSJim Jagielski 	// get xrender target for this drawable
579*b1cdbd2cSJim Jagielski     Picture aDstPic = GetXRenderPicture();
580*b1cdbd2cSJim Jagielski 	if( !aDstPic )
581*b1cdbd2cSJim Jagielski 		return;
582*b1cdbd2cSJim Jagielski 
583*b1cdbd2cSJim Jagielski     // get a XRenderPicture for the font foreground
584*b1cdbd2cSJim Jagielski     // TODO: move into own method
585*b1cdbd2cSJim Jagielski     XRenderPeer& rRenderPeer = XRenderPeer::GetInstance();
586*b1cdbd2cSJim Jagielski 	XRenderPictFormat* pVisualFormat = (XRenderPictFormat*)GetXRenderFormat();
587*b1cdbd2cSJim Jagielski 	DBG_ASSERT( pVisualFormat, "we already have a render picture, but XRenderPictFormat==NULL???");
588*b1cdbd2cSJim Jagielski     const int nVisualDepth = pVisualFormat->depth;
589*b1cdbd2cSJim Jagielski     SalDisplay::RenderEntry& rEntry = GetDisplay()->GetRenderEntries( m_nScreen )[ nVisualDepth ];
590*b1cdbd2cSJim Jagielski     if( !rEntry.m_aPicture )
591*b1cdbd2cSJim Jagielski     {
592*b1cdbd2cSJim Jagielski         // create and cache XRenderPicture for the font foreground
593*b1cdbd2cSJim Jagielski         Display* pDisplay = GetXDisplay();
594*b1cdbd2cSJim Jagielski #ifdef DEBUG
595*b1cdbd2cSJim Jagielski         int iDummy;
596*b1cdbd2cSJim Jagielski         unsigned uDummy;
597*b1cdbd2cSJim Jagielski         XLIB_Window wDummy;
598*b1cdbd2cSJim Jagielski         unsigned int nDrawDepth;
599*b1cdbd2cSJim Jagielski         ::XGetGeometry( pDisplay, hDrawable_, &wDummy, &iDummy, &iDummy,
600*b1cdbd2cSJim Jagielski                       &uDummy, &uDummy, &uDummy, &nDrawDepth );
601*b1cdbd2cSJim Jagielski         DBG_ASSERT( static_cast<unsigned>(nVisualDepth) == nDrawDepth, "depth messed up for XRender" );
602*b1cdbd2cSJim Jagielski #endif
603*b1cdbd2cSJim Jagielski 
604*b1cdbd2cSJim Jagielski         rEntry.m_aPixmap = ::XCreatePixmap( pDisplay, hDrawable_, 1, 1, nVisualDepth );
605*b1cdbd2cSJim Jagielski 
606*b1cdbd2cSJim Jagielski         XRenderPictureAttributes aAttr;
607*b1cdbd2cSJim Jagielski         aAttr.repeat = true;
608*b1cdbd2cSJim Jagielski         rEntry.m_aPicture = rRenderPeer.CreatePicture ( rEntry.m_aPixmap, pVisualFormat, CPRepeat, &aAttr );
609*b1cdbd2cSJim Jagielski     }
610*b1cdbd2cSJim Jagielski 
611*b1cdbd2cSJim Jagielski     // set font foreground color and opacity
612*b1cdbd2cSJim Jagielski     XRenderColor aRenderColor = GetXRenderColor( nTextColor_ );
613*b1cdbd2cSJim Jagielski     rRenderPeer.FillRectangle( PictOpSrc, rEntry.m_aPicture, &aRenderColor, 0, 0, 1, 1 );
614*b1cdbd2cSJim Jagielski 
615*b1cdbd2cSJim Jagielski     // set clipping
616*b1cdbd2cSJim Jagielski     // TODO: move into GetXRenderPicture()?
617*b1cdbd2cSJim Jagielski     if( mpClipRegion && !XEmptyRegion( mpClipRegion ) )
618*b1cdbd2cSJim Jagielski         rRenderPeer.SetPictureClipRegion( aDstPic, mpClipRegion );
619*b1cdbd2cSJim Jagielski 
620*b1cdbd2cSJim Jagielski     ServerFont& rFont = rLayout.GetServerFont();
621*b1cdbd2cSJim Jagielski     X11GlyphPeer& rGlyphPeer = X11GlyphCache::GetInstance().GetPeer();
622*b1cdbd2cSJim Jagielski     GlyphSet aGlyphSet = rGlyphPeer.GetGlyphSet( rFont, m_nScreen );
623*b1cdbd2cSJim Jagielski 
624*b1cdbd2cSJim Jagielski     Point aPos;
625*b1cdbd2cSJim Jagielski     static const int MAXGLYPHS = 160;
626*b1cdbd2cSJim Jagielski     sal_GlyphId aGlyphAry[ MAXGLYPHS ];
627*b1cdbd2cSJim Jagielski     int nMaxGlyphs = rLayout.GetOrientation() ? 1 : MAXGLYPHS;
628*b1cdbd2cSJim Jagielski     for( int nStart = 0;;)
629*b1cdbd2cSJim Jagielski     {
630*b1cdbd2cSJim Jagielski         int nGlyphs = rLayout.GetNextGlyphs( nMaxGlyphs, aGlyphAry, aPos, nStart );
631*b1cdbd2cSJim Jagielski         if( !nGlyphs )
632*b1cdbd2cSJim Jagielski             break;
633*b1cdbd2cSJim Jagielski 
634*b1cdbd2cSJim Jagielski         // #i51924# avoid 32->16bit coordinate truncation problem in X11
635*b1cdbd2cSJim Jagielski         // TODO: reevaluate once displays with >30000 pixels are available
636*b1cdbd2cSJim Jagielski         if( aPos.X() >= 30000 || aPos.Y() >= 30000 )
637*b1cdbd2cSJim Jagielski             continue;
638*b1cdbd2cSJim Jagielski 
639*b1cdbd2cSJim Jagielski         unsigned int aRenderAry[ MAXGLYPHS ];
640*b1cdbd2cSJim Jagielski         for( int i = 0; i < nGlyphs; ++i )
641*b1cdbd2cSJim Jagielski              aRenderAry[ i ] = rGlyphPeer.GetXRGlyph( rFont, aGlyphAry[i] );
642*b1cdbd2cSJim Jagielski         rRenderPeer.CompositeString32( rEntry.m_aPicture, aDstPic,
643*b1cdbd2cSJim Jagielski            aGlyphSet, aPos.X(), aPos.Y(), aRenderAry, nGlyphs );
644*b1cdbd2cSJim Jagielski     }
645*b1cdbd2cSJim Jagielski }
646*b1cdbd2cSJim Jagielski 
647*b1cdbd2cSJim Jagielski //--------------------------------------------------------------------------
648*b1cdbd2cSJim Jagielski 
DrawServerAAForcedString(const ServerFontLayout & rLayout)649*b1cdbd2cSJim Jagielski bool X11SalGraphics::DrawServerAAForcedString( const ServerFontLayout& rLayout )
650*b1cdbd2cSJim Jagielski {
651*b1cdbd2cSJim Jagielski     ServerFont& rFont = rLayout.GetServerFont();
652*b1cdbd2cSJim Jagielski 
653*b1cdbd2cSJim Jagielski     // prepare glyphs and get extent of operation
654*b1cdbd2cSJim Jagielski     X11GlyphPeer& rGlyphPeer = X11GlyphCache::GetInstance().GetPeer();
655*b1cdbd2cSJim Jagielski     int nXmin = 0;
656*b1cdbd2cSJim Jagielski     int nXmax = 0;
657*b1cdbd2cSJim Jagielski     int nYmin = 0;
658*b1cdbd2cSJim Jagielski     int nYmax = 0;
659*b1cdbd2cSJim Jagielski     int nStart = 0;
660*b1cdbd2cSJim Jagielski     Point aPos;
661*b1cdbd2cSJim Jagielski     sal_GlyphId nGlyph;
662*b1cdbd2cSJim Jagielski     for( bool bFirst=true; rLayout.GetNextGlyphs( 1, &nGlyph, aPos, nStart ); )
663*b1cdbd2cSJim Jagielski     {
664*b1cdbd2cSJim Jagielski         const RawBitmap* const pRawBitmap = rGlyphPeer.GetRawBitmap( rFont, nGlyph );
665*b1cdbd2cSJim Jagielski         if( !pRawBitmap )
666*b1cdbd2cSJim Jagielski             continue;
667*b1cdbd2cSJim Jagielski 
668*b1cdbd2cSJim Jagielski         const int nX1 = aPos.X() + pRawBitmap->mnXOffset;
669*b1cdbd2cSJim Jagielski         const int nY1 = aPos.Y() + pRawBitmap->mnYOffset;
670*b1cdbd2cSJim Jagielski         const int nX2 = nX1 + pRawBitmap->mnWidth;
671*b1cdbd2cSJim Jagielski         const int nY2 = nY1 + pRawBitmap->mnHeight;
672*b1cdbd2cSJim Jagielski 
673*b1cdbd2cSJim Jagielski         if( bFirst )
674*b1cdbd2cSJim Jagielski         {
675*b1cdbd2cSJim Jagielski             bFirst = false;
676*b1cdbd2cSJim Jagielski             nXmin = nX1;
677*b1cdbd2cSJim Jagielski             nXmax = nX2;
678*b1cdbd2cSJim Jagielski             nYmin = nY1;
679*b1cdbd2cSJim Jagielski             nYmax = nY2;
680*b1cdbd2cSJim Jagielski         }
681*b1cdbd2cSJim Jagielski         else
682*b1cdbd2cSJim Jagielski         {
683*b1cdbd2cSJim Jagielski             if( nXmin > nX1 ) nXmin = nX1;
684*b1cdbd2cSJim Jagielski             if( nXmax < nX2 ) nXmax = nX2;
685*b1cdbd2cSJim Jagielski             if( nYmin > nY1 ) nYmin = nY1;
686*b1cdbd2cSJim Jagielski             if( nYmax < nY2 ) nYmax = nY2;
687*b1cdbd2cSJim Jagielski         }
688*b1cdbd2cSJim Jagielski     }
689*b1cdbd2cSJim Jagielski 
690*b1cdbd2cSJim Jagielski     // get XImage
691*b1cdbd2cSJim Jagielski     GetDisplay()->GetXLib()->PushXErrorLevel( true );
692*b1cdbd2cSJim Jagielski     Display* pDisplay = GetXDisplay();
693*b1cdbd2cSJim Jagielski 
694*b1cdbd2cSJim Jagielski     XRectangle aXRect;
695*b1cdbd2cSJim Jagielski     long nWidth = 1, nHeight = 1;
696*b1cdbd2cSJim Jagielski     if( m_pFrame )
697*b1cdbd2cSJim Jagielski         nWidth = m_pFrame->maGeometry.nWidth, nHeight = m_pFrame->maGeometry.nHeight;
698*b1cdbd2cSJim Jagielski     else if( m_pVDev )
699*b1cdbd2cSJim Jagielski         nWidth = m_pVDev->GetWidth(), nHeight = m_pVDev->GetHeight();
700*b1cdbd2cSJim Jagielski 
701*b1cdbd2cSJim Jagielski     if( mpClipRegion && !XEmptyRegion( mpClipRegion ) )
702*b1cdbd2cSJim Jagielski     {
703*b1cdbd2cSJim Jagielski         // get bounding box
704*b1cdbd2cSJim Jagielski         XClipBox( mpClipRegion, &aXRect );
705*b1cdbd2cSJim Jagielski         // clip with window
706*b1cdbd2cSJim Jagielski         if( aXRect.x < 0 ) aXRect.x = 0;
707*b1cdbd2cSJim Jagielski 
708*b1cdbd2cSJim Jagielski         if( aXRect.y < 0 ) aXRect.y = 0;
709*b1cdbd2cSJim Jagielski         if( aXRect.width+aXRect.x > nWidth ) aXRect.width = nWidth-aXRect.x;
710*b1cdbd2cSJim Jagielski         if( aXRect.height+aXRect.y > nHeight ) aXRect.height = nHeight-aXRect.y;
711*b1cdbd2cSJim Jagielski     }
712*b1cdbd2cSJim Jagielski     else
713*b1cdbd2cSJim Jagielski     {
714*b1cdbd2cSJim Jagielski         aXRect.x = 0;
715*b1cdbd2cSJim Jagielski         aXRect.y = 0;
716*b1cdbd2cSJim Jagielski         aXRect.width = nWidth;
717*b1cdbd2cSJim Jagielski         aXRect.height = nHeight;
718*b1cdbd2cSJim Jagielski     }
719*b1cdbd2cSJim Jagielski     if( m_pFrame )
720*b1cdbd2cSJim Jagielski     {
721*b1cdbd2cSJim Jagielski         // clip with screen
722*b1cdbd2cSJim Jagielski         int nScreenX = m_pFrame->maGeometry.nX+aXRect.x;
723*b1cdbd2cSJim Jagielski         int nScreenY = m_pFrame->maGeometry.nY+aXRect.y;
724*b1cdbd2cSJim Jagielski         const Size& rScreenSize = GetDisplay()->getDataForScreen( m_nScreen ).m_aSize;
725*b1cdbd2cSJim Jagielski         int nScreenW = rScreenSize.Width();
726*b1cdbd2cSJim Jagielski         int nScreenH = rScreenSize.Height();
727*b1cdbd2cSJim Jagielski         if( nScreenX < 0 )
728*b1cdbd2cSJim Jagielski             aXRect.x -= nScreenX, aXRect.width += nScreenX;
729*b1cdbd2cSJim Jagielski         if( nScreenX+aXRect.width > nScreenW )
730*b1cdbd2cSJim Jagielski             aXRect.width = nScreenW-nScreenX;
731*b1cdbd2cSJim Jagielski         if( nScreenY < 0 )
732*b1cdbd2cSJim Jagielski             aXRect.y -= nScreenY, aXRect.height += nScreenY;
733*b1cdbd2cSJim Jagielski         if( nScreenY+aXRect.height > nScreenH )
734*b1cdbd2cSJim Jagielski             aXRect.height = nScreenH-nScreenY;
735*b1cdbd2cSJim Jagielski     }
736*b1cdbd2cSJim Jagielski 
737*b1cdbd2cSJim Jagielski 
738*b1cdbd2cSJim Jagielski     if( nXmin < aXRect.x )  nXmin = aXRect.x;
739*b1cdbd2cSJim Jagielski     if( nYmin < aXRect.y )  nYmin = aXRect.y;
740*b1cdbd2cSJim Jagielski     if( nXmax >= aXRect.x+aXRect.width )    nXmax = aXRect.x + aXRect.width - 1;
741*b1cdbd2cSJim Jagielski     if( nYmax >= aXRect.y+aXRect.height )   nYmax = aXRect.y + aXRect.height - 1;
742*b1cdbd2cSJim Jagielski 
743*b1cdbd2cSJim Jagielski     if( nXmin > nXmax )
744*b1cdbd2cSJim Jagielski         return false;
745*b1cdbd2cSJim Jagielski     if( nYmin > nYmax )
746*b1cdbd2cSJim Jagielski         return false;
747*b1cdbd2cSJim Jagielski 
748*b1cdbd2cSJim Jagielski     XImage* pImg = XGetImage( pDisplay, hDrawable_,
749*b1cdbd2cSJim Jagielski                               nXmin, nYmin,
750*b1cdbd2cSJim Jagielski                               (nXmax-nXmin+1), (nYmax-nYmin+1),
751*b1cdbd2cSJim Jagielski                               ~0, ZPixmap );
752*b1cdbd2cSJim Jagielski     if( pImg == NULL )
753*b1cdbd2cSJim Jagielski     {
754*b1cdbd2cSJim Jagielski         if( m_pFrame )
755*b1cdbd2cSJim Jagielski         {
756*b1cdbd2cSJim Jagielski             // the reason we did not get an image could be that the frame
757*b1cdbd2cSJim Jagielski             // geometry changed in the meantime; lets get the current geometry
758*b1cdbd2cSJim Jagielski             // and clip against the current window size as well as the screen
759*b1cdbd2cSJim Jagielski             // with the current frame position
760*b1cdbd2cSJim Jagielski             const Size& rScreenSize = GetDisplay()->getDataForScreen(m_nScreen).m_aSize;
761*b1cdbd2cSJim Jagielski             int nScreenW = rScreenSize.Width();
762*b1cdbd2cSJim Jagielski             int nScreenH = rScreenSize.Height();
763*b1cdbd2cSJim Jagielski             XLIB_Window aRoot = None;
764*b1cdbd2cSJim Jagielski             int x = 0, y = 0;
765*b1cdbd2cSJim Jagielski             unsigned int w = 0, h = 0, bw = 0, d;
766*b1cdbd2cSJim Jagielski             XGetGeometry( pDisplay, hDrawable_, &aRoot, &x, &y, &w, &h, &bw, &d );
767*b1cdbd2cSJim Jagielski             XTranslateCoordinates( pDisplay, hDrawable_, aRoot, 0, 0, &x, &y, &aRoot );
768*b1cdbd2cSJim Jagielski             if( nXmin + x < 0 ) // clip on left screen edge
769*b1cdbd2cSJim Jagielski                 nXmin += x-nXmin;
770*b1cdbd2cSJim Jagielski             if( nYmin + y < 0 ) // clip on top screen edge
771*b1cdbd2cSJim Jagielski                 nYmin += y-nYmin;
772*b1cdbd2cSJim Jagielski             if( nXmax >= int(w) ) // clip on right window egde
773*b1cdbd2cSJim Jagielski                 nXmax = w-1;
774*b1cdbd2cSJim Jagielski             if( nYmax >= int(h) ) // clip on bottom window edge
775*b1cdbd2cSJim Jagielski                 nYmax = h-1;
776*b1cdbd2cSJim Jagielski             if( nXmax + x >= nScreenW ) // clip on right screen edge
777*b1cdbd2cSJim Jagielski                 nXmax -= (nXmax + x - nScreenW)+1;
778*b1cdbd2cSJim Jagielski             if( nYmax + y >= nScreenH ) // clip on bottom screen edge
779*b1cdbd2cSJim Jagielski                 nYmax -= (nYmax + y - nScreenH)+1;
780*b1cdbd2cSJim Jagielski             if( nXmax >= nXmin && nYmax >= nYmin )
781*b1cdbd2cSJim Jagielski             {
782*b1cdbd2cSJim Jagielski                 // try again to get the image
783*b1cdbd2cSJim Jagielski                 pImg = XGetImage( pDisplay, hDrawable_,
784*b1cdbd2cSJim Jagielski                                   nXmin, nYmin,
785*b1cdbd2cSJim Jagielski                                   (nXmax-nXmin+1), (nYmax-nYmin+1),
786*b1cdbd2cSJim Jagielski                                   ~0, ZPixmap );
787*b1cdbd2cSJim Jagielski             }
788*b1cdbd2cSJim Jagielski         }
789*b1cdbd2cSJim Jagielski         if( pImg == NULL )
790*b1cdbd2cSJim Jagielski         {
791*b1cdbd2cSJim Jagielski             GetDisplay()->GetXLib()->PopXErrorLevel();
792*b1cdbd2cSJim Jagielski             return false;
793*b1cdbd2cSJim Jagielski         }
794*b1cdbd2cSJim Jagielski     }
795*b1cdbd2cSJim Jagielski 
796*b1cdbd2cSJim Jagielski     // prepare context
797*b1cdbd2cSJim Jagielski     GC nGC = GetFontGC();
798*b1cdbd2cSJim Jagielski     XGCValues aGCVal;
799*b1cdbd2cSJim Jagielski     XGetGCValues( pDisplay, nGC, GCForeground, &aGCVal );
800*b1cdbd2cSJim Jagielski 
801*b1cdbd2cSJim Jagielski     unsigned long nOrigColor = XGetPixel( pImg, 0, 0 );
802*b1cdbd2cSJim Jagielski     XPutPixel( pImg, 0, 0, aGCVal.foreground );
803*b1cdbd2cSJim Jagielski     unsigned char aColor[4];
804*b1cdbd2cSJim Jagielski     aColor[0] = pImg->data[0];
805*b1cdbd2cSJim Jagielski     aColor[1] = pImg->data[1];
806*b1cdbd2cSJim Jagielski     aColor[2] = pImg->data[2];
807*b1cdbd2cSJim Jagielski     aColor[3] = pImg->data[3];
808*b1cdbd2cSJim Jagielski     XPutPixel( pImg, 0, 0, nOrigColor );
809*b1cdbd2cSJim Jagielski 
810*b1cdbd2cSJim Jagielski     // work on XImage
811*b1cdbd2cSJim Jagielski     const int bpp = pImg->bits_per_pixel >> 3;
812*b1cdbd2cSJim Jagielski     for( nStart = 0; rLayout.GetNextGlyphs( 1, &nGlyph, aPos, nStart ); )
813*b1cdbd2cSJim Jagielski     {
814*b1cdbd2cSJim Jagielski         const RawBitmap* const pRawBitmap = rGlyphPeer.GetRawBitmap( rFont, nGlyph );
815*b1cdbd2cSJim Jagielski         if( !pRawBitmap )
816*b1cdbd2cSJim Jagielski             continue;
817*b1cdbd2cSJim Jagielski 
818*b1cdbd2cSJim Jagielski         const int nX1 = aPos.X() + pRawBitmap->mnXOffset;
819*b1cdbd2cSJim Jagielski         const int nY1 = aPos.Y() + pRawBitmap->mnYOffset;
820*b1cdbd2cSJim Jagielski 
821*b1cdbd2cSJim Jagielski         if( (nX1 <= nXmax) && (int(nX1 + pRawBitmap->mnWidth) > nXmin)
822*b1cdbd2cSJim Jagielski         &&  (nY1 <= nYmax) && (int(nY1 + pRawBitmap->mnHeight) > nYmin) )
823*b1cdbd2cSJim Jagielski         {
824*b1cdbd2cSJim Jagielski             const unsigned char* p10 = pRawBitmap->mpBits;
825*b1cdbd2cSJim Jagielski             unsigned char* p20 = (unsigned char*)pImg->data;                // dest left limit
826*b1cdbd2cSJim Jagielski             p20 += (nY1 - nYmin) * pImg->bytes_per_line;
827*b1cdbd2cSJim Jagielski             unsigned char* p21 = p20 + (nX1 - nXmin + pImg->xoffset) * bpp;
828*b1cdbd2cSJim Jagielski             int y = pRawBitmap->mnHeight;
829*b1cdbd2cSJim Jagielski             if( y > nYmax - nY1 )
830*b1cdbd2cSJim Jagielski                 y = nYmax - nY1 + 1;
831*b1cdbd2cSJim Jagielski             while( --y >= 0 )
832*b1cdbd2cSJim Jagielski             {
833*b1cdbd2cSJim Jagielski                 if( p20 >= (unsigned char*)pImg->data )
834*b1cdbd2cSJim Jagielski                 {
835*b1cdbd2cSJim Jagielski                     unsigned char* const p22 = p20 + pImg->width * bpp; // dest right limit
836*b1cdbd2cSJim Jagielski                     unsigned char* pDst = p21;
837*b1cdbd2cSJim Jagielski                     const unsigned char* pSrc = p10;
838*b1cdbd2cSJim Jagielski                     for( int x = pRawBitmap->mnWidth; (--x >= 0) && (p22 > pDst); ++pSrc )
839*b1cdbd2cSJim Jagielski                     {
840*b1cdbd2cSJim Jagielski                         if( (*pSrc == 0) || (p20 > pDst) )          // keep background
841*b1cdbd2cSJim Jagielski                             pDst += bpp;
842*b1cdbd2cSJim Jagielski                         else if( *pSrc == 0xFF )                    // paint foreground
843*b1cdbd2cSJim Jagielski                         {
844*b1cdbd2cSJim Jagielski                             const unsigned char* pColor = aColor;
845*b1cdbd2cSJim Jagielski                             for( int z = bpp; --z >= 0; ++pColor, ++pDst )
846*b1cdbd2cSJim Jagielski                                 *pDst = *pColor;
847*b1cdbd2cSJim Jagielski                         }
848*b1cdbd2cSJim Jagielski                         else                                        // blend fg into bg
849*b1cdbd2cSJim Jagielski                         {
850*b1cdbd2cSJim Jagielski                             const unsigned char* pColor = aColor;
851*b1cdbd2cSJim Jagielski                             for( int z = bpp; --z >= 0; ++pColor, ++pDst )
852*b1cdbd2cSJim Jagielski                                 // theoretically it should be *257) >> 16
853*b1cdbd2cSJim Jagielski                                 // but the error is <0.4% worst case and we are in
854*b1cdbd2cSJim Jagielski                                 // the innermost loop of very perf-sensitive code
855*b1cdbd2cSJim Jagielski 
856*b1cdbd2cSJim Jagielski                                 *pDst += (*pSrc * ((int)*pColor - *pDst)) >> 8;
857*b1cdbd2cSJim Jagielski                         }
858*b1cdbd2cSJim Jagielski                     }
859*b1cdbd2cSJim Jagielski                 }
860*b1cdbd2cSJim Jagielski                 p10 += pRawBitmap->mnScanlineSize;
861*b1cdbd2cSJim Jagielski                 p20 += pImg->bytes_per_line;
862*b1cdbd2cSJim Jagielski                 p21 += pImg->bytes_per_line;
863*b1cdbd2cSJim Jagielski             }
864*b1cdbd2cSJim Jagielski         }
865*b1cdbd2cSJim Jagielski     }
866*b1cdbd2cSJim Jagielski 
867*b1cdbd2cSJim Jagielski     // put XImage
868*b1cdbd2cSJim Jagielski     XPutImage( pDisplay, hDrawable_, nGC, pImg,
869*b1cdbd2cSJim Jagielski         0, 0, nXmin, nYmin, (nXmax - nXmin + 1), (nYmax - nYmin + 1) );
870*b1cdbd2cSJim Jagielski     XDestroyImage( pImg );
871*b1cdbd2cSJim Jagielski 
872*b1cdbd2cSJim Jagielski     GetDisplay()->GetXLib()->PopXErrorLevel();
873*b1cdbd2cSJim Jagielski     return true;
874*b1cdbd2cSJim Jagielski }
875*b1cdbd2cSJim Jagielski 
876*b1cdbd2cSJim Jagielski //--------------------------------------------------------------------------
877*b1cdbd2cSJim Jagielski 
DrawServerSimpleFontString(const ServerFontLayout & rSalLayout)878*b1cdbd2cSJim Jagielski void X11SalGraphics::DrawServerSimpleFontString( const ServerFontLayout& rSalLayout )
879*b1cdbd2cSJim Jagielski {
880*b1cdbd2cSJim Jagielski     ServerFont& rFont = rSalLayout.GetServerFont();
881*b1cdbd2cSJim Jagielski     X11GlyphPeer& rGlyphPeer = X11GlyphCache::GetInstance().GetPeer();
882*b1cdbd2cSJim Jagielski 
883*b1cdbd2cSJim Jagielski     Display* pDisplay = GetXDisplay();
884*b1cdbd2cSJim Jagielski     GC nGC = GetFontGC();
885*b1cdbd2cSJim Jagielski 
886*b1cdbd2cSJim Jagielski     XGCValues aGCVal;
887*b1cdbd2cSJim Jagielski     aGCVal.fill_style = FillStippled;
888*b1cdbd2cSJim Jagielski     aGCVal.line_width = 0;
889*b1cdbd2cSJim Jagielski     GC tmpGC = XCreateGC( pDisplay, hDrawable_, GCFillStyle|GCLineWidth, &aGCVal );
890*b1cdbd2cSJim Jagielski     XCopyGC( pDisplay, nGC, (1<<GCLastBit)-(1+GCFillStyle+GCLineWidth), tmpGC );
891*b1cdbd2cSJim Jagielski 
892*b1cdbd2cSJim Jagielski     Point aPos;
893*b1cdbd2cSJim Jagielski     sal_GlyphId nGlyph;
894*b1cdbd2cSJim Jagielski     for( int nStart = 0; rSalLayout.GetNextGlyphs( 1, &nGlyph, aPos, nStart ); )
895*b1cdbd2cSJim Jagielski     {
896*b1cdbd2cSJim Jagielski         // #i51924# avoid 32->16bit coordinate truncation problem in X11
897*b1cdbd2cSJim Jagielski         // TODO: reevaluate once displays with >30000 pixels are available
898*b1cdbd2cSJim Jagielski         if( aPos.X() >= 30000 || aPos.Y() >= 30000 )
899*b1cdbd2cSJim Jagielski             continue;
900*b1cdbd2cSJim Jagielski 
901*b1cdbd2cSJim Jagielski         Pixmap aStipple = rGlyphPeer.GetPixmap( rFont, nGlyph, m_nScreen );
902*b1cdbd2cSJim Jagielski         const GlyphMetric& rGM = rFont.GetGlyphMetric( nGlyph );
903*b1cdbd2cSJim Jagielski 
904*b1cdbd2cSJim Jagielski         if( aStipple != None )
905*b1cdbd2cSJim Jagielski         {
906*b1cdbd2cSJim Jagielski             const int nDestX    = aPos.X() + rGM.GetOffset().X();
907*b1cdbd2cSJim Jagielski             const int nDestY    = aPos.Y() + rGM.GetOffset().Y();
908*b1cdbd2cSJim Jagielski 
909*b1cdbd2cSJim Jagielski             aGCVal.stipple      = aStipple;
910*b1cdbd2cSJim Jagielski             aGCVal.ts_x_origin  = nDestX;
911*b1cdbd2cSJim Jagielski             aGCVal.ts_y_origin  = nDestY;
912*b1cdbd2cSJim Jagielski             XChangeGC( pDisplay, tmpGC, GCStipple|GCTileStipXOrigin|GCTileStipYOrigin, &aGCVal );
913*b1cdbd2cSJim Jagielski 
914*b1cdbd2cSJim Jagielski             const int nWidth    = rGM.GetSize().Width();
915*b1cdbd2cSJim Jagielski             const int nHeight   = rGM.GetSize().Height();
916*b1cdbd2cSJim Jagielski             XFillRectangle( pDisplay, hDrawable_, tmpGC, nDestX, nDestY, nWidth, nHeight );
917*b1cdbd2cSJim Jagielski         }
918*b1cdbd2cSJim Jagielski     }
919*b1cdbd2cSJim Jagielski 
920*b1cdbd2cSJim Jagielski     XFreeGC( pDisplay, tmpGC );
921*b1cdbd2cSJim Jagielski }
922*b1cdbd2cSJim Jagielski 
923*b1cdbd2cSJim Jagielski //--------------------------------------------------------------------------
924*b1cdbd2cSJim Jagielski 
DrawServerFontLayout(const ServerFontLayout & rLayout)925*b1cdbd2cSJim Jagielski void X11SalGraphics::DrawServerFontLayout( const ServerFontLayout& rLayout )
926*b1cdbd2cSJim Jagielski {
927*b1cdbd2cSJim Jagielski     // draw complex text
928*b1cdbd2cSJim Jagielski     ServerFont& rFont = rLayout.GetServerFont();
929*b1cdbd2cSJim Jagielski 	const bool bVertical = rFont.GetFontSelData().mbVertical;
930*b1cdbd2cSJim Jagielski 
931*b1cdbd2cSJim Jagielski     if( !bVertical && CairoWrapper::get().isCairoRenderable(rFont) )
932*b1cdbd2cSJim Jagielski         DrawCairoAAFontString( rLayout );
933*b1cdbd2cSJim Jagielski     else
934*b1cdbd2cSJim Jagielski     {
935*b1cdbd2cSJim Jagielski         X11GlyphPeer& rGlyphPeer = X11GlyphCache::GetInstance().GetPeer();
936*b1cdbd2cSJim Jagielski         if( rGlyphPeer.GetGlyphSet( rFont, m_nScreen ) )
937*b1cdbd2cSJim Jagielski             DrawServerAAFontString( rLayout );
938*b1cdbd2cSJim Jagielski         else if( !rGlyphPeer.ForcedAntialiasing( rFont, m_nScreen ) )
939*b1cdbd2cSJim Jagielski             DrawServerSimpleFontString( rLayout );
940*b1cdbd2cSJim Jagielski         else
941*b1cdbd2cSJim Jagielski             DrawServerAAForcedString( rLayout );
942*b1cdbd2cSJim Jagielski     }
943*b1cdbd2cSJim Jagielski }
944*b1cdbd2cSJim Jagielski 
945*b1cdbd2cSJim Jagielski //--------------------------------------------------------------------------
946*b1cdbd2cSJim Jagielski 
GetImplFontCharMap() const947*b1cdbd2cSJim Jagielski const ImplFontCharMap* X11SalGraphics::GetImplFontCharMap() const
948*b1cdbd2cSJim Jagielski {
949*b1cdbd2cSJim Jagielski     if( !mpServerFont[0] )
950*b1cdbd2cSJim Jagielski         return NULL;
951*b1cdbd2cSJim Jagielski 
952*b1cdbd2cSJim Jagielski     const ImplFontCharMap* pIFCMap = mpServerFont[0]->GetImplFontCharMap();
953*b1cdbd2cSJim Jagielski     return pIFCMap;
954*b1cdbd2cSJim Jagielski }
955*b1cdbd2cSJim Jagielski 
956*b1cdbd2cSJim Jagielski // ----------------------------------------------------------------------------
957*b1cdbd2cSJim Jagielski //
958*b1cdbd2cSJim Jagielski // SalGraphics
959*b1cdbd2cSJim Jagielski //
960*b1cdbd2cSJim Jagielski // ----------------------------------------------------------------------------
961*b1cdbd2cSJim Jagielski 
SetFont(ImplFontSelectData * pEntry,int nFallbackLevel)962*b1cdbd2cSJim Jagielski sal_uInt16 X11SalGraphics::SetFont( ImplFontSelectData *pEntry, int nFallbackLevel )
963*b1cdbd2cSJim Jagielski {
964*b1cdbd2cSJim Jagielski     sal_uInt16 nRetVal = 0;
965*b1cdbd2cSJim Jagielski     if( !setFont( pEntry, nFallbackLevel ) )
966*b1cdbd2cSJim Jagielski         nRetVal |= SAL_SETFONT_BADFONT;
967*b1cdbd2cSJim Jagielski     if( bPrinter_ || (mpServerFont[ nFallbackLevel ] != NULL) )
968*b1cdbd2cSJim Jagielski         nRetVal |= SAL_SETFONT_USEDRAWTEXTARRAY;
969*b1cdbd2cSJim Jagielski     return nRetVal;
970*b1cdbd2cSJim Jagielski }
971*b1cdbd2cSJim Jagielski 
972*b1cdbd2cSJim Jagielski // ----------------------------------------------------------------------------
973*b1cdbd2cSJim Jagielski 
974*b1cdbd2cSJim Jagielski void
SetTextColor(SalColor nSalColor)975*b1cdbd2cSJim Jagielski X11SalGraphics::SetTextColor( SalColor nSalColor )
976*b1cdbd2cSJim Jagielski {
977*b1cdbd2cSJim Jagielski     if( nTextColor_	!= nSalColor )
978*b1cdbd2cSJim Jagielski     {
979*b1cdbd2cSJim Jagielski         nTextColor_     = nSalColor;
980*b1cdbd2cSJim Jagielski         nTextPixel_     = GetPixel( nSalColor );
981*b1cdbd2cSJim Jagielski         bFontGC_        = sal_False;
982*b1cdbd2cSJim Jagielski     }
983*b1cdbd2cSJim Jagielski }
984*b1cdbd2cSJim Jagielski 
985*b1cdbd2cSJim Jagielski // ----------------------------------------------------------------------------
986*b1cdbd2cSJim Jagielski 
AddTempDevFont(ImplDevFontList * pFontList,const String & rFileURL,const String & rFontName)987*b1cdbd2cSJim Jagielski bool X11SalGraphics::AddTempDevFont( ImplDevFontList* pFontList,
988*b1cdbd2cSJim Jagielski     const String& rFileURL, const String& rFontName )
989*b1cdbd2cSJim Jagielski {
990*b1cdbd2cSJim Jagielski     // inform PSP font manager
991*b1cdbd2cSJim Jagielski     rtl::OUString aUSystemPath;
992*b1cdbd2cSJim Jagielski     OSL_VERIFY( !osl::FileBase::getSystemPathFromFileURL( rFileURL, aUSystemPath ) );
993*b1cdbd2cSJim Jagielski     rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
994*b1cdbd2cSJim Jagielski     OString aOFileName( OUStringToOString( aUSystemPath, aEncoding ) );
995*b1cdbd2cSJim Jagielski     psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
996*b1cdbd2cSJim Jagielski     int nFontId = rMgr.addFontFile( aOFileName, 0 );
997*b1cdbd2cSJim Jagielski     if( !nFontId )
998*b1cdbd2cSJim Jagielski         return false;
999*b1cdbd2cSJim Jagielski 
1000*b1cdbd2cSJim Jagielski     // prepare font data
1001*b1cdbd2cSJim Jagielski     psp::FastPrintFontInfo aInfo;
1002*b1cdbd2cSJim Jagielski     rMgr.getFontFastInfo( nFontId, aInfo );
1003*b1cdbd2cSJim Jagielski     aInfo.m_aFamilyName = rFontName;
1004*b1cdbd2cSJim Jagielski 
1005*b1cdbd2cSJim Jagielski     // inform glyph cache of new font
1006*b1cdbd2cSJim Jagielski     ImplDevFontAttributes aDFA = PspGraphics::Info2DevFontAttributes( aInfo );
1007*b1cdbd2cSJim Jagielski     aDFA.mnQuality += 5800;
1008*b1cdbd2cSJim Jagielski 
1009*b1cdbd2cSJim Jagielski     int nFaceNum = rMgr.getFontFaceNumber( aInfo.m_nID );
1010*b1cdbd2cSJim Jagielski     if( nFaceNum < 0 )
1011*b1cdbd2cSJim Jagielski         nFaceNum = 0;
1012*b1cdbd2cSJim Jagielski 
1013*b1cdbd2cSJim Jagielski     GlyphCache& rGC = X11GlyphCache::GetInstance();
1014*b1cdbd2cSJim Jagielski     const rtl::OString& rFileName = rMgr.getFontFileSysPath( aInfo.m_nID );
1015*b1cdbd2cSJim Jagielski     rGC.AddFontFile( rFileName, nFaceNum, aInfo.m_nID, aDFA );
1016*b1cdbd2cSJim Jagielski 
1017*b1cdbd2cSJim Jagielski     // announce new font to device's font list
1018*b1cdbd2cSJim Jagielski     rGC.AnnounceFonts( pFontList );
1019*b1cdbd2cSJim Jagielski     return true;
1020*b1cdbd2cSJim Jagielski }
1021*b1cdbd2cSJim Jagielski 
1022*b1cdbd2cSJim Jagielski // ----------------------------------------------------------------------------
1023*b1cdbd2cSJim Jagielski 
1024*b1cdbd2cSJim Jagielski void RegisterFontSubstitutors( ImplDevFontList* );
1025*b1cdbd2cSJim Jagielski 
GetDevFontList(ImplDevFontList * pList)1026*b1cdbd2cSJim Jagielski void X11SalGraphics::GetDevFontList( ImplDevFontList *pList )
1027*b1cdbd2cSJim Jagielski {
1028*b1cdbd2cSJim Jagielski     // prepare the GlyphCache using psprint's font infos
1029*b1cdbd2cSJim Jagielski     X11GlyphCache& rGC = X11GlyphCache::GetInstance();
1030*b1cdbd2cSJim Jagielski 
1031*b1cdbd2cSJim Jagielski     psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
1032*b1cdbd2cSJim Jagielski     ::std::list< psp::fontID > aList;
1033*b1cdbd2cSJim Jagielski     ::std::list< psp::fontID >::iterator it;
1034*b1cdbd2cSJim Jagielski     psp::FastPrintFontInfo aInfo;
1035*b1cdbd2cSJim Jagielski     rMgr.getFontList( aList );
1036*b1cdbd2cSJim Jagielski     for( it = aList.begin(); it != aList.end(); ++it )
1037*b1cdbd2cSJim Jagielski     {
1038*b1cdbd2cSJim Jagielski         if( !rMgr.getFontFastInfo( *it, aInfo ) )
1039*b1cdbd2cSJim Jagielski             continue;
1040*b1cdbd2cSJim Jagielski 
1041*b1cdbd2cSJim Jagielski         // the GlyphCache must not bother with builtin fonts because
1042*b1cdbd2cSJim Jagielski         // it cannot access or use them anyway
1043*b1cdbd2cSJim Jagielski         if( aInfo.m_eType == psp::fonttype::Builtin )
1044*b1cdbd2cSJim Jagielski             continue;
1045*b1cdbd2cSJim Jagielski 
1046*b1cdbd2cSJim Jagielski         // normalize face number to the GlyphCache
1047*b1cdbd2cSJim Jagielski         int nFaceNum = rMgr.getFontFaceNumber( aInfo.m_nID );
1048*b1cdbd2cSJim Jagielski         if( nFaceNum < 0 )
1049*b1cdbd2cSJim Jagielski             nFaceNum = 0;
1050*b1cdbd2cSJim Jagielski 
1051*b1cdbd2cSJim Jagielski         // for fonts where extra kerning info can be provided on demand
1052*b1cdbd2cSJim Jagielski         // an ExtraKernInfo object is supplied
1053*b1cdbd2cSJim Jagielski         const ExtraKernInfo* pExtraKernInfo = NULL;
1054*b1cdbd2cSJim Jagielski         if( aInfo.m_eType == psp::fonttype::Type1 )
1055*b1cdbd2cSJim Jagielski             pExtraKernInfo = new PspKernInfo( *it );
1056*b1cdbd2cSJim Jagielski 
1057*b1cdbd2cSJim Jagielski         // inform GlyphCache about this font provided by the PsPrint subsystem
1058*b1cdbd2cSJim Jagielski         ImplDevFontAttributes aDFA = PspGraphics::Info2DevFontAttributes( aInfo );
1059*b1cdbd2cSJim Jagielski         aDFA.mnQuality += 4096;
1060*b1cdbd2cSJim Jagielski         const rtl::OString& rFileName = rMgr.getFontFileSysPath( aInfo.m_nID );
1061*b1cdbd2cSJim Jagielski         rGC.AddFontFile( rFileName, nFaceNum, aInfo.m_nID, aDFA, pExtraKernInfo );
1062*b1cdbd2cSJim Jagielski    }
1063*b1cdbd2cSJim Jagielski 
1064*b1cdbd2cSJim Jagielski     // announce glyphcache fonts
1065*b1cdbd2cSJim Jagielski     rGC.AnnounceFonts( pList );
1066*b1cdbd2cSJim Jagielski 
1067*b1cdbd2cSJim Jagielski     // register platform specific font substitutions if available
1068*b1cdbd2cSJim Jagielski     if( rMgr.hasFontconfig() )
1069*b1cdbd2cSJim Jagielski         RegisterFontSubstitutors( pList );
1070*b1cdbd2cSJim Jagielski 
1071*b1cdbd2cSJim Jagielski     ImplGetSVData()->maGDIData.mbNativeFontConfig = rMgr.hasFontconfig();
1072*b1cdbd2cSJim Jagielski }
1073*b1cdbd2cSJim Jagielski 
1074*b1cdbd2cSJim Jagielski // ----------------------------------------------------------------------------
1075*b1cdbd2cSJim Jagielski 
GetDevFontSubstList(OutputDevice *)1076*b1cdbd2cSJim Jagielski void X11SalGraphics::GetDevFontSubstList( OutputDevice* )
1077*b1cdbd2cSJim Jagielski {
1078*b1cdbd2cSJim Jagielski     // no device specific font substitutions on X11 needed
1079*b1cdbd2cSJim Jagielski }
1080*b1cdbd2cSJim Jagielski 
1081*b1cdbd2cSJim Jagielski // ----------------------------------------------------------------------------
1082*b1cdbd2cSJim Jagielski 
cairosubcallback(void * pPattern)1083*b1cdbd2cSJim Jagielski void cairosubcallback( void* pPattern )
1084*b1cdbd2cSJim Jagielski {
1085*b1cdbd2cSJim Jagielski     CairoWrapper& rCairo = CairoWrapper::get();
1086*b1cdbd2cSJim Jagielski     if( !rCairo.isValid() )
1087*b1cdbd2cSJim Jagielski         return;
1088*b1cdbd2cSJim Jagielski     const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
1089*b1cdbd2cSJim Jagielski     const void* pFontOptions = rStyleSettings.GetCairoFontOptions();
1090*b1cdbd2cSJim Jagielski     if( !pFontOptions )
1091*b1cdbd2cSJim Jagielski         return;
1092*b1cdbd2cSJim Jagielski     rCairo.ft_font_options_substitute( pFontOptions, pPattern );
1093*b1cdbd2cSJim Jagielski }
1094*b1cdbd2cSJim Jagielski 
GetFCFontOptions(const ImplFontAttributes & rFontAttributes,int nSize,ImplFontOptions & rFontOptions)1095*b1cdbd2cSJim Jagielski bool GetFCFontOptions( const ImplFontAttributes& rFontAttributes, int nSize,
1096*b1cdbd2cSJim Jagielski 	ImplFontOptions& rFontOptions)
1097*b1cdbd2cSJim Jagielski {
1098*b1cdbd2cSJim Jagielski     // TODO: get rid of these insane enum-conversions
1099*b1cdbd2cSJim Jagielski     // e.g. by using the classic vclenum values inside VCL
1100*b1cdbd2cSJim Jagielski 
1101*b1cdbd2cSJim Jagielski     psp::FastPrintFontInfo aInfo;
1102*b1cdbd2cSJim Jagielski     // set family name
1103*b1cdbd2cSJim Jagielski     aInfo.m_aFamilyName = rFontAttributes.GetFamilyName();
1104*b1cdbd2cSJim Jagielski     // set italic
1105*b1cdbd2cSJim Jagielski     switch( rFontAttributes.GetSlant() )
1106*b1cdbd2cSJim Jagielski     {
1107*b1cdbd2cSJim Jagielski         case ITALIC_NONE:
1108*b1cdbd2cSJim Jagielski             aInfo.m_eItalic = psp::italic::Upright;
1109*b1cdbd2cSJim Jagielski             break;
1110*b1cdbd2cSJim Jagielski         case ITALIC_NORMAL:
1111*b1cdbd2cSJim Jagielski             aInfo.m_eItalic = psp::italic::Italic;
1112*b1cdbd2cSJim Jagielski             break;
1113*b1cdbd2cSJim Jagielski         case ITALIC_OBLIQUE:
1114*b1cdbd2cSJim Jagielski             aInfo.m_eItalic = psp::italic::Oblique;
1115*b1cdbd2cSJim Jagielski             break;
1116*b1cdbd2cSJim Jagielski         default:
1117*b1cdbd2cSJim Jagielski             aInfo.m_eItalic = psp::italic::Unknown;
1118*b1cdbd2cSJim Jagielski             break;
1119*b1cdbd2cSJim Jagielski     }
1120*b1cdbd2cSJim Jagielski     // set weight
1121*b1cdbd2cSJim Jagielski     switch( rFontAttributes.GetWeight() )
1122*b1cdbd2cSJim Jagielski     {
1123*b1cdbd2cSJim Jagielski         case WEIGHT_THIN:
1124*b1cdbd2cSJim Jagielski             aInfo.m_eWeight = psp::weight::Thin;
1125*b1cdbd2cSJim Jagielski             break;
1126*b1cdbd2cSJim Jagielski         case WEIGHT_ULTRALIGHT:
1127*b1cdbd2cSJim Jagielski             aInfo.m_eWeight = psp::weight::UltraLight;
1128*b1cdbd2cSJim Jagielski             break;
1129*b1cdbd2cSJim Jagielski         case WEIGHT_LIGHT:
1130*b1cdbd2cSJim Jagielski             aInfo.m_eWeight = psp::weight::Light;
1131*b1cdbd2cSJim Jagielski             break;
1132*b1cdbd2cSJim Jagielski         case WEIGHT_SEMILIGHT:
1133*b1cdbd2cSJim Jagielski             aInfo.m_eWeight = psp::weight::SemiLight;
1134*b1cdbd2cSJim Jagielski             break;
1135*b1cdbd2cSJim Jagielski         case WEIGHT_NORMAL:
1136*b1cdbd2cSJim Jagielski             aInfo.m_eWeight = psp::weight::Normal;
1137*b1cdbd2cSJim Jagielski             break;
1138*b1cdbd2cSJim Jagielski         case WEIGHT_MEDIUM:
1139*b1cdbd2cSJim Jagielski             aInfo.m_eWeight = psp::weight::Medium;
1140*b1cdbd2cSJim Jagielski             break;
1141*b1cdbd2cSJim Jagielski         case WEIGHT_SEMIBOLD:
1142*b1cdbd2cSJim Jagielski             aInfo.m_eWeight = psp::weight::SemiBold;
1143*b1cdbd2cSJim Jagielski             break;
1144*b1cdbd2cSJim Jagielski         case WEIGHT_BOLD:
1145*b1cdbd2cSJim Jagielski             aInfo.m_eWeight = psp::weight::Bold;
1146*b1cdbd2cSJim Jagielski             break;
1147*b1cdbd2cSJim Jagielski         case WEIGHT_ULTRABOLD:
1148*b1cdbd2cSJim Jagielski             aInfo.m_eWeight = psp::weight::UltraBold;
1149*b1cdbd2cSJim Jagielski             break;
1150*b1cdbd2cSJim Jagielski         case WEIGHT_BLACK:
1151*b1cdbd2cSJim Jagielski             aInfo.m_eWeight = psp::weight::Black;
1152*b1cdbd2cSJim Jagielski             break;
1153*b1cdbd2cSJim Jagielski         default:
1154*b1cdbd2cSJim Jagielski             aInfo.m_eWeight = psp::weight::Unknown;
1155*b1cdbd2cSJim Jagielski             break;
1156*b1cdbd2cSJim Jagielski     }
1157*b1cdbd2cSJim Jagielski     // set width
1158*b1cdbd2cSJim Jagielski     switch( rFontAttributes.GetWidthType() )
1159*b1cdbd2cSJim Jagielski     {
1160*b1cdbd2cSJim Jagielski         case WIDTH_ULTRA_CONDENSED:
1161*b1cdbd2cSJim Jagielski             aInfo.m_eWidth = psp::width::UltraCondensed;
1162*b1cdbd2cSJim Jagielski             break;
1163*b1cdbd2cSJim Jagielski         case WIDTH_EXTRA_CONDENSED:
1164*b1cdbd2cSJim Jagielski             aInfo.m_eWidth = psp::width::ExtraCondensed;
1165*b1cdbd2cSJim Jagielski             break;
1166*b1cdbd2cSJim Jagielski         case WIDTH_CONDENSED:
1167*b1cdbd2cSJim Jagielski             aInfo.m_eWidth = psp::width::Condensed;
1168*b1cdbd2cSJim Jagielski             break;
1169*b1cdbd2cSJim Jagielski         case WIDTH_SEMI_CONDENSED:
1170*b1cdbd2cSJim Jagielski             aInfo.m_eWidth = psp::width::SemiCondensed;
1171*b1cdbd2cSJim Jagielski             break;
1172*b1cdbd2cSJim Jagielski         case WIDTH_NORMAL:
1173*b1cdbd2cSJim Jagielski             aInfo.m_eWidth = psp::width::Normal;
1174*b1cdbd2cSJim Jagielski             break;
1175*b1cdbd2cSJim Jagielski         case WIDTH_SEMI_EXPANDED:
1176*b1cdbd2cSJim Jagielski             aInfo.m_eWidth = psp::width::SemiExpanded;
1177*b1cdbd2cSJim Jagielski             break;
1178*b1cdbd2cSJim Jagielski         case WIDTH_EXPANDED:
1179*b1cdbd2cSJim Jagielski             aInfo.m_eWidth = psp::width::Expanded;
1180*b1cdbd2cSJim Jagielski             break;
1181*b1cdbd2cSJim Jagielski         case WIDTH_EXTRA_EXPANDED:
1182*b1cdbd2cSJim Jagielski             aInfo.m_eWidth = psp::width::ExtraExpanded;
1183*b1cdbd2cSJim Jagielski             break;
1184*b1cdbd2cSJim Jagielski         case WIDTH_ULTRA_EXPANDED:
1185*b1cdbd2cSJim Jagielski             aInfo.m_eWidth = psp::width::UltraExpanded;
1186*b1cdbd2cSJim Jagielski             break;
1187*b1cdbd2cSJim Jagielski         default:
1188*b1cdbd2cSJim Jagielski             aInfo.m_eWidth = psp::width::Unknown;
1189*b1cdbd2cSJim Jagielski             break;
1190*b1cdbd2cSJim Jagielski     }
1191*b1cdbd2cSJim Jagielski 
1192*b1cdbd2cSJim Jagielski     const psp::PrintFontManager& rPFM = psp::PrintFontManager::get();
1193*b1cdbd2cSJim Jagielski     bool bOK = rPFM.getFontOptions( aInfo, nSize, cairosubcallback, rFontOptions);
1194*b1cdbd2cSJim Jagielski     return bOK;
1195*b1cdbd2cSJim Jagielski }
1196*b1cdbd2cSJim Jagielski 
1197*b1cdbd2cSJim Jagielski // ----------------------------------------------------------------------------
1198*b1cdbd2cSJim Jagielski 
1199*b1cdbd2cSJim Jagielski void
GetFontMetric(ImplFontMetricData * pMetric,int nFallbackLevel)1200*b1cdbd2cSJim Jagielski X11SalGraphics::GetFontMetric( ImplFontMetricData *pMetric, int nFallbackLevel )
1201*b1cdbd2cSJim Jagielski {
1202*b1cdbd2cSJim Jagielski     if( nFallbackLevel >= MAX_FALLBACK )
1203*b1cdbd2cSJim Jagielski         return;
1204*b1cdbd2cSJim Jagielski 
1205*b1cdbd2cSJim Jagielski     if( mpServerFont[nFallbackLevel] != NULL )
1206*b1cdbd2cSJim Jagielski     {
1207*b1cdbd2cSJim Jagielski         long rDummyFactor;
1208*b1cdbd2cSJim Jagielski         mpServerFont[nFallbackLevel]->FetchFontMetric( *pMetric, rDummyFactor );
1209*b1cdbd2cSJim Jagielski     }
1210*b1cdbd2cSJim Jagielski }
1211*b1cdbd2cSJim Jagielski 
1212*b1cdbd2cSJim Jagielski // ---------------------------------------------------------------------------
1213*b1cdbd2cSJim Jagielski 
1214*b1cdbd2cSJim Jagielski sal_uLong
GetKernPairs(sal_uLong nPairs,ImplKernPairData * pKernPairs)1215*b1cdbd2cSJim Jagielski X11SalGraphics::GetKernPairs( sal_uLong nPairs, ImplKernPairData *pKernPairs )
1216*b1cdbd2cSJim Jagielski {
1217*b1cdbd2cSJim Jagielski     if( ! bPrinter_ )
1218*b1cdbd2cSJim Jagielski     {
1219*b1cdbd2cSJim Jagielski         if( mpServerFont[0] != NULL )
1220*b1cdbd2cSJim Jagielski         {
1221*b1cdbd2cSJim Jagielski             ImplKernPairData* pTmpKernPairs;
1222*b1cdbd2cSJim Jagielski             sal_uLong nGotPairs = mpServerFont[0]->GetKernPairs( &pTmpKernPairs );
1223*b1cdbd2cSJim Jagielski             for( unsigned int i = 0; i < nPairs && i < nGotPairs; ++i )
1224*b1cdbd2cSJim Jagielski                 pKernPairs[ i ] = pTmpKernPairs[ i ];
1225*b1cdbd2cSJim Jagielski             delete[] pTmpKernPairs;
1226*b1cdbd2cSJim Jagielski             return nGotPairs;
1227*b1cdbd2cSJim Jagielski         }
1228*b1cdbd2cSJim Jagielski     }
1229*b1cdbd2cSJim Jagielski 	return 0;
1230*b1cdbd2cSJim Jagielski }
1231*b1cdbd2cSJim Jagielski 
1232*b1cdbd2cSJim Jagielski // ---------------------------------------------------------------------------
1233*b1cdbd2cSJim Jagielski 
GetGlyphBoundRect(sal_GlyphId aGlyphId,Rectangle & rRect)1234*b1cdbd2cSJim Jagielski bool X11SalGraphics::GetGlyphBoundRect( sal_GlyphId aGlyphId, Rectangle& rRect )
1235*b1cdbd2cSJim Jagielski {
1236*b1cdbd2cSJim Jagielski     const int nLevel = aGlyphId >> GF_FONTSHIFT;
1237*b1cdbd2cSJim Jagielski     if( nLevel >= MAX_FALLBACK )
1238*b1cdbd2cSJim Jagielski         return false;
1239*b1cdbd2cSJim Jagielski 
1240*b1cdbd2cSJim Jagielski     ServerFont* pSF = mpServerFont[ nLevel ];
1241*b1cdbd2cSJim Jagielski     if( !pSF )
1242*b1cdbd2cSJim Jagielski         return false;
1243*b1cdbd2cSJim Jagielski 
1244*b1cdbd2cSJim Jagielski     aGlyphId &= ~GF_FONTMASK;
1245*b1cdbd2cSJim Jagielski     const GlyphMetric& rGM = pSF->GetGlyphMetric( aGlyphId );
1246*b1cdbd2cSJim Jagielski     rRect = Rectangle( rGM.GetOffset(), rGM.GetSize() );
1247*b1cdbd2cSJim Jagielski     return true;
1248*b1cdbd2cSJim Jagielski }
1249*b1cdbd2cSJim Jagielski 
1250*b1cdbd2cSJim Jagielski // ---------------------------------------------------------------------------
1251*b1cdbd2cSJim Jagielski 
GetGlyphOutline(sal_GlyphId aGlyphId,::basegfx::B2DPolyPolygon & rPolyPoly)1252*b1cdbd2cSJim Jagielski bool X11SalGraphics::GetGlyphOutline( sal_GlyphId aGlyphId,
1253*b1cdbd2cSJim Jagielski     ::basegfx::B2DPolyPolygon& rPolyPoly )
1254*b1cdbd2cSJim Jagielski {
1255*b1cdbd2cSJim Jagielski     const int nLevel = aGlyphId >> GF_FONTSHIFT;
1256*b1cdbd2cSJim Jagielski     if( nLevel >= MAX_FALLBACK )
1257*b1cdbd2cSJim Jagielski         return false;
1258*b1cdbd2cSJim Jagielski 
1259*b1cdbd2cSJim Jagielski     ServerFont* pSF = mpServerFont[ nLevel ];
1260*b1cdbd2cSJim Jagielski     if( !pSF )
1261*b1cdbd2cSJim Jagielski         return false;
1262*b1cdbd2cSJim Jagielski 
1263*b1cdbd2cSJim Jagielski     aGlyphId &= ~GF_FONTMASK;
1264*b1cdbd2cSJim Jagielski     bool bOK = pSF->GetGlyphOutline( aGlyphId, rPolyPoly );
1265*b1cdbd2cSJim Jagielski     return bOK;
1266*b1cdbd2cSJim Jagielski }
1267*b1cdbd2cSJim Jagielski 
1268*b1cdbd2cSJim Jagielski //--------------------------------------------------------------------------
1269*b1cdbd2cSJim Jagielski 
GetTextLayout(ImplLayoutArgs & rArgs,int nFallbackLevel)1270*b1cdbd2cSJim Jagielski SalLayout* X11SalGraphics::GetTextLayout( ImplLayoutArgs& rArgs, int nFallbackLevel )
1271*b1cdbd2cSJim Jagielski {
1272*b1cdbd2cSJim Jagielski     SalLayout* pLayout = NULL;
1273*b1cdbd2cSJim Jagielski 
1274*b1cdbd2cSJim Jagielski     if( mpServerFont[ nFallbackLevel ]
1275*b1cdbd2cSJim Jagielski     && !(rArgs.mnFlags & SAL_LAYOUT_DISABLE_GLYPH_PROCESSING) )
1276*b1cdbd2cSJim Jagielski     {
1277*b1cdbd2cSJim Jagielski #ifdef ENABLE_GRAPHITE
1278*b1cdbd2cSJim Jagielski         // Is this a Graphite font?
1279*b1cdbd2cSJim Jagielski         if (!bDisableGraphite_ &&
1280*b1cdbd2cSJim Jagielski             GraphiteFontAdaptor::IsGraphiteEnabledFont(*mpServerFont[nFallbackLevel]))
1281*b1cdbd2cSJim Jagielski         {
1282*b1cdbd2cSJim Jagielski             sal_Int32 xdpi = GetDisplay()->GetResolution().A();
1283*b1cdbd2cSJim Jagielski             sal_Int32 ydpi = GetDisplay()->GetResolution().B();
1284*b1cdbd2cSJim Jagielski 
1285*b1cdbd2cSJim Jagielski             GraphiteFontAdaptor * pGrfont = new GraphiteFontAdaptor( *mpServerFont[nFallbackLevel], xdpi, ydpi);
1286*b1cdbd2cSJim Jagielski             if (!pGrfont) return NULL;
1287*b1cdbd2cSJim Jagielski             pLayout = new GraphiteServerFontLayout(pGrfont);
1288*b1cdbd2cSJim Jagielski         }
1289*b1cdbd2cSJim Jagielski         else
1290*b1cdbd2cSJim Jagielski #endif
1291*b1cdbd2cSJim Jagielski             pLayout = new ServerFontLayout( *mpServerFont[ nFallbackLevel ] );
1292*b1cdbd2cSJim Jagielski     }
1293*b1cdbd2cSJim Jagielski 
1294*b1cdbd2cSJim Jagielski     return pLayout;
1295*b1cdbd2cSJim Jagielski }
1296*b1cdbd2cSJim Jagielski 
1297*b1cdbd2cSJim Jagielski //--------------------------------------------------------------------------
1298*b1cdbd2cSJim Jagielski 
GetSysFontData(int nFallbacklevel) const1299*b1cdbd2cSJim Jagielski SystemFontData X11SalGraphics::GetSysFontData( int nFallbacklevel ) const
1300*b1cdbd2cSJim Jagielski {
1301*b1cdbd2cSJim Jagielski     SystemFontData aSysFontData;
1302*b1cdbd2cSJim Jagielski     aSysFontData.nSize = sizeof( SystemFontData );
1303*b1cdbd2cSJim Jagielski     aSysFontData.nFontId = 0;
1304*b1cdbd2cSJim Jagielski 
1305*b1cdbd2cSJim Jagielski     if (nFallbacklevel >= MAX_FALLBACK) nFallbacklevel = MAX_FALLBACK - 1;
1306*b1cdbd2cSJim Jagielski     if (nFallbacklevel < 0 ) nFallbacklevel = 0;
1307*b1cdbd2cSJim Jagielski 
1308*b1cdbd2cSJim Jagielski     if (mpServerFont[nFallbacklevel] != NULL)
1309*b1cdbd2cSJim Jagielski     {
1310*b1cdbd2cSJim Jagielski         ServerFont* rFont = mpServerFont[nFallbacklevel];
1311*b1cdbd2cSJim Jagielski         aSysFontData.nFontId = rFont->GetFtFace();
1312*b1cdbd2cSJim Jagielski         aSysFontData.nFontFlags = rFont->GetLoadFlags();
1313*b1cdbd2cSJim Jagielski         aSysFontData.bFakeBold = rFont->NeedsArtificialBold();
1314*b1cdbd2cSJim Jagielski         aSysFontData.bFakeItalic = rFont->NeedsArtificialItalic();
1315*b1cdbd2cSJim Jagielski         aSysFontData.bAntialias = rFont->GetAntialiasAdvice();
1316*b1cdbd2cSJim Jagielski         aSysFontData.bVerticalCharacterType = rFont->GetFontSelData().mbVertical;
1317*b1cdbd2cSJim Jagielski     }
1318*b1cdbd2cSJim Jagielski 
1319*b1cdbd2cSJim Jagielski     return aSysFontData;
1320*b1cdbd2cSJim Jagielski }
1321*b1cdbd2cSJim Jagielski 
1322*b1cdbd2cSJim Jagielski //--------------------------------------------------------------------------
1323*b1cdbd2cSJim Jagielski 
CreateFontSubset(const rtl::OUString & rToFile,const ImplFontData * pFont,sal_GlyphId * pGlyphIds,sal_uInt8 * pEncoding,sal_Int32 * pWidths,int nGlyphCount,FontSubsetInfo & rInfo)1324*b1cdbd2cSJim Jagielski sal_Bool X11SalGraphics::CreateFontSubset(
1325*b1cdbd2cSJim Jagielski                                    const rtl::OUString& rToFile,
1326*b1cdbd2cSJim Jagielski                                    const ImplFontData* pFont,
1327*b1cdbd2cSJim Jagielski                                    sal_GlyphId* pGlyphIds,
1328*b1cdbd2cSJim Jagielski                                    sal_uInt8* pEncoding,
1329*b1cdbd2cSJim Jagielski                                    sal_Int32* pWidths,
1330*b1cdbd2cSJim Jagielski                                    int nGlyphCount,
1331*b1cdbd2cSJim Jagielski                                    FontSubsetInfo& rInfo
1332*b1cdbd2cSJim Jagielski                                    )
1333*b1cdbd2cSJim Jagielski {
1334*b1cdbd2cSJim Jagielski     // in this context the pFont->GetFontId() is a valid PSP
1335*b1cdbd2cSJim Jagielski     // font since they are the only ones left after the PDF
1336*b1cdbd2cSJim Jagielski     // export has filtered its list of subsettable fonts (for
1337*b1cdbd2cSJim Jagielski     // which this method was created). The correct way would
1338*b1cdbd2cSJim Jagielski     // be to have the GlyphCache search for the ImplFontData pFont
1339*b1cdbd2cSJim Jagielski     psp::fontID aFont = pFont->GetFontId();
1340*b1cdbd2cSJim Jagielski 
1341*b1cdbd2cSJim Jagielski     psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
1342*b1cdbd2cSJim Jagielski     bool bSuccess = rMgr.createFontSubset( rInfo,
1343*b1cdbd2cSJim Jagielski                                  aFont,
1344*b1cdbd2cSJim Jagielski                                  rToFile,
1345*b1cdbd2cSJim Jagielski                                  pGlyphIds,
1346*b1cdbd2cSJim Jagielski                                  pEncoding,
1347*b1cdbd2cSJim Jagielski                                  pWidths,
1348*b1cdbd2cSJim Jagielski                                  nGlyphCount );
1349*b1cdbd2cSJim Jagielski     return bSuccess;
1350*b1cdbd2cSJim Jagielski }
1351*b1cdbd2cSJim Jagielski 
1352*b1cdbd2cSJim Jagielski //--------------------------------------------------------------------------
1353*b1cdbd2cSJim Jagielski 
GetEmbedFontData(const ImplFontData * pFont,const sal_Ucs * pUnicodes,sal_Int32 * pWidths,FontSubsetInfo & rInfo,long * pDataLen)1354*b1cdbd2cSJim Jagielski const void* X11SalGraphics::GetEmbedFontData( const ImplFontData* pFont, const sal_Ucs* pUnicodes, sal_Int32* pWidths, FontSubsetInfo& rInfo, long* pDataLen )
1355*b1cdbd2cSJim Jagielski {
1356*b1cdbd2cSJim Jagielski     // in this context the pFont->GetFontId() is a valid PSP
1357*b1cdbd2cSJim Jagielski     // font since they are the only ones left after the PDF
1358*b1cdbd2cSJim Jagielski     // export has filtered its list of subsettable fonts (for
1359*b1cdbd2cSJim Jagielski     // which this method was created). The correct way would
1360*b1cdbd2cSJim Jagielski     // be to have the GlyphCache search for the ImplFontData pFont
1361*b1cdbd2cSJim Jagielski     psp::fontID aFont = pFont->GetFontId();
1362*b1cdbd2cSJim Jagielski     return PspGraphics::DoGetEmbedFontData( aFont, pUnicodes, pWidths, rInfo, pDataLen );
1363*b1cdbd2cSJim Jagielski }
1364*b1cdbd2cSJim Jagielski 
1365*b1cdbd2cSJim Jagielski //--------------------------------------------------------------------------
1366*b1cdbd2cSJim Jagielski 
FreeEmbedFontData(const void * pData,long nLen)1367*b1cdbd2cSJim Jagielski void X11SalGraphics::FreeEmbedFontData( const void* pData, long nLen )
1368*b1cdbd2cSJim Jagielski {
1369*b1cdbd2cSJim Jagielski     PspGraphics::DoFreeEmbedFontData( pData, nLen );
1370*b1cdbd2cSJim Jagielski }
1371*b1cdbd2cSJim Jagielski 
1372*b1cdbd2cSJim Jagielski //--------------------------------------------------------------------------
1373*b1cdbd2cSJim Jagielski 
GetFontEncodingVector(const ImplFontData * pFont,const Ucs2OStrMap ** pNonEncoded)1374*b1cdbd2cSJim Jagielski const Ucs2SIntMap* X11SalGraphics::GetFontEncodingVector( const ImplFontData* pFont, const Ucs2OStrMap** pNonEncoded )
1375*b1cdbd2cSJim Jagielski {
1376*b1cdbd2cSJim Jagielski     // in this context the pFont->GetFontId() is a valid PSP
1377*b1cdbd2cSJim Jagielski     // font since they are the only ones left after the PDF
1378*b1cdbd2cSJim Jagielski     // export has filtered its list of subsettable fonts (for
1379*b1cdbd2cSJim Jagielski     // which this method was created). The correct way would
1380*b1cdbd2cSJim Jagielski     // be to have the GlyphCache search for the ImplFontData pFont
1381*b1cdbd2cSJim Jagielski     psp::fontID aFont = pFont->GetFontId();
1382*b1cdbd2cSJim Jagielski     return PspGraphics::DoGetFontEncodingVector( aFont, pNonEncoded );
1383*b1cdbd2cSJim Jagielski }
1384*b1cdbd2cSJim Jagielski 
1385*b1cdbd2cSJim Jagielski //--------------------------------------------------------------------------
1386*b1cdbd2cSJim Jagielski 
GetGlyphWidths(const ImplFontData * pFont,bool bVertical,Int32Vector & rWidths,Ucs2UIntMap & rUnicodeEnc)1387*b1cdbd2cSJim Jagielski void X11SalGraphics::GetGlyphWidths( const ImplFontData* pFont,
1388*b1cdbd2cSJim Jagielski                                    bool bVertical,
1389*b1cdbd2cSJim Jagielski                                    Int32Vector& rWidths,
1390*b1cdbd2cSJim Jagielski                                    Ucs2UIntMap& rUnicodeEnc )
1391*b1cdbd2cSJim Jagielski {
1392*b1cdbd2cSJim Jagielski     // in this context the pFont->GetFontId() is a valid PSP
1393*b1cdbd2cSJim Jagielski     // font since they are the only ones left after the PDF
1394*b1cdbd2cSJim Jagielski     // export has filtered its list of subsettable fonts (for
1395*b1cdbd2cSJim Jagielski     // which this method was created). The correct way would
1396*b1cdbd2cSJim Jagielski     // be to have the GlyphCache search for the ImplFontData pFont
1397*b1cdbd2cSJim Jagielski     psp::fontID aFont = pFont->GetFontId();
1398*b1cdbd2cSJim Jagielski     PspGraphics::DoGetGlyphWidths( aFont, bVertical, rWidths, rUnicodeEnc );
1399*b1cdbd2cSJim Jagielski }
1400*b1cdbd2cSJim Jagielski 
1401*b1cdbd2cSJim Jagielski // ===========================================================================
1402*b1cdbd2cSJim Jagielski // platform specific font substitution hooks
1403*b1cdbd2cSJim Jagielski 
1404*b1cdbd2cSJim Jagielski class FcPreMatchSubstititution
1405*b1cdbd2cSJim Jagielski :   public ImplPreMatchFontSubstitution
1406*b1cdbd2cSJim Jagielski {
1407*b1cdbd2cSJim Jagielski public:
1408*b1cdbd2cSJim Jagielski     bool FindFontSubstitute( ImplFontSelectData& ) const;
1409*b1cdbd2cSJim Jagielski };
1410*b1cdbd2cSJim Jagielski 
1411*b1cdbd2cSJim Jagielski class FcGlyphFallbackSubstititution
1412*b1cdbd2cSJim Jagielski :    public ImplGlyphFallbackFontSubstitution
1413*b1cdbd2cSJim Jagielski {
1414*b1cdbd2cSJim Jagielski     // TODO: add a cache
1415*b1cdbd2cSJim Jagielski public:
1416*b1cdbd2cSJim Jagielski     bool FindFontSubstitute( ImplFontSelectData&, OUString& rMissingCodes ) const;
1417*b1cdbd2cSJim Jagielski };
1418*b1cdbd2cSJim Jagielski 
RegisterFontSubstitutors(ImplDevFontList * pList)1419*b1cdbd2cSJim Jagielski void RegisterFontSubstitutors( ImplDevFontList* pList )
1420*b1cdbd2cSJim Jagielski {
1421*b1cdbd2cSJim Jagielski     // init font substitution defaults
1422*b1cdbd2cSJim Jagielski     int nDisableBits = 0;
1423*b1cdbd2cSJim Jagielski #ifdef SOLARIS
1424*b1cdbd2cSJim Jagielski     nDisableBits = 1; // disable "font fallback" here on default
1425*b1cdbd2cSJim Jagielski #endif
1426*b1cdbd2cSJim Jagielski     // apply the environment variable if any
1427*b1cdbd2cSJim Jagielski     const char* pEnvStr = ::getenv( "SAL_DISABLE_FC_SUBST" );
1428*b1cdbd2cSJim Jagielski     if( pEnvStr )
1429*b1cdbd2cSJim Jagielski     {
1430*b1cdbd2cSJim Jagielski         if( (*pEnvStr >= '0') && (*pEnvStr <= '9') )
1431*b1cdbd2cSJim Jagielski             nDisableBits = (*pEnvStr - '0');
1432*b1cdbd2cSJim Jagielski         else
1433*b1cdbd2cSJim Jagielski             nDisableBits = ~0U; // no specific bits set: disable all
1434*b1cdbd2cSJim Jagielski     }
1435*b1cdbd2cSJim Jagielski 
1436*b1cdbd2cSJim Jagielski     // register font fallback substitutions (unless disabled by bit0)
1437*b1cdbd2cSJim Jagielski     if( (nDisableBits & 1) == 0 )
1438*b1cdbd2cSJim Jagielski     {
1439*b1cdbd2cSJim Jagielski         static FcPreMatchSubstititution aSubstPreMatch;
1440*b1cdbd2cSJim Jagielski         pList->SetPreMatchHook( &aSubstPreMatch );
1441*b1cdbd2cSJim Jagielski     }
1442*b1cdbd2cSJim Jagielski 
1443*b1cdbd2cSJim Jagielski     // register glyph fallback substitutions (unless disabled by bit1)
1444*b1cdbd2cSJim Jagielski     if( (nDisableBits & 2) == 0 )
1445*b1cdbd2cSJim Jagielski     {
1446*b1cdbd2cSJim Jagielski         static FcGlyphFallbackSubstititution aSubstFallback;
1447*b1cdbd2cSJim Jagielski         pList->SetFallbackHook( &aSubstFallback );
1448*b1cdbd2cSJim Jagielski     }
1449*b1cdbd2cSJim Jagielski }
1450*b1cdbd2cSJim Jagielski 
1451*b1cdbd2cSJim Jagielski // -----------------------------------------------------------------------
1452*b1cdbd2cSJim Jagielski 
GetFcSubstitute(const ImplFontSelectData & rFontSelData,OUString & rMissingCodes)1453*b1cdbd2cSJim Jagielski static ImplFontSelectData GetFcSubstitute(const ImplFontSelectData &rFontSelData, OUString& rMissingCodes )
1454*b1cdbd2cSJim Jagielski {
1455*b1cdbd2cSJim Jagielski     ImplFontSelectData aRet(rFontSelData);
1456*b1cdbd2cSJim Jagielski 
1457*b1cdbd2cSJim Jagielski     const rtl::OString aLangAttrib = MsLangId::convertLanguageToIsoByteString( rFontSelData.meLanguage );
1458*b1cdbd2cSJim Jagielski 
1459*b1cdbd2cSJim Jagielski     psp::italic::type eItalic = psp::italic::Unknown;
1460*b1cdbd2cSJim Jagielski     if( rFontSelData.GetSlant() != ITALIC_DONTKNOW )
1461*b1cdbd2cSJim Jagielski     {
1462*b1cdbd2cSJim Jagielski         switch( rFontSelData.GetSlant() )
1463*b1cdbd2cSJim Jagielski         {
1464*b1cdbd2cSJim Jagielski             case ITALIC_NONE:    eItalic = psp::italic::Upright; break;
1465*b1cdbd2cSJim Jagielski             case ITALIC_NORMAL:  eItalic = psp::italic::Italic; break;
1466*b1cdbd2cSJim Jagielski             case ITALIC_OBLIQUE: eItalic = psp::italic::Oblique; break;
1467*b1cdbd2cSJim Jagielski             default:
1468*b1cdbd2cSJim Jagielski                 break;
1469*b1cdbd2cSJim Jagielski         }
1470*b1cdbd2cSJim Jagielski     }
1471*b1cdbd2cSJim Jagielski 
1472*b1cdbd2cSJim Jagielski     psp::weight::type eWeight = psp::weight::Unknown;
1473*b1cdbd2cSJim Jagielski     if( rFontSelData.GetWeight() != WEIGHT_DONTKNOW )
1474*b1cdbd2cSJim Jagielski     {
1475*b1cdbd2cSJim Jagielski         switch( rFontSelData.GetWeight() )
1476*b1cdbd2cSJim Jagielski         {
1477*b1cdbd2cSJim Jagielski             case WEIGHT_THIN:		eWeight = psp::weight::Thin; break;
1478*b1cdbd2cSJim Jagielski             case WEIGHT_ULTRALIGHT:	eWeight = psp::weight::UltraLight; break;
1479*b1cdbd2cSJim Jagielski             case WEIGHT_LIGHT:		eWeight = psp::weight::Light; break;
1480*b1cdbd2cSJim Jagielski             case WEIGHT_SEMILIGHT:	eWeight = psp::weight::SemiLight; break;
1481*b1cdbd2cSJim Jagielski             case WEIGHT_NORMAL:		eWeight = psp::weight::Normal; break;
1482*b1cdbd2cSJim Jagielski             case WEIGHT_MEDIUM:		eWeight = psp::weight::Medium; break;
1483*b1cdbd2cSJim Jagielski             case WEIGHT_SEMIBOLD:	eWeight = psp::weight::SemiBold; break;
1484*b1cdbd2cSJim Jagielski             case WEIGHT_BOLD:		eWeight = psp::weight::Bold; break;
1485*b1cdbd2cSJim Jagielski             case WEIGHT_ULTRABOLD:	eWeight = psp::weight::UltraBold; break;
1486*b1cdbd2cSJim Jagielski             case WEIGHT_BLACK:		eWeight = psp::weight::Black; break;
1487*b1cdbd2cSJim Jagielski             default:
1488*b1cdbd2cSJim Jagielski                 break;
1489*b1cdbd2cSJim Jagielski         }
1490*b1cdbd2cSJim Jagielski     }
1491*b1cdbd2cSJim Jagielski 
1492*b1cdbd2cSJim Jagielski     psp::width::type eWidth = psp::width::Unknown;
1493*b1cdbd2cSJim Jagielski     if( rFontSelData.GetWidthType() != WIDTH_DONTKNOW )
1494*b1cdbd2cSJim Jagielski     {
1495*b1cdbd2cSJim Jagielski         switch( rFontSelData.GetWidthType() )
1496*b1cdbd2cSJim Jagielski         {
1497*b1cdbd2cSJim Jagielski             case WIDTH_ULTRA_CONDENSED:	eWidth = psp::width::UltraCondensed; break;
1498*b1cdbd2cSJim Jagielski             case WIDTH_EXTRA_CONDENSED: eWidth = psp::width::ExtraCondensed; break;
1499*b1cdbd2cSJim Jagielski             case WIDTH_CONDENSED:	eWidth = psp::width::Condensed; break;
1500*b1cdbd2cSJim Jagielski             case WIDTH_SEMI_CONDENSED:	eWidth = psp::width::SemiCondensed; break;
1501*b1cdbd2cSJim Jagielski             case WIDTH_NORMAL:		eWidth = psp::width::Normal; break;
1502*b1cdbd2cSJim Jagielski             case WIDTH_SEMI_EXPANDED:	eWidth = psp::width::SemiExpanded; break;
1503*b1cdbd2cSJim Jagielski             case WIDTH_EXPANDED:	eWidth = psp::width::Expanded; break;
1504*b1cdbd2cSJim Jagielski             case WIDTH_EXTRA_EXPANDED:	eWidth = psp::width::ExtraExpanded; break;
1505*b1cdbd2cSJim Jagielski             case WIDTH_ULTRA_EXPANDED:	eWidth = psp::width::UltraExpanded; break;
1506*b1cdbd2cSJim Jagielski             default:
1507*b1cdbd2cSJim Jagielski                 break;
1508*b1cdbd2cSJim Jagielski         }
1509*b1cdbd2cSJim Jagielski     }
1510*b1cdbd2cSJim Jagielski 
1511*b1cdbd2cSJim Jagielski     psp::pitch::type ePitch = psp::pitch::Unknown;
1512*b1cdbd2cSJim Jagielski     if( rFontSelData.GetPitch() != PITCH_DONTKNOW )
1513*b1cdbd2cSJim Jagielski     {
1514*b1cdbd2cSJim Jagielski         switch( rFontSelData.GetPitch() )
1515*b1cdbd2cSJim Jagielski         {
1516*b1cdbd2cSJim Jagielski             case PITCH_FIXED:    ePitch=psp::pitch::Fixed; break;
1517*b1cdbd2cSJim Jagielski             case PITCH_VARIABLE: ePitch=psp::pitch::Variable; break;
1518*b1cdbd2cSJim Jagielski             default:
1519*b1cdbd2cSJim Jagielski                 break;
1520*b1cdbd2cSJim Jagielski         }
1521*b1cdbd2cSJim Jagielski     }
1522*b1cdbd2cSJim Jagielski 
1523*b1cdbd2cSJim Jagielski     const psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
1524*b1cdbd2cSJim Jagielski     aRet.maSearchName = rMgr.Substitute( rFontSelData.maTargetName, rMissingCodes, aLangAttrib, eItalic, eWeight, eWidth, ePitch);
1525*b1cdbd2cSJim Jagielski 
1526*b1cdbd2cSJim Jagielski     switch (eItalic)
1527*b1cdbd2cSJim Jagielski     {
1528*b1cdbd2cSJim Jagielski         case psp::italic::Upright: aRet.meItalic = ITALIC_NONE; break;
1529*b1cdbd2cSJim Jagielski         case psp::italic::Italic: aRet.meItalic = ITALIC_NORMAL; break;
1530*b1cdbd2cSJim Jagielski         case psp::italic::Oblique: aRet.meItalic = ITALIC_OBLIQUE; break;
1531*b1cdbd2cSJim Jagielski         default:
1532*b1cdbd2cSJim Jagielski             break;
1533*b1cdbd2cSJim Jagielski     }
1534*b1cdbd2cSJim Jagielski 
1535*b1cdbd2cSJim Jagielski     switch (eWeight)
1536*b1cdbd2cSJim Jagielski     {
1537*b1cdbd2cSJim Jagielski         case psp::weight::Thin: aRet.meWeight = WEIGHT_THIN; break;
1538*b1cdbd2cSJim Jagielski         case psp::weight::UltraLight: aRet.meWeight = WEIGHT_ULTRALIGHT; break;
1539*b1cdbd2cSJim Jagielski         case psp::weight::Light: aRet.meWeight = WEIGHT_LIGHT; break;
1540*b1cdbd2cSJim Jagielski         case psp::weight::SemiLight: aRet.meWeight = WEIGHT_SEMILIGHT; break;
1541*b1cdbd2cSJim Jagielski         case psp::weight::Normal: aRet.meWeight = WEIGHT_NORMAL; break;
1542*b1cdbd2cSJim Jagielski         case psp::weight::Medium: aRet.meWeight = WEIGHT_MEDIUM; break;
1543*b1cdbd2cSJim Jagielski         case psp::weight::SemiBold: aRet.meWeight = WEIGHT_SEMIBOLD; break;
1544*b1cdbd2cSJim Jagielski         case psp::weight::Bold: aRet.meWeight = WEIGHT_BOLD; break;
1545*b1cdbd2cSJim Jagielski         case psp::weight::UltraBold: aRet.meWeight = WEIGHT_ULTRABOLD; break;
1546*b1cdbd2cSJim Jagielski         case psp::weight::Black: aRet.meWeight = WEIGHT_BLACK; break;
1547*b1cdbd2cSJim Jagielski         default:
1548*b1cdbd2cSJim Jagielski                 break;
1549*b1cdbd2cSJim Jagielski     }
1550*b1cdbd2cSJim Jagielski 
1551*b1cdbd2cSJim Jagielski     switch (eWidth)
1552*b1cdbd2cSJim Jagielski     {
1553*b1cdbd2cSJim Jagielski         case psp::width::UltraCondensed: aRet.meWidthType = WIDTH_ULTRA_CONDENSED; break;
1554*b1cdbd2cSJim Jagielski         case psp::width::ExtraCondensed: aRet.meWidthType = WIDTH_EXTRA_CONDENSED; break;
1555*b1cdbd2cSJim Jagielski         case psp::width::Condensed: aRet.meWidthType = WIDTH_CONDENSED; break;
1556*b1cdbd2cSJim Jagielski         case psp::width::SemiCondensed: aRet.meWidthType = WIDTH_SEMI_CONDENSED; break;
1557*b1cdbd2cSJim Jagielski         case psp::width::Normal: aRet.meWidthType = WIDTH_NORMAL; break;
1558*b1cdbd2cSJim Jagielski         case psp::width::SemiExpanded: aRet.meWidthType = WIDTH_SEMI_EXPANDED; break;
1559*b1cdbd2cSJim Jagielski         case psp::width::Expanded: aRet.meWidthType = WIDTH_EXPANDED; break;
1560*b1cdbd2cSJim Jagielski         case psp::width::ExtraExpanded: aRet.meWidthType = WIDTH_EXTRA_EXPANDED; break;
1561*b1cdbd2cSJim Jagielski         case psp::width::UltraExpanded: aRet.meWidthType = WIDTH_ULTRA_EXPANDED; break;
1562*b1cdbd2cSJim Jagielski         default:
1563*b1cdbd2cSJim Jagielski             break;
1564*b1cdbd2cSJim Jagielski     }
1565*b1cdbd2cSJim Jagielski 
1566*b1cdbd2cSJim Jagielski     switch (ePitch)
1567*b1cdbd2cSJim Jagielski     {
1568*b1cdbd2cSJim Jagielski         case psp::pitch::Fixed: aRet.mePitch = PITCH_FIXED; break;
1569*b1cdbd2cSJim Jagielski         case psp::pitch::Variable: aRet.mePitch = PITCH_VARIABLE; break;
1570*b1cdbd2cSJim Jagielski         default:
1571*b1cdbd2cSJim Jagielski             break;
1572*b1cdbd2cSJim Jagielski     }
1573*b1cdbd2cSJim Jagielski 
1574*b1cdbd2cSJim Jagielski     return aRet;
1575*b1cdbd2cSJim Jagielski }
1576*b1cdbd2cSJim Jagielski 
1577*b1cdbd2cSJim Jagielski namespace
1578*b1cdbd2cSJim Jagielski {
uselessmatch(const ImplFontSelectData & rOrig,const ImplFontSelectData & rNew)1579*b1cdbd2cSJim Jagielski     bool uselessmatch(const ImplFontSelectData &rOrig, const ImplFontSelectData &rNew)
1580*b1cdbd2cSJim Jagielski     {
1581*b1cdbd2cSJim Jagielski         return
1582*b1cdbd2cSJim Jagielski           (
1583*b1cdbd2cSJim Jagielski             rOrig.maTargetName == rNew.maSearchName &&
1584*b1cdbd2cSJim Jagielski             rOrig.meWeight == rNew.meWeight &&
1585*b1cdbd2cSJim Jagielski             rOrig.meItalic == rNew.meItalic &&
1586*b1cdbd2cSJim Jagielski             rOrig.mePitch == rNew.mePitch &&
1587*b1cdbd2cSJim Jagielski             rOrig.meWidthType == rNew.meWidthType
1588*b1cdbd2cSJim Jagielski           );
1589*b1cdbd2cSJim Jagielski     }
1590*b1cdbd2cSJim Jagielski }
1591*b1cdbd2cSJim Jagielski 
1592*b1cdbd2cSJim Jagielski //--------------------------------------------------------------------------
1593*b1cdbd2cSJim Jagielski 
FindFontSubstitute(ImplFontSelectData & rFontSelData) const1594*b1cdbd2cSJim Jagielski bool FcPreMatchSubstititution::FindFontSubstitute( ImplFontSelectData &rFontSelData ) const
1595*b1cdbd2cSJim Jagielski {
1596*b1cdbd2cSJim Jagielski     // We dont' actually want to talk to Fontconfig at all for symbol fonts
1597*b1cdbd2cSJim Jagielski     if( rFontSelData.IsSymbolFont() )
1598*b1cdbd2cSJim Jagielski         return false;
1599*b1cdbd2cSJim Jagielski     // StarSymbol is a unicode font, but it still deserves the symbol flag
1600*b1cdbd2cSJim Jagielski     if( 0 == rFontSelData.maSearchName.CompareIgnoreCaseToAscii( "starsymbol", 10)
1601*b1cdbd2cSJim Jagielski     ||  0 == rFontSelData.maSearchName.CompareIgnoreCaseToAscii( "opensymbol", 10) )
1602*b1cdbd2cSJim Jagielski         return false;
1603*b1cdbd2cSJim Jagielski 
1604*b1cdbd2cSJim Jagielski     rtl::OUString aDummy;
1605*b1cdbd2cSJim Jagielski     const ImplFontSelectData aOut = GetFcSubstitute( rFontSelData, aDummy );
1606*b1cdbd2cSJim Jagielski     // TODO: cache the font substitution suggestion
1607*b1cdbd2cSJim Jagielski     // FC doing it would be preferable because it knows the invariables
1608*b1cdbd2cSJim Jagielski     // e.g. FC knows the FC rule that all Arial gets replaced by LiberationSans
1609*b1cdbd2cSJim Jagielski     // whereas we would have to check for every size or attribute
1610*b1cdbd2cSJim Jagielski     if( !aOut.maSearchName.Len() )
1611*b1cdbd2cSJim Jagielski         return false;
1612*b1cdbd2cSJim Jagielski 
1613*b1cdbd2cSJim Jagielski     const bool bHaveSubstitute = !uselessmatch( rFontSelData, aOut );
1614*b1cdbd2cSJim Jagielski 
1615*b1cdbd2cSJim Jagielski #ifdef DEBUG
1616*b1cdbd2cSJim Jagielski     const ByteString aOrigName( rFontSelData.maTargetName, RTL_TEXTENCODING_UTF8 );
1617*b1cdbd2cSJim Jagielski     const ByteString aSubstName( aOut.maSearchName, RTL_TEXTENCODING_UTF8 );
1618*b1cdbd2cSJim Jagielski     printf( "FcPreMatchSubstititution \"%s\" bipw=%d%d%d%d -> ",
1619*b1cdbd2cSJim Jagielski         aOrigName.GetBuffer(), rFontSelData.meWeight, rFontSelData.meItalic,
1620*b1cdbd2cSJim Jagielski         rFontSelData.mePitch, rFontSelData.meWidthType );
1621*b1cdbd2cSJim Jagielski     if( !bHaveSubstitute )
1622*b1cdbd2cSJim Jagielski         printf( "no substitute available\n" );
1623*b1cdbd2cSJim Jagielski     else
1624*b1cdbd2cSJim Jagielski         printf( "\"%s\" bipw=%d%d%d%d\n", aSubstName.GetBuffer(),
1625*b1cdbd2cSJim Jagielski 	    aOut.meWeight, aOut.meItalic, aOut.mePitch, aOut.meWidthType );
1626*b1cdbd2cSJim Jagielski #endif
1627*b1cdbd2cSJim Jagielski 
1628*b1cdbd2cSJim Jagielski     if( bHaveSubstitute )
1629*b1cdbd2cSJim Jagielski         rFontSelData = aOut;
1630*b1cdbd2cSJim Jagielski 
1631*b1cdbd2cSJim Jagielski     return bHaveSubstitute;
1632*b1cdbd2cSJim Jagielski }
1633*b1cdbd2cSJim Jagielski 
1634*b1cdbd2cSJim Jagielski // -----------------------------------------------------------------------
1635*b1cdbd2cSJim Jagielski 
FindFontSubstitute(ImplFontSelectData & rFontSelData,rtl::OUString & rMissingCodes) const1636*b1cdbd2cSJim Jagielski bool FcGlyphFallbackSubstititution::FindFontSubstitute( ImplFontSelectData& rFontSelData,
1637*b1cdbd2cSJim Jagielski     rtl::OUString& rMissingCodes ) const
1638*b1cdbd2cSJim Jagielski {
1639*b1cdbd2cSJim Jagielski     // We dont' actually want to talk to Fontconfig at all for symbol fonts
1640*b1cdbd2cSJim Jagielski     if( rFontSelData.IsSymbolFont() )
1641*b1cdbd2cSJim Jagielski 	return false;
1642*b1cdbd2cSJim Jagielski     // StarSymbol is a unicode font, but it still deserves the symbol flag
1643*b1cdbd2cSJim Jagielski     if( 0 == rFontSelData.maSearchName.CompareIgnoreCaseToAscii( "starsymbol", 10)
1644*b1cdbd2cSJim Jagielski     ||  0 == rFontSelData.maSearchName.CompareIgnoreCaseToAscii( "opensymbol", 10) )
1645*b1cdbd2cSJim Jagielski         return false;
1646*b1cdbd2cSJim Jagielski 
1647*b1cdbd2cSJim Jagielski     const ImplFontSelectData aOut = GetFcSubstitute( rFontSelData, rMissingCodes );
1648*b1cdbd2cSJim Jagielski     // TODO: cache the unicode + srcfont specific result
1649*b1cdbd2cSJim Jagielski     // FC doing it would be preferable because it knows the invariables
1650*b1cdbd2cSJim Jagielski     // e.g. FC knows the FC rule that all Arial gets replaced by LiberationSans
1651*b1cdbd2cSJim Jagielski     // whereas we would have to check for every size or attribute
1652*b1cdbd2cSJim Jagielski     if( !aOut.maSearchName.Len() )
1653*b1cdbd2cSJim Jagielski         return false;
1654*b1cdbd2cSJim Jagielski 
1655*b1cdbd2cSJim Jagielski     const bool bHaveSubstitute = !uselessmatch( rFontSelData, aOut );
1656*b1cdbd2cSJim Jagielski 
1657*b1cdbd2cSJim Jagielski #ifdef DEBUG
1658*b1cdbd2cSJim Jagielski     const ByteString aOrigName( rFontSelData.maTargetName, RTL_TEXTENCODING_UTF8 );
1659*b1cdbd2cSJim Jagielski     const ByteString aSubstName( aOut.maSearchName, RTL_TEXTENCODING_UTF8 );
1660*b1cdbd2cSJim Jagielski     printf( "FcGFSubstititution \"%s\" bipw=%d%d%d%d ->",
1661*b1cdbd2cSJim Jagielski         aOrigName.GetBuffer(), rFontSelData.meWeight, rFontSelData.meItalic,
1662*b1cdbd2cSJim Jagielski         rFontSelData.mePitch, rFontSelData.meWidthType );
1663*b1cdbd2cSJim Jagielski     if( !bHaveSubstitute )
1664*b1cdbd2cSJim Jagielski         printf( "no substitute available\n" );
1665*b1cdbd2cSJim Jagielski     else
1666*b1cdbd2cSJim Jagielski         printf( "\"%s\" bipw=%d%d%d%d\n", aSubstName.GetBuffer(),
1667*b1cdbd2cSJim Jagielski 	    aOut.meWeight, aOut.meItalic, aOut.mePitch, aOut.meWidthType );
1668*b1cdbd2cSJim Jagielski #endif
1669*b1cdbd2cSJim Jagielski 
1670*b1cdbd2cSJim Jagielski     if( bHaveSubstitute )
1671*b1cdbd2cSJim Jagielski         rFontSelData = aOut;
1672*b1cdbd2cSJim Jagielski 
1673*b1cdbd2cSJim Jagielski     return bHaveSubstitute;
1674*b1cdbd2cSJim Jagielski }
1675*b1cdbd2cSJim Jagielski 
1676*b1cdbd2cSJim Jagielski // ===========================================================================
1677*b1cdbd2cSJim Jagielski 
1678