1/*
2 * Copyright (C) 2007 Kevin Ollivier <kevino@theolliviers.com>
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// this needs to be included before fontprops.h for UChar* to be defined.
28#include <wtf/unicode/Unicode.h>
29
30#include <wx/defs.h>
31#include <wx/gdicmn.h>
32#include <wx/font.h>
33#include <wx/fontutil.h>
34#include "fontprops.h"
35#include "non-kerned-drawing.h"
36
37#include <gdk/gdk.h>
38
39#include <cairo.h>
40#include <pango/pango.h>
41#include <pango/pangocairo.h>
42
43wxFontProperties::wxFontProperties(wxFont* font):
44m_ascent(0), m_descent(0), m_lineGap(0), m_lineSpacing(0), m_xHeight(0)
45{
46    ASSERT(font && font->Ok());
47
48#if USE(WXGC)
49    cairo_font_extents_t font_extents;
50    cairo_text_extents_t text_extents;
51    cairo_scaled_font_t* scaled_font = WebCore::createScaledFontForFont(font);
52
53    cairo_scaled_font_extents(scaled_font, &font_extents);
54    m_ascent = static_cast<int>(font_extents.ascent);
55    m_descent = static_cast<int>(font_extents.descent);
56    m_lineSpacing = static_cast<int>(font_extents.height);
57    cairo_scaled_font_text_extents(scaled_font, "x", &text_extents);
58    m_xHeight = text_extents.height;
59    cairo_scaled_font_text_extents(scaled_font, " ", &text_extents);
60    m_lineGap = m_lineSpacing - m_ascent - m_descent;
61
62    cairo_scaled_font_destroy(scaled_font);
63#else
64    PangoContext* context = gdk_pango_context_get_for_screen( gdk_screen_get_default() );
65    PangoLayout* layout = pango_layout_new(context);
66    // and use it if it's valid
67    if ( font && font->Ok() )
68    {
69        pango_layout_set_font_description
70        (
71            layout,
72            font->GetNativeFontInfo()->description
73        );
74    }
75
76    PangoFontMetrics* metrics = pango_context_get_metrics (context, font->GetNativeFontInfo()->description, NULL);
77
78    int height = font->GetPixelSize().GetHeight();
79
80    m_ascent = PANGO_PIXELS(pango_font_metrics_get_ascent(metrics));
81    m_descent = PANGO_PIXELS(pango_font_metrics_get_descent(metrics));
82
83    int h;
84
85    const char* x = "x";
86    pango_layout_set_text( layout, x, strlen(x) );
87    pango_layout_get_pixel_size( layout, NULL, &h );
88
89    m_xHeight = h;
90    m_lineGap = (m_ascent + m_descent) / 4; // FIXME: How can we calculate this via Pango?
91    m_lineSpacing = m_ascent + m_descent;
92
93    pango_font_metrics_unref(metrics);
94#endif
95}
96
97bool wxFontContainsCharacters(const wxFont& font, const UChar* characters, int length)
98{
99    return true;
100}
101
102void GetTextExtent( const wxFont& font, const wxString& str, wxCoord *width, wxCoord *height,
103                            wxCoord *descent, wxCoord *externalLeading )
104{
105    if ( width )
106        *width = 0;
107    if ( height )
108        *height = 0;
109    if ( descent )
110        *descent = 0;
111    if ( externalLeading )
112        *externalLeading = 0;
113
114    if (str.empty())
115        return;
116
117// FIXME: Doesn't support height, descent or external leading, though we don't need this for WebKit
118// it will need to be implemented before merging into wx unless we craft a new API.
119#if USE(WXGC)
120    PangoFont* pangoFont = WebCore::createPangoFontForFont(&font);
121    PangoContext* pangoContext = pango_cairo_font_map_create_context(PANGO_CAIRO_FONT_MAP(WebCore::pangoFontMap()));
122    PangoGlyph pangoGlyph = WebCore::pango_font_get_glyph(pangoFont, pangoContext, (gunichar)g_utf8_get_char(str.ToUTF8()));
123    cairo_glyph_t cglyph = { pangoGlyph, 0, 0 };
124    cairo_text_extents_t extents;
125    cairo_scaled_font_t* scaled_font = WebCore::createScaledFontForFont(&font);
126    cairo_scaled_font_glyph_extents(scaled_font, &cglyph, 1, &extents);
127
128    if (cairo_scaled_font_status(scaled_font) == CAIRO_STATUS_SUCCESS && extents.x_advance != 0)
129        *width = (wxCoord)extents.x_advance;
130
131    cairo_scaled_font_destroy(scaled_font);
132    g_object_unref(pangoContext);
133    g_object_unref(pangoFont);
134#else
135    PangoContext* context = gdk_pango_context_get_for_screen( gdk_screen_get_default() );
136    PangoLayout* m_layout = pango_layout_new(context);
137    // and use it if it's valid
138    if ( font && font->IsOk() )
139    {
140        pango_layout_set_font_description
141        (
142            m_layout,
143            font->GetNativeFontInfo()->description
144        );
145    }
146
147    // Set layout's text
148    const wxCharBuffer dataUTF8 = wxConvUTF8.cWX2MB(str);
149    if ( !dataUTF8 )
150    {
151        // hardly ideal, but what else can we do if conversion failed?
152        return;
153    }
154
155    pango_layout_set_text( m_layout, dataUTF8, strlen(dataUTF8) );
156
157    int h = 0;
158    pango_layout_get_pixel_size( m_layout, width, &h );
159
160    if (descent)
161    {
162        PangoLayoutIter *iter = pango_layout_get_iter(m_layout);
163        int baseline = pango_layout_iter_get_baseline(iter);
164        pango_layout_iter_free(iter);
165        *descent = h - PANGO_PIXELS(baseline);
166    }
167
168    if (height)
169        *height = (wxCoord) h;
170#endif
171}
172
173