PageRenderTime 54ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/tags/Doduo1.1.1/WebCore/platform/graphics/gtk/FontGtk.cpp

https://github.com/weissms/owb-mirror
C++ | 360 lines | 242 code | 71 blank | 47 comment | 44 complexity | bb6d04c448ae2dbfd2eaa72d6a1169d0 MD5 | raw file
  1. /*
  2. * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
  3. * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
  4. * Copyright (c) 2007 Hiroyuki Ikezoe
  5. * Copyright (c) 2007 Kouhei Sutou
  6. * Copyright (C) 2007 Alp Toker <alp@atoker.com>
  7. * Copyright (C) 2008 Xan Lopez <xan@gnome.org>
  8. * Copyright (C) 2008 Nuanti Ltd.
  9. * All rights reserved.
  10. *
  11. * Redistribution and use in source and binary forms, with or without
  12. * modification, are permitted provided that the following conditions
  13. * are met:
  14. * 1. Redistributions of source code must retain the above copyright
  15. * notice, this list of conditions and the following disclaimer.
  16. * 2. Redistributions in binary form must reproduce the above copyright
  17. * notice, this list of conditions and the following disclaimer in the
  18. * documentation and/or other materials provided with the distribution.
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
  21. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  22. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  23. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
  24. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  25. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  26. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  27. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  28. * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  29. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  30. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31. */
  32. #include "config.h"
  33. #include "Font.h"
  34. #include "GraphicsContext.h"
  35. #include "NotImplemented.h"
  36. #include "SimpleFontData.h"
  37. #include <cairo.h>
  38. #include <gdk/gdk.h>
  39. #include <pango/pango.h>
  40. #include <pango/pangocairo.h>
  41. #if defined(USE_FREETYPE)
  42. #include <pango/pangofc-fontmap.h>
  43. #endif
  44. namespace WebCore {
  45. #define IS_HIGH_SURROGATE(u) ((UChar)(u) >= (UChar)0xd800 && (UChar)(u) <= (UChar)0xdbff)
  46. #define IS_LOW_SURROGATE(u) ((UChar)(u) >= (UChar)0xdc00 && (UChar)(u) <= (UChar)0xdfff)
  47. static void utf16_to_utf8(const UChar* aText, gint aLength, char* &text, gint &length)
  48. {
  49. gboolean need_copy = FALSE;
  50. int i;
  51. for (i = 0; i < aLength; i++) {
  52. if (!aText[i] || IS_LOW_SURROGATE(aText[i])) {
  53. need_copy = TRUE;
  54. break;
  55. }
  56. else if (IS_HIGH_SURROGATE(aText[i])) {
  57. if (i < aLength - 1 && IS_LOW_SURROGATE(aText[i+1]))
  58. i++;
  59. else {
  60. need_copy = TRUE;
  61. break;
  62. }
  63. }
  64. }
  65. if (need_copy) {
  66. /* Pango doesn't correctly handle nuls. We convert them to 0xff. */
  67. /* Also "validate" UTF-16 text to make sure conversion doesn't fail. */
  68. UChar* p = (UChar*)g_memdup(aText, aLength * sizeof(aText[0]));
  69. /* don't need to reset i */
  70. for (i = 0; i < aLength; i++) {
  71. if (!p[i] || IS_LOW_SURROGATE(p[i]))
  72. p[i] = 0xFFFD;
  73. else if (IS_HIGH_SURROGATE(p[i])) {
  74. if (i < aLength - 1 && IS_LOW_SURROGATE(aText[i+1]))
  75. i++;
  76. else
  77. p[i] = 0xFFFD;
  78. }
  79. }
  80. aText = p;
  81. }
  82. glong items_written;
  83. text = g_utf16_to_utf8(reinterpret_cast<const gunichar2*>(aText), aLength, NULL, &items_written, NULL);
  84. length = items_written;
  85. if (need_copy)
  86. g_free((gpointer)aText);
  87. }
  88. static gchar* convertUniCharToUTF8(const UChar* characters, gint length, int from, int to)
  89. {
  90. gchar* utf8 = 0;
  91. gint new_length = 0;
  92. utf16_to_utf8(characters, length, utf8, new_length);
  93. if (!utf8)
  94. return NULL;
  95. if (from > 0) {
  96. // discard the first 'from' characters
  97. // FIXME: we should do this before the conversion probably
  98. gchar* str_left = g_utf8_offset_to_pointer(utf8, from);
  99. gchar* tmp = g_strdup(str_left);
  100. g_free(utf8);
  101. utf8 = tmp;
  102. }
  103. gchar* pos = utf8;
  104. gint len = strlen(pos);
  105. GString* ret = g_string_new_len(NULL, len);
  106. // replace line break by space
  107. while (len > 0) {
  108. gint index, start;
  109. pango_find_paragraph_boundary(pos, len, &index, &start);
  110. g_string_append_len(ret, pos, index);
  111. if (index == start)
  112. break;
  113. g_string_append_c(ret, ' ');
  114. pos += start;
  115. len -= start;
  116. }
  117. return g_string_free(ret, FALSE);
  118. }
  119. static void setPangoAttributes(const Font* font, const TextRun& run, PangoLayout* layout)
  120. {
  121. #if defined(USE_FREETYPE)
  122. if (font->primaryFont()->m_font.m_pattern) {
  123. PangoFontDescription* desc = pango_fc_font_description_from_pattern(font->primaryFont()->m_font.m_pattern, FALSE);
  124. pango_layout_set_font_description(layout, desc);
  125. pango_font_description_free(desc);
  126. }
  127. #elif defined(USE_PANGO)
  128. if (font->primaryFont()->m_font.m_font) {
  129. PangoFontDescription* desc = pango_font_describe(font->primaryFont()->m_font.m_font);
  130. pango_layout_set_font_description(layout, desc);
  131. pango_font_description_free(desc);
  132. }
  133. #endif
  134. pango_layout_set_auto_dir(layout, FALSE);
  135. PangoContext* pangoContext = pango_layout_get_context(layout);
  136. PangoDirection direction = run.rtl() ? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR;
  137. pango_context_set_base_dir(pangoContext, direction);
  138. PangoAttrList* list = pango_attr_list_new();
  139. PangoAttribute* attr;
  140. attr = pango_attr_size_new_absolute(font->pixelSize() * PANGO_SCALE);
  141. attr->end_index = G_MAXUINT;
  142. pango_attr_list_insert_before(list, attr);
  143. if (!run.spacingDisabled()) {
  144. attr = pango_attr_letter_spacing_new(font->letterSpacing() * PANGO_SCALE);
  145. attr->end_index = G_MAXUINT;
  146. pango_attr_list_insert_before(list, attr);
  147. }
  148. // Pango does not yet support synthesising small caps
  149. // See http://bugs.webkit.org/show_bug.cgi?id=15610
  150. pango_layout_set_attributes(layout, list);
  151. pango_attr_list_unref(list);
  152. }
  153. void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const
  154. {
  155. cairo_t* cr = context->platformContext();
  156. cairo_save(cr);
  157. cairo_translate(cr, point.x(), point.y());
  158. PangoLayout* layout = pango_cairo_create_layout(cr);
  159. setPangoAttributes(this, run, layout);
  160. gchar* utf8 = convertUniCharToUTF8(run.characters(), run.length(), 0, run.length());
  161. pango_layout_set_text(layout, utf8, -1);
  162. // Our layouts are single line
  163. PangoLayoutLine* layoutLine = pango_layout_get_line_readonly(layout, 0);
  164. GdkRegion* partialRegion = NULL;
  165. if (to - from != run.length()) {
  166. // Clip the region of the run to be rendered
  167. char* start = g_utf8_offset_to_pointer(utf8, from);
  168. char* end = g_utf8_offset_to_pointer(start, to - from);
  169. int ranges[] = {start - utf8, end - utf8};
  170. partialRegion = gdk_pango_layout_line_get_clip_region(layoutLine, 0, 0, ranges, 1);
  171. gdk_region_shrink(partialRegion, 0, -pixelSize());
  172. }
  173. Color fillColor = context->fillColor();
  174. float red, green, blue, alpha;
  175. // Text shadow, inspired by FontMac
  176. IntSize shadowSize;
  177. int shadowBlur = 0;
  178. Color shadowColor;
  179. bool hasShadow = context->textDrawingMode() == cTextFill &&
  180. context->getShadow(shadowSize, shadowBlur, shadowColor);
  181. // TODO: Blur support
  182. if (hasShadow) {
  183. // Disable graphics context shadows (not yet implemented) and paint them manually
  184. context->clearShadow();
  185. Color shadowFillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), shadowColor.alpha() * fillColor.alpha() / 255);
  186. cairo_save(cr);
  187. shadowFillColor.getRGBA(red, green, blue, alpha);
  188. cairo_set_source_rgba(cr, red, green, blue, alpha);
  189. cairo_translate(cr, shadowSize.width(), shadowSize.height());
  190. if (partialRegion) {
  191. gdk_cairo_region(cr, partialRegion);
  192. cairo_clip(cr);
  193. }
  194. pango_cairo_show_layout_line(cr, layoutLine);
  195. cairo_restore(cr);
  196. }
  197. fillColor.getRGBA(red, green, blue, alpha);
  198. cairo_set_source_rgba(cr, red, green, blue, alpha);
  199. if (partialRegion) {
  200. gdk_cairo_region(cr, partialRegion);
  201. cairo_clip(cr);
  202. }
  203. pango_cairo_show_layout_line(cr, layoutLine);
  204. if (context->textDrawingMode() & cTextStroke) {
  205. Color strokeColor = context->strokeColor();
  206. strokeColor.getRGBA(red, green, blue, alpha);
  207. cairo_set_source_rgba(cr, red, green, blue, alpha);
  208. pango_cairo_layout_line_path(cr, layoutLine);
  209. cairo_set_line_width(cr, context->strokeThickness());
  210. cairo_stroke(cr);
  211. }
  212. // Re-enable the platform shadow we disabled earlier
  213. if (hasShadow)
  214. context->setShadow(shadowSize, shadowBlur, shadowColor);
  215. // Pango sometimes leaves behind paths we don't want
  216. cairo_new_path(cr);
  217. if (partialRegion)
  218. gdk_region_destroy(partialRegion);
  219. g_free(utf8);
  220. g_object_unref(layout);
  221. cairo_restore(cr);
  222. }
  223. // We should create the layout with our actual context but we can't access it from here.
  224. static PangoLayout* getDefaultPangoLayout(const TextRun& run)
  225. {
  226. static PangoFontMap* map = pango_cairo_font_map_get_default();
  227. static PangoContext* pangoContext = pango_cairo_font_map_create_context(PANGO_CAIRO_FONT_MAP(map));
  228. PangoLayout* layout = pango_layout_new(pangoContext);
  229. return layout;
  230. }
  231. float Font::floatWidthForComplexText(const TextRun& run) const
  232. {
  233. if (run.length() == 0)
  234. return 0.0f;
  235. PangoLayout* layout = getDefaultPangoLayout(run);
  236. setPangoAttributes(this, run, layout);
  237. gchar* utf8 = convertUniCharToUTF8(run.characters(), run.length(), 0, run.length());
  238. pango_layout_set_text(layout, utf8, -1);
  239. int width;
  240. pango_layout_get_pixel_size(layout, &width, 0);
  241. g_free(utf8);
  242. g_object_unref(layout);
  243. return width;
  244. }
  245. int Font::offsetForPositionForComplexText(const TextRun& run, int x, bool includePartialGlyphs) const
  246. {
  247. PangoLayout* layout = getDefaultPangoLayout(run);
  248. setPangoAttributes(this, run, layout);
  249. gchar* utf8 = convertUniCharToUTF8(run.characters(), run.length(), 0, run.length());
  250. pango_layout_set_text(layout, utf8, -1);
  251. int index, trailing;
  252. pango_layout_xy_to_index(layout, x * PANGO_SCALE, 1, &index, &trailing);
  253. glong offset = g_utf8_pointer_to_offset(utf8, utf8 + index);
  254. if (includePartialGlyphs)
  255. offset += trailing;
  256. g_free(utf8);
  257. g_object_unref(layout);
  258. return offset;
  259. }
  260. FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint& point, int h, int from, int to) const
  261. {
  262. PangoLayout* layout = getDefaultPangoLayout(run);
  263. setPangoAttributes(this, run, layout);
  264. gchar* utf8 = convertUniCharToUTF8(run.characters(), run.length(), 0, run.length());
  265. pango_layout_set_text(layout, utf8, -1);
  266. char* start = g_utf8_offset_to_pointer(utf8, from);
  267. char* end = g_utf8_offset_to_pointer(start, to - from);
  268. if (run.ltr()) {
  269. from = start - utf8;
  270. to = end - utf8;
  271. } else {
  272. from = end - utf8;
  273. to = start - utf8;
  274. }
  275. PangoLayoutLine* layoutLine = pango_layout_get_line_readonly(layout, 0);
  276. int x_pos;
  277. x_pos = 0;
  278. if (from < layoutLine->length)
  279. pango_layout_line_index_to_x(layoutLine, from, FALSE, &x_pos);
  280. float beforeWidth = PANGO_PIXELS_FLOOR(x_pos);
  281. x_pos = 0;
  282. if (run.ltr() || to < layoutLine->length)
  283. pango_layout_line_index_to_x(layoutLine, to, FALSE, &x_pos);
  284. float afterWidth = PANGO_PIXELS(x_pos);
  285. g_free(utf8);
  286. g_object_unref(layout);
  287. return FloatRect(point.x() + beforeWidth, point.y(), afterWidth - beforeWidth, h);
  288. }
  289. }