diff options
author | Upstream <upstream-import@none> | 1970-01-12 13:46:40 +0000 |
---|---|---|
committer | Upstream <upstream-import@none> | 1970-01-12 13:46:40 +0000 |
commit | d8543bb6618c17b12da906afa77d216f58cf4058 (patch) | |
tree | c58dc05ed86825bd0ef8d305d58c8205106b540f /WebCore/platform/graphics/gtk | |
download | external_webkit-d8543bb6618c17b12da906afa77d216f58cf4058.zip external_webkit-d8543bb6618c17b12da906afa77d216f58cf4058.tar.gz external_webkit-d8543bb6618c17b12da906afa77d216f58cf4058.tar.bz2 |
external/webkit r30707
Diffstat (limited to 'WebCore/platform/graphics/gtk')
17 files changed, 2365 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..aec5758 --- /dev/null +++ b/WebCore/platform/graphics/gtk/FontCacheGtk.cpp @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com + * 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 "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) +{ + return new SimpleFontData(FontPlatformData(font.fontDescription(), font.family().family())); +} + +FontPlatformData* FontCache::getSimilarFontPlatformData(const Font& font) +{ + return new FontPlatformData(font.fontDescription(), font.family().family()); +} + +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); +} + +bool FontCache::fontExists(const FontDescription& fontDescription, const AtomicString& family) +{ + FontPlatformData platformData(fontDescription, family); + return platformData.m_pattern != 0; +} + +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..3ff63c2 --- /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) +{ + 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..237904d --- /dev/null +++ b/WebCore/platform/graphics/gtk/FontCustomPlatformData.h @@ -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. + * + */ + +#ifndef FontCustomPlatformData_h +#define FontCustomPlatformData_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); + + cairo_font_face_t* m_fontFace; +}; + +FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer); + +} + +#endif diff --git a/WebCore/platform/graphics/gtk/FontGtk.cpp b/WebCore/platform/graphics/gtk/FontGtk.cpp new file mode 100644 index 0000000..387b61c --- /dev/null +++ b/WebCore/platform/graphics/gtk/FontGtk.cpp @@ -0,0 +1,245 @@ +/* + * 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> + * 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 <pango/pango.h> +#include <pango/pangocairo.h> + +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(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) +{ + PangoAttrList* list = pango_attr_list_new(); + PangoAttribute* attr; + + attr = pango_attr_size_new_absolute((int)(font->size() * 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); + + 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); +} + +void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const +{ + cairo_t* cr = context->platformContext(); + cairo_save(cr); + + PangoLayout* layout = pango_cairo_create_layout(cr); + + gchar* utf8 = convertUniCharToUTF8(run.characters(), run.length(), from, to); + pango_layout_set_text(layout, utf8, -1); + g_free(utf8); + + setPangoAttributes(this, run, layout); + + // Set the text color to use for drawing. + float red, green, blue, alpha; + Color penColor = context->fillColor(); + penColor.getRGBA(red, green, blue, alpha); + cairo_set_source_rgba(cr, red, green, blue, alpha); + + // Our layouts are single line + cairo_move_to(cr, point.x(), point.y()); + PangoLayoutLine* layoutLine = pango_layout_get_line_readonly(layout, 0); + pango_cairo_show_layout_line(cr, layoutLine); + + g_object_unref(layout); + cairo_restore(cr); +} + +// FIXME: we should create the layout with our actual context, but it seems +// we can't access it from here +static PangoLayout* getDefaultPangoLayout(const TextRun& run) +{ + PangoFontMap* map = pango_cairo_font_map_get_default(); + PangoContext* pangoContext = pango_cairo_font_map_create_context(PANGO_CAIRO_FONT_MAP(map)); + PangoLayout* layout = pango_layout_new(pangoContext); + g_object_unref(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); + g_free(utf8); + + int layoutWidth; + pango_layout_get_size(layout, &layoutWidth, 0); + float width = (float)layoutWidth / (double)PANGO_SCALE; + 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); + 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 +{ + notImplemented(); + return FloatRect(); +} + +} diff --git a/WebCore/platform/graphics/gtk/FontPlatformData.h b/WebCore/platform/graphics/gtk/FontPlatformData.h new file mode 100644 index 0000000..778d525 --- /dev/null +++ b/WebCore/platform/graphics/gtk/FontPlatformData.h @@ -0,0 +1,80 @@ +/* + * 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 + * 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> +#include <cairo-ft.h> +#include <fontconfig/fcfreetype.h> + +namespace WebCore { + +class FontPlatformData { +public: + class Deleted {}; + FontPlatformData(Deleted) + : m_pattern(reinterpret_cast<FcPattern*>(-1)) + , m_scaledFont(0) + { } + + FontPlatformData() + : m_pattern(0) + , 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_fontDescription.specifiedSize(); } + + void setFont(cairo_t*) const; + + unsigned hash() const + { + 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; + + FcPattern* m_pattern; + FontDescription m_fontDescription; + cairo_scaled_font_t* m_scaledFont; +}; + +} + +#endif diff --git a/WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp b/WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp new file mode 100644 index 0000000..b28146f --- /dev/null +++ b/WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp @@ -0,0 +1,200 @@ +/* + * 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_fontDescription(fontDescription) + , m_scaledFont(0) +{ + FontPlatformData::init(); + + CString familyNameString = familyName.string().utf8(); + const char* fcfamily = familyNameString.data(); + int fcslant = FC_SLANT_ROMAN; + int fcweight = FC_WEIGHT_NORMAL; + float fcsize = fontDescription.computedSize(); + if (fontDescription.italic()) + fcslant = FC_SLANT_ITALIC; + if (fontDescription.bold()) + 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::NoFamily: + case FontDescription::StandardFamily: + default: + fcfamily = "sans-serif"; + } + + if (!FcPatternAddString(pattern, FC_FAMILY, reinterpret_cast<const FcChar8*>(fcfamily))) + goto freePattern; + if (!FcPatternAddInteger(pattern, FC_SLANT, fcslant)) + goto freePattern; + if (!FcPatternAddInteger(pattern, FC_WEIGHT, fcweight)) + 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, m_fontDescription.computedSize(), m_fontDescription.computedSize()); + 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_fontDescription() + , m_scaledFont(0) +{ + m_fontDescription.setSpecifiedSize(size); + m_fontDescription.setBold(bold); + m_fontDescription.setItalic(italic); +} + +FontPlatformData::FontPlatformData(cairo_font_face_t* fontFace, int size, bool bold, bool italic) + : m_pattern(0) + , m_fontDescription() + , m_scaledFont(0) +{ + m_fontDescription.setSpecifiedSize(size); + m_fontDescription.setBold(bold); + m_fontDescription.setItalic(italic); + + 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; + 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/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/IconGtk.cpp b/WebCore/platform/graphics/gtk/IconGtk.cpp new file mode 100644 index 0000000..a8e6536 --- /dev/null +++ b/WebCore/platform/graphics/gtk/IconGtk.cpp @@ -0,0 +1,116 @@ +/* + * 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() + : RefCounted<Icon>(0) + , m_icon(0) +{ + notImplemented(); +} + +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::newIconForFile(const String& filename) +{ + if (!g_path_skip_root(filename.utf8().data())) + return 0; + + String MIMEType = MIMETypeRegistry::getMIMETypeForPath(filename); + String iconName = lookupIconName(MIMEType); + + Icon* icon = 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); + return icon->m_icon ? icon : 0; +} + +void Icon::paint(GraphicsContext* context, const IntRect& rect) +{ + // 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..a74bc54 --- /dev/null +++ b/WebCore/platform/graphics/gtk/ImageGtk.cpp @@ -0,0 +1,53 @@ +/* + * 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" +#include "Image.h" +#include "NotImplemented.h" + +// This function loads resources from WebKit +Vector<char> loadResourceIntoArray(const char*); + +namespace WebCore { + +void BitmapImage::initPlatformData() +{ +} + +void BitmapImage::invalidatePlatformData() +{ +} + +Image* Image::loadPlatformResource(const char *name) +{ + Vector<char> arr = loadResourceIntoArray(name); + BitmapImage* img = new BitmapImage; + RefPtr<SharedBuffer> buffer = new SharedBuffer(arr.data(), arr.size()); + img->setData(buffer, true); + return img; +} +} 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..c60bc20 --- /dev/null +++ b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp @@ -0,0 +1,625 @@ +/* + * 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 <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 <libgnomevfs/gnome-vfs.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) + { + GError* err; + gchar* debug; + + gst_message_parse_error(message, &err, &debug); + 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); + g_error_free(err); + g_free(debug); + } + } + 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..a754c45 --- /dev/null +++ b/WebCore/platform/graphics/gtk/SimpleFontDataGtk.cpp @@ -0,0 +1,135 @@ +/* + * 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() +{ + if (!isCustomFont()) { + 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_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 +{ + 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/VideoSinkGStreamer.cpp b/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp new file mode 100644 index 0000000..7e97688 --- /dev/null +++ b/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp @@ -0,0 +1,314 @@ +/* + * 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("WebKit video sink", + "Sink/Video", + "Sends video data from a GStreamer pipeline to a Cairo surface", + "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 == 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) +{ + WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(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 |