[Libreoffice-commits] core.git: 18 commits - config_host.mk.in configure.ac download.lst external/glyphy external/Module_external.mk include/vcl Makefile.fetch RepositoryExternal.mk vcl/generic vcl/glyphy vcl/inc vcl/Library_vcl.mk vcl/quartz vcl/source vcl/win
Tor Lillqvist
tml at collabora.com
Thu Nov 19 04:18:58 PST 2015
Makefile.fetch | 1
RepositoryExternal.mk | 29 +
config_host.mk.in | 1
configure.ac | 7
download.lst | 1
external/Module_external.mk | 1
external/glyphy/ExternalPackage_glyphy.mk | 22
external/glyphy/ExternalProject_glyphy.mk | 38 +
external/glyphy/Makefile | 7
external/glyphy/Module_glyphy.mk | 21
external/glyphy/UnpackedTarball_glyphy.mk | 21
external/glyphy/glyphy-upstream.patch.1 | 211 ++++++++
external/glyphy/glyphy-windows.patch.1 | 744 ++++++++++++++++++++++++++++++
include/vcl/opengl/OpenGLContext.hxx | 1
vcl/Library_vcl.mk | 12
vcl/generic/glyphs/gcach_ftyp.cxx | 3
vcl/generic/print/genpspgraphics.cxx | 1
vcl/glyphy/demo.cxx | 19
vcl/glyphy/demo/demo-atlas.cc | 144 +++++
vcl/glyphy/demo/demo-buffer.cc | 191 +++++++
vcl/glyphy/demo/demo-font.cc | 333 +++++++++++++
vcl/glyphy/demo/demo-shader.cc | 212 ++++++++
vcl/glyphy/demo/matrix4x4.c | 481 +++++++++++++++++++
vcl/inc/glyphy/demo.hxx | 21
vcl/inc/glyphy/demo/demo-atlas-glsl.h | 18
vcl/inc/glyphy/demo/demo-atlas.h | 54 ++
vcl/inc/glyphy/demo/demo-buffer.h | 64 ++
vcl/inc/glyphy/demo/demo-common.h | 186 +++++++
vcl/inc/glyphy/demo/demo-font.h | 88 +++
vcl/inc/glyphy/demo/demo-fshader-glsl.h | 88 +++
vcl/inc/glyphy/demo/demo-shader.h | 47 +
vcl/inc/glyphy/demo/demo-vshader-glsl.h | 24
vcl/inc/glyphy/demo/matrix4x4.h | 107 ++++
vcl/inc/outfont.hxx | 1
vcl/quartz/ctfonts.cxx | 1
vcl/source/opengl/OpenGLContext.cxx | 10
vcl/source/outdev/font.cxx | 1
vcl/win/source/gdi/salgdi3.cxx | 1
vcl/win/source/gdi/winlayout.cxx | 329 ++++++++++++-
vcl/win/source/gdi/winlayout.hxx | 3
40 files changed, 3512 insertions(+), 32 deletions(-)
New commits:
commit 0c5e59d93345a6a4a1fc965adcb0bb743a933ebf
Author: Tor Lillqvist <tml at collabora.com>
Date: Thu Nov 19 13:48:59 2015 +0200
Check for system GLyphy only on Linux and Windows
Won't ever be any "system" one on Windows, of course. And I think it
will take some time before Linux distros packages GLyphy, too.
But the main point is that I don't want to bother with building GLyphy
for anything it isn't used on anyway. (Sure, it isn't actually used on
Linux, either, but there might be somebody who wants to work on that.)
Also, there is no "include" in the GLyphy source tree.
Change-Id: I063369c92e8d4b868cc66513c9ec12aa4fc65f37
diff --git a/configure.ac b/configure.ac
index b068e9b..6829c70 100644
--- a/configure.ac
+++ b/configure.ac
@@ -8813,7 +8813,9 @@ AS_IF([test "$with_system_glew" = "yes"],
dnl ===================================================================
dnl Check for system glyphy
dnl ===================================================================
-libo_CHECK_SYSTEM_MODULE([glyphy], [GLYPHY], [glyphy >= 0.12.0], ["-I${WORKDIR}/UnpackedTarball/glyphy/include"])
+if test $_os = Linux -o $_os = WINNT; then
+ libo_CHECK_SYSTEM_MODULE([glyphy], [GLYPHY], [glyphy >= 0.12.0], ["-I${WORKDIR}/UnpackedTarball/glyphy/src"])
+fi
dnl ===================================================================
dnl Check for system vigra
commit 77cea16a2805364ab78eeec4a80155da25dcbd66
Author: Tor Lillqvist <tml at collabora.com>
Date: Thu Nov 19 12:35:30 2015 +0200
Make using GLyphy optional at run-time
Change-Id: I7053f16c25f5506d15ebc88f1b0465493dd35077
diff --git a/vcl/win/source/gdi/winlayout.cxx b/vcl/win/source/gdi/winlayout.cxx
index 5ae2ce4..ec07be1 100644
--- a/vcl/win/source/gdi/winlayout.cxx
+++ b/vcl/win/source/gdi/winlayout.cxx
@@ -66,6 +66,27 @@ 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
{
@@ -82,6 +103,7 @@ public:
{ return maScriptCache; }
private:
mutable SCRIPT_CACHE maScriptCache;
+ std::vector<OpenGLGlyphCacheChunk> maOpenGLGlyphCache;
public:
bool InitKashidaHandling( HDC );
@@ -92,6 +114,10 @@ public:
GLyphyDemo::demo_atlas_t* mpGLyphyAtlas;
GLyphyDemo::demo_font_t* mpGLyphyFont;
+ bool GlyphIsCached(int nGlyphIndex) const;
+ bool AddChunkOfGlyphs(int nGlyphIndex, const WinLayout& rLayout, SalGraphics& rGraphics);
+ const OpenGLGlyphCacheChunk& GetCachedGlyphChunkFor(int nGlyphIndex) const;
+
private:
mutable int mnMinKashidaWidth;
mutable int mnMinKashidaGlyph;
@@ -100,13 +126,128 @@ private:
GLuint ImplWinFontEntry::mnGLyphyProgram = 0;
-#if 0
+#ifdef SAL_LOG_INFO
-bool ImplWinFontEntry::AddGlyphToCache(WORD nGlyphIndex, const WinLayout& rLayout, SalGraphics& rGraphics)
+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 << "}";
+}
+
+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;
+
+ return false;
+}
+
+bool ImplWinFontEntry::AddChunkOfGlyphs(int 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)
{
@@ -123,7 +264,7 @@ bool ImplWinFontEntry::AddGlyphToCache(WORD nGlyphIndex, const WinLayout& rLayou
SIZE aSize;
- if (!GetTextExtentExPointI(hDC, &nGlyphIndex, 1, 0, NULL, NULL, &aSize))
+ if (!GetTextExtentExPointI(hDC, aGlyphIndices.data(), nCount, 0, NULL, NULL, &aSize))
{
SAL_WARN("vcl.gdi", "GetTextExtentExPointI failed: " << WindowsErrorString(GetLastError()));
SelectObject(hDC, hOrigFont);
@@ -131,8 +272,8 @@ bool ImplWinFontEntry::AddGlyphToCache(WORD nGlyphIndex, const WinLayout& rLayou
return false;
}
- ABC aABC;
- if (!GetCharABCWidthsI(hDC, 0, 1, &nGlyphIndex, &aABC))
+ std::vector<ABC> aABC(nCount);
+ if (!GetCharABCWidthsI(hDC, 0, nCount, aGlyphIndices.data(), aABC.data()))
{
SAL_WARN("vcl.gdi", "GetCharABCWidthsI failed: " << WindowsErrorString(GetLastError()));
SelectObject(hDC, hOrigFont);
@@ -140,7 +281,10 @@ bool ImplWinFontEntry::AddGlyphToCache(WORD nGlyphIndex, const WinLayout& rLayou
return false;
}
- SAL_INFO("vcl.gdi.opengl", "ABC width: " << aABC.abcA << ":" << aABC.abcB << ":" << aABC.abcC);
+ 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());
TEXTMETRICW aTextMetric;
if (!GetTextMetricsW(hDC, &aTextMetric))
@@ -150,6 +294,25 @@ bool ImplWinFontEntry::AddGlyphToCache(WORD 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))
@@ -175,19 +338,121 @@ bool ImplWinFontEntry::AddGlyphToCache(WORD nGlyphIndex, const WinLayout& rLayou
" Orientation=" << aLogfont.lfOrientation <<
" Ascent=" << aTextMetric.tmAscent <<
" InternalLeading=" << aTextMetric.tmInternalLeading <<
- " Size=(" << aSize.cx << "," << aSize.cy << ")");
+ " Size=(" << aSize.cx << "," << aSize.cy << ") totWidth=" << totWidth);
if (SelectObject(hDC, hOrigFont) == NULL)
SAL_WARN("vcl.gdi", "SelectObject failed: " << WindowsErrorString(GetLastError()));
if (!DeleteDC(hDC))
SAL_WARN("vcl.gdi", "DeleteDC failed: " << WindowsErrorString(GetLastError()));
- // FIXME HERE, in case this code snipet actually is needed any more?
+ // 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;
+ }
+
+ if (aChunk.mbVertical && aLogfont.lfEscapement != 2700)
+ return false;
+
+ OpenGLCompatibleDC aDC(rGraphics, 0, 0, nBitmapWidth, nBitmapHeight);
+
+ HFONT hNonAntialiasedFont = NULL;
+
+#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
+
+ hOrigFont = SelectFont(aDC.getCompatibleHDC(), hNonAntialiasedFont != NULL ? hNonAntialiasedFont : rLayout.mhFont);
+ if (hOrigFont == NULL)
+ {
+ SAL_WARN("vcl.gdi", "SelectObject failed: " << WindowsErrorString(GetLastError()));
+ return false;
+ }
+
+ SetTextColor(aDC.getCompatibleHDC(), RGB(0, 0, 0));
+ SetBkColor(aDC.getCompatibleHDC(), RGB(255, 255, 255));
+
+ aDC.fill(MAKE_SALCOLOR(0xff, 0xff, 0xff));
+
+ 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()))
+ {
+ SAL_WARN("vcl.gdi", "ExtTextOutW failed: " << WindowsErrorString(GetLastError()));
+ SelectFont(aDC.getCompatibleHDC(), hOrigFont);
+ if (hNonAntialiasedFont != NULL)
+ DeleteObject(hNonAntialiasedFont);
+ return false;
+ }
+
+ aChunk.maLocation.resize(nCount);
+ UINT nPos = 0;
+ for (int i = 0; i < nCount; i++)
+ {
+ 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();
+ }
+ }
+
+ 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
return true;
}
-#endif
+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;
+}
void ImplWinFontEntry::setupGLyphy(HDC hDC)
{
@@ -463,8 +728,12 @@ UniscribeLayout::UniscribeLayout(HDC hDC, const ImplWinFontData& rWinFontData,
mpGlyphs2Chars( NULL ),
mnMinKashidaWidth( 0 ),
mnMinKashidaGlyph( 0 ),
- mbDisableGlyphInjection( false )
-{}
+ mbDisableGlyphInjection( false ),
+ mbUseGLyphy( false )
+{
+ static bool bUseGLyphy = std::getenv("SAL_USE_GLYPHY") != NULL;
+ mbUseGLyphy = bUseGLyphy;
+}
UniscribeLayout::~UniscribeLayout()
{
@@ -1544,32 +1813,46 @@ void UniscribeLayout::DrawTextImpl(HDC hDC) const
DeleteFont(SelectFont(hDC, hOrigFont));
}
-bool UniscribeLayout::CacheGlyphs(SalGraphics&) const
+bool UniscribeLayout::CacheGlyphs(SalGraphics& rGraphics) const
{
static bool bDoGlyphCaching = (std::getenv("SAL_DISABLE_GLYPH_CACHING") == NULL);
if (!bDoGlyphCaching)
return false;
- if (!mrWinFontEntry.maMetric.mbTrueTypeFont)
- return false;
+ if (mbUseGLyphy)
+ {
+ if (!mrWinFontEntry.maMetric.mbTrueTypeFont)
+ return false;
+
+ mrWinFontEntry.setupGLyphy(mhDC);
- mrWinFontEntry.setupGLyphy(mhDC);
+ for (int i = 0; i < mnGlyphCount; i++)
+ {
+ if (mpOutGlyphs[i] == DROPPED_OUTGLYPH)
+ continue;
- for (int i = 0; i < mnGlyphCount; i++)
+ 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 );
+ }
+ }
+ else
{
- if (mpOutGlyphs[i] == DROPPED_OUTGLYPH)
- continue;
+ for (int i = 0; i < mnGlyphCount; i++)
+ {
+ if (mrWinFontEntry.GlyphIsCached(mpOutGlyphs[i]))
+ continue;
- 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 );
+ if (!mrWinFontEntry.AddChunkOfGlyphs(mpOutGlyphs[i], *this, rGraphics))
+ return false;
+ }
}
return true;
}
-bool UniscribeLayout::DrawCachedGlyphs(SalGraphics& rGraphics) const
+bool UniscribeLayout::DrawCachedGlyphsUsingGLyphy(SalGraphics& rGraphics) const
{
WinSalGraphics& rWinGraphics = static_cast<WinSalGraphics&>(rGraphics);
@@ -1757,6 +2040,107 @@ bool UniscribeLayout::DrawCachedGlyphs(SalGraphics& rGraphics) const
return true;
}
+bool UniscribeLayout::DrawCachedGlyphsUsingTextures(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();
+
+ // FIXME: This code snippet is mostly copied from the one in
+ // UniscribeLayout::DrawTextImpl. Should be factored out.
+ int nBaseClusterOffset = 0;
+ int nBaseGlyphPos = -1;
+ for( int nItem = 0; nItem < mnItemCount; ++nItem )
+ {
+ const VisualItem& rVisualItem = mpVisualItems[ nItem ];
+
+ // skip if there is nothing to display
+ int nMinGlyphPos, nEndGlyphPos;
+ if( !GetItemSubrange( rVisualItem, nMinGlyphPos, nEndGlyphPos ) )
+ continue;
+
+ if( nBaseGlyphPos < 0 )
+ {
+ // adjust draw position relative to cluster start
+ if( rVisualItem.IsRTL() )
+ nBaseGlyphPos = nEndGlyphPos - 1;
+ else
+ nBaseGlyphPos = nMinGlyphPos;
+
+ int i = mnMinCharPos;
+ while( (--i >= rVisualItem.mnMinCharPos)
+ && (nBaseGlyphPos == mpLogClusters[i]) )
+ nBaseClusterOffset += mpCharWidths[i];
+
+ if( !rVisualItem.IsRTL() )
+ nBaseClusterOffset = -nBaseClusterOffset;
+ }
+
+ // now draw the matching glyphs in this item
+ Point aRelPos( rVisualItem.mnXOffset + nBaseClusterOffset, 0 );
+ Point aPos = GetDrawPosition( aRelPos );
+
+ int nAdvance = 0;
+
+ // This has to be in sync with UniscribeLayout::FillDXArray(), so that
+ // actual and reported glyph positions (used for e.g. cursor caret
+ // positioning) match.
+ const int* pGlyphWidths = mpJustifications ? mpJustifications : mpGlyphAdvances;
+
+ for (int i = nMinGlyphPos; i < nEndGlyphPos; i++)
+ {
+ // Ignore dropped glyphs.
+ if (mpOutGlyphs[i] == DROPPED_OUTGLYPH)
+ continue;
+
+ assert(mrWinFontEntry.GlyphIsCached(mpOutGlyphs[i]));
+
+ 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];
+ }
+ }
+ pImpl->PostDraw();
+
+ return true;
+}
+
+bool UniscribeLayout::DrawCachedGlyphs(SalGraphics& rGraphics) const
+{
+ if (mbUseGLyphy)
+ return DrawCachedGlyphsUsingGLyphy(rGraphics);
+ else
+ return DrawCachedGlyphsUsingTextures( rGraphics );
+}
+
DeviceCoordinate UniscribeLayout::FillDXArray( DeviceCoordinate* pDXArray ) const
{
// calculate width of the complete layout
diff --git a/vcl/win/source/gdi/winlayout.hxx b/vcl/win/source/gdi/winlayout.hxx
index 72b0921..664915b 100644
--- a/vcl/win/source/gdi/winlayout.hxx
+++ b/vcl/win/source/gdi/winlayout.hxx
@@ -134,6 +134,9 @@ private:
int mnMinKashidaWidth;
int mnMinKashidaGlyph;
bool mbDisableGlyphInjection;
+ bool mbUseGLyphy;
+ bool DrawCachedGlyphsUsingGLyphy(SalGraphics& rGraphics) const;
+ bool DrawCachedGlyphsUsingTextures(SalGraphics& rGraphics) const;
};
#if ENABLE_GRAPHITE
commit a12454b390a718e982461255491c0f26a5a3bbca
Author: Tor Lillqvist <tml at collabora.com>
Date: Thu Nov 19 11:46:03 2015 +0200
Use GLyphy for text on Windows (broken)
Work in progress. Produces visible text in some cases, but not nearly
all. The text that is visible is roughly in the right place and of the
right size, but horribly ugly. Compare to glyphy-demo, which does
produce beautiful text, so the problem is not in the GLyphy code but
in the way we use it.
Include sources from GLyphy's "demo" directory (with only slight
modifications to avoid unconditional debug output) and use that "demo"
API from vcl.
The changes to existing vcl code are all in one place, in the
winlayout.cxx file.
Change-Id: I69cce5d66db534c6f4c1ab85d520b6090baf8fe0
diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk
index 983e10f..f3981dd 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 0000000..7f4f12a
--- /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 0000000..d84da06
--- /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 0000000..8ce5b34
--- /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 0000000..c28778e
--- /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 0000000..9b82123
--- /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 0000000..f103589
--- /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 0000000..2323186
--- /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 0000000..9b93c2a
--- /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 0000000..729403f
--- /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 0000000..2948a7f
--- /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 0000000..380942f
--- /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 0000000..d4e75ff
--- /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 0000000..d80a6cc
--- /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 0000000..dfa5480
--- /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 0000000..c952ab7
--- /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 0000000..2169561
--- /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 2409d4b..5ae2ce4 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;
... etc. - the rest is truncated
More information about the Libreoffice-commits
mailing list