summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--build/SConscript.main1
-rw-r--r--webkit/port/platform/graphics/chromium/FontCacheLinux.cpp22
-rw-r--r--webkit/port/platform/graphics/chromium/FontLinux.cpp56
-rw-r--r--webkit/port/platform/graphics/chromium/FontPlatformDataLinux.cpp136
-rw-r--r--webkit/port/platform/graphics/chromium/FontPlatformDataLinux.h52
-rw-r--r--webkit/port/platform/graphics/chromium/GlyphPageTreeNodeLinux.cpp35
-rw-r--r--webkit/port/platform/graphics/chromium/SimpleFontDataLinux.cpp67
-rw-r--r--webkit/tools/test_shell/SConscript2
-rw-r--r--webkit/tools/test_shell/event_sending_controller.cc6
-rw-r--r--webkit/tools/test_shell/gtk/test_shell.cc283
-rw-r--r--webkit/tools/test_shell/gtk/test_webview_delegate.cc5
-rw-r--r--webkit/tools/test_shell/gtk/webview_host.cc13
-rw-r--r--webkit/tools/test_shell/gtk/webwidget_host.cc52
-rw-r--r--webkit/tools/test_shell/test_shell_main_gtk.cc3
-rw-r--r--webkit/tools/test_shell/webwidget_host.h10
15 files changed, 653 insertions, 90 deletions
diff --git a/build/SConscript.main b/build/SConscript.main
index 0bab58b..3c3903d 100644
--- a/build/SConscript.main
+++ b/build/SConscript.main
@@ -490,6 +490,7 @@ if ARGUMENTS.get('COVERAGE') == '1':
if root_env['PLATFORM'] in ['linux', 'linux2', 'posix']:
linux_env.ParseConfig('pkg-config --cflags --libs nss')
linux_env.ParseConfig('pkg-config --cflags --libs gtk+-2.0')
+ linux_env.ParseConfig('pkg-config --cflags --libs pangoft2')
# --------------------------------------------------------------------------
diff --git a/webkit/port/platform/graphics/chromium/FontCacheLinux.cpp b/webkit/port/platform/graphics/chromium/FontCacheLinux.cpp
index 6630f670..2163c45 100644
--- a/webkit/port/platform/graphics/chromium/FontCacheLinux.cpp
+++ b/webkit/port/platform/graphics/chromium/FontCacheLinux.cpp
@@ -4,16 +4,20 @@
#include "config.h"
#include "FontCache.h"
-#include "AtomicString.h"
+#include "AtomicString.h"
+#include "FontDescription.h"
+#include "FontPlatformData.h"
+#include "Logging.h"
#include "NotImplemented.h"
namespace WebCore {
-// TODO(agl): stubs only
-
-
-void FontCache::platformInit() { }
+void FontCache::platformInit()
+{
+ if (!FontPlatformData::init())
+ ASSERT_NOT_REACHED();
+}
const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font,
const UChar* characters,
@@ -35,13 +39,14 @@ const AtomicString& FontCache::alternateFamilyName(const AtomicString& familyNam
FontPlatformData* FontCache::getSimilarFontPlatformData(const Font& font)
{
+ notImplemented();
return 0;
}
FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription& description)
{
- notImplemented();
- return 0;
+ static AtomicString arialStr("Arial");
+ return getCachedFontPlatformData(description, arialStr);
}
void FontCache::getTraitsInFamily(const AtomicString& familyName,
@@ -53,8 +58,7 @@ void FontCache::getTraitsInFamily(const AtomicString& familyName,
FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription,
const AtomicString& family)
{
- notImplemented();
- return 0;
+ return new FontPlatformData(fontDescription, family);
}
AtomicString FontCache::getGenericFontForScript(UScriptCode script,
diff --git a/webkit/port/platform/graphics/chromium/FontLinux.cpp b/webkit/port/platform/graphics/chromium/FontLinux.cpp
index 9ee965f..2c186d1 100644
--- a/webkit/port/platform/graphics/chromium/FontLinux.cpp
+++ b/webkit/port/platform/graphics/chromium/FontLinux.cpp
@@ -5,18 +5,64 @@
#include "config.h"
#include "Font.h"
+#include <pango/pango.h>
+#include <pango/pangoft2.h>
+
#include "FloatRect.h"
#include "NotImplemented.h"
+#include "PlatformContextSkia.h"
+#include "GraphicsContext.h"
+#include "SimpleFontData.h"
+#include "GlyphBuffer.h"
namespace WebCore {
-// TODO(agl): stubs only
+// -----------------------------------------------------------------------------
+// Bitblit a Freetype bitmap onto a canvas at the given location in the given
+// colour.
+// pgc: the Skia canvas
+// bm: A freetype bitmap which is an 8-bit alpha bitmap
+// -----------------------------------------------------------------------------
+static void bitBlitAlpha(PlatformGraphicsContext* pgc, FT_Bitmap* bm,
+ int x, int y, const Color& col)
+{
+ SkPaint paint;
+ paint.setARGB(col.alpha(), col.red(), col.green(), col.blue());
+
+ // Here we are constructing an SkBitmap by pointing directly into the
+ // Freetype bitmap data
+ SkBitmap glyph;
+ glyph.setConfig(SkBitmap::kA8_Config, bm->width, bm->rows, bm->pitch);
+ glyph.setPixels(bm->buffer);
+ pgc->canvas()->drawBitmap(glyph, x, y, &paint);
+}
-void Font::drawGlyphs(GraphicsContext*, const SimpleFontData*,
- const GlyphBuffer&, int from, int to,
- const FloatPoint&) const
+void Font::drawGlyphs(GraphicsContext* ctx, const SimpleFontData* sfd,
+ const GlyphBuffer& glyphBuffer, int from, int to,
+ const FloatPoint& point) const
{
- notImplemented();
+ // For now we draw text by getting the Freetype face from Pango and asking
+ // Freetype to render each glyph as an 8-bit alpha bitmap and drawing that
+ // to the canvas. This, obviously, ignores kerning, ligatures and other
+ // things that we should have in the real version.
+ GlyphBufferGlyph* glyphs = (GlyphBufferGlyph*)glyphBuffer.glyphs(from);
+ PlatformGraphicsContext* pgc = ctx->platformContext();
+ FT_Face face = pango_ft2_font_get_face(sfd->m_font.m_font);
+ FT_GlyphSlot slot = face->glyph;
+
+ int x = point.x(), y = point.y();
+
+ for (int i = from; i < to; ++i) {
+ const FT_Error error = FT_Load_Glyph(face, glyphs[i], FT_LOAD_RENDER);
+ if (error)
+ continue;
+
+ bitBlitAlpha(pgc, &slot->bitmap, x + slot->bitmap_left,
+ y - slot->bitmap_top, ctx->fillColor());
+ // Freetype works in 1/64ths of a pixel, so we divide by 64 to get the
+ // number of pixels to advance.
+ x += slot->advance.x >> 6;
+ }
}
void Font::drawComplexText(GraphicsContext* context, const TextRun& run,
diff --git a/webkit/port/platform/graphics/chromium/FontPlatformDataLinux.cpp b/webkit/port/platform/graphics/chromium/FontPlatformDataLinux.cpp
index 855d6d8..e14a023 100644
--- a/webkit/port/platform/graphics/chromium/FontPlatformDataLinux.cpp
+++ b/webkit/port/platform/graphics/chromium/FontPlatformDataLinux.cpp
@@ -5,51 +5,133 @@
#include "config.h"
#include "FontPlatformData.h"
+#include <gtk/gtk.h>
+#include <pango/pango.h>
+#include <pango/pangoft2.h>
+
+#include "CString.h"
+#include "FontDescription.h"
#include "NotImplemented.h"
+#include "PlatformString.h"
namespace WebCore {
-// TODO(agl): stubs only
+PangoFontMap* FontPlatformData::m_fontMap = 0;
+GHashTable* FontPlatformData::m_hashTable = 0;
-FontPlatformData::FontPlatformData() {
- notImplemented();
-}
+FontPlatformData::FontPlatformData(const FontDescription& fontDescription, const AtomicString& familyName)
+ : m_context(0)
+ , m_font(0)
+ , m_size(fontDescription.computedSize())
+ , m_syntheticBold(false)
+ , m_syntheticOblique(false)
+{
+ FontPlatformData::init();
-FontPlatformData::FontPlatformData(WTF::HashTableDeletedValueType) {
- notImplemented();
-}
+ CString stored_family = familyName.string().utf8();
+ char const* families[] = {
+ stored_family.data(),
+ NULL
+ };
-FontPlatformData::FontPlatformData(const FontDescription& fontDescription,
- const AtomicString& familyName) {
- notImplemented();
-}
+ 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);
+
+ m_context = pango_ft2_font_map_create_context(PANGO_FT2_FONT_MAP(m_fontMap));
+
+ 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);
+ }
-FontPlatformData::FontPlatformData(float size, bool bold, bool oblique) {
- notImplemented();
+ pango_font_description_free(description);
}
-FontPlatformData::~FontPlatformData() {
- notImplemented();
+FontPlatformData::FontPlatformData(float size, bool bold, bool oblique)
+ : m_context(0)
+ , m_font(0)
+ , m_size(size)
+ , m_syntheticBold(bold)
+ , m_syntheticOblique(oblique)
+{
}
-bool FontPlatformData::isHashTableDeletedValue() const {
- notImplemented();
- return false;
+bool FontPlatformData::init()
+{
+ static bool initialized = false;
+ if (initialized)
+ return true;
+ initialized = true;
+
+ if (!m_fontMap)
+ m_fontMap = pango_ft2_font_map_new();
+ 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;
}
-unsigned FontPlatformData::hash() const {
- notImplemented();
- return 0;
+bool FontPlatformData::isFixedPitch() const
+{
+ 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);
}
-bool FontPlatformData::operator==(const FontPlatformData &other) const {
- notImplemented();
- return false;
+FontPlatformData::~FontPlatformData() {
}
-float FontPlatformData::size() const {
- notImplemented();
- return 0;
+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;
}
} // namespace WebCore
diff --git a/webkit/port/platform/graphics/chromium/FontPlatformDataLinux.h b/webkit/port/platform/graphics/chromium/FontPlatformDataLinux.h
index 383fbf3..b8ae94f 100644
--- a/webkit/port/platform/graphics/chromium/FontPlatformDataLinux.h
+++ b/webkit/port/platform/graphics/chromium/FontPlatformDataLinux.h
@@ -8,7 +8,10 @@
#include "config.h"
#include "build/build_config.h"
+#include <pango/pango.h>
+
#include "StringImpl.h"
+#include "NotImplemented.h"
#include <wtf/PassRefPtr.h>
#include <wtf/RefCounted.h>
@@ -16,20 +19,55 @@ namespace WebCore {
class FontDescription;
-// TODO(agl): stubs only
-
class FontPlatformData {
public:
- FontPlatformData();
- FontPlatformData(WTF::HashTableDeletedValueType);
+ // Used for deleted values in the font cache's hash tables. The hash table
+ // will create us with this structure, and it will compare other values
+ // to this "Deleted" one. It expects the Deleted one to be differentiable
+ // from the NULL one (created with the empty constructor), so we can't just
+ // set everything to NULL.
+ FontPlatformData(WTF::HashTableDeletedValueType)
+ : m_context(0)
+ , m_font(hashTableDeletedFontValue())
+ { }
+
+ FontPlatformData()
+ : m_context(0)
+ , m_font(0)
+ { }
+
FontPlatformData(const FontDescription&, const AtomicString& family);
+
FontPlatformData(float size, bool bold, bool oblique);
+
~FontPlatformData();
- bool isHashTableDeletedValue() const;
- unsigned hash() const;
+ static bool init();
+
+ bool isFixedPitch() const;
+ float size() const { return m_size; }
+
+ unsigned hash() const
+ {
+ notImplemented();
+ return 0;
+ }
+
bool operator==(const FontPlatformData& other) const;
- float size() const;
+ bool isHashTableDeletedValue() const { return m_font == hashTableDeletedFontValue(); }
+
+ static PangoFontMap* m_fontMap;
+ static GHashTable* m_hashTable;
+
+ PangoContext* m_context;
+ PangoFont* m_font;
+
+ float m_size;
+ bool m_syntheticBold;
+ bool m_syntheticOblique;
+
+private:
+ static PangoFont* hashTableDeletedFontValue() { return reinterpret_cast<PangoFont*>(-1); }
};
} // namespace WebCore
diff --git a/webkit/port/platform/graphics/chromium/GlyphPageTreeNodeLinux.cpp b/webkit/port/platform/graphics/chromium/GlyphPageTreeNodeLinux.cpp
index 8dece07..1e7eb79 100644
--- a/webkit/port/platform/graphics/chromium/GlyphPageTreeNodeLinux.cpp
+++ b/webkit/port/platform/graphics/chromium/GlyphPageTreeNodeLinux.cpp
@@ -28,19 +28,46 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "config.h"
+#include "GlyphPageTreeNode.h"
+
+// This PANGO_ENABLE_BACKEND define lets us get at some of the internal Pango
+// call which we need. This include must be here otherwise we include pango.h
+// via another route (without the define) and that sets the include guard.
+// Then, when we try to include it in the future the guard stops us getting the
+// functions that we need.
+#define PANGO_ENABLE_BACKEND
+#include <pango/pango.h>
+#include <pango/pangofc-font.h>
#include "Font.h"
-#include "GlyphPageTreeNode.h"
#include "NotImplemented.h"
#include "SimpleFontData.h"
namespace WebCore
{
-bool GlyphPage::fill(unsigned offset, unsigned length, UChar* characterBuffer, unsigned bufferLength, const SimpleFontData* fontData)
+bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData)
{
- notImplemented();
- return false;
+ // 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_fc_font_get_glyph(PANGO_FC_FONT(fontData->m_font.m_font), buffer[i]);
+ if (!glyph)
+ setGlyphDataForIndex(offset + i, 0, 0);
+ else {
+ setGlyphDataForIndex(offset + i, glyph, fontData);
+ haveGlyphs = true;
+ }
+ }
+
+ return haveGlyphs;
}
} // namespace WebCore
diff --git a/webkit/port/platform/graphics/chromium/SimpleFontDataLinux.cpp b/webkit/port/platform/graphics/chromium/SimpleFontDataLinux.cpp
index 4525bd3..26caef8 100644
--- a/webkit/port/platform/graphics/chromium/SimpleFontDataLinux.cpp
+++ b/webkit/port/platform/graphics/chromium/SimpleFontDataLinux.cpp
@@ -2,19 +2,53 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#define PANGO_ENABLE_BACKEND
+
#include "config.h"
+#include "SimpleFontData.h"
+
+#include <pango/pango.h>
+#include <pango/pangoft2.h>
+#include <pango/pangofc-font.h>
+
#include "Font.h"
#include "FontCache.h"
-#include "SimpleFontData.h"
#include "FloatRect.h"
#include "FontDescription.h"
+#include "Logging.h"
#include "NotImplemented.h"
namespace WebCore {
// TODO(agl): only stubs
-void SimpleFontData::platformInit() { }
+void SimpleFontData::platformInit()
+{
+ PangoFont *const font = platformData().m_font;
+
+ PangoFontMetrics *const metrics = pango_font_get_metrics(font, NULL);
+ m_ascent = pango_font_metrics_get_ascent(metrics) / PANGO_SCALE;
+ m_descent = pango_font_metrics_get_descent(metrics) / PANGO_SCALE;
+ m_lineSpacing = m_ascent + m_descent;
+ m_avgCharWidth = pango_font_metrics_get_approximate_char_width(metrics) / PANGO_SCALE;
+ pango_font_metrics_unref(metrics);
+
+ const guint xglyph = pango_fc_font_get_glyph(PANGO_FC_FONT(font), 'x');
+ const guint spaceglyph = pango_fc_font_get_glyph(PANGO_FC_FONT(font), ' ');
+ PangoRectangle rect;
+
+ pango_font_get_glyph_extents(font, xglyph, &rect, NULL);
+ m_xHeight = rect.height / PANGO_SCALE;
+ pango_font_get_glyph_extents(font, spaceglyph, NULL, &rect);
+ m_spaceWidth = rect.width / PANGO_SCALE;
+ m_lineGap = m_lineSpacing - m_ascent - m_descent;
+
+ FT_Face face = pango_ft2_font_get_face(font);
+ m_unitsPerEm = face->units_per_EM / PANGO_SCALE;
+
+ // TODO(agl): I'm not sure we have good data for this so it's 0 for now
+ m_maxCharWidth = 0;
+}
void SimpleFontData::platformDestroy() { }
@@ -27,19 +61,38 @@ SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDes
bool SimpleFontData::containsCharacters(const UChar* characters,
int length) const
{
- notImplemented();
- return false;
+ 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()
{
- notImplemented();
+ m_treatAsFixedPitch = platformData().isFixedPitch();
}
float SimpleFontData::platformWidthForGlyph(Glyph glyph) const
{
- notImplemented();
- return 0;
+ PangoFont *const font = platformData().m_font;
+ PangoRectangle rect;
+
+ pango_font_get_glyph_extents(font, glyph, NULL, &rect);
+
+ return static_cast<float>(rect.width) / PANGO_SCALE;
}
} // namespace WebCore
diff --git a/webkit/tools/test_shell/SConscript b/webkit/tools/test_shell/SConscript
index 92e9d0d..30c4f96 100644
--- a/webkit/tools/test_shell/SConscript
+++ b/webkit/tools/test_shell/SConscript
@@ -93,6 +93,7 @@ elif env['PLATFORM'] in ('posix', 'darwin'):
)
input_files = [
+ 'event_sending_controller.cc',
'layout_test_controller.cc',
'simple_resource_loader_bridge.cc',
'test_navigation_controller.cc',
@@ -104,7 +105,6 @@ if env['PLATFORM'] == 'win32':
input_files.extend([
'drag_delegate.cc',
'drop_delegate.cc',
- 'event_sending_controller.cc',
'test_shell.cc',
'test_shell_win.cc',
'test_webview_delegate.cc',
diff --git a/webkit/tools/test_shell/event_sending_controller.cc b/webkit/tools/test_shell/event_sending_controller.cc
index 12e69d3..ac10803 100644
--- a/webkit/tools/test_shell/event_sending_controller.cc
+++ b/webkit/tools/test_shell/event_sending_controller.cc
@@ -21,6 +21,7 @@
#endif
#include <queue>
+#include "base/logging.h"
#include "base/ref_counted.h"
#include "base/string_util.h"
#include "base/time.h"
@@ -400,6 +401,11 @@ int EventSendingController::GetButtonNumberFromSingleArg(
} else if (L"delete" == code_str) {
code = 0x33;
}
+#elif defined(OS_LINUX)
+ // TODO(agl): We obviously need to do something about keycodes here
+ if (true) {
+ NOTIMPLEMENTED();
+ }
#endif
else {
DCHECK(code_str.length() == 1);
diff --git a/webkit/tools/test_shell/gtk/test_shell.cc b/webkit/tools/test_shell/gtk/test_shell.cc
index c048f04..8a72e86 100644
--- a/webkit/tools/test_shell/gtk/test_shell.cc
+++ b/webkit/tools/test_shell/gtk/test_shell.cc
@@ -4,17 +4,24 @@
#include "webkit/tools/test_shell/test_shell.h"
+#include <errno.h>
+#include <fcntl.h>
#include <gtk/gtk.h>
+#include <unistd.h>
+#include "base/file_path.h"
#include "base/file_util.h"
+#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/string_util.h"
#include "net/base/mime_util.h"
+#include "webkit/glue/plugins/plugin_list.h"
+#include "webkit/glue/resource_loader_bridge.h"
+#include "webkit/glue/webdatasource.h"
#include "webkit/glue/webframe.h"
+#include "webkit/glue/webkit_glue.h"
#include "webkit/glue/webpreferences.h"
#include "webkit/glue/webview.h"
-#include "webkit/glue/plugins/plugin_list.h"
-#include "webkit/glue/resource_loader_bridge.h"
#include "webkit/tools/test_shell/test_navigation_controller.h"
#include "webkit/tools/test_shell/test_webview_delegate.h"
@@ -25,6 +32,7 @@ WindowList* TestShell::window_list_;
TestShell::TestShell()
: delegate_(new TestWebViewDelegate(this)) {
layout_test_controller_.reset(new LayoutTestController(this));
+ event_sending_controller_.reset(new EventSendingController(this));
navigation_controller_.reset(new TestNavigationController(this));
}
@@ -52,6 +60,44 @@ bool TestShell::CreateNewWindow(const std::wstring& startingURL,
return true;
}
+void TestShell::ResetWebPreferences() {
+ DCHECK(web_prefs_);
+
+ // Match the settings used by Mac DumpRenderTree.
+ if (web_prefs_) {
+ *web_prefs_ = WebPreferences();
+ web_prefs_->standard_font_family = L"Times";
+ web_prefs_->fixed_font_family = L"Courier";
+ web_prefs_->serif_font_family = L"Times";
+ web_prefs_->sans_serif_font_family = L"Helvetica";
+ // These two fonts are picked from the intersection of
+ // Win XP font list and Vista font list :
+ // http://www.microsoft.com/typography/fonts/winxp.htm
+ // http://blogs.msdn.com/michkap/archive/2006/04/04/567881.aspx
+ // Some of them are installed only with CJK and complex script
+ // support enabled on Windows XP and are out of consideration here.
+ // (although we enabled both on our buildbots.)
+ // They (especially Impact for fantasy) are not typical cursive
+ // and fantasy fonts, but it should not matter for layout tests
+ // as long as they're available.
+ web_prefs_->cursive_font_family = L"Comic Sans MS";
+ web_prefs_->fantasy_font_family = L"Impact";
+ web_prefs_->default_encoding = L"ISO-8859-1";
+ web_prefs_->default_font_size = 16;
+ web_prefs_->default_fixed_font_size = 13;
+ web_prefs_->minimum_font_size = 1;
+ web_prefs_->minimum_logical_font_size = 9;
+ web_prefs_->javascript_can_open_windows_automatically = true;
+ web_prefs_->dom_paste_enabled = true;
+ web_prefs_->developer_extras_enabled = interactive_;
+ web_prefs_->shrinks_standalone_images_to_fit = false;
+ web_prefs_->uses_universal_detector = false;
+ web_prefs_->text_areas_are_resizable = false;
+ web_prefs_->java_enabled = true;
+ web_prefs_->allow_scripts_to_close_windows = false;
+ }
+}
+
bool TestShell::Initialize(const std::wstring& startingURL) {
m_mainWnd = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(m_mainWnd), "Test Shell");
@@ -84,7 +130,7 @@ bool TestShell::Initialize(const std::wstring& startingURL) {
-1 /* append */);
gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE, 0);
- m_webViewHost.reset(WebViewHost::Create(vbox, NULL, *TestShell::web_prefs_));
+ m_webViewHost.reset(WebViewHost::Create(vbox, delegate_, *TestShell::web_prefs_));
if (!startingURL.empty())
LoadURL(startingURL.c_str());
@@ -99,6 +145,21 @@ void TestShell::TestFinished() {
NOTIMPLEMENTED();
}
+void TestShell::WaitTestFinished() {
+ DCHECK(!test_is_pending_) << "cannot be used recursively";
+
+ test_is_pending_ = true;
+
+ // TODO(agl): Here windows forks a watchdog thread, but I'm punting on that
+ // for the moment. On POSIX systems we probably want to install a signal
+ // handler and use alarm(2).
+
+ // TestFinished() will post a quit message to break this loop when the page
+ // finishes loading.
+ while (test_is_pending_)
+ MessageLoop::current()->Run();
+}
+
void TestShell::Show(WebView* webview, WindowOpenDisposition disposition) {
delegate_->Show(webview, disposition);
}
@@ -126,6 +187,139 @@ WebWidget* TestShell::CreatePopupWidget(WebView* webview) {
return NULL;
}
+void TestShell::ResizeSubViews() {
+ // The GTK functions to do this are deprecated because it's not really
+ // something that X windows supports. It's not clear exactly what should be
+ // done here.
+ NOTIMPLEMENTED();
+}
+
+/* static */ std::string TestShell::DumpImage(
+ WebFrame* web_frame,
+ const std::wstring& file_name) {
+ // Windows uses some platform specific bitmap functions here.
+ // TODO(agl): port
+ NOTIMPLEMENTED();
+ return "00000000000000000000000000000000";
+}
+
+/* static */ void TestShell::DumpBackForwardList(std::wstring* result) {
+ result->clear();
+ for (WindowList::iterator iter = TestShell::windowList()->begin();
+ iter != TestShell::windowList()->end(); iter++) {
+ GtkWidget* window = *iter;
+ TestShell* shell =
+ static_cast<TestShell*>(g_object_get_data(G_OBJECT(window), "test-shell"));
+ webkit_glue::DumpBackForwardList(shell->webView(), NULL, result);
+ }
+}
+
+/* static */ bool TestShell::RunFileTest(const char *filename,
+ const TestParams& params) {
+ // Load the test file into the first available window.
+ if (TestShell::windowList()->empty()) {
+ LOG(ERROR) << "No windows open.";
+ return false;
+ }
+
+ GtkWidget* window = *(TestShell::windowList()->begin());
+ TestShell* shell =
+ static_cast<TestShell*>(g_object_get_data(G_OBJECT(window), "test-shell"));
+ shell->ResetTestController();
+
+ // ResetTestController may have closed the window we were holding on to.
+ // Grab the first window again.
+ window = *(TestShell::windowList()->begin());
+ shell = static_cast<TestShell*>(g_object_get_data(G_OBJECT(window), "test-shell"));
+ DCHECK(shell);
+
+ // Clear focus between tests.
+ shell->m_focusedWidgetHost = NULL;
+
+ // Make sure the previous load is stopped.
+ shell->webView()->StopLoading();
+ shell->navigation_controller()->Reset();
+
+ // Clean up state between test runs.
+ webkit_glue::ResetBeforeTestRun(shell->webView());
+ ResetWebPreferences();
+ shell->webView()->SetPreferences(*web_prefs_);
+
+ // TODO(agl): Maybe make the window hidden in the future. Window does this
+ // by positioning it off the screen but the GTK function to do this is
+ // deprecated and appears to have been removed.
+
+ shell->ResizeSubViews();
+
+ if (strstr(filename, "loading/") || strstr(filename, "loading\\"))
+ shell->layout_test_controller()->SetShouldDumpFrameLoadCallbacks(true);
+
+ shell->test_is_preparing_ = true;
+
+ const std::wstring wstr = UTF8ToWide(filename);
+ shell->LoadURL(wstr.c_str());
+
+ shell->test_is_preparing_ = false;
+ shell->WaitTestFinished();
+
+ // Echo the url in the output so we know we're not getting out of sync.
+ printf("#URL:%s\n", filename);
+
+ // Dump the requested representation.
+ WebFrame* webFrame = shell->webView()->GetMainFrame();
+ if (webFrame) {
+ bool should_dump_as_text =
+ shell->layout_test_controller_->ShouldDumpAsText();
+ bool dumped_anything = false;
+ if (params.dump_tree) {
+ dumped_anything = true;
+ // Text output: the test page can request different types of output
+ // which we handle here.
+ if (!should_dump_as_text) {
+ // Plain text pages should be dumped as text
+ std::wstring mime_type = webFrame->GetDataSource()->GetResponseMimeType();
+ should_dump_as_text = (mime_type == L"text/plain");
+ }
+ if (should_dump_as_text) {
+ bool recursive = shell->layout_test_controller_->
+ ShouldDumpChildFramesAsText();
+ std::string data_utf8 = WideToUTF8(
+ webkit_glue::DumpFramesAsText(webFrame, recursive));
+ fwrite(data_utf8.c_str(), 1, data_utf8.size(), stdout);
+ } else {
+ printf("%s", WideToUTF8(
+ webkit_glue::DumpRenderer(webFrame)).c_str());
+
+ bool recursive = shell->layout_test_controller_->
+ ShouldDumpChildFrameScrollPositions();
+ printf("%s", WideToUTF8(
+ webkit_glue::DumpFrameScrollPosition(webFrame, recursive)).
+ c_str());
+ }
+
+ if (shell->layout_test_controller_->ShouldDumpBackForwardList()) {
+ std::wstring bfDump;
+ DumpBackForwardList(&bfDump);
+ printf("%s", WideToUTF8(bfDump).c_str());
+ }
+ }
+
+ if (params.dump_pixels && !should_dump_as_text) {
+ // Image output: we write the image data to the file given on the
+ // command line (for the dump pixels argument), and the MD5 sum to
+ // stdout.
+ dumped_anything = true;
+ std::string md5sum = DumpImage(webFrame, params.pixel_file_name);
+ printf("#MD5:%s\n", md5sum.c_str());
+ }
+ if (dumped_anything)
+ printf("#EOF\n");
+ fflush(stdout);
+ }
+
+ return true;
+}
+
void TestShell::LoadURL(const wchar_t* url)
{
LoadURLForFrame(url, NULL);
@@ -140,6 +334,9 @@ void TestShell::LoadURLForFrame(const wchar_t* url,
if (frame_name)
frame_string = frame_name;
+ LOG(INFO) << "Loading " << WideToUTF8(url) << " in frame '"
+ << WideToUTF8(frame_string) << "'";
+
navigation_controller_->LoadEntry(new TestNavigationEntry(
-1, GURL(WideToUTF8(url)), std::wstring(), frame_string));
}
@@ -187,13 +384,89 @@ void TestShell::GoBackOrForward(int offset) {
navigation_controller_->GoToOffset(offset);
}
+static void WriteTextToFile(const std::wstring& data,
+ const FilePath& filepath)
+{
+ // This function does the same thing as the Windows version except that it
+ // takes a FilePath. We should be using WriteFile in base/file_util.h, but
+ // the patch to add the FilePath version of that file hasn't landed yet, so
+ // this is another TODO(agl) for the merging.
+ const int fd = open(filepath.value().c_str(), O_TRUNC | O_WRONLY | O_CREAT, 0600);
+ if (fd < 0)
+ return;
+ const std::string data_utf8 = WideToUTF8(data);
+ ssize_t n;
+ do {
+ n = write(fd, data_utf8.data(), data.size());
+ } while (n == -1 && errno == EINTR);
+ close(fd);
+}
+
+
+std::wstring TestShell::GetDocumentText()
+{
+ return webkit_glue::DumpDocumentText(webView()->GetMainFrame());
+}
+
+// TODO(agl):
+// This version of PromptForSaveFile uses FilePath, which is what the real
+// version should be using. However, I don't want to step on tony's toes (as he
+// is also editing this file), so this is a hack until we merge the files again.
+// (There is also a PromptForSaveFile member in TestShell which returns a wstring)
+static bool PromptForSaveFile(const char* prompt_title,
+ FilePath* result)
+{
+ char filenamebuffer[512];
+ printf("Enter filename for \"%s\"\n", prompt_title);
+ fgets(filenamebuffer, sizeof(filenamebuffer), stdin);
+ *result = FilePath(filenamebuffer);
+ return true;
+}
+
+void TestShell::DumpDocumentText()
+{
+ FilePath file_path;
+ if (!::PromptForSaveFile("Dump document text", &file_path))
+ return;
+
+ WriteTextToFile(webkit_glue::DumpDocumentText(webView()->GetMainFrame()),
+ file_path);
+}
+
+void TestShell::DumpRenderTree()
+{
+ FilePath file_path;
+ if (!::PromptForSaveFile("Dump render tree", &file_path))
+ return;
+
+ WriteTextToFile(webkit_glue::DumpRenderer(webView()->GetMainFrame()),
+ file_path);
+}
+
void TestShell::Reload() {
navigation_controller_->Reload();
}
std::string TestShell::RewriteLocalUrl(const std::string& url) {
- NOTIMPLEMENTED();
- return "";
+ // Convert file:///tmp/LayoutTests urls to the actual location on disk.
+ const char kPrefix[] = "file:///tmp/LayoutTests/";
+ const int kPrefixLen = arraysize(kPrefix) - 1;
+
+ std::string new_url(url);
+ if (url.compare(0, kPrefixLen, kPrefix, kPrefixLen) == 0) {
+ std::wstring replace_url;
+ PathService::Get(base::DIR_EXE, &replace_url);
+ file_util::UpOneDirectory(&replace_url);
+ file_util::UpOneDirectory(&replace_url);
+ file_util::AppendToPath(&replace_url, L"webkit");
+ file_util::AppendToPath(&replace_url, L"data");
+ file_util::AppendToPath(&replace_url, L"layout_tests");
+ file_util::AppendToPath(&replace_url, L"LayoutTests");
+ replace_url.push_back(file_util::kPathSeparator);
+ new_url = std::string("file:///") +
+ WideToUTF8(replace_url).append(url.substr(kPrefixLen));
+ }
+ return new_url;
}
//-----------------------------------------------------------------------------
diff --git a/webkit/tools/test_shell/gtk/test_webview_delegate.cc b/webkit/tools/test_shell/gtk/test_webview_delegate.cc
index 739b459..92079a8 100644
--- a/webkit/tools/test_shell/gtk/test_webview_delegate.cc
+++ b/webkit/tools/test_shell/gtk/test_webview_delegate.cc
@@ -576,7 +576,9 @@ gfx::ViewHandle TestWebViewDelegate::GetContainingWindow(WebWidget* webwidget) {
void TestWebViewDelegate::DidInvalidateRect(WebWidget* webwidget,
const gfx::Rect& rect) {
- NOTIMPLEMENTED();
+ WebWidgetHost* host = GetHostForWidget(webwidget);
+ if (host)
+ host->DidInvalidateRect(rect);
}
void TestWebViewDelegate::DidScrollRect(WebWidget* webwidget, int dx, int dy,
@@ -668,6 +670,7 @@ void TestWebViewDelegate::UpdateAddressBar(WebView* webView) {
return;
std::string frameURL = dataSource->GetRequest().GetMainDocumentURL().spec();
+ LOG(INFO) << " -- Address bar " << frameURL;
NOTIMPLEMENTED();
}
diff --git a/webkit/tools/test_shell/gtk/webview_host.cc b/webkit/tools/test_shell/gtk/webview_host.cc
index 4eecae1..e21099d 100644
--- a/webkit/tools/test_shell/gtk/webview_host.cc
+++ b/webkit/tools/test_shell/gtk/webview_host.cc
@@ -9,6 +9,7 @@
#include "base/gfx/platform_canvas.h"
#include "base/gfx/rect.h"
#include "base/gfx/size.h"
+#include "base/logging.h"
#include "webkit/glue/webinputevent.h"
#include "webkit/glue/webview.h"
@@ -16,13 +17,13 @@
WebViewHost* WebViewHost::Create(GtkWidget* box,
WebViewDelegate* delegate,
const WebPreferences& prefs) {
- // TODO(agl):
- // /usr/local/google/agl/src/chrome/src/webkit/tools/test_shell/gtk/webview_host.cc:19: error: no matching function for call to 'WebWidgetHost::Create(GtkWidget*&, WebViewDelegate*&)'
- WebViewHost* host = reinterpret_cast<WebViewHost *>(WebWidgetHost::Create(box, NULL));
+ WebViewHost* host = new WebViewHost();
+
+ LOG(INFO) << "In WebViewHost::Create";
+
+ host->view_ = WebWidgetHost::CreateWindow(box, host);
+ g_object_set_data(G_OBJECT(host->view_), "webwidgethost", host);
- // TODO(erg):
- // - Set "host->view_"
- // - Call "host->webwidget_->Resize"
host->webwidget_ = WebView::Create(delegate, prefs);
host->webwidget_->Resize(gfx::Size(640, 480));
host->webwidget_->Layout();
diff --git a/webkit/tools/test_shell/gtk/webwidget_host.cc b/webkit/tools/test_shell/gtk/webwidget_host.cc
index 847a0a7..edc0a92 100644
--- a/webkit/tools/test_shell/gtk/webwidget_host.cc
+++ b/webkit/tools/test_shell/gtk/webwidget_host.cc
@@ -66,30 +66,47 @@ gboolean FocusOut(GtkWidget* widget, GdkEventFocus* focus, gpointer userdata) {
// -----------------------------------------------------------------------------
+gfx::WindowHandle WebWidgetHost::CreateWindow(gfx::WindowHandle box,
+ void* host) {
+ GtkWidget* widget = gtk_drawing_area_new();
+ gtk_box_pack_start(GTK_BOX(box), widget, TRUE, TRUE, 0);
+
+ gtk_widget_add_events(widget, GDK_EXPOSURE_MASK |
+ GDK_POINTER_MOTION_MASK |
+ GDK_BUTTON_PRESS_MASK |
+ GDK_BUTTON_RELEASE_MASK |
+ GDK_KEY_PRESS_MASK |
+ GDK_KEY_RELEASE_MASK);
+ // TODO(agl): set GTK_CAN_FOCUS flag
+ g_signal_connect(widget, "configure-event", G_CALLBACK(ConfigureEvent), host);
+ g_signal_connect(widget, "expose-event", G_CALLBACK(ExposeEvent), host);
+ g_signal_connect(widget, "destroy-event", G_CALLBACK(DestroyEvent), host);
+ g_signal_connect(widget, "key-press-event", G_CALLBACK(KeyPressEvent), host);
+ g_signal_connect(widget, "focus-in-event", G_CALLBACK(FocusIn), host);
+ g_signal_connect(widget, "focus-out-event", G_CALLBACK(FocusOut), host);
+
+ return widget;
+}
+
WebWidgetHost* WebWidgetHost::Create(gfx::WindowHandle box,
WebWidgetDelegate* delegate) {
+ LOG(INFO) << "In WebWidgetHost::Create";
+
WebWidgetHost* host = new WebWidgetHost();
- host->view_ = gtk_drawing_area_new();
- gtk_widget_add_events(host->view_, GDK_EXPOSURE_MASK |
- GDK_POINTER_MOTION_MASK |
- GDK_BUTTON_PRESS_MASK |
- GDK_BUTTON_RELEASE_MASK |
- GDK_KEY_PRESS_MASK |
- GDK_KEY_RELEASE_MASK);
- // TODO(agl): set GTK_CAN_FOCUS flag
+ host->view_ = CreateWindow(box, host);
host->webwidget_ = WebWidget::Create(delegate);
- g_object_set_data(G_OBJECT(host->view_), "webwidgethost", host);
- g_signal_connect(host->view_, "configure-event", G_CALLBACK(ConfigureEvent), host);
- g_signal_connect(host->view_, "expose-event", G_CALLBACK(ExposeEvent), host);
- g_signal_connect(host->view_, "destroy-event", G_CALLBACK(DestroyEvent), host);
- g_signal_connect(host->view_, "key-press-event", G_CALLBACK(KeyPressEvent), host);
- g_signal_connect(host->view_, "focus-in-event", G_CALLBACK(FocusIn), host);
- g_signal_connect(host->view_, "focus-out-event", G_CALLBACK(FocusOut), host);
+ return host;
+}
- gtk_box_pack_start(GTK_BOX(box), host->view_, TRUE, TRUE, 0);
+void WebWidgetHost::DidInvalidateRect(const gfx::Rect& rect) {
+ LOG(INFO) << " -- Invalidate " << rect.x() << " "
+ << rect.y() << " "
+ << rect.width() << " "
+ << rect.height() << " ";
- return host;
+ gtk_widget_queue_draw_area(GTK_WIDGET(view_), rect.x(), rect.y(), rect.width(),
+ rect.height());
}
void WebWidgetHost::DidScrollRect(int dx, int dy, const gfx::Rect& clip_rect) {
@@ -167,7 +184,6 @@ void WebWidgetHost::Paint() {
LOG(INFO) << "Using pixel data at " << (void *) gdk_pixbuf_get_pixels(bitdev->pixbuf());
gdk_draw_pixbuf(view_->window, NULL, bitdev->pixbuf(),
0, 0, 0, 0, width, height, GDK_RGB_DITHER_NONE, 0, 0);
- gdk_pixbuf_save(bitdev->pixbuf(), "output.png", "png", NULL, NULL);
}
void WebWidgetHost::PaintRect(const gfx::Rect& rect) {
diff --git a/webkit/tools/test_shell/test_shell_main_gtk.cc b/webkit/tools/test_shell/test_shell_main_gtk.cc
index 48cf47a..57b94ed 100644
--- a/webkit/tools/test_shell/test_shell_main_gtk.cc
+++ b/webkit/tools/test_shell/test_shell_main_gtk.cc
@@ -46,6 +46,9 @@ int main(int argc, char* argv[]) {
file_util::AppendToPath(&uri, L"data");
file_util::AppendToPath(&uri, L"test_shell");
file_util::AppendToPath(&uri, L"index.html");
+ // For now, loading from disk doesn't work so we set the URI to the
+ // homepage.
+ uri = L"http://www.google.com";
}
if (parsed_command_line.GetLooseValueCount() > 0) {
diff --git a/webkit/tools/test_shell/webwidget_host.h b/webkit/tools/test_shell/webwidget_host.h
index eb52bc0..583c9bf 100644
--- a/webkit/tools/test_shell/webwidget_host.h
+++ b/webkit/tools/test_shell/webwidget_host.h
@@ -71,6 +71,16 @@ class WebWidgetHost {
protected:
#elif defined(OS_LINUX)
public:
+ // ---------------------------------------------------------------------------
+ // This is needed on Linux because the GtkWidget creation is the same between
+ // both web view hosts and web widget hosts. The Windows code manages this by
+ // reusing the WndProc function (static, above). However, GTK doesn't use a
+ // single big callback function like that so we have a static function that
+ // sets up a GtkWidget correctly.
+ // parent: a GtkBox to pack the new widget at the end of
+ // host: a pointer to a WebWidgetHost (or subclass thereof)
+ // ---------------------------------------------------------------------------
+ static gfx::WindowHandle CreateWindow(gfx::WindowHandle parent, void* host);
void WindowDestroyed();
void Resize(const gfx::Size& size);
#endif