diff options
Diffstat (limited to 'WebCore/platform/graphics/gtk')
21 files changed, 3090 insertions, 0 deletions
diff --git a/WebCore/platform/graphics/gtk/ColorGtk.cpp b/WebCore/platform/graphics/gtk/ColorGtk.cpp new file mode 100644 index 0000000..27f1b14 --- /dev/null +++ b/WebCore/platform/graphics/gtk/ColorGtk.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2007 Alp Toker <alp@atoker.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "Color.h" + +#include <gdk/gdk.h> + +namespace WebCore { + +Color::Color(const GdkColor& c) + : m_color(makeRGB(c.red >> 8, c.green >> 8, c.blue >> 8)) + , m_valid(true) +{ +} + +} + +// vim: ts=4 sw=4 et diff --git a/WebCore/platform/graphics/gtk/FontCacheGtk.cpp b/WebCore/platform/graphics/gtk/FontCacheGtk.cpp new file mode 100644 index 0000000..d2b43cc --- /dev/null +++ b/WebCore/platform/graphics/gtk/FontCacheGtk.cpp @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2008 Alp Toker <alp@atoker.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "FontCache.h" + +#include "Font.h" +#include "SimpleFontData.h" +#include <wtf/Assertions.h> + +namespace WebCore { + +void FontCache::platformInit() +{ + if (!FontPlatformData::init()) + ASSERT_NOT_REACHED(); +} + +const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, const UChar* characters, int length) +{ +#if defined(USE_FREETYPE) + FcResult fresult; + FontPlatformData* prim = const_cast<FontPlatformData*>(&font.primaryFont()->m_font); + + if (!prim->m_fallbacks) + prim->m_fallbacks = FcFontSort(NULL, prim->m_pattern, FcTrue, NULL, &fresult); + + FcFontSet* fs = prim->m_fallbacks; + + for (int i = 0; i < fs->nfont; i++) { + FcPattern* fin = FcFontRenderPrepare(NULL, prim->m_pattern, fs->fonts[i]); + cairo_font_face_t* fontFace = cairo_ft_font_face_create_for_pattern(fin); + FontPlatformData alternateFont(fontFace, font.fontDescription().computedPixelSize(), false, false); + cairo_font_face_destroy(fontFace); + alternateFont.m_pattern = fin; + SimpleFontData* sfd = getCachedFontData(&alternateFont); + if (sfd->containsCharacters(characters, length)) + return sfd; + } +#endif + + return 0; +} + +FontPlatformData* FontCache::getSimilarFontPlatformData(const Font& font) +{ + return 0; +} + +FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription& fontDescription) +{ + // FIXME: Would be even better to somehow get the user's default font here. + // For now we'll pick the default that the user would get without changing any prefs. + static AtomicString timesStr("Times New Roman"); + return getCachedFontPlatformData(fontDescription, timesStr); +} + +void FontCache::getTraitsInFamily(const AtomicString& familyName, Vector<unsigned>& traitsMasks) +{ +} + +FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family) +{ + return new FontPlatformData(fontDescription, family); +} + +} diff --git a/WebCore/platform/graphics/gtk/FontCustomPlatformData.cpp b/WebCore/platform/graphics/gtk/FontCustomPlatformData.cpp new file mode 100644 index 0000000..bb2e064 --- /dev/null +++ b/WebCore/platform/graphics/gtk/FontCustomPlatformData.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2008 Alp Toker <alp@atoker.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "FontCustomPlatformData.h" + +#include "SharedBuffer.h" +#include "FontPlatformData.h" + +namespace WebCore { + +FontCustomPlatformData::~FontCustomPlatformData() +{ + cairo_font_face_destroy(m_fontFace); +} + +FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontRenderingMode) +{ + return FontPlatformData(m_fontFace, size, bold, italic); +} + +static void releaseData(void* data) +{ + static_cast<SharedBuffer*>(data)->deref(); +} + +FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer) +{ + ASSERT_ARG(buffer, buffer); + + int error; + + static FT_Library library = 0; + if (!library) { + error = FT_Init_FreeType(&library); + if (error) { + library = 0; + return 0; + } + } + + FT_Face face; + error = FT_New_Memory_Face(library, reinterpret_cast<const FT_Byte*>(buffer->data()), buffer->size(), 0, &face); + if (error) + return 0; + + buffer->ref(); + cairo_font_face_t* fontFace = cairo_ft_font_face_create_for_ft_face(face, 0); + + static cairo_user_data_key_t bufferKey; + cairo_font_face_set_user_data(fontFace, &bufferKey, buffer, releaseData); + + return new FontCustomPlatformData(fontFace); +} + +} diff --git a/WebCore/platform/graphics/gtk/FontCustomPlatformData.h b/WebCore/platform/graphics/gtk/FontCustomPlatformData.h new file mode 100644 index 0000000..b36cc79 --- /dev/null +++ b/WebCore/platform/graphics/gtk/FontCustomPlatformData.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2008 Alp Toker <alp@atoker.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef FontCustomPlatformData_h +#define FontCustomPlatformData_h + +#include "FontRenderingMode.h" +#include <wtf/Noncopyable.h> + +typedef struct _cairo_font_face cairo_font_face_t; + +namespace WebCore { + +class FontPlatformData; +class SharedBuffer; + +struct FontCustomPlatformData : Noncopyable { + FontCustomPlatformData(cairo_font_face_t* fontFace) + : m_fontFace(fontFace) + {} + + ~FontCustomPlatformData(); + + FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontRenderingMode = NormalRenderingMode); + + cairo_font_face_t* m_fontFace; +}; + +FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer); + +} + +#endif diff --git a/WebCore/platform/graphics/gtk/FontCustomPlatformDataPango.cpp b/WebCore/platform/graphics/gtk/FontCustomPlatformDataPango.cpp new file mode 100644 index 0000000..4f2f2bb --- /dev/null +++ b/WebCore/platform/graphics/gtk/FontCustomPlatformDataPango.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2008 Alp Toker <alp@atoker.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "FontCustomPlatformData.h" + +#include "SharedBuffer.h" +#include "FontPlatformData.h" + +namespace WebCore { + +FontCustomPlatformData::~FontCustomPlatformData() +{ +} + +FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontRenderingMode) +{ + return FontPlatformData(m_fontFace, size, bold, italic); +} + +static void releaseData(void* data) +{ + static_cast<SharedBuffer*>(data)->deref(); +} + +FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer) +{ + // FIXME: we need support in pango to read fonts from memory to implement this.y + return 0; +} + +} diff --git a/WebCore/platform/graphics/gtk/FontGtk.cpp b/WebCore/platform/graphics/gtk/FontGtk.cpp new file mode 100644 index 0000000..288ba91 --- /dev/null +++ b/WebCore/platform/graphics/gtk/FontGtk.cpp @@ -0,0 +1,371 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com + * Copyright (c) 2007 Hiroyuki Ikezoe + * Copyright (c) 2007 Kouhei Sutou + * Copyright (C) 2007 Alp Toker <alp@atoker.com> + * Copyright (C) 2008 Xan Lopez <xan@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 "GraphicsContext.h" +#include "NotImplemented.h" +#include "SimpleFontData.h" + +#include <cairo.h> +#include <gdk/gdk.h> +#include <pango/pango.h> +#include <pango/pangocairo.h> +#if defined(USE_FREETYPE) +#include <pango/pangofc-fontmap.h> +#endif + +#if !defined(PANGO_VERSION_CHECK) +// PANGO_VERSION_CHECK() and pango_layout_get_line_readonly() appeared in 1.5.2 +#define pango_layout_get_line_readonly pango_layout_get_line +#define PANGO_VERSION_CHECK(major,minor,micro) 0 +#endif + +namespace WebCore { + +#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 void utf16_to_utf8(const UChar* aText, gint aLength, char* &text, gint &length) +{ + gboolean need_copy = FALSE; + int i; + + for (i = 0; i < aLength; i++) { + if (!aText[i] || IS_LOW_SURROGATE(aText[i])) { + need_copy = TRUE; + break; + } + else if (IS_HIGH_SURROGATE(aText[i])) { + if (i < aLength - 1 && IS_LOW_SURROGATE(aText[i+1])) + i++; + else { + need_copy = TRUE; + break; + } + } + } + + if (need_copy) { + + /* Pango doesn't correctly handle nuls. We convert them to 0xff. */ + /* Also "validate" UTF-16 text to make sure conversion doesn't fail. */ + + UChar* p = (UChar*)g_memdup(aText, aLength * sizeof(aText[0])); + + /* don't need to reset i */ + for (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; + } + + glong items_written; + text = g_utf16_to_utf8(reinterpret_cast<const gunichar2*>(aText), aLength, NULL, &items_written, NULL); + length = items_written; + + if (need_copy) + g_free((gpointer)aText); + +} + +static gchar* convertUniCharToUTF8(const UChar* characters, gint length, int from, int to) +{ + gchar* utf8 = 0; + gint new_length = 0; + utf16_to_utf8(characters, length, utf8, new_length); + if (!utf8) + return NULL; + + if (from > 0) { + // discard the first 'from' characters + // FIXME: we should do this before the conversion probably + gchar* str_left = g_utf8_offset_to_pointer(utf8, from); + gchar* tmp = g_strdup(str_left); + g_free(utf8); + utf8 = tmp; + } + + gchar* pos = utf8; + 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 defined(USE_FREETYPE) + if (font->primaryFont()->m_font.m_pattern) { + PangoFontDescription* desc = pango_fc_font_description_from_pattern(font->primaryFont()->m_font.m_pattern, FALSE); + pango_layout_set_font_description(layout, desc); + pango_font_description_free(desc); + } +#elif defined(USE_PANGO) + if (font->primaryFont()->m_font.m_font) { + PangoFontDescription* desc = pango_font_describe(font->primaryFont()->m_font.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); +} + +void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const +{ + cairo_t* cr = context->platformContext(); + cairo_save(cr); + cairo_translate(cr, point.x(), point.y()); + + 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); + + GdkRegion* partialRegion = NULL; + if (to - from != run.length()) { + // Clip the region of the run to be rendered + 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); + gdk_region_shrink(partialRegion, 0, -pixelSize()); + } + + Color fillColor = context->fillColor(); + float red, green, blue, alpha; + + // Text shadow, inspired by FontMac + IntSize shadowSize; + int shadowBlur = 0; + Color shadowColor; + bool hasShadow = context->textDrawingMode() == cTextFill && + context->getShadow(shadowSize, shadowBlur, shadowColor); + + // TODO: Blur support + if (hasShadow) { + // Disable graphics context shadows (not yet implemented) and paint them manually + context->clearShadow(); + Color shadowFillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), shadowColor.alpha() * fillColor.alpha() / 255); + cairo_save(cr); + + shadowFillColor.getRGBA(red, green, blue, alpha); + cairo_set_source_rgba(cr, red, green, blue, alpha); + + cairo_translate(cr, shadowSize.width(), shadowSize.height()); + + if (partialRegion) { + gdk_cairo_region(cr, partialRegion); + cairo_clip(cr); + } + + pango_cairo_show_layout_line(cr, layoutLine); + + cairo_restore(cr); + } + + fillColor.getRGBA(red, green, blue, alpha); + cairo_set_source_rgba(cr, red, green, blue, alpha); + + if (partialRegion) { + gdk_cairo_region(cr, partialRegion); + cairo_clip(cr); + } + + pango_cairo_show_layout_line(cr, layoutLine); + + if (context->textDrawingMode() & cTextStroke) { + 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); + } + + // Re-enable the platform shadow we disabled earlier + if (hasShadow) + context->setShadow(shadowSize, shadowBlur, shadowColor); + + // Pango sometimes leaves behind paths we don't want + cairo_new_path(cr); + + if (partialRegion) + gdk_region_destroy(partialRegion); + + g_free(utf8); + g_object_unref(layout); + + cairo_restore(cr); +} + +// 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) const +{ + 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, int x, bool includePartialGlyphs) const +{ + 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 IntPoint& point, int h, int from, int to) const +{ + 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); +} + +} diff --git a/WebCore/platform/graphics/gtk/FontPlatformData.h b/WebCore/platform/graphics/gtk/FontPlatformData.h new file mode 100644 index 0000000..efa5dd5 --- /dev/null +++ b/WebCore/platform/graphics/gtk/FontPlatformData.h @@ -0,0 +1,132 @@ +/* + * This file is part of the internal font implementation. It should not be included by anyone other than + * FontMac.cpp, FontWin.cpp and Font.cpp. + * + * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com + * Copyright (C) 2007 Holger Hans Peter Freyther + * Copyright (C) 2007 Pioneer Research Center USA, Inc. + * All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef FontPlatformData_h +#define FontPlatformData_h + +#include "GlyphBuffer.h" +#include "FontDescription.h" +#include <cairo.h> +#if defined(USE_FREETYPE) +#include <cairo-ft.h> +#include <fontconfig/fcfreetype.h> +#elif defined(USE_PANGO) +#include <pango/pangocairo.h> +#else +#error "Must defined a font backend" +#endif + +namespace WebCore { + +class FontPlatformData { +public: + FontPlatformData(WTF::HashTableDeletedValueType) +#if defined(USE_FREETYPE) + : m_pattern(hashTableDeletedFontValue()) + , m_fallbacks(0) +#elif defined(USE_PANGO) + : m_context(0) + , m_font(hashTableDeletedFontValue()) +#else +#error "Must defined a font backend" +#endif + , m_scaledFont(0) + { } + + FontPlatformData() +#if defined(USE_FREETYPE) + : m_pattern(0) + , m_fallbacks(0) +#elif defined(USE_PANGO) + : m_context(0) + , m_font(0) +#else +#error "Must defined a font backend" +#endif + , m_scaledFont(0) + { } + + FontPlatformData(const FontDescription&, const AtomicString& family); + + FontPlatformData(float size, bool bold, bool italic); + FontPlatformData(cairo_font_face_t* fontFace, int size, bool bold, bool italic); + + ~FontPlatformData(); + + static bool init(); + + bool isFixedPitch(); + float size() const { return m_size; } + + void setFont(cairo_t*) const; + + unsigned hash() const + { +#if defined(USE_FREETYPE) + if (m_pattern) + return FcPatternHash(m_pattern); +#endif + uintptr_t hashCodes[1] = { reinterpret_cast<uintptr_t>(m_scaledFont) }; + return StringImpl::computeHash(reinterpret_cast<UChar*>(hashCodes), sizeof(hashCodes) / sizeof(UChar)); + } + + bool operator==(const FontPlatformData&) const; + bool isHashTableDeletedValue() const { +#if defined(USE_FREETYPE) + return m_pattern == hashTableDeletedFontValue(); +#elif defined(USE_PANGO) + return m_font == hashTableDeletedFontValue(); +#endif + }; + +#if defined(USE_FREETYPE) + FcPattern* m_pattern; + FcFontSet* m_fallbacks; +#elif defined(USE_PANGO) + static PangoFontMap* m_fontMap; + static GHashTable* m_hashTable; + + PangoContext* m_context; + PangoFont* m_font; +#else +#error "Must defined a font backend" +#endif + float m_size; + bool m_syntheticBold; + bool m_syntheticOblique; + cairo_scaled_font_t* m_scaledFont; +private: +#if defined(USE_FREETYPE) + static FcPattern *hashTableDeletedFontValue() { return reinterpret_cast<FcPattern*>(-1); } +#elif defined(USE_PANGO) + static PangoFont *hashTableDeletedFontValue() { return reinterpret_cast<PangoFont*>(-1); } +#endif +}; + +} + +#endif diff --git a/WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp b/WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp new file mode 100644 index 0000000..17d789b --- /dev/null +++ b/WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com + * Copyright (C) 2007, 2008 Alp Toker <alp@atoker.com> + * Copyright (C) 2007 Holger Hans Peter Freyther + * All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "FontPlatformData.h" + +#include "CString.h" +#include "PlatformString.h" +#include "FontDescription.h" + +#include <cairo-ft.h> +#include <cairo.h> +#include <fontconfig/fcfreetype.h> +#include <gtk/gtk.h> + +namespace WebCore { + +FontPlatformData::FontPlatformData(const FontDescription& fontDescription, const AtomicString& familyName) + : m_pattern(0) + , m_fallbacks(0) + , m_size(fontDescription.computedPixelSize()) + , m_syntheticBold(false) + , m_syntheticOblique(false) + , m_scaledFont(0) +{ + FontPlatformData::init(); + + CString familyNameString = familyName.string().utf8(); + const char* fcfamily = familyNameString.data(); + int fcslant = FC_SLANT_ROMAN; + // FIXME: Map all FontWeight values to fontconfig weights. + int fcweight = FC_WEIGHT_NORMAL; + double fcsize = fontDescription.computedPixelSize(); + if (fontDescription.italic()) + fcslant = FC_SLANT_ITALIC; + if (fontDescription.weight() >= FontWeight600) + fcweight = FC_WEIGHT_BOLD; + + int type = fontDescription.genericFamily(); + + FcPattern* pattern = FcPatternCreate(); + cairo_font_face_t* fontFace; + static const cairo_font_options_t* defaultOptions = cairo_font_options_create(); + const cairo_font_options_t* options = NULL; + cairo_matrix_t fontMatrix; + + if (!FcPatternAddString(pattern, FC_FAMILY, reinterpret_cast<const FcChar8*>(fcfamily))) + goto freePattern; + + switch (type) { + case FontDescription::SerifFamily: + fcfamily = "serif"; + break; + case FontDescription::SansSerifFamily: + fcfamily = "sans-serif"; + break; + case FontDescription::MonospaceFamily: + fcfamily = "monospace"; + break; + case FontDescription::StandardFamily: + fcfamily = "sans-serif"; + break; + case FontDescription::NoFamily: + default: + fcfamily = NULL; + break; + } + + if (fcfamily && !FcPatternAddString(pattern, FC_FAMILY, reinterpret_cast<const FcChar8*>(fcfamily))) + goto freePattern; + if (!FcPatternAddInteger(pattern, FC_WEIGHT, fcweight)) + goto freePattern; + if (!FcPatternAddInteger(pattern, FC_SLANT, fcslant)) + goto freePattern; + if (!FcPatternAddDouble(pattern, FC_PIXEL_SIZE, fcsize)) + goto freePattern; + + FcConfigSubstitute(NULL, pattern, FcMatchPattern); + FcDefaultSubstitute(pattern); + + FcResult fcresult; + m_pattern = FcFontMatch(NULL, pattern, &fcresult); + // FIXME: should we set some default font? + if (!m_pattern) + goto freePattern; + fontFace = cairo_ft_font_face_create_for_pattern(m_pattern); + cairo_matrix_t ctm; + cairo_matrix_init_scale(&fontMatrix, fontDescription.computedPixelSize(), fontDescription.computedPixelSize()); + cairo_matrix_init_identity(&ctm); + +#if GTK_CHECK_VERSION(2,10,0) + if (GdkScreen* screen = gdk_screen_get_default()) + options = gdk_screen_get_font_options(screen); +#endif + // gdk_screen_get_font_options() returns NULL if no default options are + // set, so we always have to check. + if (!options) + options = defaultOptions; + + m_scaledFont = cairo_scaled_font_create(fontFace, &fontMatrix, &ctm, options); + cairo_font_face_destroy(fontFace); + +freePattern: + FcPatternDestroy(pattern); +} + +FontPlatformData::FontPlatformData(float size, bool bold, bool italic) + : m_pattern(0) + , m_fallbacks(0) + , m_size(size) + , m_syntheticBold(bold) + , m_syntheticOblique(italic) + , m_scaledFont(0) +{ +} + +FontPlatformData::FontPlatformData(cairo_font_face_t* fontFace, int size, bool bold, bool italic) + : m_pattern(0) + , m_fallbacks(0) + , m_size(size) + , m_syntheticBold(bold) + , m_syntheticOblique(italic) + , m_scaledFont(0) +{ + cairo_matrix_t fontMatrix; + cairo_matrix_init_scale(&fontMatrix, size, size); + cairo_matrix_t ctm; + cairo_matrix_init_identity(&ctm); + static const cairo_font_options_t* defaultOptions = cairo_font_options_create(); + const cairo_font_options_t* options = NULL; + +#if GTK_CHECK_VERSION(2,10,0) + if (GdkScreen* screen = gdk_screen_get_default()) + options = gdk_screen_get_font_options(screen); +#endif + // gdk_screen_get_font_options() returns NULL if no default options are + // set, so we always have to check. + if (!options) + options = defaultOptions; + + m_scaledFont = cairo_scaled_font_create(fontFace, &fontMatrix, &ctm, options); +} + +bool FontPlatformData::init() +{ + static bool initialized = false; + if (initialized) + return true; + if (!FcInit()) { + fprintf(stderr, "Can't init font config library\n"); + return false; + } + initialized = true; + return true; +} + +FontPlatformData::~FontPlatformData() +{ +} + +bool FontPlatformData::isFixedPitch() +{ + // TODO: Support isFixedPitch() for custom fonts. + if (!m_pattern) + return false; + + int spacing; + if (FcPatternGetInteger(m_pattern, FC_SPACING, 0, &spacing) == FcResultMatch) + return spacing == FC_MONO; + return false; +} + +void FontPlatformData::setFont(cairo_t* cr) const +{ + ASSERT(m_scaledFont); + + cairo_set_scaled_font(cr, m_scaledFont); +} + +bool FontPlatformData::operator==(const FontPlatformData& other) const +{ + if (m_pattern == other.m_pattern) + return true; + if (m_pattern == 0 || m_pattern == reinterpret_cast<FcPattern*>(-1) + || other.m_pattern == 0 || other.m_pattern == reinterpret_cast<FcPattern*>(-1)) + return false; + return FcPatternEqual(m_pattern, other.m_pattern); +} + +} diff --git a/WebCore/platform/graphics/gtk/FontPlatformDataPango.cpp b/WebCore/platform/graphics/gtk/FontPlatformDataPango.cpp new file mode 100644 index 0000000..be3fd43 --- /dev/null +++ b/WebCore/platform/graphics/gtk/FontPlatformDataPango.cpp @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com + * Copyright (C) 2007, 2008 Alp Toker <alp@atoker.com> + * Copyright (C) 2007 Holger Hans Peter Freyther + * Copyright (C) 2007 Pioneer Research Center USA, Inc. + * All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#include "config.h" +#include "FontPlatformData.h" + +#include "CString.h" +#include "PlatformString.h" +#include "FontDescription.h" +#include <cairo.h> +#include <assert.h> + +#include <pango/pango.h> +#include <pango/pangocairo.h> + +#if !defined(PANGO_VERSION_CHECK) +#define PANGO_VERSION_CHECK(major,minor,micro) 0 +#endif + +// Use cairo-ft i a recent enough Pango version isn't available +#if !PANGO_VERSION_CHECK(1,18,0) +#include <cairo-ft.h> +#include <pango/pangofc-fontmap.h> +#endif +#include <gtk/gtk.h> + +namespace WebCore { + + PangoFontMap* FontPlatformData::m_fontMap = 0; + GHashTable* FontPlatformData::m_hashTable = 0; + +FontPlatformData::FontPlatformData(const FontDescription& fontDescription, const AtomicString& familyName) + : m_context(0) + , m_font(0) + , m_size(fontDescription.computedSize()) + , m_syntheticBold(false) + , m_syntheticOblique(false) + , m_scaledFont(0) +{ + FontPlatformData::init(); + + CString stored_family = familyName.string().utf8(); + char const* families[] = { + stored_family.data(), + NULL + }; + + switch (fontDescription.genericFamily()) { + case FontDescription::SerifFamily: + families[1] = "serif"; + break; + case FontDescription::SansSerifFamily: + families[1] = "sans"; + break; + case FontDescription::MonospaceFamily: + families[1] = "monospace"; + break; + case FontDescription::NoFamily: + case FontDescription::StandardFamily: + default: + families[1] = "sans"; + break; + } + + PangoFontDescription* description = pango_font_description_new(); + pango_font_description_set_absolute_size(description, fontDescription.computedSize() * PANGO_SCALE); + + // FIXME: Map all FontWeight values to Pango font weights. + if (fontDescription.weight() >= FontWeight600) + pango_font_description_set_weight(description, PANGO_WEIGHT_BOLD); + if (fontDescription.italic()) + pango_font_description_set_style(description, PANGO_STYLE_ITALIC); + +#if PANGO_VERSION_CHECK(1,21,5) // deprecated in 1.21 + m_context = pango_font_map_create_context(m_fontMap); +#else + m_context = pango_cairo_font_map_create_context(PANGO_CAIRO_FONT_MAP(m_fontMap)); +#endif + for (unsigned int i = 0; !m_font && i < G_N_ELEMENTS(families); i++) { + pango_font_description_set_family(description, families[i]); + pango_context_set_font_description(m_context, description); + m_font = pango_font_map_load_font(m_fontMap, m_context, description); + } + +#if PANGO_VERSION_CHECK(1,18,0) + if (m_font) + m_scaledFont = cairo_scaled_font_reference(pango_cairo_font_get_scaled_font(PANGO_CAIRO_FONT(m_font))); +#else + // This compatibility code for older versions of Pango is not well-tested. + if (m_font) { + PangoFcFont* fcfont = PANGO_FC_FONT(m_font); + cairo_font_face_t* face = cairo_ft_font_face_create_for_pattern(fcfont->font_pattern); + double size; + if (FcPatternGetDouble(fcfont->font_pattern, FC_PIXEL_SIZE, 0, &size) != FcResultMatch) + size = 12.0; + cairo_matrix_t fontMatrix; + cairo_matrix_init_scale(&fontMatrix, size, size); + cairo_font_options_t* fontOptions; + if (pango_cairo_context_get_font_options(m_context)) + fontOptions = cairo_font_options_copy(pango_cairo_context_get_font_options(m_context)); + else + fontOptions = cairo_font_options_create(); + cairo_matrix_t ctm; + cairo_matrix_init_identity(&ctm); + m_scaledFont = cairo_scaled_font_create(face, &fontMatrix, &ctm, fontOptions); + cairo_font_options_destroy(fontOptions); + cairo_font_face_destroy(face); + } +#endif + pango_font_description_free(description); +} + +FontPlatformData::FontPlatformData(float size, bool bold, bool italic) + : m_context(0) + , m_font(0) + , m_size(size) + , m_syntheticBold(bold) + , m_syntheticOblique(italic) + , m_scaledFont(0) +{ +} + +FontPlatformData::FontPlatformData(cairo_font_face_t* fontFace, int size, bool bold, bool italic) + : m_context(0) + , m_font(0) + , m_size(size) + , m_syntheticBold(bold) + , m_syntheticOblique(italic) + , m_scaledFont(0) +{ + cairo_matrix_t fontMatrix; + cairo_matrix_init_scale(&fontMatrix, size, size); + cairo_matrix_t ctm; + cairo_matrix_init_identity(&ctm); + cairo_font_options_t* options = cairo_font_options_create(); + + // We force antialiasing and disable hinting to provide consistent + // typographic qualities for custom fonts on all platforms. + cairo_font_options_set_hint_style(options, CAIRO_HINT_STYLE_NONE); + cairo_font_options_set_antialias(options, CAIRO_ANTIALIAS_GRAY); + + m_scaledFont = cairo_scaled_font_create(fontFace, &fontMatrix, &ctm, options); + cairo_font_options_destroy(options); +} + +bool FontPlatformData::init() +{ + static bool initialized = false; + if (initialized) + return true; + initialized = true; + + if (!m_fontMap) + m_fontMap = pango_cairo_font_map_get_default(); + if (!m_hashTable) { + PangoFontFamily** families = 0; + int n_families = 0; + + m_hashTable = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_object_unref); + + pango_font_map_list_families(m_fontMap, &families, &n_families); + + for (int family = 0; family < n_families; family++) + g_hash_table_insert(m_hashTable, + g_strdup(pango_font_family_get_name(families[family])), + g_object_ref(families[family])); + + g_free(families); + } + + return true; +} + +FontPlatformData::~FontPlatformData() +{ + // Destroy takes place in FontData::platformDestroy(). +} + +bool FontPlatformData::isFixedPitch() +{ + PangoFontDescription* description = pango_font_describe_with_absolute_size(m_font); + PangoFontFamily* family = reinterpret_cast<PangoFontFamily*>(g_hash_table_lookup(m_hashTable, pango_font_description_get_family(description))); + pango_font_description_free(description); + return pango_font_family_is_monospace(family); +} + +void FontPlatformData::setFont(cairo_t* cr) const +{ + ASSERT(m_scaledFont); + + cairo_set_scaled_font(cr, m_scaledFont); +} + +bool FontPlatformData::operator==(const FontPlatformData& other) const +{ + if (m_font == other.m_font) + return true; + if (m_font == 0 || m_font == reinterpret_cast<PangoFont*>(-1) + || other.m_font == 0 || other.m_font == reinterpret_cast<PangoFont*>(-1)) + return false; + PangoFontDescription* thisDesc = pango_font_describe(m_font); + PangoFontDescription* otherDesc = pango_font_describe(other.m_font); + bool result = pango_font_description_equal(thisDesc, otherDesc); + pango_font_description_free(otherDesc); + pango_font_description_free(thisDesc); + return result; +} + +} diff --git a/WebCore/platform/graphics/gtk/GlyphPageTreeNodeGtk.cpp b/WebCore/platform/graphics/gtk/GlyphPageTreeNodeGtk.cpp new file mode 100644 index 0000000..24ad864 --- /dev/null +++ b/WebCore/platform/graphics/gtk/GlyphPageTreeNodeGtk.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com + * Copyright (C) 2007 Alp Toker <alp.toker@collabora.co.uk> + * + * 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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 "GlyphPageTreeNode.h" + +#include "SimpleFontData.h" + +namespace WebCore { + +bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData) +{ + // The bufferLength will be greater than the glyph page size if the buffer has Unicode supplementary characters. + // We won't support this for now. + if (bufferLength > GlyphPage::size) + return false; + + FT_Face face = cairo_ft_scaled_font_lock_face(fontData->m_font.m_scaledFont); + if (!face) + return false; + + bool haveGlyphs = false; + for (unsigned i = 0; i < length; i++) { + Glyph glyph = FcFreeTypeCharIndex(face, buffer[i]); + if (!glyph) + setGlyphDataForIndex(offset + i, 0, 0); + else { + setGlyphDataForIndex(offset + i, glyph, fontData); + haveGlyphs = true; + } + } + + cairo_ft_scaled_font_unlock_face(fontData->m_font.m_scaledFont); + + return haveGlyphs; +} + +} diff --git a/WebCore/platform/graphics/gtk/GlyphPageTreeNodePango.cpp b/WebCore/platform/graphics/gtk/GlyphPageTreeNodePango.cpp new file mode 100644 index 0000000..8fada5c --- /dev/null +++ b/WebCore/platform/graphics/gtk/GlyphPageTreeNodePango.cpp @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com + * Copyright (C) 2007 Alp Toker <alp.toker@collabora.co.uk> + * Copyright (C) 2007 Pioneer Research Center USA, Inc. + * + * 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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 "GlyphPageTreeNode.h" + +#include "SimpleFontData.h" +#include <pango/pango-font.h> + +namespace WebCore { + +static PangoGlyph pango_font_get_glyph(PangoFont* font, PangoContext* context, gunichar wc) +{ + PangoGlyph result = 0; + gchar buffer[7]; + + gint length = g_unichar_to_utf8(wc, buffer); + g_return_val_if_fail(length, 0); + + GList* items = pango_itemize(context, buffer, 0, length, NULL, NULL); + + if (g_list_length(items) == 1) { + PangoItem* item = reinterpret_cast<PangoItem*>(items->data); + PangoFont* tmpFont = item->analysis.font; + item->analysis.font = font; + + PangoGlyphString* glyphs = pango_glyph_string_new(); + pango_shape(buffer, length, &item->analysis, glyphs); + + item->analysis.font = tmpFont; + + if (glyphs->num_glyphs == 1) + result = glyphs->glyphs[0].glyph; + else + g_warning("didn't get 1 glyph but %d", glyphs->num_glyphs); + + pango_glyph_string_free(glyphs); + } + + g_list_foreach(items, (GFunc)pango_item_free, NULL); + g_list_free(items); + + return result; +} + +bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData) +{ + // The bufferLength will be greater than the glyph page size if the buffer has Unicode supplementary characters. + // We won't support this for now. + if (bufferLength > GlyphPage::size) + return false; + + if (!fontData->m_font.m_font || fontData->m_font.m_font == reinterpret_cast<PangoFont*>(-1)) + return false; + + bool haveGlyphs = false; + for (unsigned i = 0; i < length; i++) { + Glyph glyph = pango_font_get_glyph(fontData->m_font.m_font, fontData->m_font.m_context, buffer[i]); + if (!glyph) + setGlyphDataForIndex(offset + i, 0, 0); + else { + setGlyphDataForIndex(offset + i, glyph, fontData); + haveGlyphs = true; + } + } + + return haveGlyphs; +} + +} diff --git a/WebCore/platform/graphics/gtk/IconGtk.cpp b/WebCore/platform/graphics/gtk/IconGtk.cpp new file mode 100644 index 0000000..d8b38a0 --- /dev/null +++ b/WebCore/platform/graphics/gtk/IconGtk.cpp @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2007 Holger Hans Peter Freyther + * + * 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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 "Icon.h" + +#include "CString.h" +#include "GraphicsContext.h" +#include "MIMETypeRegistry.h" +#include "NotImplemented.h" +#include "PassRefPtr.h" + +#include <gtk/gtk.h> + +namespace WebCore { + +Icon::Icon() + : m_icon(0) +{ +} + +Icon::~Icon() +{ + if (m_icon) + g_object_unref(m_icon); +} + +static String lookupIconName(String MIMEType) +{ + /* + Lookup an appropriate icon according to either the Icon Naming Spec + or conventional Gnome icon names respectively. + + See http://standards.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html + + The icon theme is probed for the following names: + 1. media-subtype + 2. gnome-mime-media-subtype + 3. media-x-generic + 4. gnome-mime-media + + In the worst case it falls back to the stock file icon. + */ + int pos = MIMEType.find('/'); + if(pos >= 0) { + String media = MIMEType.substring(0, pos); + String subtype = MIMEType.substring(pos + 1); + GtkIconTheme* iconTheme = gtk_icon_theme_get_default(); + String iconName = media + "-" + subtype; + if(gtk_icon_theme_has_icon(iconTheme, iconName.utf8().data())) + return iconName; + iconName = "gnome-mime-" + media + "-" + subtype; + if(gtk_icon_theme_has_icon(iconTheme, iconName.utf8().data())) + return iconName; + iconName = media + "-x-generic"; + if(gtk_icon_theme_has_icon(iconTheme, iconName.utf8().data())) + return iconName; + iconName = media + "gnome-mime-" + media; + if(gtk_icon_theme_has_icon(iconTheme, iconName.utf8().data())) + return iconName; + } + return GTK_STOCK_FILE; +} + +PassRefPtr<Icon> Icon::createIconForFile(const String& filename) +{ + if (!g_path_skip_root(filename.utf8().data())) + return 0; + + String MIMEType = MIMETypeRegistry::getMIMETypeForPath(filename); + String iconName = lookupIconName(MIMEType); + + RefPtr<Icon> icon = adoptRef(new Icon); + icon->m_icon = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), iconName.utf8().data(), 16, GTK_ICON_LOOKUP_USE_BUILTIN, NULL); + if (!icon->m_icon) + return 0; + return icon.release(); +} + +PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames) +{ + //FIXME: Implement this + return 0; +} + +void Icon::paint(GraphicsContext* context, const IntRect& rect) +{ + if (context->paintingDisabled()) + return; + + // TODO: Scale/clip the image if necessary. + cairo_t* cr = context->platformContext(); + cairo_save(cr); + gdk_cairo_set_source_pixbuf(cr, m_icon, rect.x(), rect.y()); + cairo_paint(cr); + cairo_restore(cr); +} + +} diff --git a/WebCore/platform/graphics/gtk/ImageGtk.cpp b/WebCore/platform/graphics/gtk/ImageGtk.cpp new file mode 100644 index 0000000..b745209 --- /dev/null +++ b/WebCore/platform/graphics/gtk/ImageGtk.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. 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 "BitmapImage.h" + +// This function loads resources from WebKit +Vector<char> loadResourceIntoArray(const char*); + +namespace WebCore { + +void BitmapImage::initPlatformData() +{ +} + +void BitmapImage::invalidatePlatformData() +{ +} + +PassRefPtr<Image> Image::loadPlatformResource(const char *name) +{ + Vector<char> arr = loadResourceIntoArray(name); + RefPtr<BitmapImage> img = BitmapImage::create(); + RefPtr<SharedBuffer> buffer = SharedBuffer::create(arr.data(), arr.size()); + img->setData(buffer, true); + return img.release(); +} + +} diff --git a/WebCore/platform/graphics/gtk/IntPointGtk.cpp b/WebCore/platform/graphics/gtk/IntPointGtk.cpp new file mode 100644 index 0000000..c402158 --- /dev/null +++ b/WebCore/platform/graphics/gtk/IntPointGtk.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2007 Alp Toker <alp@atoker.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "IntPoint.h" + +#include <gdk/gdk.h> + +namespace WebCore { + +IntPoint::IntPoint(const GdkPoint& p) + : m_x(p.x) + , m_y(p.y) +{ +} + +IntPoint::operator GdkPoint() const +{ + GdkPoint p = { x(), y() }; + return p; +} + +} + +// vim: ts=4 sw=4 et diff --git a/WebCore/platform/graphics/gtk/IntRectGtk.cpp b/WebCore/platform/graphics/gtk/IntRectGtk.cpp new file mode 100644 index 0000000..aaa1944 --- /dev/null +++ b/WebCore/platform/graphics/gtk/IntRectGtk.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2007 Alp Toker <alp@atoker.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "IntRect.h" + +#include <gdk/gdk.h> + +namespace WebCore { + +IntRect::IntRect(const GdkRectangle& r) + : m_location(IntPoint(r.x, r.y)) + , m_size(r.width, r.height) +{ +} + +IntRect::operator GdkRectangle() const +{ + GdkRectangle r = { x(), y(), width(), height() }; + return r; +} + +} + +// vim: ts=4 sw=4 et diff --git a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp new file mode 100644 index 0000000..1f0cac6 --- /dev/null +++ b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp @@ -0,0 +1,622 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * Copyright (C) 2007 Collabora Ltd. All rights reserved. + * Copyright (C) 2007 Alp Toker <alp@atoker.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * aint with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#if ENABLE(VIDEO) + +#include "MediaPlayerPrivateGStreamer.h" +#include "VideoSinkGStreamer.h" + +#include "CString.h" +#include "GraphicsContext.h" +#include "IntRect.h" +#include "KURL.h" +#include "MIMETypeRegistry.h" +#include "MediaPlayer.h" +#include "NotImplemented.h" +#include "ScrollView.h" +#include "Widget.h" +#include <wtf/GOwnPtr.h> + +#include <gdk/gdkx.h> +#include <gst/base/gstbasesrc.h> +#include <gst/gst.h> +#include <gst/interfaces/mixer.h> +#include <gst/interfaces/xoverlay.h> +#include <gst/video/video.h> +#include <limits> +#include <math.h> + +using namespace std; + +namespace WebCore { + +gboolean mediaPlayerPrivateErrorCallback(GstBus* bus, GstMessage* message, gpointer data) +{ + if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_ERROR) + { + GOwnPtr<GError> err; + GOwnPtr<gchar> debug; + + gst_message_parse_error(message, &err.outPtr(), &debug.outPtr()); + if (err->code == 3) { + LOG_VERBOSE(Media, "File not found"); + MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data); + if (mp) + mp->loadingFailed(); + } else + LOG_VERBOSE(Media, "Error: %d, %s", err->code, err->message); + } + return true; +} + +gboolean mediaPlayerPrivateEOSCallback(GstBus* bus, GstMessage* message, gpointer data) +{ + if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_EOS) + { + LOG_VERBOSE(Media, "End of Stream"); + MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data); + mp->didEnd(); + } + return true; +} + +gboolean mediaPlayerPrivateStateCallback(GstBus* bus, GstMessage* message, gpointer data) +{ + if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_STATE_CHANGED) + { + MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data); + mp->updateStates(); + } + return true; +} + +gboolean mediaPlayerPrivateBufferingCallback(GstBus* bus, GstMessage* message, gpointer data) +{ + if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_BUFFERING) + { + gint percent = 0; + gst_message_parse_buffering(message, &percent); + LOG_VERBOSE(Media, "Buffering %d", percent); + } + return true; +} + +MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) + : m_player(player) + , m_playBin(0) + , m_videoSink(0) + , m_source(0) + , m_rate(1.0f) + , m_endTime(numeric_limits<float>::infinity()) + , m_isEndReached(false) + , m_volume(0.5f) + , m_networkState(MediaPlayer::Empty) + , m_readyState(MediaPlayer::DataUnavailable) + , m_startedPlaying(false) + , m_isStreaming(false) + , m_rect(IntRect()) + , m_visible(true) +{ + + static bool gstInitialized = false; + // FIXME: We should pass the arguments from the command line + if (!gstInitialized) { + gst_init(0, NULL); + gstInitialized = true; + } + + // FIXME: The size shouldn't be fixed here, this is just a quick hack. + m_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 640, 480); +} + +MediaPlayerPrivate::~MediaPlayerPrivate() +{ + if (m_surface) + cairo_surface_destroy(m_surface); + + if (m_playBin) { + gst_element_set_state(m_playBin, GST_STATE_NULL); + gst_object_unref(GST_OBJECT(m_playBin)); + } +} + +void MediaPlayerPrivate::load(String url) +{ + LOG_VERBOSE(Media, "Load %s", url.utf8().data()); + if (m_networkState != MediaPlayer::Loading) { + m_networkState = MediaPlayer::Loading; + m_player->networkStateChanged(); + } + if (m_readyState != MediaPlayer::DataUnavailable) { + m_readyState = MediaPlayer::DataUnavailable; + m_player->readyStateChanged(); + } + + createGSTPlayBin(url); + pause(); +} + +void MediaPlayerPrivate::play() +{ + LOG_VERBOSE(Media, "Play"); + // When end reached, rewind for Test video-seek-past-end-playing + if (m_isEndReached) + seek(0); + m_isEndReached = false; + + gst_element_set_state(m_playBin, GST_STATE_PLAYING); + m_startedPlaying = true; +} + +void MediaPlayerPrivate::pause() +{ + LOG_VERBOSE(Media, "Pause"); + gst_element_set_state(m_playBin, GST_STATE_PAUSED); + m_startedPlaying = false; +} + +float MediaPlayerPrivate::duration() +{ + if (!m_playBin) + return 0.0; + + GstFormat fmt = GST_FORMAT_TIME; + gint64 len = 0; + + if (gst_element_query_duration(m_playBin, &fmt, &len)) + LOG_VERBOSE(Media, "Duration: %" GST_TIME_FORMAT, GST_TIME_ARGS(len)); + else + LOG_VERBOSE(Media, "Duration query failed "); + + if ((GstClockTime)len == GST_CLOCK_TIME_NONE) { + m_isStreaming = true; + return numeric_limits<float>::infinity(); + } + return (float) (len / 1000000000.0); + // FIXME: handle 3.14.9.5 properly +} + +float MediaPlayerPrivate::currentTime() const +{ + if (!m_playBin) + return 0; + // Necessary as sometimes, gstreamer return 0:00 at the EOS + if (m_isEndReached) + return m_endTime; + + float ret; + + GstQuery* query = gst_query_new_position(GST_FORMAT_TIME); + if (gst_element_query(m_playBin, query)) { + gint64 position; + gst_query_parse_position(query, NULL, &position); + ret = (float) (position / 1000000000.0); + LOG_VERBOSE(Media, "Position %" GST_TIME_FORMAT, GST_TIME_ARGS(position)); + } else { + LOG_VERBOSE(Media, "Position query failed..."); + ret = 0.0; + } + gst_query_unref(query); + + return ret; +} + +void MediaPlayerPrivate::seek(float time) +{ + GstClockTime sec = (GstClockTime)(time * GST_SECOND); + + if (!m_playBin) + return; + + if (m_isStreaming) + return; + + LOG_VERBOSE(Media, "Seek: %" GST_TIME_FORMAT, GST_TIME_ARGS(sec)); + // FIXME: What happens when the seeked position is not available? + if (!gst_element_seek( m_playBin, m_rate, + GST_FORMAT_TIME, + (GstSeekFlags)(GST_SEEK_FLAG_FLUSH), + GST_SEEK_TYPE_SET, sec, + GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) + LOG_VERBOSE(Media, "Seek to %f failed", time); +} + +void MediaPlayerPrivate::setEndTime(float time) +{ + if (!m_playBin) + return; + if (m_isStreaming) + return; + if (m_endTime != time) { + m_endTime = time; + GstClockTime start = (GstClockTime)(currentTime() * GST_SECOND); + GstClockTime end = (GstClockTime)(time * GST_SECOND); + LOG_VERBOSE(Media, "setEndTime: %" GST_TIME_FORMAT, GST_TIME_ARGS(end)); + // FIXME: What happens when the seeked position is not available? + if (!gst_element_seek(m_playBin, m_rate, + GST_FORMAT_TIME, + (GstSeekFlags)(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE), + GST_SEEK_TYPE_SET, start, + GST_SEEK_TYPE_SET, end )) + LOG_VERBOSE(Media, "Seek to %f failed", time); + } +} + +void MediaPlayerPrivate::startEndPointTimerIfNeeded() +{ + notImplemented(); +} + +void MediaPlayerPrivate::cancelSeek() +{ + notImplemented(); +} + +void MediaPlayerPrivate::endPointTimerFired(Timer<MediaPlayerPrivate>*) +{ + notImplemented(); +} + +bool MediaPlayerPrivate::paused() const +{ + return !m_startedPlaying; +} + +bool MediaPlayerPrivate::seeking() const +{ + return false; +} + +// Returns the size of the video +IntSize MediaPlayerPrivate::naturalSize() +{ + if (!hasVideo()) + return IntSize(); + + int x = 0, y = 0; + if (GstPad* pad = gst_element_get_static_pad(m_videoSink, "sink")) { + gst_video_get_size(GST_PAD(pad), &x, &y); + gst_object_unref(GST_OBJECT(pad)); + } + + return IntSize(x, y); +} + +bool MediaPlayerPrivate::hasVideo() +{ + gint currentVideo = -1; + if (m_playBin) + g_object_get(G_OBJECT(m_playBin), "current-video", ¤tVideo, NULL); + return currentVideo > -1; +} + +void MediaPlayerPrivate::setVolume(float volume) +{ + m_volume = volume; + LOG_VERBOSE(Media, "Volume to %f", volume); + setMuted(false); +} + +void MediaPlayerPrivate::setMuted(bool b) +{ + if (!m_playBin) + return; + + if (b) { + g_object_get(G_OBJECT(m_playBin), "volume", &m_volume, NULL); + g_object_set(G_OBJECT(m_playBin), "volume", (double)0.0, NULL); + } else { + g_object_set(G_OBJECT(m_playBin), "volume", m_volume, NULL); + } +} + +void MediaPlayerPrivate::setRate(float rate) +{ + if (rate == 0.0) { + gst_element_set_state(m_playBin, GST_STATE_PAUSED); + return; + } + if (m_isStreaming) + return; + + m_rate = rate; + LOG_VERBOSE(Media, "Set Rate to %f", rate); + if (!gst_element_seek(m_playBin, rate, + GST_FORMAT_TIME, + (GstSeekFlags)(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE), + GST_SEEK_TYPE_SET, (GstClockTime) (currentTime() * GST_SECOND), + GST_SEEK_TYPE_SET, (GstClockTime) (m_endTime * GST_SECOND))) + LOG_VERBOSE(Media, "Set Rate to %f failed", rate); +} + +int MediaPlayerPrivate::dataRate() const +{ + notImplemented(); + return 1; +} + +MediaPlayer::NetworkState MediaPlayerPrivate::networkState() +{ + return m_networkState; +} + +MediaPlayer::ReadyState MediaPlayerPrivate::readyState() +{ + return m_readyState; +} + +float MediaPlayerPrivate::maxTimeBuffered() +{ + notImplemented(); + LOG_VERBOSE(Media, "maxTimeBuffered"); + // rtsp streams are not buffered + return m_isStreaming ? 0 : maxTimeLoaded(); +} + +float MediaPlayerPrivate::maxTimeSeekable() +{ + // TODO + LOG_VERBOSE(Media, "maxTimeSeekable"); + if (m_isStreaming) + return numeric_limits<float>::infinity(); + // infinite duration means live stream + return maxTimeLoaded(); +} + +float MediaPlayerPrivate::maxTimeLoaded() +{ + // TODO + LOG_VERBOSE(Media, "maxTimeLoaded"); + notImplemented(); + return duration(); +} + +unsigned MediaPlayerPrivate::bytesLoaded() +{ + notImplemented(); + LOG_VERBOSE(Media, "bytesLoaded"); + /*if (!m_playBin) + return 0; + float dur = duration(); + float maxTime = maxTimeLoaded(); + if (!dur) + return 0;*/ + return 1;//totalBytes() * maxTime / dur; +} + +bool MediaPlayerPrivate::totalBytesKnown() +{ + notImplemented(); + LOG_VERBOSE(Media, "totalBytesKnown"); + return totalBytes() > 0; +} + +unsigned MediaPlayerPrivate::totalBytes() +{ + notImplemented(); + LOG_VERBOSE(Media, "totalBytes"); + if (!m_playBin) + return 0; + + if (!m_source) + return 0; + + // Do something with m_source to get the total bytes of the media + + return 100; +} + +void MediaPlayerPrivate::cancelLoad() +{ + notImplemented(); +} + +void MediaPlayerPrivate::updateStates() +{ + // There is no (known) way to get such level of information about + // the state of GStreamer, therefore, when in PAUSED state, + // we are sure we can display the first frame and go to play + + MediaPlayer::NetworkState oldNetworkState = m_networkState; + MediaPlayer::ReadyState oldReadyState = m_readyState; + GstState state; + GstState pending; + + if (!m_playBin) + return; + + GstStateChangeReturn ret = gst_element_get_state (m_playBin, + &state, &pending, 250 * GST_NSECOND); + + switch(ret) { + case GST_STATE_CHANGE_SUCCESS: + LOG_VERBOSE(Media, "State: %s, pending: %s", + gst_element_state_get_name(state), + gst_element_state_get_name(pending)); + + if (state == GST_STATE_READY) { + m_readyState = MediaPlayer::CanPlayThrough; + } else if (state == GST_STATE_PAUSED) { + m_readyState = MediaPlayer::CanPlayThrough; + } + if (m_networkState < MediaPlayer::Loaded) + m_networkState = MediaPlayer::Loaded; + + g_object_get(m_playBin, "source", &m_source, NULL); + if (!m_source) + LOG_VERBOSE(Media, "m_source is NULL"); + break; + case GST_STATE_CHANGE_ASYNC: + LOG_VERBOSE(Media, "Async: State: %s, pending: %s", + gst_element_state_get_name(state), + gst_element_state_get_name(pending)); + // Change in progress + return; + break; + case GST_STATE_CHANGE_NO_PREROLL: + LOG_VERBOSE(Media, "No preroll: State: %s, pending: %s", + gst_element_state_get_name(state), + gst_element_state_get_name(pending)); + if (state == GST_STATE_READY) { + m_readyState = MediaPlayer::CanPlay; + } else if (state == GST_STATE_PAUSED) { + m_readyState = MediaPlayer::CanPlay; + } + if (m_networkState < MediaPlayer::LoadedMetaData) + m_networkState = MediaPlayer::LoadedMetaData; + break; + default: + LOG_VERBOSE(Media, "Else : %d", ret); + break; + } + + if (seeking()) + m_readyState = MediaPlayer::DataUnavailable; + + if (m_networkState != oldNetworkState) { + LOG_VERBOSE(Media, "Network State Changed from %u to %u", + oldNetworkState, m_networkState); + m_player->networkStateChanged(); + } + if (m_readyState != oldReadyState) { + LOG_VERBOSE(Media, "Ready State Changed from %u to %u", + oldReadyState, m_readyState); + m_player->readyStateChanged(); + } +} + +void MediaPlayerPrivate::loadStateChanged() +{ + updateStates(); +} + +void MediaPlayerPrivate::rateChanged() +{ + updateStates(); +} + +void MediaPlayerPrivate::sizeChanged() +{ + notImplemented(); +} + +void MediaPlayerPrivate::timeChanged() +{ + updateStates(); + m_player->timeChanged(); +} + +void MediaPlayerPrivate::volumeChanged() +{ + m_player->volumeChanged(); +} + +void MediaPlayerPrivate::didEnd() +{ + m_isEndReached = true; + pause(); + timeChanged(); +} + +void MediaPlayerPrivate::loadingFailed() +{ + if (m_networkState != MediaPlayer::LoadFailed) { + m_networkState = MediaPlayer::LoadFailed; + m_player->networkStateChanged(); + } + if (m_readyState != MediaPlayer::DataUnavailable) { + m_readyState = MediaPlayer::DataUnavailable; + m_player->readyStateChanged(); + } +} + +void MediaPlayerPrivate::setRect(const IntRect& rect) +{ + m_rect = rect; +} + +void MediaPlayerPrivate::setVisible(bool visible) +{ + m_visible = visible; +} + +void MediaPlayerPrivate::repaint() +{ + m_player->repaint(); +} + +void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& rect) +{ + if (context->paintingDisabled()) + return; + + if (!m_visible) + return; + + //TODO: m_rect vs rect? + cairo_t* cr = context->platformContext(); + + cairo_save(cr); + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + cairo_translate(cr, rect.x(), rect.y()); + cairo_rectangle(cr, 0, 0, rect.width(), rect.height()); + cairo_set_source_surface(cr, m_surface, 0, 0); + cairo_fill(cr); + cairo_restore(cr); +} + +void MediaPlayerPrivate::getSupportedTypes(HashSet<String>& types) +{ + // FIXME: do the real thing + notImplemented(); + types.add(String("video/x-theora+ogg")); +} + +void MediaPlayerPrivate::createGSTPlayBin(String url) +{ + ASSERT(!m_playBin); + m_playBin = gst_element_factory_make("playbin", "play"); + + GstBus* bus = gst_pipeline_get_bus(GST_PIPELINE(m_playBin)); + gst_bus_add_signal_watch(bus); + g_signal_connect(bus, "message::error", G_CALLBACK(mediaPlayerPrivateErrorCallback), this); + g_signal_connect(bus, "message::eos", G_CALLBACK(mediaPlayerPrivateEOSCallback), this); + g_signal_connect(bus, "message::state-changed", G_CALLBACK(mediaPlayerPrivateStateCallback), this); + g_signal_connect(bus, "message::buffering", G_CALLBACK(mediaPlayerPrivateBufferingCallback), this); + gst_object_unref(bus); + + g_object_set(G_OBJECT(m_playBin), "uri", url.utf8().data(), NULL); + + GstElement* audioSink = gst_element_factory_make("gconfaudiosink", NULL); + m_videoSink = webkit_video_sink_new(m_surface); + + g_object_set(m_playBin, "audio-sink", audioSink, NULL); + g_object_set(m_playBin, "video-sink", m_videoSink, NULL); + + setVolume(m_volume); +} + +} + +#endif + diff --git a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h new file mode 100644 index 0000000..3f08bc0 --- /dev/null +++ b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * Copyright (C) 2007 Collabora Ltd. All rights reserved. + * Copyright (C) 2007 Alp Toker <alp@atoker.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * aint with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef MediaPlayerPrivateGStreamer_h +#define MediaPlayerPrivateGStreamer_h + +#if ENABLE(VIDEO) + +#include "MediaPlayer.h" +#include "Timer.h" + +#include <gtk/gtk.h> + +typedef struct _GstElement GstElement; +typedef struct _GstMessage GstMessage; +typedef struct _GstBus GstBus; + +namespace WebCore { + + class GraphicsContext; + class IntSize; + class IntRect; + class String; + + gboolean mediaPlayerPrivateErrorCallback(GstBus* bus, GstMessage* message, gpointer data); + gboolean mediaPlayerPrivateEOSCallback(GstBus* bus, GstMessage* message, gpointer data); + gboolean mediaPlayerPrivateStateCallback(GstBus* bus, GstMessage* message, gpointer data); + + class MediaPlayerPrivate : Noncopyable + { + friend gboolean mediaPlayerPrivateErrorCallback(GstBus* bus, GstMessage* message, gpointer data); + friend gboolean mediaPlayerPrivateEOSCallback(GstBus* bus, GstMessage* message, gpointer data); + friend gboolean mediaPlayerPrivateStateCallback(GstBus* bus, GstMessage* message, gpointer data); + + public: + MediaPlayerPrivate(MediaPlayer*); + ~MediaPlayerPrivate(); + + IntSize naturalSize(); + bool hasVideo(); + + void load(String url); + void cancelLoad(); + + void play(); + void pause(); + + bool paused() const; + bool seeking() const; + + float duration(); + float currentTime() const; + void seek(float); + void setEndTime(float); + + void setRate(float); + void setVolume(float); + void setMuted(bool); + + int dataRate() const; + + MediaPlayer::NetworkState networkState(); + MediaPlayer::ReadyState readyState(); + + float maxTimeBuffered(); + float maxTimeSeekable(); + unsigned bytesLoaded(); + bool totalBytesKnown(); + unsigned totalBytes(); + + void setVisible(bool); + void setRect(const IntRect&); + + void loadStateChanged(); + void rateChanged(); + void sizeChanged(); + void timeChanged(); + void volumeChanged(); + void didEnd(); + void loadingFailed(); + + void repaint(); + void paint(GraphicsContext*, const IntRect&); + static void getSupportedTypes(HashSet<String>&); + static bool isAvailable() { return true; } + + private: + + void updateStates(); + void cancelSeek(); + void endPointTimerFired(Timer<MediaPlayerPrivate>*); + float maxTimeLoaded(); + void startEndPointTimerIfNeeded(); + + void createGSTPlayBin(String url); + + private: + MediaPlayer* m_player; + GstElement* m_playBin; + GstElement* m_videoSink; + GstElement* m_source; + float m_rate; + float m_endTime; + bool m_isEndReached; + double m_volume; + MediaPlayer::NetworkState m_networkState; + MediaPlayer::ReadyState m_readyState; + bool m_startedPlaying; + bool m_isStreaming; + IntRect m_rect; + bool m_visible; + cairo_surface_t* m_surface; + }; +} + +#endif +#endif diff --git a/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp b/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp new file mode 100644 index 0000000..1ca3e95 --- /dev/null +++ b/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com + * Copyright (C) 2007, 2008 Alp Toker <alp@atoker.com> + * Copyright (C) 2007 Holger Hans Peter Freyther + * 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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 "SimpleFontData.h" + +#include "FloatRect.h" +#include "Font.h" +#include "FontCache.h" +#include "FontDescription.h" +#include "GlyphBuffer.h" +#include <cairo.h> +#include <unicode/uchar.h> +#include <unicode/unorm.h> +#include <wtf/MathExtras.h> + +namespace WebCore { + +void SimpleFontData::platformInit() +{ + cairo_font_extents_t font_extents; + cairo_text_extents_t text_extents; + cairo_scaled_font_extents(m_font.m_scaledFont, &font_extents); + m_ascent = static_cast<int>(font_extents.ascent); + m_descent = static_cast<int>(font_extents.descent); + m_lineSpacing = static_cast<int>(font_extents.height); + cairo_scaled_font_text_extents(m_font.m_scaledFont, "x", &text_extents); + m_xHeight = text_extents.height; + cairo_scaled_font_text_extents(m_font.m_scaledFont, " ", &text_extents); + m_spaceWidth = static_cast<int>(text_extents.x_advance); + m_lineGap = m_lineSpacing - m_ascent - m_descent; +} + +void SimpleFontData::platformDestroy() +{ + delete m_smallCapsFontData; + + if (isCustomFont()) + return; + + if (m_font.m_pattern && ((FcPattern*)-1 != m_font.m_pattern)) { + FcPatternDestroy(m_font.m_pattern); + m_font.m_pattern = 0; + } + + if (m_font.m_fallbacks) { + FcFontSetDestroy(m_font.m_fallbacks); + m_font.m_fallbacks = 0; + } + + if (m_font.m_scaledFont) { + cairo_scaled_font_destroy(m_font.m_scaledFont); + m_font.m_scaledFont = 0; + } +} + +SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const +{ + if (!m_smallCapsFontData) { + FontDescription desc = FontDescription(fontDescription); + desc.setSpecifiedSize(0.70f*fontDescription.computedSize()); + const FontPlatformData* pdata = new FontPlatformData(desc, desc.family().family()); + m_smallCapsFontData = new SimpleFontData(*pdata); + } + return m_smallCapsFontData; +} + +bool SimpleFontData::containsCharacters(const UChar* characters, int length) const +{ + FT_Face face = cairo_ft_scaled_font_lock_face(m_font.m_scaledFont); + + if (!face) + return false; + + for (unsigned i = 0; i < length; i++) { + if (FcFreeTypeCharIndex(face, characters[i]) == 0) { + cairo_ft_scaled_font_unlock_face(m_font.m_scaledFont); + return false; + } + } + + cairo_ft_scaled_font_unlock_face(m_font.m_scaledFont); + + return true; +} + +void SimpleFontData::determinePitch() +{ + m_treatAsFixedPitch = m_font.isFixedPitch(); +} + +float SimpleFontData::platformWidthForGlyph(Glyph glyph) const +{ + ASSERT(m_font.m_scaledFont); + + cairo_glyph_t cglyph = { glyph, 0, 0 }; + cairo_text_extents_t extents; + cairo_scaled_font_glyph_extents(m_font.m_scaledFont, &cglyph, 1, &extents); + + float w = (float)m_spaceWidth; + if (cairo_scaled_font_status(m_font.m_scaledFont) == CAIRO_STATUS_SUCCESS && extents.x_advance != 0) + w = (float)extents.x_advance; + return w; +} + +void SimpleFontData::setFont(cairo_t* cr) const +{ + ASSERT(cr); + m_font.setFont(cr); +} + +} diff --git a/WebCore/platform/graphics/gtk/SimpleFontDataPango.cpp b/WebCore/platform/graphics/gtk/SimpleFontDataPango.cpp new file mode 100644 index 0000000..8621865 --- /dev/null +++ b/WebCore/platform/graphics/gtk/SimpleFontDataPango.cpp @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com + * Copyright (C) 2007, 2008 Alp Toker <alp@atoker.com> + * Copyright (C) 2007 Holger Hans Peter Freyther + * Copyright (C) 2007 Pioneer Research Center USA, Inc. + * 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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 "SimpleFontData.h" + +#include "FloatRect.h" +#include "Font.h" +#include "FontCache.h" +#include "FontDescription.h" +#include "GlyphBuffer.h" +#include <cairo.h> +#include <wtf/MathExtras.h> + +namespace WebCore { + +void SimpleFontData::platformInit() +{ + cairo_font_extents_t font_extents; + cairo_text_extents_t text_extents; + cairo_scaled_font_extents(m_font.m_scaledFont, &font_extents); + m_ascent = static_cast<int>(font_extents.ascent); + m_descent = static_cast<int>(font_extents.descent); + m_lineSpacing = static_cast<int>(font_extents.height); + cairo_scaled_font_text_extents(m_font.m_scaledFont, "x", &text_extents); + m_xHeight = text_extents.height; + cairo_scaled_font_text_extents(m_font.m_scaledFont, " ", &text_extents); + m_spaceWidth = static_cast<int>(text_extents.x_advance); + m_lineGap = m_lineSpacing - m_ascent - m_descent; +} + +void SimpleFontData::platformDestroy() +{ + if (!isCustomFont()) { + + if (m_font.m_font && m_font.m_font != reinterpret_cast<PangoFont*>(-1)) { + g_object_unref(m_font.m_font); + m_font.m_font = 0; + } + + if (m_font.m_context) { + g_object_unref (m_font.m_context); + m_font.m_context = 0; + } + + if (m_font.m_scaledFont) { + cairo_scaled_font_destroy(m_font.m_scaledFont); + m_font.m_scaledFont = 0; + } + } + + delete m_smallCapsFontData; +} + +SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const +{ + if (!m_smallCapsFontData) { + FontDescription desc = FontDescription(fontDescription); + desc.setSpecifiedSize(0.70f*fontDescription.computedSize()); + const FontPlatformData* pdata = new FontPlatformData(desc, desc.family().family()); + m_smallCapsFontData = new SimpleFontData(*pdata); + } + return m_smallCapsFontData; +} + +bool SimpleFontData::containsCharacters(const UChar* characters, int length) const +{ + bool result = true; + + PangoCoverage* requested = pango_coverage_from_bytes((guchar*)characters, length); + PangoCoverage* available = pango_font_get_coverage(m_font.m_font, pango_language_get_default()); + pango_coverage_max(requested, available); + + for (int i = 0; i < length; i++) { + if (PANGO_COVERAGE_NONE == pango_coverage_get(requested, i)) { + result = false; + break; + } + } + + pango_coverage_unref(requested); + pango_coverage_unref(available); + + return result; +} + +void SimpleFontData::determinePitch() +{ + m_treatAsFixedPitch = m_font.isFixedPitch(); +} + +float SimpleFontData::platformWidthForGlyph(Glyph glyph) const +{ + ASSERT(m_font.m_scaledFont); + + cairo_glyph_t cglyph = { glyph, 0, 0 }; + cairo_text_extents_t extents; + cairo_scaled_font_glyph_extents(m_font.m_scaledFont, &cglyph, 1, &extents); + + float w = (float)m_spaceWidth; + if (cairo_scaled_font_status(m_font.m_scaledFont) == CAIRO_STATUS_SUCCESS && extents.x_advance != 0) + w = (float)extents.x_advance; + return w; +} + +void SimpleFontData::setFont(cairo_t* cr) const +{ + ASSERT(cr); + m_font.setFont(cr); +} + +} diff --git a/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp b/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp new file mode 100644 index 0000000..04df7ac --- /dev/null +++ b/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp @@ -0,0 +1,312 @@ +/* + * Copyright (C) 2007 OpenedHand + * Copyright (C) 2007 Alp Toker <alp@atoker.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * SECTION:webkit-video-sink + * @short_description: GStreamer video sink + * + * #WebKitVideoSink is a GStreamer sink element that sends + * data to a #cairo_surface_t. + */ + +#include "config.h" +#include "VideoSinkGStreamer.h" + +#include <glib.h> +#include <gst/gst.h> +#include <gst/video/video.h> + +static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE("sink", + GST_PAD_SINK, GST_PAD_ALWAYS, + GST_STATIC_CAPS(GST_VIDEO_CAPS_RGBx ";" GST_VIDEO_CAPS_BGRx)); + +GST_DEBUG_CATEGORY_STATIC(webkit_video_sink_debug); +#define GST_CAT_DEFAULT webkit_video_sink_debug + +static GstElementDetails webkit_video_sink_details = + GST_ELEMENT_DETAILS((gchar*) "WebKit video sink", + (gchar*) "Sink/Video", + (gchar*) "Sends video data from a GStreamer pipeline to a Cairo surface", + (gchar*) "Alp Toker <alp@atoker.com>"); + +enum { + PROP_0, + PROP_SURFACE +}; + +struct _WebKitVideoSinkPrivate { + cairo_surface_t* surface; + GAsyncQueue* async_queue; + gboolean rgb_ordering; + int width; + int height; + int fps_n; + int fps_d; + int par_n; + int par_d; +}; + +#define _do_init(bla) \ + GST_DEBUG_CATEGORY_INIT (webkit_video_sink_debug, \ + "webkitsink", \ + 0, \ + "webkit video sink") + +GST_BOILERPLATE_FULL(WebKitVideoSink, + webkit_video_sink, + GstBaseSink, + GST_TYPE_BASE_SINK, + _do_init); + +static void +webkit_video_sink_base_init(gpointer g_class) +{ + GstElementClass* element_class = GST_ELEMENT_CLASS(g_class); + + gst_element_class_add_pad_template(element_class, gst_static_pad_template_get(&sinktemplate)); + gst_element_class_set_details(element_class, &webkit_video_sink_details); +} + +static void +webkit_video_sink_init(WebKitVideoSink* sink, WebKitVideoSinkClass* klass) +{ + WebKitVideoSinkPrivate* priv; + + sink->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE(sink, WEBKIT_TYPE_VIDEO_SINK, WebKitVideoSinkPrivate); + priv->async_queue = g_async_queue_new(); +} + +static gboolean +webkit_video_sink_idle_func(gpointer data) +{ + WebKitVideoSinkPrivate* priv; + GstBuffer* buffer; + + priv = (WebKitVideoSinkPrivate*)data; + + if (!priv->async_queue) + return FALSE; + + buffer = (GstBuffer*)g_async_queue_try_pop(priv->async_queue); + if (buffer == NULL || G_UNLIKELY(!GST_IS_BUFFER(buffer))) + return FALSE; + + // TODO: consider priv->rgb_ordering? + cairo_surface_t* src = cairo_image_surface_create_for_data(GST_BUFFER_DATA(buffer), CAIRO_FORMAT_RGB24, priv->width, priv->height, (4 * priv->width + 3) & ~ 3); + + // TODO: We copy the data twice right now. This could be easily improved. + cairo_t* cr = cairo_create(priv->surface); + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_surface(cr, src, 0, 0); + cairo_surface_destroy(src); + cairo_rectangle(cr, 0, 0, priv->width, priv->height); + cairo_fill(cr); + cairo_destroy(cr); + + gst_buffer_unref(buffer); + + return FALSE; +} + +static GstFlowReturn +webkit_video_sink_render(GstBaseSink* bsink, GstBuffer* buffer) +{ + WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(bsink); + WebKitVideoSinkPrivate* priv = sink->priv; + + g_async_queue_push(priv->async_queue, gst_buffer_ref(buffer)); + g_idle_add_full(G_PRIORITY_HIGH_IDLE, webkit_video_sink_idle_func, priv, NULL); + + return GST_FLOW_OK; +} + +static gboolean +webkit_video_sink_set_caps(GstBaseSink* bsink, GstCaps* caps) +{ + WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(bsink); + WebKitVideoSinkPrivate* priv = sink->priv; + GstStructure* structure; + gboolean ret; + const GValue* fps; + const GValue* par; + gint width, height; + int red_mask; + + GstCaps* intersection = gst_caps_intersect(gst_static_pad_template_get_caps(&sinktemplate), caps); + + if (gst_caps_is_empty(intersection)) + return FALSE; + + gst_caps_unref(intersection); + + structure = gst_caps_get_structure(caps, 0); + + ret = gst_structure_get_int(structure, "width", &width); + ret &= gst_structure_get_int(structure, "height", &height); + fps = gst_structure_get_value(structure, "framerate"); + ret &= (fps != NULL); + + par = gst_structure_get_value(structure, "pixel-aspect-ratio"); + + if (!ret) + return FALSE; + + priv->width = width; + priv->height = height; + + /* We dont yet use fps or pixel aspect into but handy to have */ + priv->fps_n = gst_value_get_fraction_numerator(fps); + priv->fps_d = gst_value_get_fraction_denominator(fps); + + if (par) { + priv->par_n = gst_value_get_fraction_numerator(par); + priv->par_d = gst_value_get_fraction_denominator(par); + } else + priv->par_n = priv->par_d = 1; + + gst_structure_get_int(structure, "red_mask", &red_mask); + priv->rgb_ordering = (red_mask == static_cast<int>(0xff000000)); + + return TRUE; +} + +static void +webkit_video_sink_dispose(GObject* object) +{ + WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(object); + WebKitVideoSinkPrivate* priv = sink->priv; + + if (priv->surface) { + cairo_surface_destroy(priv->surface); + priv->surface = NULL; + } + + if (priv->async_queue) { + g_async_queue_unref(priv->async_queue); + priv->async_queue = NULL; + } + + G_OBJECT_CLASS(parent_class)->dispose(object); +} + +static void +webkit_video_sink_finalize(GObject* object) +{ + G_OBJECT_CLASS(parent_class)->finalize(object); +} + +static void +webkit_video_sink_set_property(GObject* object, guint prop_id, const GValue* value, GParamSpec* pspec) +{ + WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(object); + WebKitVideoSinkPrivate* priv = sink->priv; + + switch (prop_id) { + case PROP_SURFACE: + if (priv->surface) + cairo_surface_destroy(priv->surface); + priv->surface = cairo_surface_reference((cairo_surface_t*)g_value_get_pointer(value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +webkit_video_sink_get_property(GObject* object, guint prop_id, GValue* value, GParamSpec* pspec) +{ + WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(object); + + switch (prop_id) { + case PROP_SURFACE: + g_value_set_pointer(value, sink->priv->surface); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static gboolean +webkit_video_sink_stop(GstBaseSink* base_sink) +{ + WebKitVideoSinkPrivate* priv = WEBKIT_VIDEO_SINK(base_sink)->priv; + + g_async_queue_lock(priv->async_queue); + + /* Remove all remaining objects from the queue */ + while(GstBuffer* buffer = (GstBuffer*)g_async_queue_try_pop_unlocked(priv->async_queue)) + gst_buffer_unref(buffer); + + g_async_queue_unlock(priv->async_queue); + + return TRUE; +} + +static void +webkit_video_sink_class_init(WebKitVideoSinkClass* klass) +{ + GObjectClass* gobject_class = G_OBJECT_CLASS(klass); + GstBaseSinkClass* gstbase_sink_class = GST_BASE_SINK_CLASS(klass); + + g_type_class_add_private(klass, sizeof(WebKitVideoSinkPrivate)); + + gobject_class->set_property = webkit_video_sink_set_property; + gobject_class->get_property = webkit_video_sink_get_property; + + gobject_class->dispose = webkit_video_sink_dispose; + gobject_class->finalize = webkit_video_sink_finalize; + + gstbase_sink_class->render = webkit_video_sink_render; + gstbase_sink_class->preroll = webkit_video_sink_render; + gstbase_sink_class->stop = webkit_video_sink_stop; + gstbase_sink_class->set_caps = webkit_video_sink_set_caps; + + g_object_class_install_property( + gobject_class, PROP_SURFACE, + g_param_spec_pointer("surface", "surface", "Target cairo_surface_t*", + (GParamFlags)(G_PARAM_READWRITE))); +} + +/** + * webkit_video_sink_new: + * @surface: a #cairo_surface_t + * + * Creates a new GStreamer video sink which uses @surface as the target + * for sinking a video stream from GStreamer. + * + * Return value: a #GstElement for the newly created video sink + */ +GstElement* +webkit_video_sink_new(cairo_surface_t* surface) +{ + return (GstElement*)g_object_new(WEBKIT_TYPE_VIDEO_SINK, "surface", surface, NULL); +} + +void +webkit_video_sink_set_surface(WebKitVideoSink* sink, cairo_surface_t* surface) +{ + WebKitVideoSinkPrivate* priv; + + sink->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE(sink, WEBKIT_TYPE_VIDEO_SINK, WebKitVideoSinkPrivate); + if (priv->surface) + cairo_surface_destroy(priv->surface); + priv->surface = cairo_surface_reference(surface); +} diff --git a/WebCore/platform/graphics/gtk/VideoSinkGStreamer.h b/WebCore/platform/graphics/gtk/VideoSinkGStreamer.h new file mode 100644 index 0000000..2a706fb --- /dev/null +++ b/WebCore/platform/graphics/gtk/VideoSinkGStreamer.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2007 OpenedHand + * Copyright (C) 2007 Alp Toker <alp@atoker.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _HAVE_WEBKIT_VIDEO_SINK_H +#define _HAVE_WEBKIT_VIDEO_SINK_H + +#include <cairo.h> +#include <glib-object.h> +#include <gst/base/gstbasesink.h> + +G_BEGIN_DECLS + +#define WEBKIT_TYPE_VIDEO_SINK webkit_video_sink_get_type() + +#define WEBKIT_VIDEO_SINK(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ + WEBKIT_TYPE_VIDEO_SINK, WebKitVideoSink)) + +#define WEBKIT_VIDEO_SINK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), \ + WEBKIT_TYPE_VIDEO_SINK, WebKitVideoSinkClass)) + +#define WEBKIT_IS_VIDEO_SINK(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ + WEBKIT_TYPE_VIDEO_SINK)) + +#define WEBKIT_IS_VIDEO_SINK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), \ + WEBKIT_TYPE_VIDEO_SINK)) + +#define WEBKIT_VIDEO_SINK_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), \ + WEBKIT_TYPE_VIDEO_SINK, WebKitVideoSinkClass)) + +typedef struct _WebKitVideoSink WebKitVideoSink; +typedef struct _WebKitVideoSinkClass WebKitVideoSinkClass; +typedef struct _WebKitVideoSinkPrivate WebKitVideoSinkPrivate; + +struct _WebKitVideoSink +{ + /*< private >*/ + GstBaseSink parent; + WebKitVideoSinkPrivate *priv; +}; + +struct _WebKitVideoSinkClass +{ + /*< private >*/ + GstBaseSinkClass parent_class; + + /* Future padding */ + void (* _webkit_reserved1) (void); + void (* _webkit_reserved2) (void); + void (* _webkit_reserved3) (void); + void (* _webkit_reserved4) (void); + void (* _webkit_reserved5) (void); + void (* _webkit_reserved6) (void); +}; + +GType webkit_video_sink_get_type (void) G_GNUC_CONST; +GstElement *webkit_video_sink_new (cairo_surface_t *surface); + +void webkit_video_sink_set_surface (WebKitVideoSink *sink, cairo_surface_t *surface); + +G_END_DECLS + +#endif |