Diff
Modified: trunk/Source/WebCore/ChangeLog (94873 => 94874)
--- trunk/Source/WebCore/ChangeLog 2011-09-09 21:17:18 UTC (rev 94873)
+++ trunk/Source/WebCore/ChangeLog 2011-09-09 21:40:04 UTC (rev 94874)
@@ -1,3 +1,18 @@
+2011-09-09 Rafael Antognolli <antogno...@profusion.mobi>
+
+ Rename FontGtk.cpp to FontPango.cpp
+ https://bugs.webkit.org/show_bug.cgi?id=66323
+
+ Reviewed by Martin Robinson.
+
+ This file will be used by the EFL port too, and since it's not GTK
+ specific anymore, rename it to something better.
+
+ No new functionality so no new tests.
+
+ * GNUmakefile.list.am:
+ * platform/graphics/pango/FontPango.cpp: Renamed from Source/WebCore/platform/graphics/gtk/FontGtk.cpp.
+
2011-09-09 Adam Klein <ad...@chromium.org>
Initialize ExceptionCode in Element::removeAttribute
Modified: trunk/Source/WebCore/GNUmakefile.list.am (94873 => 94874)
--- trunk/Source/WebCore/GNUmakefile.list.am 2011-09-09 21:17:18 UTC (rev 94873)
+++ trunk/Source/WebCore/GNUmakefile.list.am 2011-09-09 21:40:04 UTC (rev 94874)
@@ -3959,7 +3959,6 @@
Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp \
Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.h \
Source/WebCore/platform/graphics/gtk/ColorGtk.cpp \
- Source/WebCore/platform/graphics/gtk/FontGtk.cpp \
Source/WebCore/platform/graphics/gtk/GdkCairoUtilities.cpp \
Source/WebCore/platform/graphics/gtk/GdkCairoUtilities.h \
Source/WebCore/platform/graphics/gtk/IconGtk.cpp \
@@ -4085,6 +4084,7 @@
Source/WebCore/platform/graphics/freetype/GlyphPageTreeNodeFreeType.cpp \
Source/WebCore/platform/graphics/freetype/SimpleFontDataFreeType.cpp
webcoregtk_sources += \
+ Source/WebCore/platform/graphics/pango/FontPango.cpp \
Source/WebCore/platform/graphics/freetype/FontPlatformDataFreeType.cpp
endif # END USE_FREETYPE
@@ -4099,6 +4099,8 @@
Source/WebCore/platform/graphics/pango/FontPlatformData.h \
Source/WebCore/platform/graphics/pango/GlyphPageTreeNodePango.cpp \
Source/WebCore/platform/graphics/pango/SimpleFontDataPango.cpp
+webcoregtk_sources += \
+ Source/WebCore/platform/graphics/pango/FontPango.cpp
endif # END USE_PANGO
# ----
Deleted: trunk/Source/WebCore/platform/graphics/gtk/FontGtk.cpp (94873 => 94874)
--- trunk/Source/WebCore/platform/graphics/gtk/FontGtk.cpp 2011-09-09 21:17:18 UTC (rev 94873)
+++ trunk/Source/WebCore/platform/graphics/gtk/FontGtk.cpp 2011-09-09 21:40:04 UTC (rev 94874)
@@ -1,444 +0,0 @@
-/*
- * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
- * Copyright (C) 2006 Michael Emmel mike.em...@gmail.com
- * Copyright (c) 2007 Hiroyuki Ikezoe
- * Copyright (c) 2007 Kouhei Sutou
- * Copyright (C) 2007 Alp Toker <a...@atoker.com>
- * Copyright (C) 2008 Xan Lopez <x...@gnome.org>
- * Copyright (C) 2008 Nuanti Ltd.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "Font.h"
-
-#include "CairoUtilities.h"
-#include "GOwnPtr.h"
-#include "GraphicsContext.h"
-#include "NotImplemented.h"
-#include "PlatformContextCairo.h"
-#include "ShadowBlur.h"
-#include "SimpleFontData.h"
-#include "TextRun.h"
-#include <cairo.h>
-#include <gdk/gdk.h>
-#include <pango/pango.h>
-#include <pango/pangocairo.h>
-
-#if USE(FREETYPE)
-#include <pango/pangofc-fontmap.h>
-#endif
-
-namespace WebCore {
-
-#ifdef GTK_API_VERSION_2
-typedef GdkRegion* PangoRegionType;
-
-void destroyPangoRegion(PangoRegionType region)
-{
- gdk_region_destroy(region);
-}
-
-IntRect getPangoRegionExtents(PangoRegionType region)
-{
- GdkRectangle rectangle;
- gdk_region_get_clipbox(region, &rectangle);
- return IntRect(rectangle.x, rectangle.y, rectangle.width, rectangle.height);
-}
-#else
-typedef cairo_region_t* PangoRegionType;
-
-void destroyPangoRegion(PangoRegionType region)
-{
- cairo_region_destroy(region);
-}
-
-IntRect getPangoRegionExtents(PangoRegionType region)
-{
- cairo_rectangle_int_t rectangle;
- cairo_region_get_extents(region, &rectangle);
- return IntRect(rectangle.x, rectangle.y, rectangle.width, rectangle.height);
-}
-#endif
-
-#define IS_HIGH_SURROGATE(u) ((UChar)(u) >= (UChar)0xd800 && (UChar)(u) <= (UChar)0xdbff)
-#define IS_LOW_SURROGATE(u) ((UChar)(u) >= (UChar)0xdc00 && (UChar)(u) <= (UChar)0xdfff)
-
-static gchar* utf16ToUtf8(const UChar* aText, gint aLength, gint &length)
-{
- gboolean needCopy = FALSE;
-
- for (int i = 0; i < aLength; i++) {
- if (!aText[i] || IS_LOW_SURROGATE(aText[i])) {
- needCopy = TRUE;
- break;
- }
-
- if (IS_HIGH_SURROGATE(aText[i])) {
- if (i < aLength - 1 && IS_LOW_SURROGATE(aText[i+1]))
- i++;
- else {
- needCopy = TRUE;
- break;
- }
- }
- }
-
- GOwnPtr<UChar> copiedString;
- if (needCopy) {
- /* Pango doesn't correctly handle nuls. We convert them to 0xff. */
- /* Also "validate" UTF-16 text to make sure conversion doesn't fail. */
-
- copiedString.set(static_cast<UChar*>(g_memdup(aText, aLength * sizeof(aText[0]))));
- UChar* p = copiedString.get();
-
- /* don't need to reset i */
- for (int i = 0; i < aLength; i++) {
- if (!p[i] || IS_LOW_SURROGATE(p[i]))
- p[i] = 0xFFFD;
- else if (IS_HIGH_SURROGATE(p[i])) {
- if (i < aLength - 1 && IS_LOW_SURROGATE(aText[i+1]))
- i++;
- else
- p[i] = 0xFFFD;
- }
- }
-
- aText = p;
- }
-
- gchar* utf8Text;
- glong itemsWritten;
- utf8Text = g_utf16_to_utf8(static_cast<const gunichar2*>(aText), aLength, 0, &itemsWritten, 0);
- length = itemsWritten;
-
- return utf8Text;
-}
-
-static gchar* convertUniCharToUTF8(const UChar* characters, gint length, int from, int to)
-{
- gint newLength = 0;
- GOwnPtr<gchar> utf8Text(utf16ToUtf8(characters, length, newLength));
- if (!utf8Text)
- return 0;
-
- gchar* pos = utf8Text.get();
- if (from > 0) {
- // discard the first 'from' characters
- // FIXME: we should do this before the conversion probably
- pos = g_utf8_offset_to_pointer(utf8Text.get(), from);
- }
-
- gint len = strlen(pos);
- GString* ret = g_string_new_len(NULL, len);
-
- // replace line break by space
- while (len > 0) {
- gint index, start;
- pango_find_paragraph_boundary(pos, len, &index, &start);
- g_string_append_len(ret, pos, index);
- if (index == start)
- break;
- g_string_append_c(ret, ' ');
- pos += start;
- len -= start;
- }
- return g_string_free(ret, FALSE);
-}
-
-static void setPangoAttributes(const Font* font, const TextRun& run, PangoLayout* layout)
-{
-#if USE(FREETYPE)
- if (font->primaryFont()->platformData().m_pattern) {
- PangoFontDescription* desc = pango_fc_font_description_from_pattern(font->primaryFont()->platformData().m_pattern.get(), FALSE);
- pango_layout_set_font_description(layout, desc);
- pango_font_description_free(desc);
- }
-#elif USE(PANGO)
- if (font->primaryFont()->platformData().m_font) {
- PangoFontDescription* desc = pango_font_describe(font->primaryFont()->platformData().m_font);
- pango_layout_set_font_description(layout, desc);
- pango_font_description_free(desc);
- }
-#endif
-
- pango_layout_set_auto_dir(layout, FALSE);
-
- PangoContext* pangoContext = pango_layout_get_context(layout);
- PangoDirection direction = run.rtl() ? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR;
- pango_context_set_base_dir(pangoContext, direction);
- PangoAttrList* list = pango_attr_list_new();
- PangoAttribute* attr;
-
- attr = pango_attr_size_new_absolute(font->pixelSize() * PANGO_SCALE);
- attr->end_index = G_MAXUINT;
- pango_attr_list_insert_before(list, attr);
-
- if (!run.spacingDisabled()) {
- attr = pango_attr_letter_spacing_new(font->letterSpacing() * PANGO_SCALE);
- attr->end_index = G_MAXUINT;
- pango_attr_list_insert_before(list, attr);
- }
-
- // Pango does not yet support synthesising small caps
- // See http://bugs.webkit.org/show_bug.cgi?id=15610
-
- pango_layout_set_attributes(layout, list);
- pango_attr_list_unref(list);
-}
-
-bool Font::canReturnFallbackFontsForComplexText()
-{
- return false;
-}
-
-bool Font::canExpandAroundIdeographsInComplexText()
-{
- return false;
-}
-
-static void drawGlyphsShadow(GraphicsContext* graphicsContext, const FloatPoint& point, PangoLayoutLine* layoutLine, PangoRegionType renderRegion)
-{
- ShadowBlur& shadow = graphicsContext->platformContext()->shadowBlur();
-
- if (!(graphicsContext->textDrawingMode() & TextModeFill) || shadow.type() == ShadowBlur::NoShadow)
- return;
-
- FloatPoint totalOffset(point + graphicsContext->state().shadowOffset);
-
- // Optimize non-blurry shadows, by just drawing text without the ShadowBlur.
- if (!shadow.mustUseShadowBlur(graphicsContext)) {
- cairo_t* context = graphicsContext->platformContext()->cr();
- cairo_save(context);
- cairo_translate(context, totalOffset.x(), totalOffset.y());
-
- setSourceRGBAFromColor(context, graphicsContext->state().shadowColor);
- gdk_cairo_region(context, renderRegion);
- cairo_clip(context);
- pango_cairo_show_layout_line(context, layoutLine);
-
- cairo_restore(context);
- return;
- }
-
- FloatRect extents(getPangoRegionExtents(renderRegion));
- extents.setLocation(FloatPoint(point.x(), point.y() - extents.height()));
- if (GraphicsContext* shadowContext = shadow.beginShadowLayer(graphicsContext, extents)) {
- cairo_t* cairoShadowContext = shadowContext->platformContext()->cr();
- cairo_translate(cairoShadowContext, point.x(), point.y());
- pango_cairo_show_layout_line(cairoShadowContext, layoutLine);
-
- // We need the clipping region to be active when we blit the blurred shadow back,
- // because we don't want any bits and pieces of characters out of range to be
- // drawn. Since ShadowBlur expects a consistent transform, we have to undo the
- // translation before calling endShadowLayer as well.
- cairo_t* context = graphicsContext->platformContext()->cr();
- cairo_save(context);
- cairo_translate(context, totalOffset.x(), totalOffset.y());
- gdk_cairo_region(context, renderRegion);
- cairo_clip(context);
- cairo_translate(context, -totalOffset.x(), -totalOffset.y());
-
- shadow.endShadowLayer(graphicsContext);
- cairo_restore(context);
- }
-}
-
-void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const
-{
-#if USE(FREETYPE)
- if (!primaryFont()->platformData().m_pattern) {
- drawSimpleText(context, run, point, from, to);
- return;
- }
-#endif
-
- cairo_t* cr = context->platformContext()->cr();
- PangoLayout* layout = pango_cairo_create_layout(cr);
- setPangoAttributes(this, run, layout);
-
- gchar* utf8 = convertUniCharToUTF8(run.characters(), run.length(), 0, run.length());
- pango_layout_set_text(layout, utf8, -1);
-
- // Our layouts are single line
- PangoLayoutLine* layoutLine = pango_layout_get_line_readonly(layout, 0);
-
- // Get the region where this text will be laid out. We will use it to clip
- // the Cairo context, for when we are only painting part of the text run and
- // to calculate the size of the shadow buffer.
- PangoRegionType partialRegion = 0;
- char* start = g_utf8_offset_to_pointer(utf8, from);
- char* end = g_utf8_offset_to_pointer(start, to - from);
- int ranges[] = {start - utf8, end - utf8};
- partialRegion = gdk_pango_layout_line_get_clip_region(layoutLine, 0, 0, ranges, 1);
-
- drawGlyphsShadow(context, point, layoutLine, partialRegion);
-
- cairo_save(cr);
- cairo_translate(cr, point.x(), point.y());
-
- float red, green, blue, alpha;
- context->fillColor().getRGBA(red, green, blue, alpha);
- cairo_set_source_rgba(cr, red, green, blue, alpha);
- gdk_cairo_region(cr, partialRegion);
- cairo_clip(cr);
-
- pango_cairo_show_layout_line(cr, layoutLine);
-
- if (context->textDrawingMode() & TextModeStroke) {
- Color strokeColor = context->strokeColor();
- strokeColor.getRGBA(red, green, blue, alpha);
- cairo_set_source_rgba(cr, red, green, blue, alpha);
- pango_cairo_layout_line_path(cr, layoutLine);
- cairo_set_line_width(cr, context->strokeThickness());
- cairo_stroke(cr);
- }
-
- // Pango sometimes leaves behind paths we don't want
- cairo_new_path(cr);
-
- destroyPangoRegion(partialRegion);
- g_free(utf8);
- g_object_unref(layout);
-
- cairo_restore(cr);
-}
-
-void Font::drawEmphasisMarksForComplexText(GraphicsContext* /* context */, const TextRun& /* run */, const AtomicString& /* mark */, const FloatPoint& /* point */, int /* from */, int /* to */) const
-{
- notImplemented();
-}
-
-// We should create the layout with our actual context but we can't access it from here.
-static PangoLayout* getDefaultPangoLayout(const TextRun& run)
-{
- static PangoFontMap* map = pango_cairo_font_map_get_default();
-#if PANGO_VERSION_CHECK(1,21,5)
- static PangoContext* pangoContext = pango_font_map_create_context(map);
-#else
- // Deprecated in Pango 1.21.
- static PangoContext* pangoContext = pango_cairo_font_map_create_context(PANGO_CAIRO_FONT_MAP(map));
-#endif
- PangoLayout* layout = pango_layout_new(pangoContext);
-
- return layout;
-}
-
-float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* overflow) const
-{
-#if USE(FREETYPE)
- if (!primaryFont()->platformData().m_pattern)
- return floatWidthForSimpleText(run, 0, fallbackFonts, overflow);
-#endif
-
- if (run.length() == 0)
- return 0.0f;
-
- PangoLayout* layout = getDefaultPangoLayout(run);
- setPangoAttributes(this, run, layout);
-
- gchar* utf8 = convertUniCharToUTF8(run.characters(), run.length(), 0, run.length());
- pango_layout_set_text(layout, utf8, -1);
-
- int width;
- pango_layout_get_pixel_size(layout, &width, 0);
-
- g_free(utf8);
- g_object_unref(layout);
-
- return width;
-}
-
-int Font::offsetForPositionForComplexText(const TextRun& run, float xFloat, bool includePartialGlyphs) const
-{
-#if USE(FREETYPE)
- if (!primaryFont()->platformData().m_pattern)
- return offsetForPositionForSimpleText(run, xFloat, includePartialGlyphs);
-#endif
- // FIXME: This truncation is not a problem for HTML, but only affects SVG, which passes floating-point numbers
- // to Font::offsetForPosition(). Bug http://webkit.org/b/40673 tracks fixing this problem.
- int x = static_cast<int>(xFloat);
-
- PangoLayout* layout = getDefaultPangoLayout(run);
- setPangoAttributes(this, run, layout);
-
- gchar* utf8 = convertUniCharToUTF8(run.characters(), run.length(), 0, run.length());
- pango_layout_set_text(layout, utf8, -1);
-
- int index, trailing;
- pango_layout_xy_to_index(layout, x * PANGO_SCALE, 1, &index, &trailing);
- glong offset = g_utf8_pointer_to_offset(utf8, utf8 + index);
- if (includePartialGlyphs)
- offset += trailing;
-
- g_free(utf8);
- g_object_unref(layout);
-
- return offset;
-}
-
-FloatRect Font::selectionRectForComplexText(const TextRun& run, const FloatPoint& point, int h, int from, int to) const
-{
-#if USE(FREETYPE)
- if (!primaryFont()->platformData().m_pattern)
- return selectionRectForSimpleText(run, point, h, from, to);
-#endif
-
- PangoLayout* layout = getDefaultPangoLayout(run);
- setPangoAttributes(this, run, layout);
-
- gchar* utf8 = convertUniCharToUTF8(run.characters(), run.length(), 0, run.length());
- pango_layout_set_text(layout, utf8, -1);
-
- char* start = g_utf8_offset_to_pointer(utf8, from);
- char* end = g_utf8_offset_to_pointer(start, to - from);
-
- if (run.ltr()) {
- from = start - utf8;
- to = end - utf8;
- } else {
- from = end - utf8;
- to = start - utf8;
- }
-
- PangoLayoutLine* layoutLine = pango_layout_get_line_readonly(layout, 0);
- int x_pos;
-
- x_pos = 0;
- if (from < layoutLine->length)
- pango_layout_line_index_to_x(layoutLine, from, FALSE, &x_pos);
- float beforeWidth = PANGO_PIXELS_FLOOR(x_pos);
-
- x_pos = 0;
- if (run.ltr() || to < layoutLine->length)
- pango_layout_line_index_to_x(layoutLine, to, FALSE, &x_pos);
- float afterWidth = PANGO_PIXELS(x_pos);
-
- g_free(utf8);
- g_object_unref(layout);
-
- return FloatRect(point.x() + beforeWidth, point.y(), afterWidth - beforeWidth, h);
-}
-
-}
Copied: trunk/Source/WebCore/platform/graphics/pango/FontPango.cpp (from rev 94873, trunk/Source/WebCore/platform/graphics/gtk/FontGtk.cpp) (0 => 94874)
--- trunk/Source/WebCore/platform/graphics/pango/FontPango.cpp (rev 0)
+++ trunk/Source/WebCore/platform/graphics/pango/FontPango.cpp 2011-09-09 21:40:04 UTC (rev 94874)
@@ -0,0 +1,444 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2006 Michael Emmel mike.em...@gmail.com
+ * Copyright (c) 2007 Hiroyuki Ikezoe
+ * Copyright (c) 2007 Kouhei Sutou
+ * Copyright (C) 2007 Alp Toker <a...@atoker.com>
+ * Copyright (C) 2008 Xan Lopez <x...@gnome.org>
+ * Copyright (C) 2008 Nuanti Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Font.h"
+
+#include "CairoUtilities.h"
+#include "GOwnPtr.h"
+#include "GraphicsContext.h"
+#include "NotImplemented.h"
+#include "PlatformContextCairo.h"
+#include "ShadowBlur.h"
+#include "SimpleFontData.h"
+#include "TextRun.h"
+#include <cairo.h>
+#include <gdk/gdk.h>
+#include <pango/pango.h>
+#include <pango/pangocairo.h>
+
+#if USE(FREETYPE)
+#include <pango/pangofc-fontmap.h>
+#endif
+
+namespace WebCore {
+
+#ifdef GTK_API_VERSION_2
+typedef GdkRegion* PangoRegionType;
+
+void destroyPangoRegion(PangoRegionType region)
+{
+ gdk_region_destroy(region);
+}
+
+IntRect getPangoRegionExtents(PangoRegionType region)
+{
+ GdkRectangle rectangle;
+ gdk_region_get_clipbox(region, &rectangle);
+ return IntRect(rectangle.x, rectangle.y, rectangle.width, rectangle.height);
+}
+#else
+typedef cairo_region_t* PangoRegionType;
+
+void destroyPangoRegion(PangoRegionType region)
+{
+ cairo_region_destroy(region);
+}
+
+IntRect getPangoRegionExtents(PangoRegionType region)
+{
+ cairo_rectangle_int_t rectangle;
+ cairo_region_get_extents(region, &rectangle);
+ return IntRect(rectangle.x, rectangle.y, rectangle.width, rectangle.height);
+}
+#endif
+
+#define IS_HIGH_SURROGATE(u) ((UChar)(u) >= (UChar)0xd800 && (UChar)(u) <= (UChar)0xdbff)
+#define IS_LOW_SURROGATE(u) ((UChar)(u) >= (UChar)0xdc00 && (UChar)(u) <= (UChar)0xdfff)
+
+static gchar* utf16ToUtf8(const UChar* aText, gint aLength, gint &length)
+{
+ gboolean needCopy = FALSE;
+
+ for (int i = 0; i < aLength; i++) {
+ if (!aText[i] || IS_LOW_SURROGATE(aText[i])) {
+ needCopy = TRUE;
+ break;
+ }
+
+ if (IS_HIGH_SURROGATE(aText[i])) {
+ if (i < aLength - 1 && IS_LOW_SURROGATE(aText[i+1]))
+ i++;
+ else {
+ needCopy = TRUE;
+ break;
+ }
+ }
+ }
+
+ GOwnPtr<UChar> copiedString;
+ if (needCopy) {
+ /* Pango doesn't correctly handle nuls. We convert them to 0xff. */
+ /* Also "validate" UTF-16 text to make sure conversion doesn't fail. */
+
+ copiedString.set(static_cast<UChar*>(g_memdup(aText, aLength * sizeof(aText[0]))));
+ UChar* p = copiedString.get();
+
+ /* don't need to reset i */
+ for (int i = 0; i < aLength; i++) {
+ if (!p[i] || IS_LOW_SURROGATE(p[i]))
+ p[i] = 0xFFFD;
+ else if (IS_HIGH_SURROGATE(p[i])) {
+ if (i < aLength - 1 && IS_LOW_SURROGATE(aText[i+1]))
+ i++;
+ else
+ p[i] = 0xFFFD;
+ }
+ }
+
+ aText = p;
+ }
+
+ gchar* utf8Text;
+ glong itemsWritten;
+ utf8Text = g_utf16_to_utf8(static_cast<const gunichar2*>(aText), aLength, 0, &itemsWritten, 0);
+ length = itemsWritten;
+
+ return utf8Text;
+}
+
+static gchar* convertUniCharToUTF8(const UChar* characters, gint length, int from, int to)
+{
+ gint newLength = 0;
+ GOwnPtr<gchar> utf8Text(utf16ToUtf8(characters, length, newLength));
+ if (!utf8Text)
+ return 0;
+
+ gchar* pos = utf8Text.get();
+ if (from > 0) {
+ // discard the first 'from' characters
+ // FIXME: we should do this before the conversion probably
+ pos = g_utf8_offset_to_pointer(utf8Text.get(), from);
+ }
+
+ gint len = strlen(pos);
+ GString* ret = g_string_new_len(NULL, len);
+
+ // replace line break by space
+ while (len > 0) {
+ gint index, start;
+ pango_find_paragraph_boundary(pos, len, &index, &start);
+ g_string_append_len(ret, pos, index);
+ if (index == start)
+ break;
+ g_string_append_c(ret, ' ');
+ pos += start;
+ len -= start;
+ }
+ return g_string_free(ret, FALSE);
+}
+
+static void setPangoAttributes(const Font* font, const TextRun& run, PangoLayout* layout)
+{
+#if USE(FREETYPE)
+ if (font->primaryFont()->platformData().m_pattern) {
+ PangoFontDescription* desc = pango_fc_font_description_from_pattern(font->primaryFont()->platformData().m_pattern.get(), FALSE);
+ pango_layout_set_font_description(layout, desc);
+ pango_font_description_free(desc);
+ }
+#elif USE(PANGO)
+ if (font->primaryFont()->platformData().m_font) {
+ PangoFontDescription* desc = pango_font_describe(font->primaryFont()->platformData().m_font);
+ pango_layout_set_font_description(layout, desc);
+ pango_font_description_free(desc);
+ }
+#endif
+
+ pango_layout_set_auto_dir(layout, FALSE);
+
+ PangoContext* pangoContext = pango_layout_get_context(layout);
+ PangoDirection direction = run.rtl() ? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR;
+ pango_context_set_base_dir(pangoContext, direction);
+ PangoAttrList* list = pango_attr_list_new();
+ PangoAttribute* attr;
+
+ attr = pango_attr_size_new_absolute(font->pixelSize() * PANGO_SCALE);
+ attr->end_index = G_MAXUINT;
+ pango_attr_list_insert_before(list, attr);
+
+ if (!run.spacingDisabled()) {
+ attr = pango_attr_letter_spacing_new(font->letterSpacing() * PANGO_SCALE);
+ attr->end_index = G_MAXUINT;
+ pango_attr_list_insert_before(list, attr);
+ }
+
+ // Pango does not yet support synthesising small caps
+ // See http://bugs.webkit.org/show_bug.cgi?id=15610
+
+ pango_layout_set_attributes(layout, list);
+ pango_attr_list_unref(list);
+}
+
+bool Font::canReturnFallbackFontsForComplexText()
+{
+ return false;
+}
+
+bool Font::canExpandAroundIdeographsInComplexText()
+{
+ return false;
+}
+
+static void drawGlyphsShadow(GraphicsContext* graphicsContext, const FloatPoint& point, PangoLayoutLine* layoutLine, PangoRegionType renderRegion)
+{
+ ShadowBlur& shadow = graphicsContext->platformContext()->shadowBlur();
+
+ if (!(graphicsContext->textDrawingMode() & TextModeFill) || shadow.type() == ShadowBlur::NoShadow)
+ return;
+
+ FloatPoint totalOffset(point + graphicsContext->state().shadowOffset);
+
+ // Optimize non-blurry shadows, by just drawing text without the ShadowBlur.
+ if (!shadow.mustUseShadowBlur(graphicsContext)) {
+ cairo_t* context = graphicsContext->platformContext()->cr();
+ cairo_save(context);
+ cairo_translate(context, totalOffset.x(), totalOffset.y());
+
+ setSourceRGBAFromColor(context, graphicsContext->state().shadowColor);
+ gdk_cairo_region(context, renderRegion);
+ cairo_clip(context);
+ pango_cairo_show_layout_line(context, layoutLine);
+
+ cairo_restore(context);
+ return;
+ }
+
+ FloatRect extents(getPangoRegionExtents(renderRegion));
+ extents.setLocation(FloatPoint(point.x(), point.y() - extents.height()));
+ if (GraphicsContext* shadowContext = shadow.beginShadowLayer(graphicsContext, extents)) {
+ cairo_t* cairoShadowContext = shadowContext->platformContext()->cr();
+ cairo_translate(cairoShadowContext, point.x(), point.y());
+ pango_cairo_show_layout_line(cairoShadowContext, layoutLine);
+
+ // We need the clipping region to be active when we blit the blurred shadow back,
+ // because we don't want any bits and pieces of characters out of range to be
+ // drawn. Since ShadowBlur expects a consistent transform, we have to undo the
+ // translation before calling endShadowLayer as well.
+ cairo_t* context = graphicsContext->platformContext()->cr();
+ cairo_save(context);
+ cairo_translate(context, totalOffset.x(), totalOffset.y());
+ gdk_cairo_region(context, renderRegion);
+ cairo_clip(context);
+ cairo_translate(context, -totalOffset.x(), -totalOffset.y());
+
+ shadow.endShadowLayer(graphicsContext);
+ cairo_restore(context);
+ }
+}
+
+void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const
+{
+#if USE(FREETYPE)
+ if (!primaryFont()->platformData().m_pattern) {
+ drawSimpleText(context, run, point, from, to);
+ return;
+ }
+#endif
+
+ cairo_t* cr = context->platformContext()->cr();
+ PangoLayout* layout = pango_cairo_create_layout(cr);
+ setPangoAttributes(this, run, layout);
+
+ gchar* utf8 = convertUniCharToUTF8(run.characters(), run.length(), 0, run.length());
+ pango_layout_set_text(layout, utf8, -1);
+
+ // Our layouts are single line
+ PangoLayoutLine* layoutLine = pango_layout_get_line_readonly(layout, 0);
+
+ // Get the region where this text will be laid out. We will use it to clip
+ // the Cairo context, for when we are only painting part of the text run and
+ // to calculate the size of the shadow buffer.
+ PangoRegionType partialRegion = 0;
+ char* start = g_utf8_offset_to_pointer(utf8, from);
+ char* end = g_utf8_offset_to_pointer(start, to - from);
+ int ranges[] = {start - utf8, end - utf8};
+ partialRegion = gdk_pango_layout_line_get_clip_region(layoutLine, 0, 0, ranges, 1);
+
+ drawGlyphsShadow(context, point, layoutLine, partialRegion);
+
+ cairo_save(cr);
+ cairo_translate(cr, point.x(), point.y());
+
+ float red, green, blue, alpha;
+ context->fillColor().getRGBA(red, green, blue, alpha);
+ cairo_set_source_rgba(cr, red, green, blue, alpha);
+ gdk_cairo_region(cr, partialRegion);
+ cairo_clip(cr);
+
+ pango_cairo_show_layout_line(cr, layoutLine);
+
+ if (context->textDrawingMode() & TextModeStroke) {
+ Color strokeColor = context->strokeColor();
+ strokeColor.getRGBA(red, green, blue, alpha);
+ cairo_set_source_rgba(cr, red, green, blue, alpha);
+ pango_cairo_layout_line_path(cr, layoutLine);
+ cairo_set_line_width(cr, context->strokeThickness());
+ cairo_stroke(cr);
+ }
+
+ // Pango sometimes leaves behind paths we don't want
+ cairo_new_path(cr);
+
+ destroyPangoRegion(partialRegion);
+ g_free(utf8);
+ g_object_unref(layout);
+
+ cairo_restore(cr);
+}
+
+void Font::drawEmphasisMarksForComplexText(GraphicsContext* /* context */, const TextRun& /* run */, const AtomicString& /* mark */, const FloatPoint& /* point */, int /* from */, int /* to */) const
+{
+ notImplemented();
+}
+
+// We should create the layout with our actual context but we can't access it from here.
+static PangoLayout* getDefaultPangoLayout(const TextRun& run)
+{
+ static PangoFontMap* map = pango_cairo_font_map_get_default();
+#if PANGO_VERSION_CHECK(1, 21, 5)
+ static PangoContext* pangoContext = pango_font_map_create_context(map);
+#else
+ // Deprecated in Pango 1.21.
+ static PangoContext* pangoContext = pango_cairo_font_map_create_context(PANGO_CAIRO_FONT_MAP(map));
+#endif
+ PangoLayout* layout = pango_layout_new(pangoContext);
+
+ return layout;
+}
+
+float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* overflow) const
+{
+#if USE(FREETYPE)
+ if (!primaryFont()->platformData().m_pattern)
+ return floatWidthForSimpleText(run, 0, fallbackFonts, overflow);
+#endif
+
+ if (!run.length())
+ return 0.0f;
+
+ PangoLayout* layout = getDefaultPangoLayout(run);
+ setPangoAttributes(this, run, layout);
+
+ gchar* utf8 = convertUniCharToUTF8(run.characters(), run.length(), 0, run.length());
+ pango_layout_set_text(layout, utf8, -1);
+
+ int width;
+ pango_layout_get_pixel_size(layout, &width, 0);
+
+ g_free(utf8);
+ g_object_unref(layout);
+
+ return width;
+}
+
+int Font::offsetForPositionForComplexText(const TextRun& run, float xFloat, bool includePartialGlyphs) const
+{
+#if USE(FREETYPE)
+ if (!primaryFont()->platformData().m_pattern)
+ return offsetForPositionForSimpleText(run, xFloat, includePartialGlyphs);
+#endif
+ // FIXME: This truncation is not a problem for HTML, but only affects SVG, which passes floating-point numbers
+ // to Font::offsetForPosition(). Bug http://webkit.org/b/40673 tracks fixing this problem.
+ int x = static_cast<int>(xFloat);
+
+ PangoLayout* layout = getDefaultPangoLayout(run);
+ setPangoAttributes(this, run, layout);
+
+ gchar* utf8 = convertUniCharToUTF8(run.characters(), run.length(), 0, run.length());
+ pango_layout_set_text(layout, utf8, -1);
+
+ int index, trailing;
+ pango_layout_xy_to_index(layout, x * PANGO_SCALE, 1, &index, &trailing);
+ glong offset = g_utf8_pointer_to_offset(utf8, utf8 + index);
+ if (includePartialGlyphs)
+ offset += trailing;
+
+ g_free(utf8);
+ g_object_unref(layout);
+
+ return offset;
+}
+
+FloatRect Font::selectionRectForComplexText(const TextRun& run, const FloatPoint& point, int h, int from, int to) const
+{
+#if USE(FREETYPE)
+ if (!primaryFont()->platformData().m_pattern)
+ return selectionRectForSimpleText(run, point, h, from, to);
+#endif
+
+ PangoLayout* layout = getDefaultPangoLayout(run);
+ setPangoAttributes(this, run, layout);
+
+ gchar* utf8 = convertUniCharToUTF8(run.characters(), run.length(), 0, run.length());
+ pango_layout_set_text(layout, utf8, -1);
+
+ char* start = g_utf8_offset_to_pointer(utf8, from);
+ char* end = g_utf8_offset_to_pointer(start, to - from);
+
+ if (run.ltr()) {
+ from = start - utf8;
+ to = end - utf8;
+ } else {
+ from = end - utf8;
+ to = start - utf8;
+ }
+
+ PangoLayoutLine* layoutLine = pango_layout_get_line_readonly(layout, 0);
+ int xPos;
+
+ xPos = 0;
+ if (from < layoutLine->length)
+ pango_layout_line_index_to_x(layoutLine, from, FALSE, &xPos);
+ float beforeWidth = PANGO_PIXELS_FLOOR(xPos);
+
+ xPos = 0;
+ if (run.ltr() || to < layoutLine->length)
+ pango_layout_line_index_to_x(layoutLine, to, FALSE, &xPos);
+ float afterWidth = PANGO_PIXELS(xPos);
+
+ g_free(utf8);
+ g_object_unref(layout);
+
+ return FloatRect(point.x() + beforeWidth, point.y(), afterWidth - beforeWidth, h);
+}
+
+}