summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--vcl/Library_vcl.mk2
-rwxr-xr-xvcl/glyphy/demo.cxx19
-rw-r--r--vcl/glyphy/demo/demo-atlas.cc144
-rw-r--r--vcl/glyphy/demo/demo-buffer.cc191
-rw-r--r--vcl/glyphy/demo/demo-font.cc333
-rw-r--r--vcl/glyphy/demo/demo-shader.cc212
-rw-r--r--vcl/glyphy/demo/matrix4x4.c481
-rw-r--r--vcl/inc/glyphy/demo.hxx21
-rw-r--r--vcl/inc/glyphy/demo/demo-atlas-glsl.h18
-rw-r--r--vcl/inc/glyphy/demo/demo-atlas.h54
-rw-r--r--vcl/inc/glyphy/demo/demo-buffer.h64
-rw-r--r--vcl/inc/glyphy/demo/demo-common.h186
-rw-r--r--vcl/inc/glyphy/demo/demo-font.h88
-rw-r--r--vcl/inc/glyphy/demo/demo-fshader-glsl.h88
-rw-r--r--vcl/inc/glyphy/demo/demo-shader.h47
-rw-r--r--vcl/inc/glyphy/demo/demo-vshader-glsl.h24
-rw-r--r--vcl/inc/glyphy/demo/matrix4x4.h107
-rw-r--r--vcl/win/source/gdi/winlayout.cxx499
18 files changed, 2270 insertions, 308 deletions
diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk
index 983e10fd228a..f3981dd774e1 100644
--- a/vcl/Library_vcl.mk
+++ b/vcl/Library_vcl.mk
@@ -41,6 +41,7 @@ $(eval $(call gb_Library_set_include,vcl,\
$$(INCLUDE) \
-I$(SRCDIR)/vcl/inc \
$(if $(filter WNTGCC,$(OS)$(COM)),-I$(MINGW_SYSROOT)/include/gdiplus) \
+ $(if $(filter WNT,$(OS)),-I$(SRCDIR)/vcl/inc/glyphy/demo) \
))
ifeq ($(ENABLE_DBUS),TRUE)
@@ -690,6 +691,7 @@ endif
ifeq ($(OS),WNT)
$(eval $(call gb_Library_add_exception_objects,vcl,\
+ vcl/glyphy/demo \
vcl/opengl/win/gdiimpl \
vcl/opengl/win/WinDeviceInfo \
vcl/opengl/win/blocklist_parser \
diff --git a/vcl/glyphy/demo.cxx b/vcl/glyphy/demo.cxx
new file mode 100755
index 000000000000..7f4f12adc74e
--- /dev/null
+++ b/vcl/glyphy/demo.cxx
@@ -0,0 +1,19 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <prewin.h>
+#include <postwin.h>
+
+namespace GLyphyDemo {
+#include "demo/demo-atlas.cc"
+#include "demo/demo-buffer.cc"
+#include "demo/demo-font.cc"
+#include "demo/demo-shader.cc"
+#include "demo/matrix4x4.c"
+}
diff --git a/vcl/glyphy/demo/demo-atlas.cc b/vcl/glyphy/demo/demo-atlas.cc
new file mode 100644
index 000000000000..d84da068363a
--- /dev/null
+++ b/vcl/glyphy/demo/demo-atlas.cc
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2012 Google, Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "demo-atlas.h"
+
+
+struct demo_atlas_t {
+ unsigned int refcount;
+
+ GLuint tex_unit;
+ GLuint tex_name;
+ GLuint tex_w;
+ GLuint tex_h;
+ GLuint item_w;
+ GLuint item_h_q; /* height quantum */
+ GLuint cursor_x;
+ GLuint cursor_y;
+};
+
+
+demo_atlas_t *
+demo_atlas_create (unsigned int w,
+ unsigned int h,
+ unsigned int item_w,
+ unsigned int item_h_quantum)
+{
+ TRACE();
+
+ demo_atlas_t *at = (demo_atlas_t *) calloc (1, sizeof (demo_atlas_t));
+ at->refcount = 1;
+
+ glGetIntegerv (GL_ACTIVE_TEXTURE, (GLint *) &at->tex_unit);
+ glGenTextures (1, &at->tex_name);
+ at->tex_w = w;
+ at->tex_h = h;
+ at->item_w = item_w;
+ at->item_h_q = item_h_quantum;
+ at->cursor_x = 0;
+ at->cursor_y = 0;
+
+ demo_atlas_bind_texture (at);
+
+ glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ gl(TexImage2D) (GL_TEXTURE_2D, 0, GL_RGBA, at->tex_w, at->tex_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+
+ return at;
+}
+
+demo_atlas_t *
+demo_atlas_reference (demo_atlas_t *at)
+{
+ if (at) at->refcount++;
+ return at;
+}
+
+void
+demo_atlas_destroy (demo_atlas_t *at)
+{
+ if (!at || --at->refcount)
+ return;
+
+ glDeleteTextures (1, &at->tex_name);
+ free (at);
+}
+
+void
+demo_atlas_bind_texture (demo_atlas_t *at)
+{
+ glActiveTexture (at->tex_unit);
+ glBindTexture (GL_TEXTURE_2D, at->tex_name);
+}
+
+void
+demo_atlas_set_uniforms (demo_atlas_t *at)
+{
+ GLuint program;
+ glGetIntegerv (GL_CURRENT_PROGRAM, (GLint *) &program);
+
+ glUniform4i (glGetUniformLocation (program, "u_atlas_info"),
+ at->tex_w, at->tex_h, at->item_w, at->item_h_q);
+ glUniform1i (glGetUniformLocation (program, "u_atlas_tex"), at->tex_unit - GL_TEXTURE0);
+}
+
+void
+demo_atlas_alloc (demo_atlas_t *at,
+ glyphy_rgba_t *data,
+ unsigned int len,
+ unsigned int *px,
+ unsigned int *py)
+{
+ GLuint w, h, x, y;
+
+ w = at->item_w;
+ h = (len + w - 1) / w;
+
+ if (at->cursor_y + h > at->tex_h) {
+ /* Go to next column */
+ at->cursor_x += at->item_w;
+ at->cursor_y = 0;
+ }
+
+ if (at->cursor_x + w <= at->tex_w &&
+ at->cursor_y + h <= at->tex_h)
+ {
+ x = at->cursor_x;
+ y = at->cursor_y;
+ at->cursor_y += (h + at->item_h_q - 1) & ~(at->item_h_q - 1);
+ } else
+ die ("Ran out of atlas memory");
+
+ demo_atlas_bind_texture (at);
+ if (w * h == len)
+ gl(TexSubImage2D) (GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, data);
+ else {
+ gl(TexSubImage2D) (GL_TEXTURE_2D, 0, x, y, w, h - 1, GL_RGBA, GL_UNSIGNED_BYTE, data);
+ /* Upload the last row separately */
+ gl(TexSubImage2D) (GL_TEXTURE_2D, 0, x, y + h - 1, len - (w * (h - 1)), 1, GL_RGBA, GL_UNSIGNED_BYTE,
+ data + w * (h - 1));
+ }
+
+ *px = x / at->item_w;
+ *py = y / at->item_h_q;
+}
diff --git a/vcl/glyphy/demo/demo-buffer.cc b/vcl/glyphy/demo/demo-buffer.cc
new file mode 100644
index 000000000000..8ce5b34fcd78
--- /dev/null
+++ b/vcl/glyphy/demo/demo-buffer.cc
@@ -0,0 +1,191 @@
+/*
+ * Copyright 2012 Google, Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "demo-buffer.h"
+
+struct demo_buffer_t {
+ unsigned int refcount;
+
+ glyphy_point_t cursor;
+ std::vector<glyph_vertex_t> *vertices;
+ glyphy_extents_t ink_extents;
+ glyphy_extents_t logical_extents;
+ bool dirty;
+ GLuint buf_name;
+};
+
+demo_buffer_t *
+demo_buffer_create (void)
+{
+ demo_buffer_t *buffer = (demo_buffer_t *) calloc (1, sizeof (demo_buffer_t));
+ buffer->refcount = 1;
+
+ buffer->vertices = new std::vector<glyph_vertex_t>;
+ glGenBuffers (1, &buffer->buf_name);
+
+ demo_buffer_clear (buffer);
+
+ return buffer;
+}
+
+demo_buffer_t *
+demo_buffer_reference (demo_buffer_t *buffer)
+{
+ if (buffer) buffer->refcount++;
+ return buffer;
+}
+
+void
+demo_buffer_destroy (demo_buffer_t *buffer)
+{
+ if (!buffer || --buffer->refcount)
+ return;
+
+ glDeleteBuffers (1, &buffer->buf_name);
+ delete buffer->vertices;
+ free (buffer);
+}
+
+
+void
+demo_buffer_clear (demo_buffer_t *buffer)
+{
+ buffer->vertices->clear ();
+ glyphy_extents_clear (&buffer->ink_extents);
+ glyphy_extents_clear (&buffer->logical_extents);
+ buffer->dirty = true;
+}
+
+void
+demo_buffer_extents (demo_buffer_t *buffer,
+ glyphy_extents_t *ink_extents,
+ glyphy_extents_t *logical_extents)
+{
+ if (ink_extents)
+ *ink_extents = buffer->ink_extents;
+ if (logical_extents)
+ *logical_extents = buffer->logical_extents;
+}
+
+void
+demo_buffer_move_to (demo_buffer_t *buffer,
+ const glyphy_point_t *p)
+{
+ buffer->cursor = *p;
+}
+
+void
+demo_buffer_current_point (demo_buffer_t *buffer,
+ glyphy_point_t *p)
+{
+ *p = buffer->cursor;
+}
+
+void
+demo_buffer_add_text (demo_buffer_t *buffer,
+ const char *utf8,
+ demo_font_t *font,
+ double font_size)
+{
+#ifndef _WIN32
+ FT_Face face = demo_font_get_face (font);
+#else
+ HDC hdc = demo_font_get_face (font);
+#endif
+ glyphy_point_t top_left = buffer->cursor;
+ buffer->cursor.y += font_size /* * font->ascent */;
+ unsigned int unicode;
+ for (const unsigned char *p = (const unsigned char *) utf8; *p; p++) {
+ if (*p < 128) {
+ unicode = *p;
+ } else {
+ unsigned int j;
+ if (*p < 0xE0) {
+ unicode = *p & ~0xE0;
+ j = 1;
+ } else if (*p < 0xF0) {
+ unicode = *p & ~0xF0;
+ j = 2;
+ } else {
+ unicode = *p & ~0xF8;
+ j = 3;
+ continue;
+ }
+ p++;
+ for (; j && *p; j--, p++)
+ unicode = (unicode << 6) | (*p & ~0xC0);
+ p--;
+ }
+
+ if (unicode == '\n') {
+ buffer->cursor.y += font_size;
+ buffer->cursor.x = top_left.x;
+ continue;
+ }
+
+#ifndef _WIN32
+ unsigned int glyph_index = FT_Get_Char_Index (face, unicode);
+#else
+ wchar_t wc = unicode; /* FIXME: What about non-BMP chars? */
+ WORD glyph_index;
+ if (GetGlyphIndicesW (hdc, &wc, 1, &glyph_index, GGI_MARK_NONEXISTING_GLYPHS) == GDI_ERROR)
+ die ("GetGlyphIndicesW failed");
+#endif
+ glyph_info_t gi;
+ demo_font_lookup_glyph (font, glyph_index, &gi);
+
+ /* Update ink extents */
+ glyphy_extents_t ink_extents;
+ demo_shader_add_glyph_vertices (buffer->cursor, font_size, &gi, buffer->vertices, &ink_extents);
+ glyphy_extents_extend (&buffer->ink_extents, &ink_extents);
+
+ /* Update logical extents */
+ glyphy_point_t corner;
+ corner.x = buffer->cursor.x;
+ corner.y = buffer->cursor.y - font_size;
+ glyphy_extents_add (&buffer->logical_extents, &corner);
+ corner.x = buffer->cursor.x + font_size * gi.advance;
+ corner.y = buffer->cursor.y;
+ glyphy_extents_add (&buffer->logical_extents, &corner);
+
+ buffer->cursor.x += font_size * gi.advance;
+ }
+
+ buffer->dirty = true;
+}
+
+void
+demo_buffer_draw (demo_buffer_t *buffer)
+{
+ GLint program;
+ glGetIntegerv (GL_CURRENT_PROGRAM, &program);
+ GLuint a_glyph_vertex_loc = glGetAttribLocation (program, "a_glyph_vertex");
+ glBindBuffer (GL_ARRAY_BUFFER, buffer->buf_name);
+ if (buffer->dirty) {
+ glBufferData (GL_ARRAY_BUFFER, sizeof (glyph_vertex_t) * buffer->vertices->size (), (const char *) &(*buffer->vertices)[0], GL_STATIC_DRAW);
+ buffer->dirty = false;
+ }
+ glEnableVertexAttribArray (a_glyph_vertex_loc);
+ glVertexAttribPointer (a_glyph_vertex_loc, 4, GL_FLOAT, GL_FALSE, sizeof (glyph_vertex_t), 0);
+ glDrawArrays (GL_TRIANGLES, 0, buffer->vertices->size ());
+ glDisableVertexAttribArray (a_glyph_vertex_loc);
+}
diff --git a/vcl/glyphy/demo/demo-font.cc b/vcl/glyphy/demo/demo-font.cc
new file mode 100644
index 000000000000..c28778e899c3
--- /dev/null
+++ b/vcl/glyphy/demo/demo-font.cc
@@ -0,0 +1,333 @@
+/*
+ * Copyright 2012 Google, Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "demo-font.h"
+
+#ifndef _WIN32
+#include <glyphy-freetype.h>
+#endif
+
+#ifdef _WIN32
+#include <glyphy-windows.h>
+#endif
+
+#include <map>
+#include <vector>
+
+typedef std::map<unsigned int, glyph_info_t> glyph_cache_t;
+
+struct demo_font_t {
+ unsigned int refcount;
+
+#ifndef _WIN32
+ FT_Face face;
+#endif
+
+#ifdef _WIN32
+ HDC face; /* A memory DC that has the font instance selected into it */
+#endif
+
+ glyph_cache_t *glyph_cache;
+ demo_atlas_t *atlas;
+ glyphy_arc_accumulator_t *acc;
+
+ /* stats */
+ unsigned int num_glyphs;
+ double sum_error;
+ unsigned int sum_endpoints;
+ double sum_fetch;
+ unsigned int sum_bytes;
+};
+
+demo_font_t *
+demo_font_create (
+#ifndef _WIN32
+ FT_Face face,
+#endif
+#ifdef _WIN32
+ HDC face,
+#endif
+ demo_atlas_t *atlas)
+{
+ demo_font_t *font = (demo_font_t *) calloc (1, sizeof (demo_font_t));
+ font->refcount = 1;
+
+ font->face = face;
+ font->glyph_cache = new glyph_cache_t ();
+ font->atlas = demo_atlas_reference (atlas);
+ font->acc = glyphy_arc_accumulator_create ();
+
+ font->num_glyphs = 0;
+ font->sum_error = 0;
+ font->sum_endpoints = 0;
+ font->sum_fetch = 0;
+ font->sum_bytes = 0;
+
+ return font;
+}
+
+demo_font_t *
+demo_font_reference (demo_font_t *font)
+{
+ if (font) font->refcount++;
+ return font;
+}
+
+void
+demo_font_destroy (demo_font_t *font)
+{
+ if (!font || --font->refcount)
+ return;
+
+ glyphy_arc_accumulator_destroy (font->acc);
+ demo_atlas_destroy (font->atlas);
+ delete font->glyph_cache;
+ free (font);
+}
+
+
+#ifndef _WIN32
+FT_Face
+#endif
+#ifdef _WIN32
+HDC
+#endif
+demo_font_get_face (demo_font_t *font)
+{
+ return font->face;
+}
+
+demo_atlas_t *
+demo_font_get_atlas (demo_font_t *font)
+{
+ return font->atlas;
+}
+
+
+static glyphy_bool_t
+accumulate_endpoint (glyphy_arc_endpoint_t *endpoint,
+ std::vector<glyphy_arc_endpoint_t> *endpoints)
+{
+ endpoints->push_back (*endpoint);
+ return true;
+}
+
+static void
+encode_glyph (demo_font_t *font,
+ unsigned int glyph_index,
+ double tolerance_per_em,
+ glyphy_rgba_t *buffer,
+ unsigned int buffer_len,
+ unsigned int *output_len,
+ unsigned int *nominal_width,
+ unsigned int *nominal_height,
+ glyphy_extents_t *extents,
+ double *advance)
+{
+/* Used for testing only */
+#define SCALE (1. * (1 << 0))
+
+#ifndef _WIN32
+ FT_Face face = font->face;
+ if (FT_Err_Ok != FT_Load_Glyph (face,
+ glyph_index,
+ FT_LOAD_NO_BITMAP |
+ FT_LOAD_NO_HINTING |
+ FT_LOAD_NO_AUTOHINT |
+ FT_LOAD_NO_SCALE |
+ FT_LOAD_LINEAR_DESIGN |
+ FT_LOAD_IGNORE_TRANSFORM))
+ die ("Failed loading FreeType glyph");
+
+ if (face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
+ die ("FreeType loaded glyph format is not outline");
+
+ unsigned int upem = face->units_per_EM;
+ double tolerance = upem * tolerance_per_em; /* in font design units */
+ double faraway = double (upem) / (MIN_FONT_SIZE * M_SQRT2);
+ std::vector<glyphy_arc_endpoint_t> endpoints;
+
+ glyphy_arc_accumulator_reset (font->acc);
+ glyphy_arc_accumulator_set_tolerance (font->acc, tolerance);
+ glyphy_arc_accumulator_set_callback (font->acc,
+ (glyphy_arc_endpoint_accumulator_callback_t) accumulate_endpoint,
+ &endpoints);
+
+ if (FT_Err_Ok != glyphy_freetype(outline_decompose) (&face->glyph->outline, font->acc))
+ die ("Failed converting glyph outline to arcs");
+#endif
+
+#ifdef _WIN32
+ HDC hdc = font->face;
+
+ GLYPHMETRICS glyph_metrics;
+ MAT2 matrix;
+
+ matrix.eM11.value = 1;
+ matrix.eM11.fract = 0;
+ matrix.eM12.value = 0;
+ matrix.eM12.fract = 0;
+ matrix.eM21.value = 0;
+ matrix.eM21.fract = 0;
+ matrix.eM22.value = 1;
+ matrix.eM22.fract = 0;
+
+ DWORD size = GetGlyphOutlineW (hdc, glyph_index, GGO_NATIVE|GGO_GLYPH_INDEX, &glyph_metrics, 0, NULL, &matrix);
+ if (size == GDI_ERROR)
+ die ("GetGlyphOutlineW failed");
+ std::vector<char> buf(size);
+ size = GetGlyphOutlineW (hdc, glyph_index, GGO_NATIVE|GGO_GLYPH_INDEX, &glyph_metrics, size, buf.data(), &matrix);
+ if (size == GDI_ERROR)
+ die ("GetGlyphOutlineW failed");
+
+ size = GetGlyphOutlineW (hdc, glyph_index, GGO_METRICS|GGO_GLYPH_INDEX, &glyph_metrics, 0, NULL, &matrix);
+ if (size == GDI_ERROR)
+ die ("GetGlyphOutlineW failed");
+
+ OUTLINETEXTMETRICW outline_text_metric;
+ if (!GetOutlineTextMetricsW (hdc, sizeof (OUTLINETEXTMETRICW), &outline_text_metric))
+ die ("GetOutlineTextMetricsW failed");
+
+ unsigned int upem = outline_text_metric.otmEMSquare;
+ double tolerance = upem * tolerance_per_em; /* in font design units */
+ double faraway = double (upem) / (MIN_FONT_SIZE * M_SQRT2);
+ std::vector<glyphy_arc_endpoint_t> endpoints;
+
+ glyphy_arc_accumulator_reset (font->acc);
+ glyphy_arc_accumulator_set_tolerance (font->acc, tolerance);
+ glyphy_arc_accumulator_set_callback (font->acc,
+ (glyphy_arc_endpoint_accumulator_callback_t) accumulate_endpoint,
+ &endpoints);
+
+ if (0 != glyphy_windows(outline_decompose) ((TTPOLYGONHEADER *) buf.data(), buf.size(), font->acc))
+ die ("Failed converting glyph outline to arcs");
+#endif
+
+ assert (glyphy_arc_accumulator_get_error (font->acc) <= tolerance);
+
+ if (endpoints.size ())
+ {
+#if 0
+ /* Technically speaking, we want the following code,
+ * however, crappy fonts have crappy flags. So we just
+ * fixup unconditionally... */
+ if (face->glyph->outline.flags & FT_OUTLINE_EVEN_ODD_FILL)
+ glyphy_outline_winding_from_even_odd (&endpoints[0], endpoints.size (), false);
+ else if (face->glyph->outline.flags & FT_OUTLINE_REVERSE_FILL)
+ glyphy_outline_reverse (&endpoints[0], endpoints.size ());
+#else
+ glyphy_outline_winding_from_even_odd (&endpoints[0], endpoints.size (), false);
+#endif
+ }
+
+ if (SCALE != 1.)
+ for (unsigned int i = 0; i < endpoints.size (); i++)
+ {
+ endpoints[i].p.x /= SCALE;
+ endpoints[i].p.y /= SCALE;
+ }
+
+ double avg_fetch_achieved;
+ if (!glyphy_arc_list_encode_blob (endpoints.size () ? &endpoints[0] : NULL, endpoints.size (),
+ buffer,
+ buffer_len,
+ faraway / SCALE,
+ 4, /* UNUSED */
+ &avg_fetch_achieved,
+ output_len,
+ nominal_width,
+ nominal_height,
+ extents))
+ die ("Failed encoding arcs");
+
+ glyphy_extents_scale (extents, 1. / upem, 1. / upem);
+ glyphy_extents_scale (extents, SCALE, SCALE);
+
+#ifndef _WIN32
+ *advance = face->glyph->metrics.horiAdvance / (double) upem;
+#endif
+
+#ifdef _WIN32
+ *advance = glyph_metrics.gmCellIncX / (double) upem; /* ??? */
+#endif
+
+ if (0)
+ LOGI ("gid%3u: endpoints%3d; err%3g%%; tex fetch%4.1f; mem%4.1fkb\n",
+ glyph_index,
+ (unsigned int) glyphy_arc_accumulator_get_num_endpoints (font->acc),
+ round (100 * glyphy_arc_accumulator_get_error (font->acc) / tolerance),
+ avg_fetch_achieved,
+ (*output_len * sizeof (glyphy_rgba_t)) / 1024.);
+
+ font->num_glyphs++;
+ font->sum_error += glyphy_arc_accumulator_get_error (font->acc) / tolerance;
+ font->sum_endpoints += glyphy_arc_accumulator_get_num_endpoints (font->acc);
+ font->sum_fetch += avg_fetch_achieved;
+ font->sum_bytes += (*output_len * sizeof (glyphy_rgba_t));
+}
+
+static void
+_demo_font_upload_glyph (demo_font_t *font,
+ unsigned int glyph_index,
+ glyph_info_t *glyph_info)
+{
+ glyphy_rgba_t buffer[4096 * 16];
+ unsigned int output_len;
+
+ encode_glyph (font,
+ glyph_index,
+ TOLERANCE,
+ buffer, ARRAY_LEN (buffer),
+ &output_len,
+ &glyph_info->nominal_w,
+ &glyph_info->nominal_h,
+ &glyph_info->extents,
+ &glyph_info->advance);
+
+ glyph_info->is_empty = glyphy_extents_is_empty (&glyph_info->extents);
+ if (!glyph_info->is_empty)
+ demo_atlas_alloc (font->atlas, buffer, output_len,
+ &glyph_info->atlas_x, &glyph_info->atlas_y);
+}
+
+void
+demo_font_lookup_glyph (demo_font_t *font,
+ unsigned int glyph_index,
+ glyph_info_t *glyph_info)
+{
+ if (font->glyph_cache->find (glyph_index) == font->glyph_cache->end ()) {
+ _demo_font_upload_glyph (font, glyph_index, glyph_info);
+ (*font->glyph_cache)[glyph_index] = *glyph_info;
+ } else
+ *glyph_info = (*font->glyph_cache)[glyph_index];
+}
+
+void
+demo_font_print_stats (demo_font_t *font)
+{
+ LOGI ("%3d glyphs; avg num endpoints%6.2f; avg error%5.1f%%; avg tex fetch%5.2f; avg %5.2fkb per glyph\n",
+ font->num_glyphs,
+ (double) font->sum_endpoints / font->num_glyphs,
+ 100. * font->sum_error / font->num_glyphs,
+ font->sum_fetch / font->num_glyphs,
+ font->sum_bytes / 1024. / font->num_glyphs);
+}
diff --git a/vcl/glyphy/demo/demo-shader.cc b/vcl/glyphy/demo/demo-shader.cc
new file mode 100644
index 000000000000..9b8212333175
--- /dev/null
+++ b/vcl/glyphy/demo/demo-shader.cc
@@ -0,0 +1,212 @@
+/*
+ * Copyright 2012 Google, Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "demo-shader.h"
+
+#include "demo-atlas-glsl.h"
+#include "demo-vshader-glsl.h"
+#include "demo-fshader-glsl.h"
+
+
+static unsigned int
+glyph_encode (unsigned int atlas_x , /* 7 bits */
+ unsigned int atlas_y, /* 7 bits */
+ unsigned int corner_x, /* 1 bit */
+ unsigned int corner_y, /* 1 bit */
+ unsigned int nominal_w, /* 6 bits */
+ unsigned int nominal_h /* 6 bits */)
+{
+ assert (0 == (atlas_x & ~0x7F));
+ assert (0 == (atlas_y & ~0x7F));
+ assert (0 == (corner_x & ~1));
+ assert (0 == (corner_y & ~1));
+ assert (0 == (nominal_w & ~0x3F));
+ assert (0 == (nominal_h & ~0x3F));
+
+ unsigned int x = (((atlas_x << 6) | nominal_w) << 1) | corner_x;
+ unsigned int y = (((atlas_y << 6) | nominal_h) << 1) | corner_y;
+
+ return (x << 16) | y;
+}
+
+static void
+glyph_vertex_encode (double x, double y,
+ unsigned int corner_x, unsigned int corner_y,
+ const glyph_info_t *gi,
+ glyph_vertex_t *v)
+{
+ unsigned int encoded = glyph_encode (gi->atlas_x, gi->atlas_y,
+ corner_x, corner_y,
+ gi->nominal_w, gi->nominal_h);
+ v->x = x;
+ v->y = y;
+ v->g16hi = encoded >> 16;
+ v->g16lo = encoded & 0xFFFF;
+}
+
+void
+demo_shader_add_glyph_vertices (const glyphy_point_t &p,
+ double font_size,
+ glyph_info_t *gi,
+ std::vector<glyph_vertex_t> *vertices,
+ glyphy_extents_t *extents)
+{
+ if (gi->is_empty)
+ return;
+
+ glyph_vertex_t v[4];
+
+#define ENCODE_CORNER(_cx, _cy) \
+ do { \
+ double _vx = p.x + font_size * ((1-_cx) * gi->extents.min_x + _cx * gi->extents.max_x); \
+ double _vy = p.y - font_size * ((1-_cy) * gi->extents.min_y + _cy * gi->extents.max_y); \
+ glyph_vertex_encode (_vx, _vy, _cx, _cy, gi, &v[_cx * 2 + _cy]); \
+ } while (0)
+ ENCODE_CORNER (0, 0);
+ ENCODE_CORNER (0, 1);
+ ENCODE_CORNER (1, 0);
+ ENCODE_CORNER (1, 1);
+#undef ENCODE_CORNER
+
+ vertices->push_back (v[0]);
+ vertices->push_back (v[1]);
+ vertices->push_back (v[2]);
+
+ vertices->push_back (v[1]);
+ vertices->push_back (v[2]);
+ vertices->push_back (v[3]);
+
+ if (extents) {
+ glyphy_extents_clear (extents);
+ for (unsigned int i = 0; i < 4; i++) {
+ glyphy_point_t p = {v[i].x, v[i].y};
+ glyphy_extents_add (extents, &p);
+ }
+ }
+}
+
+
+
+
+static GLuint
+compile_shader (GLenum type,
+ GLsizei count,
+ const GLchar** sources)
+{
+ TRACE();
+
+ GLuint shader;
+ GLint compiled;
+
+ if (!(shader = glCreateShader (type)))
+ return shader;
+
+ glShaderSource (shader, count, sources, 0);
+ glCompileShader (shader);
+
+ glGetShaderiv (shader, GL_COMPILE_STATUS, &compiled);
+ if (!compiled) {
+ GLint info_len = 0;
+ LOGW ("%s shader failed to compile\n",
+ type == GL_VERTEX_SHADER ? "Vertex" : "Fragment");
+ glGetShaderiv (shader, GL_INFO_LOG_LENGTH, &info_len);
+
+ if (info_len > 0) {
+ char *info_log = (char*) malloc (info_len);
+ glGetShaderInfoLog (shader, info_len, NULL, info_log);
+
+ LOGW ("%s\n", info_log);
+ free (info_log);
+ }
+
+ abort ();
+ }
+
+ return shader;
+}
+
+static GLuint
+link_program (GLuint vshader,
+ GLuint fshader)
+{
+ TRACE();
+
+ GLuint program;
+ GLint linked;
+
+ program = glCreateProgram ();
+ glAttachShader (program, vshader);
+ glAttachShader (program, fshader);
+ glLinkProgram (program);
+ glDeleteShader (vshader);
+ glDeleteShader (fshader);
+
+ glGetProgramiv (program, GL_LINK_STATUS, &linked);
+ if (!linked) {
+ GLint info_len = 0;
+ LOGW ("Program failed to link\n");
+ glGetProgramiv (program, GL_INFO_LOG_LENGTH, &info_len);
+
+ if (info_len > 0) {
+ char *info_log = (char*) malloc (info_len);
+ glGetProgramInfoLog (program, info_len, NULL, info_log);
+
+ LOGW ("%s\n", info_log);
+ free (info_log);
+ }
+
+ abort ();
+ }
+
+ return program;
+}
+
+#ifdef GL_ES_VERSION_2_0
+# define GLSL_HEADER_STRING \
+ "#extension GL_OES_standard_derivatives : enable\n" \
+ "precision highp float;\n" \
+ "precision highp int;\n"
+#else
+# define GLSL_HEADER_STRING \
+ "#version 110\n"
+#endif
+
+GLuint
+demo_shader_create_program (void)
+{
+ TRACE();
+
+ GLuint vshader, fshader, program;
+ const GLchar *vshader_sources[] = {GLSL_HEADER_STRING,
+ demo_vshader_glsl};
+ vshader = compile_shader (GL_VERTEX_SHADER, ARRAY_LEN (vshader_sources), vshader_sources);
+ const GLchar *fshader_sources[] = {GLSL_HEADER_STRING,
+ demo_atlas_glsl,
+ glyphy_common_shader_source (),
+ "#define GLYPHY_SDF_PSEUDO_DISTANCE 1\n",
+ glyphy_sdf_shader_source (),
+ demo_fshader_glsl};
+ fshader = compile_shader (GL_FRAGMENT_SHADER, ARRAY_LEN (fshader_sources), fshader_sources);
+
+ program = link_program (vshader, fshader);
+ return program;
+}
diff --git a/vcl/glyphy/demo/matrix4x4.c b/vcl/glyphy/demo/matrix4x4.c
new file mode 100644
index 000000000000..f103589e6593
--- /dev/null
+++ b/vcl/glyphy/demo/matrix4x4.c
@@ -0,0 +1,481 @@
+/*
+ * Copyright (c) 2009, Mozilla Corp
+ * Copyright (c) 2012, Google, 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:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the <organization> 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 <copyright holder> ''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 <copyright holder> 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.
+ */
+
+/*
+ * Based on sample code from the OpenGL(R) ES 2.0 Programming Guide, which carriers
+ * the following header:
+ *
+ * Book: OpenGL(R) ES 2.0 Programming Guide
+ * Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner
+ * ISBN-10: 0321502795
+ * ISBN-13: 9780321502797
+ * Publisher: Addison-Wesley Professional
+ * URLs: http://safari.informit.com/9780321563835
+ * http://www.opengles-book.com
+ */
+
+/*
+ * Ported from JavaScript to C by Behdad Esfahbod, 2012.
+ * Added MultMatrix. Converting from fixed-function OpenGL matrix
+ * operations to these functions should be as simple as renaming the
+ * 'gl' prefix to 'm4' and adding the matrix argument to the call.
+ *
+ * The C version lives at http://code.google.com/p/matrix4x4-c/
+ */
+
+#include "matrix4x4.h"
+#include <math.h>
+
+/*
+ * A simple 4x4 matrix utility implementation
+ */
+
+
+float *
+m4LoadIdentity (float *mat) {
+ unsigned int i;
+ for (i = 0; i < 16; i++)
+ mat[i] = 0;
+ mat[0*4+0] = 1.0;
+ mat[1*4+1] = 1.0;
+ mat[2*4+2] = 1.0;
+ mat[3*4+3] = 1.0;
+ return mat;
+}
+
+/* Copies other matrix into mat */
+float *
+m4Copy (float *mat, const float *other) {
+ unsigned int i;
+ for (i = 0; i < 16; i++) {
+ mat[i] = other[i];
+ }
+ return mat;
+}
+
+float *
+m4Multiply (float *mat, const float *right) {
+ float tmp[16];
+ unsigned int i;
+
+ for (i = 0; i < 4; i++) {
+ tmp[i*4+0] =
+ (mat[i*4+0] * right[0*4+0]) +
+ (mat[i*4+1] * right[1*4+0]) +
+ (mat[i*4+2] * right[2*4+0]) +
+ (mat[i*4+3] * right[3*4+0]) ;
+
+ tmp[i*4+1] =
+ (mat[i*4+0] * right[0*4+1]) +
+ (mat[i*4+1] * right[1*4+1]) +
+ (mat[i*4+2] * right[2*4+1]) +
+ (mat[i*4+3] * right[3*4+1]) ;
+
+ tmp[i*4+2] =
+ (mat[i*4+0] * right[0*4+2]) +
+ (mat[i*4+1] * right[1*4+2]) +
+ (mat[i*4+2] * right[2*4+2]) +
+ (mat[i*4+3] * right[3*4+2]) ;
+
+ tmp[i*4+3] =
+ (mat[i*4+0] * right[0*4+3]) +
+ (mat[i*4+1] * right[1*4+3]) +
+ (mat[i*4+2] * right[2*4+3]) +
+ (mat[i*4+3] * right[3*4+3]) ;
+ }
+
+ return m4Copy (mat, tmp);
+}
+
+float
+m4Get (float *mat, unsigned int row, unsigned int col) {
+ return mat[4*row+col];
+}
+
+float *
+m4MultMatrix (float *mat, const float *left) {
+ float tmp[16];
+ return m4Copy (mat, m4Multiply (m4Copy (tmp, left), mat));
+}
+
+float *
+m4Scale (float *mat, float sx, float sy, float sz) {
+ mat[0*4+0] *= sx;
+ mat[0*4+1] *= sx;
+ mat[0*4+2] *= sx;
+ mat[0*4+3] *= sx;
+
+ mat[1*4+0] *= sy;
+ mat[1*4+1] *= sy;
+ mat[1*4+2] *= sy;
+ mat[1*4+3] *= sy;
+
+ mat[2*4+0] *= sz;
+ mat[2*4+1] *= sz;
+ mat[2*4+2] *= sz;
+ mat[2*4+3] *= sz;
+
+ return mat;
+}
+
+float *
+m4Translate (float *mat, float tx, float ty, float tz) {
+ mat[3*4+0] += mat[0*4+0] * tx + mat[1*4+0] * ty + mat[2*4+0] * tz;
+ mat[3*4+1] += mat[0*4+1] * tx + mat[1*4+1] * ty + mat[2*4+1] * tz;
+ mat[3*4+2] += mat[0*4+2] * tx + mat[1*4+2] * ty + mat[2*4+2] * tz;
+ mat[3*4+3] += mat[0*4+3] * tx + mat[1*4+3] * ty + mat[2*4+3] * tz;
+
+ return mat;
+}
+
+float *
+m4Rotate (float *mat, float angle, float x, float y, float z) {
+ float mag = sqrt(x*x + y*y + z*z);
+ float sinAngle = sin(angle * M_PI / 180.0);
+ float cosAngle = cos(angle * M_PI / 180.0);
+
+ float xx, yy, zz, xy, yz, zx, xs, ys, zs;
+ float oneMinusCos;
+
+ float rotMat[16];
+
+ if (mag <= 0)
+ return mat;
+
+ m4LoadIdentity (rotMat);
+
+ x /= mag;
+ y /= mag;
+ z /= mag;
+
+ xx = x * x;
+ yy = y * y;
+ zz = z * z;
+ xy = x * y;
+ yz = y * z;
+ zx = z * x;
+ xs = x * sinAngle;
+ ys = y * sinAngle;
+ zs = z * sinAngle;
+ oneMinusCos = 1.0 - cosAngle;
+
+ rotMat[0*4+0] = (oneMinusCos * xx) + cosAngle;
+ rotMat[0*4+1] = (oneMinusCos * xy) - zs;
+ rotMat[0*4+2] = (oneMinusCos * zx) + ys;
+ rotMat[0*4+3] = 0.0;
+
+ rotMat[1*4+0] = (oneMinusCos * xy) + zs;
+ rotMat[1*4+1] = (oneMinusCos * yy) + cosAngle;
+ rotMat[1*4+2] = (oneMinusCos * yz) - xs;
+ rotMat[1*4+3] = 0.0;
+
+ rotMat[2*4+0] = (oneMinusCos * zx) - ys;
+ rotMat[2*4+1] = (oneMinusCos * yz) + xs;
+ rotMat[2*4+2] = (oneMinusCos * zz) + cosAngle;
+ rotMat[2*4+3] = 0.0;
+
+ rotMat[3*4+0] = 0.0;
+ rotMat[3*4+1] = 0.0;
+ rotMat[3*4+2] = 0.0;
+ rotMat[3*4+3] = 1.0;
+
+ return m4Copy (mat, m4Multiply (rotMat, mat));
+}
+
+float *
+m4Frustum (float *mat, float left, float right, float bottom, float top, float nearZ, float farZ) {
+ float deltaX = right - left;
+ float deltaY = top - bottom;
+ float deltaZ = farZ - nearZ;
+
+ float frust[16];
+
+ if ( (nearZ <= 0.0) || (farZ <= 0.0) ||
+ (deltaX <= 0.0) || (deltaY <= 0.0) || (deltaZ <= 0.0) )
+ return mat;
+
+ m4LoadIdentity (frust);
+
+ frust[0*4+0] = 2.0 * nearZ / deltaX;
+ frust[0*4+1] = frust[0*4+2] = frust[0*4+3] = 0.0;
+
+ frust[1*4+1] = 2.0 * nearZ / deltaY;
+ frust[1*4+0] = frust[1*4+2] = frust[1*4+3] = 0.0;
+
+ frust[2*4+0] = (right + left) / deltaX;
+ frust[2*4+1] = (top + bottom) / deltaY;
+ frust[2*4+2] = -(nearZ + farZ) / deltaZ;
+ frust[2*4+3] = -1.0;
+
+ frust[3*4+2] = -2.0 * nearZ * farZ / deltaZ;
+ frust[3*4+0] = frust[3*4+1] = frust[3*4+3] = 0.0;
+
+ return m4Copy (mat, m4Multiply (frust, mat));
+}
+
+float *
+m4Perspective (float *mat, float fovy, float aspect, float nearZ, float farZ) {
+ float frustumH = tan(fovy / 360.0 * M_PI) * nearZ;
+ float frustumW = frustumH * aspect;
+
+ return m4Frustum(mat, -frustumW, frustumW, -frustumH, frustumH, nearZ, farZ);
+}
+
+float *
+m4Ortho (float *mat, float left, float right, float bottom, float top, float nearZ, float farZ) {
+ float deltaX = right - left;
+ float deltaY = top - bottom;
+ float deltaZ = farZ - nearZ;
+
+ float ortho[16];
+
+ if ( (deltaX == 0.0) || (deltaY == 0.0) || (deltaZ == 0.0) )
+ return mat;
+
+ m4LoadIdentity (ortho);
+
+ ortho[0*4+0] = 2.0 / deltaX;
+ ortho[3*4+0] = -(right + left) / deltaX;
+ ortho[1*4+1] = 2.0 / deltaY;
+ ortho[3*4+1] = -(top + bottom) / deltaY;
+ ortho[2*4+2] = -2.0 / deltaZ;
+ ortho[3*4+2] = -(nearZ + farZ) / deltaZ;
+
+ return m4Copy (mat, m4Multiply (ortho, mat));
+}
+
+/* In-place inversion */
+float *
+m4Invert (float *mat) {
+ float tmp_0 = m4Get(mat,2,2) * m4Get(mat,3,3);
+ float tmp_1 = m4Get(mat,3,2) * m4Get(mat,2,3);
+ float tmp_2 = m4Get(mat,1,2) * m4Get(mat,3,3);
+ float tmp_3 = m4Get(mat,3,2) * m4Get(mat,1,3);
+ float tmp_4 = m4Get(mat,1,2) * m4Get(mat,2,3);
+ float tmp_5 = m4Get(mat,2,2) * m4Get(mat,1,3);
+ float tmp_6 = m4Get(mat,0,2) * m4Get(mat,3,3);
+ float tmp_7 = m4Get(mat,3,2) * m4Get(mat,0,3);
+ float tmp_8 = m4Get(mat,0,2) * m4Get(mat,2,3);
+ float tmp_9 = m4Get(mat,2,2) * m4Get(mat,0,3);
+ float tmp_10 = m4Get(mat,0,2) * m4Get(mat,1,3);
+ float tmp_11 = m4Get(mat,1,2) * m4Get(mat,0,3);
+ float tmp_12 = m4Get(mat,2,0) * m4Get(mat,3,1);
+ float tmp_13 = m4Get(mat,3,0) * m4Get(mat,2,1);
+ float tmp_14 = m4Get(mat,1,0) * m4Get(mat,3,1);
+ float tmp_15 = m4Get(mat,3,0) * m4Get(mat,1,1);
+ float tmp_16 = m4Get(mat,1,0) * m4Get(mat,2,1);
+ float tmp_17 = m4Get(mat,2,0) * m4Get(mat,1,1);
+ float tmp_18 = m4Get(mat,0,0) * m4Get(mat,3,1);
+ float tmp_19 = m4Get(mat,3,0) * m4Get(mat,0,1);
+ float tmp_20 = m4Get(mat,0,0) * m4Get(mat,2,1);
+ float tmp_21 = m4Get(mat,2,0) * m4Get(mat,0,1);
+ float tmp_22 = m4Get(mat,0,0) * m4Get(mat,1,1);
+ float tmp_23 = m4Get(mat,1,0) * m4Get(mat,0,1);
+
+ float t0 = ((tmp_0 * m4Get(mat,1,1) + tmp_3 * m4Get(mat,2,1) + tmp_4 * m4Get(mat,3,1)) -
+ (tmp_1 * m4Get(mat,1,1) + tmp_2 * m4Get(mat,2,1) + tmp_5 * m4Get(mat,3,1)));
+ float t1 = ((tmp_1 * m4Get(mat,0,1) + tmp_6 * m4Get(mat,2,1) + tmp_9 * m4Get(mat,3,1)) -
+ (tmp_0 * m4Get(mat,0,1) + tmp_7 * m4Get(mat,2,1) + tmp_8 * m4Get(mat,3,1)));
+ float t2 = ((tmp_2 * m4Get(mat,0,1) + tmp_7 * m4Get(mat,1,1) + tmp_10 * m4Get(mat,3,1)) -
+ (tmp_3 * m4Get(mat,0,1) + tmp_6 * m4Get(mat,1,1) + tmp_11 * m4Get(mat,3,1)));
+ float t3 = ((tmp_5 * m4Get(mat,0,1) + tmp_8 * m4Get(mat,1,1) + tmp_11 * m4Get(mat,2,1)) -
+ (tmp_4 * m4Get(mat,0,1) + tmp_9 * m4Get(mat,1,1) + tmp_10 * m4Get(mat,2,1)));
+
+ float d = 1.0 / (m4Get(mat,0,0) * t0 + m4Get(mat,1,0) * t1 + m4Get(mat,2,0) * t2 + m4Get(mat,3,0) * t3);
+
+ float out_00 = d * t0;
+ float out_01 = d * t1;
+ float out_02 = d * t2;
+ float out_03 = d * t3;
+
+ float out_10 = d * ((tmp_1 * m4Get(mat,1,0) + tmp_2 * m4Get(mat,2,0) + tmp_5 * m4Get(mat,3,0)) -
+ (tmp_0 * m4Get(mat,1,0) + tmp_3 * m4Get(mat,2,0) + tmp_4 * m4Get(mat,3,0)));
+ float out_11 = d * ((tmp_0 * m4Get(mat,0,0) + tmp_7 * m4Get(mat,2,0) + tmp_8 * m4Get(mat,3,0)) -
+ (tmp_1 * m4Get(mat,0,0) + tmp_6 * m4Get(mat,2,0) + tmp_9 * m4Get(mat,3,0)));
+ float out_12 = d * ((tmp_3 * m4Get(mat,0,0) + tmp_6 * m4Get(mat,1,0) + tmp_11 * m4Get(mat,3,0)) -
+ (tmp_2 * m4Get(mat,0,0) + tmp_7 * m4Get(mat,1,0) + tmp_10 * m4Get(mat,3,0)));
+ float out_13 = d * ((tmp_4 * m4Get(mat,0,0) + tmp_9 * m4Get(mat,1,0) + tmp_10 * m4Get(mat,2,0)) -
+ (tmp_5 * m4Get(mat,0,0) + tmp_8 * m4Get(mat,1,0) + tmp_11 * m4Get(mat,2,0)));
+
+ float out_20 = d * ((tmp_12 * m4Get(mat,1,3) + tmp_15 * m4Get(mat,2,3) + tmp_16 * m4Get(mat,3,3)) -
+ (tmp_13 * m4Get(mat,1,3) + tmp_14 * m4Get(mat,2,3) + tmp_17 * m4Get(mat,3,3)));
+ float out_21 = d * ((tmp_13 * m4Get(mat,0,3) + tmp_18 * m4Get(mat,2,3) + tmp_21 * m4Get(mat,3,3)) -
+ (tmp_12 * m4Get(mat,0,3) + tmp_19 * m4Get(mat,2,3) + tmp_20 * m4Get(mat,3,3)));
+ float out_22 = d * ((tmp_14 * m4Get(mat,0,3) + tmp_19 * m4Get(mat,1,3) + tmp_22 * m4Get(mat,3,3)) -
+ (tmp_15 * m4Get(mat,0,3) + tmp_18 * m4Get(mat,1,3) + tmp_23 * m4Get(mat,3,3)));
+ float out_23 = d * ((tmp_17 * m4Get(mat,0,3) + tmp_20 * m4Get(mat,1,3) + tmp_23 * m4Get(mat,2,3)) -
+ (tmp_16 * m4Get(mat,0,3) + tmp_21 * m4Get(mat,1,3) + tmp_22 * m4Get(mat,2,3)));
+
+ float out_30 = d * ((tmp_14 * m4Get(mat,2,2) + tmp_17 * m4Get(mat,3,2) + tmp_13 * m4Get(mat,1,2)) -
+ (tmp_16 * m4Get(mat,3,2) + tmp_12 * m4Get(mat,1,2) + tmp_15 * m4Get(mat,2,2)));
+ float out_31 = d * ((tmp_20 * m4Get(mat,3,2) + tmp_12 * m4Get(mat,0,2) + tmp_19 * m4Get(mat,2,2)) -
+ (tmp_18 * m4Get(mat,2,2) + tmp_21 * m4Get(mat,3,2) + tmp_13 * m4Get(mat,0,2)));
+ float out_32 = d * ((tmp_18 * m4Get(mat,1,2) + tmp_23 * m4Get(mat,3,2) + tmp_15 * m4Get(mat,0,2)) -
+ (tmp_22 * m4Get(mat,3,2) + tmp_14 * m4Get(mat,0,2) + tmp_19 * m4Get(mat,1,2)));
+ float out_33 = d * ((tmp_22 * m4Get(mat,2,2) + tmp_16 * m4Get(mat,0,2) + tmp_21 * m4Get(mat,1,2)) -
+ (tmp_20 * m4Get(mat,1,2) + tmp_23 * m4Get(mat,2,2) + tmp_17 * m4Get(mat,0,2)));
+
+ mat[0*4+0] = out_00;
+ mat[0*4+1] = out_01;
+ mat[0*4+2] = out_02;
+ mat[0*4+3] = out_03;
+ mat[1*4+0] = out_10;
+ mat[1*4+1] = out_11;
+ mat[1*4+2] = out_12;
+ mat[1*4+3] = out_13;
+ mat[2*4+0] = out_20;
+ mat[2*4+1] = out_21;
+ mat[2*4+2] = out_22;
+ mat[2*4+3] = out_23;
+ mat[3*4+0] = out_30;
+ mat[3*4+1] = out_31;
+ mat[3*4+2] = out_32;
+ mat[3*4+3] = out_33;
+ return mat;
+}
+
+/* Puts the inverse of other matrix into mat */
+float *
+m4Inverse (float *mat, const float *other) {
+ m4Copy (mat, other);
+ m4Invert (mat);
+ return mat;
+}
+
+/* In-place transpose */
+float *
+m4Transpose (float *mat) {
+ float tmp = mat[0*4+1];
+ mat[0*4+1] = mat[1*4+0];
+ mat[1*4+0] = tmp;
+
+ tmp = mat[0*4+2];
+ mat[0*4+2] = mat[2*4+0];
+ mat[2*4+0] = tmp;
+
+ tmp = mat[0*4+3];
+ mat[0*4+3] = mat[3*4+0];
+ mat[3*4+0] = tmp;
+
+ tmp = mat[1*4+2];
+ mat[1*4+2] = mat[2*4+1];
+ mat[2*4+1] = tmp;
+
+ tmp = mat[1*4+3];
+ mat[1*4+3] = mat[3*4+1];
+ mat[3*4+1] = tmp;
+
+ tmp = mat[2*4+3];
+ mat[2*4+3] = mat[3*4+2];
+ mat[3*4+2] = tmp;
+
+ return mat;
+}
+
+float *
+m4ApplyToVect (float *mat, float *vec)
+{
+ float tmp[4] = {vec[0], vec[1], vec[2], vec[3]};
+
+ vec[0] = mat[0]*tmp[0] + mat[4]*tmp[1] + mat[8]*tmp[2] + mat[12]*tmp[3];
+ vec[1] = mat[1]*tmp[0] + mat[5]*tmp[1] + mat[9]*tmp[2] + mat[13]*tmp[3];
+ vec[2] = mat[2]*tmp[0] + mat[6]*tmp[1] + mat[10]*tmp[2] + mat[14]*tmp[3];
+ vec[3] = mat[3]*tmp[0] + mat[7]*tmp[1] + mat[11]*tmp[2] + mat[15]*tmp[3];
+
+ return vec;
+}
+
+#ifdef TEST
+
+#include <stdio.h>
+
+static void setvec (float *vec, float x, float y, float z, float w)
+{
+ vec[0] = x;
+ vec[1] = y;
+ vec[2] = z;
+ vec[3] = w;
+}
+
+static void printmat (float *mat)
+{
+ printf("(%f,%f,%f,%f,\n", mat[0], mat[1], mat[2], mat[3]);
+ printf(" %f,%f,%f,%f,\n", mat[4], mat[5], mat[6], mat[7]);
+ printf(" %f,%f,%f,%f,\n", mat[8], mat[9], mat[10], mat[11]);
+ printf(" %f,%f,%f,%f)\n", mat[12], mat[13], mat[14], mat[15]);
+}
+
+static void printvec (float *vec)
+{
+ printf("(%f,%f,%f,%f)\n", vec[0], vec[1], vec[2], vec[3]);
+}
+
+int main(int argc, char **argv)
+{
+ float mat[16];
+ float vec[4];
+
+ setvec (vec, 1, 2, 3, 1);
+ printf ("vec:\n");
+ printvec (vec);
+
+ m4LoadIdentity (mat);
+ printf ("Identity matrix:\n");
+ printmat (mat);
+
+ m4Scale (mat, 2, 2, 2);
+ printf ("Scale by 2:\n");
+ printmat (mat);
+
+ m4LoadIdentity (mat);
+ m4Translate (mat, 2, 3, 0);
+ printf ("Translate by (2,3,0):\n");
+ printmat (mat);
+
+ printf ("Apply that to vec:\n");
+ m4ApplyToVect (mat, vec);
+ printvec (vec);
+
+ m4LoadIdentity (mat);
+ m4Scale (mat, 2, 2, 2);
+ m4ApplyToVect (mat, vec);
+ printf ("Scale then by 2:\n");
+ printvec (vec);
+
+ setvec (vec, 1, 2, 3, 1);
+ m4LoadIdentity (mat);
+ m4Scale (mat, 2, 2, 2);
+ m4Translate (mat, 2, 3, 0);
+ m4ApplyToVect (mat, vec);
+ printf ("Both in one step:\n");
+ printvec (vec);
+
+ return 0;
+}
+
+#endif
diff --git a/vcl/inc/glyphy/demo.hxx b/vcl/inc/glyphy/demo.hxx
new file mode 100644
index 000000000000..2323186764cf
--- /dev/null
+++ b/vcl/inc/glyphy/demo.hxx
@@ -0,0 +1,21 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_VCL_INC_GLYPHY_DEMO_HXX
+#define INCLUDED_VCL_INC_GLYPHY_DEMO_HXX
+
+namespace GLyphyDemo {
+#include "demo-atlas.h"
+#include "demo-buffer.h"
+#include "demo-font.h"
+#include "demo-shader.h"
+#include "matrix4x4.h"
+}
+
+#endif // INCLUDED_VCL_INC_GLYPHY_DEMO_HXX
diff --git a/vcl/inc/glyphy/demo/demo-atlas-glsl.h b/vcl/inc/glyphy/demo/demo-atlas-glsl.h
new file mode 100644
index 000000000000..9b93c2ab129f
--- /dev/null
+++ b/vcl/inc/glyphy/demo/demo-atlas-glsl.h
@@ -0,0 +1,18 @@
+static const char *demo_atlas_glsl =
+"uniform sampler2D u_atlas_tex;\n"
+"uniform ivec4 u_atlas_info;\n"
+"\n"
+"#define GLYPHY_TEXTURE1D_EXTRA_DECLS , sampler2D _tex, ivec4 _atlas_info, ivec2 _atlas_pos\n"
+"#define GLYPHY_TEXTURE1D_EXTRA_ARGS , _tex, _atlas_info, _atlas_pos\n"
+"#define GLYPHY_DEMO_EXTRA_ARGS , u_atlas_tex, u_atlas_info, gi.atlas_pos\n"
+"\n"
+"vec4\n"
+"glyphy_texture1D_func (int offset GLYPHY_TEXTURE1D_EXTRA_DECLS)\n"
+"{\n"
+" ivec2 item_geom = _atlas_info.zw;\n"
+" vec2 pos = (vec2 (_atlas_pos.xy * item_geom +\n"
+" ivec2 (mod (float (offset), float (item_geom.x)), offset / item_geom.x)) +\n"
+" + vec2 (.5, .5)) / vec2(_atlas_info.xy);\n"
+" return texture2D (_tex, pos);\n"
+"}\n"
+;
diff --git a/vcl/inc/glyphy/demo/demo-atlas.h b/vcl/inc/glyphy/demo/demo-atlas.h
new file mode 100644
index 000000000000..729403f472fa
--- /dev/null
+++ b/vcl/inc/glyphy/demo/demo-atlas.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2012 Google, Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Google Author(s): Behdad Esfahbod, Maysum Panju
+ */
+
+#ifndef DEMO_ATLAS_H
+#define DEMO_ATLAS_H
+
+#include "demo-common.h"
+
+
+typedef struct demo_atlas_t demo_atlas_t;
+
+demo_atlas_t *
+demo_atlas_create (unsigned int w,
+ unsigned int h,
+ unsigned int item_w,
+ unsigned int item_h_quantum);
+
+demo_atlas_t *
+demo_atlas_reference (demo_atlas_t *at);
+
+void
+demo_atlas_destroy (demo_atlas_t *at);
+
+
+void
+demo_atlas_alloc (demo_atlas_t *at,
+ glyphy_rgba_t *data,
+ unsigned int len,
+ unsigned int *px,
+ unsigned int *py);
+
+void
+demo_atlas_bind_texture (demo_atlas_t *at);
+
+void
+demo_atlas_set_uniforms (demo_atlas_t *at);
+
+
+#endif /* DEMO_ATLAS_H */
diff --git a/vcl/inc/glyphy/demo/demo-buffer.h b/vcl/inc/glyphy/demo/demo-buffer.h
new file mode 100644
index 000000000000..2948a7ff0a04
--- /dev/null
+++ b/vcl/inc/glyphy/demo/demo-buffer.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2012 Google, Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef DEMO_BUFFER_H
+#define DEMO_BUFFER_H
+
+#include "demo-common.h"
+#include "demo-font.h"
+#include "demo-shader.h"
+
+typedef struct demo_buffer_t demo_buffer_t;
+
+demo_buffer_t *
+demo_buffer_create (void);
+
+demo_buffer_t *
+demo_buffer_reference (demo_buffer_t *buffer);
+
+void
+demo_buffer_destroy (demo_buffer_t *buffer);
+
+
+void
+demo_buffer_clear (demo_buffer_t *buffer);
+
+void
+demo_buffer_extents (demo_buffer_t *buffer,
+ glyphy_extents_t *ink_extents,
+ glyphy_extents_t *logical_extents);
+
+void
+demo_buffer_move_to (demo_buffer_t *buffer,
+ const glyphy_point_t *p);
+
+void
+demo_buffer_current_point (demo_buffer_t *buffer,
+ glyphy_point_t *p);
+
+void
+demo_buffer_add_text (demo_buffer_t *buffer,
+ const char *utf8,
+ demo_font_t *font,
+ double font_size);
+
+void
+demo_buffer_draw (demo_buffer_t *buffer);
+
+
+#endif /* DEMO_BUFFER_H */
diff --git a/vcl/inc/glyphy/demo/demo-common.h b/vcl/inc/glyphy/demo/demo-common.h
new file mode 100644
index 000000000000..380942f82297
--- /dev/null
+++ b/vcl/inc/glyphy/demo/demo-common.h
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2012 Google, Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Google Author(s): Behdad Esfahbod, Maysum Panju
+ */
+
+#ifndef DEMO_COMMON_H
+#define DEMO_COMMON_H
+
+#include <glyphy.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+#include <assert.h>
+
+#include <algorithm>
+#include <vector>
+
+/* Tailor config for various platforms. */
+
+#ifdef EMSCRIPTEN
+/* https://github.com/kripken/emscripten/issues/340 */
+# undef HAVE_GLEW
+ /* WebGL shaders are ES2 */
+# define GL_ES_VERSION_2_0 1
+#endif
+
+#if defined(__ANDROID__)
+# define HAVE_GLES2 1
+# define HAVE_GLUT 1
+#endif
+
+#ifdef _WIN32
+# define HAVE_GL 1
+# define HAVE_GLEW 1
+#endif
+
+/* Get Glew out of the way. */
+#ifdef HAVE_GLEW
+# include <GL/glew.h>
+#else
+# define GLEW_OK 0
+ static inline int glewInit (void) { return GLEW_OK; }
+ static inline int glewIsSupported (const char *s)
+ { return 0 == strcmp ("GL_VERSION_2_0", s); }
+#endif /* HAVE_GLEW */
+
+/* WTF this block?! */
+#if defined(HAVE_GLES2)
+# include <GLES2/gl2.h>
+#elif defined(HAVE_GL)
+# ifndef HAVE_GLEW
+# define GL_GLEXT_PROTOTYPES 1
+# if defined(__APPLE__)
+# include <OpenGL/gl.h>
+# else
+# include <GL/gl.h>
+# endif
+# endif
+# if defined(__APPLE__)
+# include <OpenGL/OpenGL.h>
+# else
+# ifdef HAVE_GLEW
+# ifdef _WIN32
+# include <GL/wglew.h>
+# else
+# include <GL/glxew.h>
+# endif
+# endif
+# endif
+#endif /* HAVE_GL */
+
+/* Finally, Glut. */
+#ifdef HAVE_GLUT
+# if defined(__APPLE__)
+# include <GLUT/glut.h>
+# else
+# include <GL/glut.h>
+# endif
+#endif
+
+
+
+
+/* Logging. */
+#ifdef __ANDROID__
+# include <android/log.h>
+# define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "glyphy-demo", __VA_ARGS__))
+# define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "glyphy-demo", __VA_ARGS__))
+# define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "glyphy-demo", __VA_ARGS__))
+#else /* !__ANDROID__ */
+#if 0
+# define LOGI(...) ((void) fprintf (stderr, __VA_ARGS__))
+# define LOGW(...) ((void) fprintf (stderr, __VA_ARGS__))
+# define LOGE(...) ((void) fprintf (stderr, __VA_ARGS__), abort ())
+#else
+# define LOGI(...) do { } while(false)
+# define LOGW(...) do { } while(false)
+# define LOGE(...) do { } while(false)
+#endif
+#endif
+
+
+
+#define STRINGIZE1(Src) #Src
+#define STRINGIZE(Src) STRINGIZE1(Src)
+
+#define ARRAY_LEN(Array) (sizeof (Array) / sizeof (*Array))
+
+
+#define MIN_FONT_SIZE 10
+#define TOLERANCE (1./2048)
+
+
+#define gl(name) \
+ for (GLint __ee, __ii = 0; \
+ __ii < 1; \
+ (__ii++, \
+ (__ee = glGetError()) && \
+ (reportGLerror (__ee, #name, __LINE__, __FILE__), 0))) \
+ gl##name
+
+
+static inline void
+reportGLerror(GLint e, const char *api, int line, const char *file)
+{
+ fflush(stdout);
+ fprintf(stderr, "\nwglGetCurrentDC=%p wglGetCurrentContext=%p\n", wglGetCurrentDC(), wglGetCurrentContext());
+ fprintf (stderr, "gl%s failed with error %04X on %s:%d\n", api, e, file, line);
+ fflush (stderr);
+ exit (1);
+}
+
+static inline void
+die (const char *msg)
+{
+ fprintf (stderr, "%s\n", msg);
+ exit (1);
+}
+
+template <typename T>
+T clamp (T v, T m, T M)
+{
+ return v < m ? m : v > M ? M : v;
+}
+
+
+#if defined(_MSC_VER)
+#define DEMO_FUNC __FUNCSIG__
+#else
+#define DEMO_FUNC __func__
+#endif
+
+struct auto_trace_t
+{
+ auto_trace_t (const char *func_) : func (func_)
+ { printf ("Enter: %s\n", func); }
+
+ ~auto_trace_t (void)
+ { printf ("Leave: %s\n", func); }
+
+ private:
+ const char * const func;
+};
+
+#if 0
+#define TRACE() auto_trace_t trace(DEMO_FUNC)
+#else
+#define TRACE() do { } while(false)
+#endif
+
+#endif /* DEMO_COMMON_H */
diff --git a/vcl/inc/glyphy/demo/demo-font.h b/vcl/inc/glyphy/demo/demo-font.h
new file mode 100644
index 000000000000..d4e75ff3f2d6
--- /dev/null
+++ b/vcl/inc/glyphy/demo/demo-font.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2012 Google, Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef DEMO_FONT_H
+#define DEMO_FONT_H
+
+#include "demo-common.h"
+#include "demo-atlas.h"
+
+#ifndef _WIN32
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#endif
+
+#ifdef _WIN32
+#include <windows.h>
+#define DEFAULT_FONT "Calibri"
+#undef near
+#undef far
+#endif
+
+typedef struct {
+ glyphy_extents_t extents;
+ double advance;
+ glyphy_bool_t is_empty; /* has no outline; eg. space; don't draw it */
+ unsigned int nominal_w;
+ unsigned int nominal_h;
+ unsigned int atlas_x;
+ unsigned int atlas_y;
+} glyph_info_t;
+
+
+typedef struct demo_font_t demo_font_t;
+
+demo_font_t *
+demo_font_create (
+#ifndef _WIN32
+ FT_Face face,
+#endif
+#ifdef _WIN32
+ HDC hdc,
+#endif
+ demo_atlas_t *atlas);
+
+demo_font_t *
+demo_font_reference (demo_font_t *font);
+
+void
+demo_font_destroy (demo_font_t *font);
+
+
+#ifndef _WIN32
+FT_Face
+#endif
+#ifdef _WIN32
+HDC
+#endif
+demo_font_get_face (demo_font_t *font);
+
+demo_atlas_t *
+demo_font_get_atlas (demo_font_t *font);
+
+
+void
+demo_font_lookup_glyph (demo_font_t *font,
+ unsigned int glyph_index,
+ glyph_info_t *glyph_info);
+
+void
+demo_font_print_stats (demo_font_t *font);
+
+
+#endif /* DEMO_FONT_H */
diff --git a/vcl/inc/glyphy/demo/demo-fshader-glsl.h b/vcl/inc/glyphy/demo/demo-fshader-glsl.h
new file mode 100644
index 000000000000..d80a6cc82b26
--- /dev/null
+++ b/vcl/inc/glyphy/demo/demo-fshader-glsl.h
@@ -0,0 +1,88 @@
+static const char *demo_fshader_glsl =
+"uniform float u_contrast;\n"
+"uniform float u_gamma_adjust;\n"
+"uniform float u_outline_thickness;\n"
+"uniform bool u_outline;\n"
+"uniform float u_boldness;\n"
+"uniform bool u_debug;\n"
+"\n"
+"varying vec4 v_glyph;\n"
+"\n"
+"\n"
+"#define SQRT2_2 0.70710678118654757 /* 1 / sqrt(2.) */\n"
+"#define SQRT2 1.4142135623730951\n"
+"\n"
+"struct glyph_info_t {\n"
+" ivec2 nominal_size;\n"
+" ivec2 atlas_pos;\n"
+"};\n"
+"\n"
+"glyph_info_t\n"
+"glyph_info_decode (vec4 v)\n"
+"{\n"
+" glyph_info_t gi;\n"
+" gi.nominal_size = (ivec2 (mod (v.zw, 256.)) + 2) / 4;\n"
+" gi.atlas_pos = ivec2 (v_glyph.zw) / 256;\n"
+" return gi;\n"
+"}\n"
+"\n"
+"\n"
+"float\n"
+"antialias (float d)\n"
+"{\n"
+" return smoothstep (-.75, +.75, d);\n"
+"}\n"
+"\n"
+"vec4\n"
+"source_over (const vec4 src, const vec4 dst)\n"
+"{\n"
+" // http://dev.w3.org/fxtf/compositing-1/#porterduffcompositingoperators_srcover\n"
+" float alpha = src.a + (dst.a * (1. - src.a));\n"
+" return vec4 (((src.rgb * src.a) + (dst.rgb * dst.a * (1. - src.a))) / alpha, alpha);\n"
+"}\n"
+"\n"
+"void\n"
+"main()\n"
+"{\n"
+" vec2 p = v_glyph.xy;\n"
+" glyph_info_t gi = glyph_info_decode (v_glyph);\n"
+"\n"
+" /* isotropic antialiasing */\n"
+" vec2 dpdx = dFdx (p);\n"
+" vec2 dpdy = dFdy (p);\n"
+" float m = length (vec2 (length (dpdx), length (dpdy))) * SQRT2_2;\n"
+"\n"
+" vec4 color = vec4 (0,0,0,1);\n"
+"\n"
+" float gsdist = glyphy_sdf (p, gi.nominal_size GLYPHY_DEMO_EXTRA_ARGS);\n"
+" float sdist = gsdist / m * u_contrast;\n"
+"\n"
+" if (!u_debug) {\n"
+" sdist -= u_boldness * 10.;\n"
+" if (u_outline)\n"
+" sdist = abs (sdist) - u_outline_thickness * .5;\n"
+" if (sdist > 1.)\n"
+" discard;\n"
+" float alpha = antialias (-sdist);\n"
+" if (u_gamma_adjust != 1.)\n"
+" alpha = pow (alpha, 1./u_gamma_adjust);\n"
+" color = vec4 (color.rgb,color.a * alpha);\n"
+" } else {\n"
+" float gudist = abs (gsdist);\n"
+" float debug_color = 0.4;\n"
+" // Color the distance field red inside and green outside\n"
+" if (!glyphy_isinf (gudist))\n"
+" color = source_over (vec4 (debug_color * smoothstep (1., -1., sdist), debug_color * smoothstep (-1., 1., sdist), 0, 1. - gudist), color);\n"
+"\n"
+" glyphy_arc_list_t arc_list = glyphy_arc_list (p, gi.nominal_size GLYPHY_DEMO_EXTRA_ARGS);\n"
+" // Color the number of endpoints per cell blue\n"
+" color = source_over (vec4 (0, 0, debug_color, float(arc_list.num_endpoints) / float(GLYPHY_MAX_NUM_ENDPOINTS)), color);\n"
+"\n"
+" float pdist = glyphy_point_dist (p, gi.nominal_size GLYPHY_DEMO_EXTRA_ARGS);\n"
+" // Color points yellow\n"
+" color = source_over (vec4 (1, 1, 0, smoothstep (.06, .05, pdist)), color);\n"
+" }\n"
+"\n"
+" gl_FragColor = color;\n"
+"}\n"
+;
diff --git a/vcl/inc/glyphy/demo/demo-shader.h b/vcl/inc/glyphy/demo/demo-shader.h
new file mode 100644
index 000000000000..dfa548091039
--- /dev/null
+++ b/vcl/inc/glyphy/demo/demo-shader.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2012 Google, Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef DEMO_SHADERS_H
+#define DEMO_SHADERS_H
+
+#include "demo-common.h"
+#include "demo-font.h"
+
+
+struct glyph_vertex_t {
+ /* Position */
+ GLfloat x;
+ GLfloat y;
+ /* Glyph info */
+ GLfloat g16hi;
+ GLfloat g16lo;
+};
+
+void
+demo_shader_add_glyph_vertices (const glyphy_point_t &p,
+ double font_size,
+ glyph_info_t *gi,
+ std::vector<glyph_vertex_t> *vertices,
+ glyphy_extents_t *extents);
+
+
+GLuint
+demo_shader_create_program (void);
+
+
+#endif /* DEMO_SHADERS_H */
diff --git a/vcl/inc/glyphy/demo/demo-vshader-glsl.h b/vcl/inc/glyphy/demo/demo-vshader-glsl.h
new file mode 100644
index 000000000000..c952ab719b2c
--- /dev/null
+++ b/vcl/inc/glyphy/demo/demo-vshader-glsl.h
@@ -0,0 +1,24 @@
+static const char *demo_vshader_glsl =
+"uniform mat4 u_matViewProjection;\n"
+"\n"
+"attribute vec4 a_glyph_vertex;\n"
+"\n"
+"varying vec4 v_glyph;\n"
+"\n"
+"vec4\n"
+"glyph_vertex_transcode (vec2 v)\n"
+"{\n"
+" ivec2 g = ivec2 (v);\n"
+" ivec2 corner = ivec2 (mod (v, 2.));\n"
+" g /= 2;\n"
+" ivec2 nominal_size = ivec2 (mod (vec2(g), 64.));\n"
+" return vec4 (corner * nominal_size, g * 4);\n"
+"}\n"
+"\n"
+"void\n"
+"main()\n"
+"{\n"
+" gl_Position = u_matViewProjection * vec4 (a_glyph_vertex.xy, 0, 1);\n"
+" v_glyph = glyph_vertex_transcode (a_glyph_vertex.zw);\n"
+"}\n"
+;
diff --git a/vcl/inc/glyphy/demo/matrix4x4.h b/vcl/inc/glyphy/demo/matrix4x4.h
new file mode 100644
index 000000000000..2169561007e3
--- /dev/null
+++ b/vcl/inc/glyphy/demo/matrix4x4.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2009, Mozilla Corp
+ * Copyright (c) 2012, Google, 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:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of the <organization> 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 <copyright holder> ''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 <copyright holder> 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.
+ */
+
+/*
+ * Based on sample code from the OpenGL(R) ES 2.0 Programming Guide, which carriers
+ * the following header:
+ *
+ * Book: OpenGL(R) ES 2.0 Programming Guide
+ * Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner
+ * ISBN-10: 0321502795
+ * ISBN-13: 9780321502797
+ * Publisher: Addison-Wesley Professional
+ * URLs: http://safari.informit.com/9780321563835
+ * http://www.opengles-book.com
+ */
+
+/*
+ * Ported from JavaScript to C by Behdad Esfahbod, 2012.
+ * Added MultMatrix. Converting from fixed-function OpenGL matrix
+ * operations to these functions should be as simple as renaming the
+ * 'gl' prefix to 'm4' and adding the matrix argument to the call.
+ *
+ * The C version lives at http://code.google.com/p/matrix4x4-c/
+ */
+
+/*
+ * A simple 4x4 matrix utility implementation
+ */
+
+#ifndef MATRIX4x4_H
+#define MATRIX4x4_H
+
+/* Copies other matrix into mat */
+float *
+m4Copy (float *mat, const float *other);
+
+float *
+m4Multiply (float *mat, const float *right);
+
+float *
+m4MultMatrix (float *mat, const float *left);
+
+float
+m4Get (float *mat, unsigned int row, unsigned int col);
+
+float *
+m4Scale (float *mat, float sx, float sy, float sz);
+
+float *
+m4Translate (float *mat, float tx, float ty, float tz);
+
+float *
+m4Rotate (float *mat, float angle, float x, float y, float z);
+
+float *
+m4Frustum (float *mat, float left, float right, float bottom, float top, float nearZ, float farZ);
+
+float *
+m4Perspective (float *mat, float fovy, float aspect, float nearZ, float farZ);
+
+float *
+m4Ortho (float *mat, float left, float right, float bottom, float top, float nearZ, float farZ);
+
+/* In-place inversion */
+float *
+m4Invert (float *mat);
+
+/* Puts the inverse of other matrix into mat */
+float *
+m4Inverse (float *mat, const float *other);
+
+/* In-place transpose */
+float *
+m4Transpose (float *mat);
+
+float *
+m4LoadIdentity (float *mat);
+
+float *
+m4ApplyToVect (float *mat, float *vec);
+
+#endif
diff --git a/vcl/win/source/gdi/winlayout.cxx b/vcl/win/source/gdi/winlayout.cxx
index 2409d4b36303..5ae2ce4b4722 100644
--- a/vcl/win/source/gdi/winlayout.cxx
+++ b/vcl/win/source/gdi/winlayout.cxx
@@ -33,6 +33,7 @@
#include "sft.hxx"
#include "sallayout.hxx"
+#include "glyphy/demo.hxx"
#include <cstdio>
#include <cstdlib>
@@ -46,8 +47,6 @@
#include <unordered_map>
-typedef std::unordered_map<int,int> IntMap;
-
// Graphite headers
#include <config_graphite.h>
#if ENABLE_GRAPHITE
@@ -67,33 +66,13 @@ const int GLYPH_SPACE_RATIO = 8;
const int GLYPH_OFFSET_RATIO = GLYPH_SPACE_RATIO * 2;
}
-struct OpenGLGlyphCacheChunk
-{
- WORD mnFirstGlyph;
- int mnGlyphCount;
- std::vector<Rectangle> maLocation;
- std::shared_ptr<OpenGLTexture> mpTexture;
- int mnAscent;
- int mnHeight;
- bool mbVertical;
-
- int getExtraSpace() const
- {
- return std::max(mnHeight / GLYPH_SPACE_RATIO, 4);
- }
-
- int getExtraOffset() const
- {
- return std::max(mnHeight / GLYPH_OFFSET_RATIO, 2);
- }
-};
-
// win32 specific physical font instance
class ImplWinFontEntry : public ImplFontEntry
{
public:
explicit ImplWinFontEntry( FontSelectPattern& );
virtual ~ImplWinFontEntry();
+ void setupGLyphy(HDC hDC);
private:
// TODO: also add HFONT??? Watch out for issues with too many active fonts...
@@ -103,162 +82,31 @@ public:
{ return maScriptCache; }
private:
mutable SCRIPT_CACHE maScriptCache;
- std::vector<OpenGLGlyphCacheChunk> maOpenGLGlyphCache;
public:
- int GetCachedGlyphWidth( int nCharCode ) const;
- void CacheGlyphWidth( int nCharCode, int nCharWidth );
-
bool InitKashidaHandling( HDC );
int GetMinKashidaWidth() const { return mnMinKashidaWidth; }
int GetMinKashidaGlyph() const { return mnMinKashidaGlyph; }
+ static GLuint mnGLyphyProgram;
+ GLyphyDemo::demo_atlas_t* mpGLyphyAtlas;
+ GLyphyDemo::demo_font_t* mpGLyphyFont;
+
private:
- IntMap maWidthMap;
mutable int mnMinKashidaWidth;
mutable int mnMinKashidaGlyph;
-
-public:
- bool GlyphIsCached(int nGlyphIndex) const;
- bool AddChunkOfGlyphs(int nGlyphIndex, const WinLayout& rLayout, SalGraphics& rGraphics);
- const OpenGLGlyphCacheChunk& GetCachedGlyphChunkFor(int nGlyphIndex) const;
+ bool mbGLyphySetupCalled;
};
-#ifdef SAL_LOG_INFO
-
-namespace {
-
-char ColorFor(COLORREF aColor)
-{
- if (aColor == RGB(0xFF, 0xFF, 0xFF))
- return ' ';
- else if (aColor == RGB(0x00, 0x00, 0x00))
- return 'X';
-
- return '0' + (10*(GetRValue(aColor) + GetGValue(aColor) + GetBValue(aColor))) / (0xFF*3);
-}
-
-void DumpGlyphBitmap(HDC hDC)
-{
- HBITMAP hBitmap = static_cast<HBITMAP>(GetCurrentObject(hDC, OBJ_BITMAP));
- if (hBitmap == NULL)
- {
- SAL_WARN("vcl.gdi", "GetCurrentObject failed: " << WindowsErrorString(GetLastError()));
- return;
- }
-
- BITMAP aBitmap;
- if (!GetObjectW(hBitmap, sizeof(aBitmap), &aBitmap))
- {
- SAL_WARN("vcl.gdi", "GetObjectW failed: " << WindowsErrorString(GetLastError()));
- return;
- }
-
- SAL_INFO("vcl.gdi.opengl", "Bitmap " << hBitmap << ": " << aBitmap.bmWidth << "x" << aBitmap.bmHeight << ":");
-
- std::ostringstream sLine("\n");
- for (long y = 0; y < aBitmap.bmHeight; y++)
- {
- for (long x = 0; x < std::min(75l, aBitmap.bmWidth); x++)
- sLine << ColorFor(GetPixel(hDC, x, y));
- if (y < aBitmap.bmHeight - 1)
- sLine << "\n";
- }
- SAL_INFO("vcl.gdi.opengl", sLine.str());
-}
-
-} // anonymous namespace
-
-#endif // SAL_LOG_INFO
-
-template< typename charT, typename traits >
-inline std::basic_ostream<charT, traits> & operator <<(
- std::basic_ostream<charT, traits> & stream, const std::vector<OpenGLGlyphCacheChunk>& rCache )
-{
- stream << "{";
- for (auto i = rCache.cbegin(); i != rCache.cend(); ++i)
- {
- stream << "[" << i->mnFirstGlyph;
- if (i->mnGlyphCount > 1)
- stream << ".." << (i->mnFirstGlyph + i->mnGlyphCount - 1);
- stream << "]";
- if (i+1 != rCache.cend())
- {
- stream << ",";
- assert(i->mnFirstGlyph + i->mnGlyphCount <= (i+1)->mnFirstGlyph);
- }
- }
-
- return stream << "}";
-}
-
-inline void ImplWinFontEntry::CacheGlyphWidth( int nCharCode, int nCharWidth )
-{
- maWidthMap[ nCharCode ] = nCharWidth;
-}
-
-inline int ImplWinFontEntry::GetCachedGlyphWidth( int nCharCode ) const
-{
- IntMap::const_iterator it = maWidthMap.find( nCharCode );
- if( it == maWidthMap.end() )
- return -1;
- return it->second;
-}
-
-bool ImplWinFontEntry::GlyphIsCached(int nGlyphIndex) const
-{
- if (nGlyphIndex == DROPPED_OUTGLYPH)
- return true;
-
- for (size_t i = 0; i < maOpenGLGlyphCache.size(); i++)
- if (nGlyphIndex >= maOpenGLGlyphCache[i].mnFirstGlyph &&
- nGlyphIndex < maOpenGLGlyphCache[i].mnFirstGlyph + maOpenGLGlyphCache[i].mnGlyphCount)
- return true;
+GLuint ImplWinFontEntry::mnGLyphyProgram = 0;
- return false;
-}
+#if 0
-bool ImplWinFontEntry::AddChunkOfGlyphs(int nGlyphIndex, const WinLayout& rLayout, SalGraphics& rGraphics)
+bool ImplWinFontEntry::AddGlyphToCache(WORD nGlyphIndex, const WinLayout& rLayout, SalGraphics& rGraphics)
{
- const int DEFAULT_CHUNK_SIZE = 20;
-
if (nGlyphIndex == DROPPED_OUTGLYPH)
return true;
- SAL_INFO("vcl.gdi.opengl", "this=" << this << " " << nGlyphIndex << " old: " << maOpenGLGlyphCache);
-
- auto n = maOpenGLGlyphCache.begin();
- while (n != maOpenGLGlyphCache.end() &&
- nGlyphIndex > n->mnFirstGlyph)
- ++n;
- assert(n == maOpenGLGlyphCache.end() || nGlyphIndex < n->mnFirstGlyph);
-
- int nCount = DEFAULT_CHUNK_SIZE;
- if (n != maOpenGLGlyphCache.end() && nGlyphIndex + nCount >= n->mnFirstGlyph)
- nCount = n->mnFirstGlyph - nGlyphIndex;
-
- if (nCount < DEFAULT_CHUNK_SIZE)
- {
- if (n == maOpenGLGlyphCache.begin())
- {
- nGlyphIndex = std::max(0, n->mnFirstGlyph - DEFAULT_CHUNK_SIZE);
- }
- else
- {
- nGlyphIndex = std::max(n[-1].mnFirstGlyph + n[-1].mnGlyphCount,
- n->mnFirstGlyph - DEFAULT_CHUNK_SIZE);
- }
- nCount = n->mnFirstGlyph - nGlyphIndex;
- }
-
- OpenGLGlyphCacheChunk aChunk;
- aChunk.mnFirstGlyph = nGlyphIndex;
- aChunk.mnGlyphCount = nCount;
-
- std::vector<WORD> aGlyphIndices(nCount);
- for (int i = 0; i < nCount; i++)
- aGlyphIndices[i] = nGlyphIndex + i;
-
HDC hDC = CreateCompatibleDC(rLayout.mhDC);
if (hDC == NULL)
{
@@ -275,7 +123,7 @@ bool ImplWinFontEntry::AddChunkOfGlyphs(int nGlyphIndex, const WinLayout& rLayou
SIZE aSize;
- if (!GetTextExtentExPointI(hDC, aGlyphIndices.data(), nCount, 0, NULL, NULL, &aSize))
+ if (!GetTextExtentExPointI(hDC, &nGlyphIndex, 1, 0, NULL, NULL, &aSize))
{
SAL_WARN("vcl.gdi", "GetTextExtentExPointI failed: " << WindowsErrorString(GetLastError()));
SelectObject(hDC, hOrigFont);
@@ -283,8 +131,8 @@ bool ImplWinFontEntry::AddChunkOfGlyphs(int nGlyphIndex, const WinLayout& rLayou
return false;
}
- std::vector<ABC> aABC(nCount);
- if (!GetCharABCWidthsI(hDC, 0, nCount, aGlyphIndices.data(), aABC.data()))
+ ABC aABC;
+ if (!GetCharABCWidthsI(hDC, 0, 1, &nGlyphIndex, &aABC))
{
SAL_WARN("vcl.gdi", "GetCharABCWidthsI failed: " << WindowsErrorString(GetLastError()));
SelectObject(hDC, hOrigFont);
@@ -292,10 +140,7 @@ bool ImplWinFontEntry::AddChunkOfGlyphs(int nGlyphIndex, const WinLayout& rLayou
return false;
}
- std::ostringstream sLine;
- for (int i = 0; i < nCount; i++)
- sLine << aABC[i].abcA << ":" << aABC[i].abcB << ":" << aABC[i].abcC << " ";
- SAL_INFO("vcl.gdi.opengl", "ABC widths: " << sLine.str());
+ SAL_INFO("vcl.gdi.opengl", "ABC width: " << aABC.abcA << ":" << aABC.abcB << ":" << aABC.abcC);
TEXTMETRICW aTextMetric;
if (!GetTextMetricsW(hDC, &aTextMetric))
@@ -305,25 +150,6 @@ bool ImplWinFontEntry::AddChunkOfGlyphs(int nGlyphIndex, const WinLayout& rLayou
DeleteDC(hDC);
return false;
}
- aChunk.mnAscent = aTextMetric.tmAscent;
- aChunk.mnHeight = aTextMetric.tmHeight;
-
- // Try hard to avoid overlap as we want to be able to use
- // individual rectangles for each glyph. The ABC widths don't
- // take anti-aliasing into consideration. Let's hope that leaving
- // "extra" space inbetween glyphs will help.
- std::vector<int> aDX(nCount);
- int totWidth = 0;
- for (int i = 0; i < nCount; i++)
- {
- aDX[i] = aABC[i].abcB + std::abs(aABC[i].abcC);
- if (i == 0)
- aDX[0] += std::abs(aABC[0].abcA);
- if (i < nCount-1)
- aDX[i] += std::abs(aABC[i+1].abcA);
- aDX[i] += aChunk.getExtraSpace();
- totWidth += aDX[i];
- }
LOGFONTW aLogfont;
if (!GetObjectW(rLayout.mhFont, sizeof(aLogfont), &aLogfont))
@@ -349,120 +175,73 @@ bool ImplWinFontEntry::AddChunkOfGlyphs(int nGlyphIndex, const WinLayout& rLayou
" Orientation=" << aLogfont.lfOrientation <<
" Ascent=" << aTextMetric.tmAscent <<
" InternalLeading=" << aTextMetric.tmInternalLeading <<
- " Size=(" << aSize.cx << "," << aSize.cy << ") totWidth=" << totWidth);
+ " Size=(" << aSize.cx << "," << aSize.cy << ")");
if (SelectObject(hDC, hOrigFont) == NULL)
SAL_WARN("vcl.gdi", "SelectObject failed: " << WindowsErrorString(GetLastError()));
if (!DeleteDC(hDC))
SAL_WARN("vcl.gdi", "DeleteDC failed: " << WindowsErrorString(GetLastError()));
- // Leave extra space also at top and bottom
- int nBitmapWidth, nBitmapHeight;
- if (sFaceName[0] == '@')
- {
- nBitmapWidth = aSize.cy + aChunk.getExtraSpace();
- nBitmapHeight = totWidth;
- aChunk.mbVertical = true;
- }
- else
- {
- nBitmapWidth = totWidth;
- nBitmapHeight = aSize.cy + aChunk.getExtraSpace();
- aChunk.mbVertical = false;
- }
+ // FIXME HERE, in case this code snipet actually is needed any more?
- if (aChunk.mbVertical && aLogfont.lfEscapement != 2700)
- return false;
+ return true;
+}
- OpenGLCompatibleDC aDC(rGraphics, 0, 0, nBitmapWidth, nBitmapHeight);
+#endif
- HFONT hNonAntialiasedFont = NULL;
+void ImplWinFontEntry::setupGLyphy(HDC hDC)
+{
+ if (mbGLyphySetupCalled)
+ return;
-#ifdef DBG_UTIL
- static bool bNoAntialias = (std::getenv("VCL_GLYPH_CACHING_HACK_NO_ANTIALIAS") != NULL);
- if (bNoAntialias)
- {
- aLogfont.lfQuality = NONANTIALIASED_QUALITY;
- hNonAntialiasedFont = CreateFontIndirectW(&aLogfont);
- if (hNonAntialiasedFont == NULL)
- {
- SAL_WARN("vcl.gdi", "CreateFontIndirect failed: " << WindowsErrorString(GetLastError()));
- return false;
- }
- }
-#endif
+ mbGLyphySetupCalled = true;
- hOrigFont = SelectFont(aDC.getCompatibleHDC(), hNonAntialiasedFont != NULL ? hNonAntialiasedFont : rLayout.mhFont);
- if (hOrigFont == NULL)
+ // First get the OUTLINETEXTMETRIC to find the font's em unit. Then, to get an unmodified (not
+ // grid-fitted) glyph outline, create the font anew at that size. That is as the doc for
+ // GetGlyphOutline() suggests.
+ OUTLINETEXTMETRICW aOutlineTextMetric;
+ if (!GetOutlineTextMetricsW (hDC, sizeof (OUTLINETEXTMETRICW), &aOutlineTextMetric))
{
- SAL_WARN("vcl.gdi", "SelectObject failed: " << WindowsErrorString(GetLastError()));
- return false;
+ SAL_WARN("vcl.gdi.opengl", "GetOutlineTextMetricsW failed: " << WindowsErrorString(GetLastError()));
+ return;
}
- SetTextColor(aDC.getCompatibleHDC(), RGB(0, 0, 0));
- SetBkColor(aDC.getCompatibleHDC(), RGB(255, 255, 255));
-
- aDC.fill(MAKE_SALCOLOR(0xff, 0xff, 0xff));
+ HFONT hFont = (HFONT)GetCurrentObject(hDC, OBJ_FONT);
+ LOGFONTW aLogFont;
+ GetObjectW(hFont, sizeof(LOGFONTW), &aLogFont);
- int nY = aChunk.getExtraOffset();
- int nX = nY;
- if (aChunk.mbVertical)
- nX += aDX[0];
- if (!ExtTextOutW(aDC.getCompatibleHDC(), nX, nY, ETO_GLYPH_INDEX, NULL, aGlyphIndices.data(), nCount, aDX.data()))
+ HDC hNewDC = GetDC(NULL);
+ if (hNewDC == NULL)
{
- SAL_WARN("vcl.gdi", "ExtTextOutW failed: " << WindowsErrorString(GetLastError()));
- SelectFont(aDC.getCompatibleHDC(), hOrigFont);
- if (hNonAntialiasedFont != NULL)
- DeleteObject(hNonAntialiasedFont);
- return false;
+ SAL_WARN("vcl.gdi.opengl", "GetDC failed: " << WindowsErrorString(GetLastError()));
+ return;
}
- aChunk.maLocation.resize(nCount);
- UINT nPos = 0;
- for (int i = 0; i < nCount; i++)
+ hNewDC = CreateCompatibleDC(hNewDC);
+ if (hNewDC == NULL)
{
- if (aChunk.mbVertical)
- {
- aChunk.maLocation[i].Left() = 0;
- aChunk.maLocation[i].Right() = nBitmapWidth;
- aChunk.maLocation[i].Top() = nPos;
- aChunk.maLocation[i].Bottom() = nPos + aDX[i];
- nPos = aChunk.maLocation[i].Bottom();
- }
- else
- {
- aChunk.maLocation[i].Left() = nPos;
- aChunk.maLocation[i].Right() = nPos + aDX[i];
- nPos = aChunk.maLocation[i].Right();
- aChunk.maLocation[i].Top() = 0;
- aChunk.maLocation[i].Bottom() = aSize.cy + aChunk.getExtraSpace();
- }
+ SAL_WARN("vcl.gdi.opengl", "CreateCompatibleDC failed: " << WindowsErrorString(GetLastError()));
+ return;
}
- aChunk.mpTexture = std::unique_ptr<OpenGLTexture>(aDC.getTexture());
-
- maOpenGLGlyphCache.insert(n, aChunk);
-
- SelectFont(aDC.getCompatibleHDC(), hOrigFont);
- if (hNonAntialiasedFont != NULL)
- DeleteObject(hNonAntialiasedFont);
-
-#ifdef SAL_LOG_INFO
- SAL_INFO("vcl.gdi.opengl", "this=" << this << " now: " << maOpenGLGlyphCache);
- DumpGlyphBitmap(aDC.getCompatibleHDC());
-#endif
+ aLogFont.lfHeight = aOutlineTextMetric.otmEMSquare;
+ hFont = CreateFontIndirectW(&aLogFont);
+ if (hFont == NULL)
+ {
+ SAL_WARN("vcl.gdi.opengl", "CreateFontIndirectW failed: " << WindowsErrorString(GetLastError()));
+ return;
+ }
+ if (SelectObject(hNewDC, hFont) == NULL)
+ {
+ SAL_WARN("vcl.gdi.opengl", "SelectObject failed: " << WindowsErrorString(GetLastError()));
+ return;
+ }
- return true;
-}
+ if (mnGLyphyProgram == 0)
+ mnGLyphyProgram = GLyphyDemo::demo_shader_create_program();
-const OpenGLGlyphCacheChunk& ImplWinFontEntry::GetCachedGlyphChunkFor(int nGlyphIndex) const
-{
- auto i = maOpenGLGlyphCache.cbegin();
- while (i != maOpenGLGlyphCache.cend() && nGlyphIndex >= i->mnFirstGlyph + i->mnGlyphCount)
- ++i;
- assert(i != maOpenGLGlyphCache.cend());
- assert(nGlyphIndex >= i->mnFirstGlyph && nGlyphIndex < i->mnFirstGlyph + i->mnGlyphCount);
- return *i;
+ mpGLyphyAtlas = GLyphyDemo::demo_atlas_create(2048, 1024, 64, 8);
+ mpGLyphyFont = GLyphyDemo::demo_font_create(hNewDC, mpGLyphyAtlas);
}
WinLayout::WinLayout(HDC hDC, const ImplWinFontData& rWFD, ImplWinFontEntry& rWFE, bool bUseOpenGL)
@@ -1765,20 +1544,26 @@ void UniscribeLayout::DrawTextImpl(HDC hDC) const
DeleteFont(SelectFont(hDC, hOrigFont));
}
-bool UniscribeLayout::CacheGlyphs(SalGraphics& rGraphics) const
+bool UniscribeLayout::CacheGlyphs(SalGraphics&) const
{
static bool bDoGlyphCaching = (std::getenv("SAL_DISABLE_GLYPH_CACHING") == NULL);
if (!bDoGlyphCaching)
return false;
+ if (!mrWinFontEntry.maMetric.mbTrueTypeFont)
+ return false;
+
+ mrWinFontEntry.setupGLyphy(mhDC);
+
for (int i = 0; i < mnGlyphCount; i++)
{
- if (mrWinFontEntry.GlyphIsCached(mpOutGlyphs[i]))
+ if (mpOutGlyphs[i] == DROPPED_OUTGLYPH)
continue;
- if (!mrWinFontEntry.AddChunkOfGlyphs(mpOutGlyphs[i], *this, rGraphics))
- return false;
+ GLyphyDemo::glyph_info_t aGI;
+ VCL_GL_INFO("vcl.opengl", "Calling demo_font_lookup_glyph");
+ GLyphyDemo::demo_font_lookup_glyph( mrWinFontEntry.mpGLyphyFont, mpOutGlyphs[i], &aGI );
}
return true;
@@ -1787,20 +1572,53 @@ bool UniscribeLayout::CacheGlyphs(SalGraphics& rGraphics) const
bool UniscribeLayout::DrawCachedGlyphs(SalGraphics& rGraphics) const
{
WinSalGraphics& rWinGraphics = static_cast<WinSalGraphics&>(rGraphics);
- HDC hDC = rWinGraphics.getHDC();
Rectangle aRect;
GetBoundRect(rGraphics, aRect);
- COLORREF color = GetTextColor(hDC);
- SalColor salColor = MAKE_SALCOLOR(GetRValue(color), GetGValue(color), GetBValue(color));
-
WinOpenGLSalGraphicsImpl *pImpl = dynamic_cast<WinOpenGLSalGraphicsImpl*>(rWinGraphics.mpImpl.get());
if (!pImpl)
return false;
pImpl->PreDraw();
+ rGraphics.GetOpenGLContext()->UseNoProgram();
+ glUseProgram( mrWinFontEntry.mnGLyphyProgram );
+ CHECK_GL_ERROR();
+ GLyphyDemo::demo_atlas_set_uniforms( mrWinFontEntry.mpGLyphyAtlas );
+
+ GLint nLoc;
+
+ nLoc = glGetUniformLocation( mrWinFontEntry.mnGLyphyProgram, "u_debug" );
+ CHECK_GL_ERROR();
+ glUniform1f( nLoc, 0 ); // FIXME: Try to get the "debug" thing displayed first
+ CHECK_GL_ERROR();
+
+ nLoc = glGetUniformLocation( mrWinFontEntry.mnGLyphyProgram, "u_contrast" );
+ CHECK_GL_ERROR();
+ glUniform1f( nLoc, 1 );
+ CHECK_GL_ERROR();
+
+ nLoc = glGetUniformLocation( mrWinFontEntry.mnGLyphyProgram, "u_gamma_adjust" );
+ CHECK_GL_ERROR();
+ glUniform1f( nLoc, 1 );
+ CHECK_GL_ERROR();
+
+ nLoc = glGetUniformLocation( mrWinFontEntry.mnGLyphyProgram, "u_outline" );
+ CHECK_GL_ERROR();
+ glUniform1f( nLoc, false );
+ CHECK_GL_ERROR();
+
+ nLoc = glGetUniformLocation( mrWinFontEntry.mnGLyphyProgram, "u_outline_thickness" );
+ CHECK_GL_ERROR();
+ glUniform1f( nLoc, 1 );
+ CHECK_GL_ERROR();
+
+ nLoc = glGetUniformLocation( mrWinFontEntry.mnGLyphyProgram, "u_boldness" );
+ CHECK_GL_ERROR();
+ glUniform1f( nLoc, 0 );
+ CHECK_GL_ERROR();
+
// FIXME: This code snippet is mostly copied from the one in
// UniscribeLayout::DrawTextImpl. Should be factored out.
int nBaseClusterOffset = 0;
@@ -1842,35 +1660,97 @@ bool UniscribeLayout::DrawCachedGlyphs(SalGraphics& rGraphics) const
// positioning) match.
const int* pGlyphWidths = mpJustifications ? mpJustifications : mpGlyphAdvances;
+ double font_size = mrWinFontEntry.maFontSelData.mfExactHeight; // ???
+
+ // font_size = 1; // ???
+
+ std::vector<GLyphyDemo::glyph_vertex_t> vertices;
for (int i = nMinGlyphPos; i < nEndGlyphPos; i++)
{
// Ignore dropped glyphs.
if (mpOutGlyphs[i] == DROPPED_OUTGLYPH)
continue;
- assert(mrWinFontEntry.GlyphIsCached(mpOutGlyphs[i]));
+ // Total crack
+ GLyphyDemo::glyphy_point_t pt;
+ pt.x = nAdvance + aPos.X() + mpGlyphOffsets[i].du;
+ pt.y = aPos.Y() + mpGlyphOffsets[i].dv;
+ GLyphyDemo::glyph_info_t gi;
+ GLyphyDemo::demo_font_lookup_glyph( mrWinFontEntry.mpGLyphyFont, mpOutGlyphs[i], &gi );
+ GLyphyDemo::demo_shader_add_glyph_vertices( pt, font_size, &gi, &vertices, NULL );
- const OpenGLGlyphCacheChunk& rChunk = mrWinFontEntry.GetCachedGlyphChunkFor(mpOutGlyphs[i]);
- const int n = mpOutGlyphs[i] - rChunk.mnFirstGlyph;
-
- if (rChunk.mbVertical)
- {
- SalTwoRect a2Rects(rChunk.maLocation[n].Left(), rChunk.maLocation[n].Top(),
- rChunk.maLocation[n].getWidth(), rChunk.maLocation[n].getHeight(),
- aPos.X(), nAdvance + aPos.Y(),
- rChunk.maLocation[n].getWidth(), rChunk.maLocation[n].getHeight()); // ???
- pImpl->DrawMask(*rChunk.mpTexture, salColor, a2Rects);
- }
- else
- {
- SalTwoRect a2Rects(rChunk.maLocation[n].Left(), rChunk.maLocation[n].Top(),
- rChunk.maLocation[n].getWidth(), rChunk.maLocation[n].getHeight(),
- nAdvance + aPos.X() + mpGlyphOffsets[i].du - rChunk.getExtraOffset(), aPos.Y() + mpGlyphOffsets[i].dv - rChunk.mnAscent - rChunk.getExtraOffset(),
- rChunk.maLocation[n].getWidth(), rChunk.maLocation[n].getHeight()); // ???
- pImpl->DrawMask(*rChunk.mpTexture, salColor, a2Rects);
- }
nAdvance += pGlyphWidths[i];
}
+
+ GLfloat mat[16];
+ GLyphyDemo::m4LoadIdentity( mat );
+
+ GLint viewport[4];
+ glGetIntegerv( GL_VIEWPORT, viewport );
+ CHECK_GL_ERROR();
+
+ double width = viewport[2];
+ double height = viewport[3];
+
+#if 0
+ // Based on demo_view_apply_transform(). I don't really understand it.
+
+ // No scaling, no translation needed here
+
+ // Perspective (but why would we want that in LO; it's needed in glyphy-demo because there
+ // you can rotate the "sheet" the text is drawn on)
+ {
+ double d = std::max( width, height );
+ double near = d / 4;
+ double far = near + d;
+ double factor = near / (2 * near + d);
+ GLyphyDemo::m4Frustum( mat, -width * factor, width * factor, -height * factor, height * factor, near, far );
+ GLyphyDemo::m4Translate( mat, 0, 0, -(near + d * 0.5) );
+ }
+
+ // No rotation here
+
+ // Fix 'up'
+ GLyphyDemo::m4Scale( mat, 1, -1, 1 );
+
+ // Foo
+ // GLyphyDemo::m4Scale( mat, 0.5, 0.5, 1 );
+
+ // The "Center buffer" part in demo_view_display()
+ GLyphyDemo::m4Translate( mat, width/2, height/2, 0 );
+
+#else
+ // Crack that just happens to show something (even if not completely in correct location) in
+ // some cases, but not all. I don't understand why.
+ double scale = std::max( 2/width, 2/height );
+ GLyphyDemo::m4Scale( mat, scale, -scale, 1);
+ GLyphyDemo::m4Translate( mat, -width/2, -height/2, 0 );
+#endif
+
+ GLuint u_matViewProjection_loc = glGetUniformLocation( mrWinFontEntry.mnGLyphyProgram, "u_matViewProjection" );
+ CHECK_GL_ERROR();
+ glUniformMatrix4fv( u_matViewProjection_loc, 1, GL_FALSE, mat );
+ CHECK_GL_ERROR();
+
+ GLuint a_glyph_vertex_loc = glGetAttribLocation( mrWinFontEntry.mnGLyphyProgram, "a_glyph_vertex" );
+ GLuint buf_name;
+ glGenBuffers( 1, &buf_name );
+ CHECK_GL_ERROR();
+ glBindBuffer( GL_ARRAY_BUFFER, buf_name );
+ CHECK_GL_ERROR();
+
+ glBufferData( GL_ARRAY_BUFFER, sizeof(GLyphyDemo::glyph_vertex_t) * vertices.size(), (const char *) &vertices[0], GL_STATIC_DRAW );
+ CHECK_GL_ERROR();
+ glEnableVertexAttribArray( a_glyph_vertex_loc );
+ CHECK_GL_ERROR();
+ glVertexAttribPointer( a_glyph_vertex_loc, 4, GL_FLOAT, GL_FALSE, sizeof(GLyphyDemo::glyph_vertex_t), 0 );
+ CHECK_GL_ERROR();
+ glDrawArrays( GL_TRIANGLES, 0, vertices.size() );
+ CHECK_GL_ERROR();
+ glDisableVertexAttribArray( a_glyph_vertex_loc );
+ CHECK_GL_ERROR();
+ glDeleteBuffers( 1, &buf_name );
+ CHECK_GL_ERROR();
}
pImpl->PostDraw();
@@ -2625,11 +2505,14 @@ int WinSalGraphics::GetMinKashidaWidth()
ImplWinFontEntry::ImplWinFontEntry( FontSelectPattern& rFSD )
: ImplFontEntry( rFSD )
-, maWidthMap( 512 )
+, mpGLyphyAtlas( nullptr )
+, mpGLyphyFont( nullptr )
, mnMinKashidaWidth( -1 )
, mnMinKashidaGlyph( -1 )
{
maScriptCache = NULL;
+ mpGLyphyFont = NULL;
+ mbGLyphySetupCalled = false;
}
ImplWinFontEntry::~ImplWinFontEntry()