1 /* 2 * Copyright (C) 2007 Kevin Watters, Kevin Ollivier. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "config.h" 27 #include "GlyphBuffer.h" 28 #include "GraphicsContext.h" 29 #include "SimpleFontData.h" 30 31 #include <wx/dc.h> 32 #include <wx/dcgraph.h> 33 #include <wx/defs.h> 34 #include <wx/dcclient.h> 35 #include <wx/gdicmn.h> 36 #include <vector> 37 38 #if USE(WXGC) 39 #include <cairo.h> 40 #include <assert.h> 41 42 #include <pango/pango.h> 43 #include <pango/pangocairo.h> 44 45 // Use cairo-ft if a recent enough Pango version isn't available 46 #if !PANGO_VERSION_CHECK(1,18,0) 47 #include <cairo-ft.h> 48 #include <pango/pangofc-fontmap.h> 49 #endif 50 51 #endif 52 53 #include <gtk/gtk.h> 54 55 namespace WebCore { 56 57 #if USE(WXGC) 58 static PangoFontMap* g_fontMap; 59 60 PangoFontMap* pangoFontMap() 61 { 62 if (!g_fontMap) 63 g_fontMap = pango_cairo_font_map_get_default(); 64 65 return g_fontMap; 66 } 67 68 PangoFont* createPangoFontForFont(const wxFont* wxfont) 69 { 70 ASSERT(wxfont && wxfont->Ok()); 71 72 const char* face = wxfont->GetFaceName().mb_str(wxConvUTF8); 73 char const* families[] = { 74 face, 75 0 76 }; 77 78 switch (wxfont->GetFamily()) { 79 case wxFONTFAMILY_ROMAN: 80 families[1] = "serif"; 81 break; 82 case wxFONTFAMILY_SWISS: 83 families[1] = "sans"; 84 break; 85 case wxFONTFAMILY_MODERN: 86 families[1] = "monospace"; 87 break; 88 default: 89 families[1] = "sans"; 90 } 91 92 PangoFontDescription* description = pango_font_description_new(); 93 pango_font_description_set_absolute_size(description, wxfont->GetPointSize() * PANGO_SCALE); 94 95 PangoFont* pangoFont = 0; 96 PangoContext* pangoContext = 0; 97 98 switch (wxfont->GetWeight()) { 99 case wxFONTWEIGHT_LIGHT: 100 pango_font_description_set_weight(description, PANGO_WEIGHT_LIGHT); 101 break; 102 case wxFONTWEIGHT_NORMAL: 103 pango_font_description_set_weight(description, PANGO_WEIGHT_NORMAL); 104 break; 105 case wxFONTWEIGHT_BOLD: 106 pango_font_description_set_weight(description, PANGO_WEIGHT_BOLD); 107 break; 108 } 109 110 switch (wxfont->GetStyle()) { 111 case wxFONTSTYLE_NORMAL: 112 pango_font_description_set_style(description, PANGO_STYLE_NORMAL); 113 break; 114 case wxFONTSTYLE_ITALIC: 115 pango_font_description_set_style(description, PANGO_STYLE_ITALIC); 116 break; 117 case wxFONTSTYLE_SLANT: 118 pango_font_description_set_style(description, PANGO_STYLE_OBLIQUE); 119 break; 120 } 121 122 PangoFontMap* fontMap = pangoFontMap(); 123 124 pangoContext = pango_cairo_font_map_create_context(PANGO_CAIRO_FONT_MAP(fontMap)); 125 for (unsigned i = 0; !pangoFont && i < G_N_ELEMENTS(families); i++) { 126 pango_font_description_set_family(description, families[i]); 127 pango_context_set_font_description(pangoContext, description); 128 pangoFont = pango_font_map_load_font(fontMap, pangoContext, description); 129 } 130 pango_font_description_free(description); 131 132 return pangoFont; 133 } 134 135 cairo_scaled_font_t* createScaledFontForFont(const wxFont* wxfont) 136 { 137 ASSERT(wxfont && wxfont->Ok()); 138 139 cairo_scaled_font_t* scaledFont = NULL; 140 PangoFont* pangoFont = createPangoFontForFont(wxfont); 141 142 #if PANGO_VERSION_CHECK(1,18,0) 143 if (pangoFont) 144 scaledFont = cairo_scaled_font_reference(pango_cairo_font_get_scaled_font(PANGO_CAIRO_FONT(pangoFont))); 145 #endif 146 147 return scaledFont; 148 } 149 150 PangoGlyph pango_font_get_glyph(PangoFont* font, PangoContext* context, gunichar wc) 151 { 152 PangoGlyph result = 0; 153 gchar buffer[7]; 154 155 gint length = g_unichar_to_utf8(wc, buffer); 156 g_return_val_if_fail(length, 0); 157 158 GList* items = pango_itemize(context, buffer, 0, length, NULL, NULL); 159 160 if (g_list_length(items) == 1) { 161 PangoItem* item = static_cast<PangoItem*>(items->data); 162 PangoFont* tmpFont = item->analysis.font; 163 item->analysis.font = font; 164 165 PangoGlyphString* glyphs = pango_glyph_string_new(); 166 pango_shape(buffer, length, &item->analysis, glyphs); 167 168 item->analysis.font = tmpFont; 169 170 if (glyphs->num_glyphs == 1) 171 result = glyphs->glyphs[0].glyph; 172 else 173 g_warning("didn't get 1 glyph but %d", glyphs->num_glyphs); 174 175 pango_glyph_string_free(glyphs); 176 } 177 178 g_list_foreach(items, (GFunc)pango_item_free, NULL); 179 g_list_free(items); 180 181 return result; 182 } 183 #endif // USE(WXGC) 184 185 186 void drawTextWithSpacing(GraphicsContext* graphicsContext, const SimpleFontData* font, const wxColour& color, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) 187 { 188 #if USE(WXGC) 189 wxGCDC* dc = static_cast<wxGCDC*>(graphicsContext->platformContext()); 190 wxGraphicsContext* gc = dc->GetGraphicsContext(); 191 gc->PushState(); 192 cairo_t* cr = (cairo_t*)gc->GetNativeContext(); 193 194 wxFont* wxfont = font->getWxFont(); 195 PangoFont* pangoFont = createPangoFontForFont(wxfont); 196 PangoFontMap* fontMap = pangoFontMap(); 197 PangoContext* pangoContext = pango_cairo_font_map_create_context(PANGO_CAIRO_FONT_MAP(fontMap)); 198 cairo_scaled_font_t* scaled_font = createScaledFontForFont(wxfont); 199 ASSERT(scaled_font); 200 201 cairo_glyph_t* glyphs = NULL; 202 glyphs = static_cast<cairo_glyph_t*>(malloc(sizeof(cairo_glyph_t) * numGlyphs)); 203 204 float offset = point.x(); 205 206 for (int i = 0; i < numGlyphs; i++) { 207 glyphs[i].index = pango_font_get_glyph(pangoFont, pangoContext, glyphBuffer.glyphAt(from + i)); 208 glyphs[i].x = offset; 209 glyphs[i].y = point.y(); 210 offset += glyphBuffer.advanceAt(from + i); 211 } 212 213 cairo_set_source_rgba(cr, color.Red()/255.0, color.Green()/255.0, color.Blue()/255.0, color.Alpha()/255.0); 214 cairo_set_scaled_font(cr, scaled_font); 215 216 cairo_show_glyphs(cr, glyphs, numGlyphs); 217 218 cairo_scaled_font_destroy(scaled_font); 219 gc->PopState(); 220 #else 221 wxDC* dc = graphicsContext->platformContext(); 222 223 wxFont* wxfont = font->getWxFont(); 224 if (wxfont && wxfont->IsOk()) 225 dc->SetFont(*wxfont); 226 dc->SetTextForeground(color); 227 228 // convert glyphs to wxString 229 GlyphBufferGlyph* glyphs = const_cast<GlyphBufferGlyph*>(glyphBuffer.glyphs(from)); 230 int offset = point.x(); 231 wxString text = wxEmptyString; 232 for (unsigned i = 0; i < numGlyphs; i++) { 233 text = text.Append((wxChar)glyphs[i]); 234 offset += glyphBuffer.advanceAt(from + i); 235 } 236 237 // the y point is actually the bottom point of the text, turn it into the top 238 float height = font->ascent() - font->descent(); 239 wxCoord ypoint = (wxCoord) (point.y() - height); 240 241 dc->DrawText(text, (wxCoord)point.x(), ypoint); 242 #endif 243 } 244 245 } 246