Skip to content

Issue with storing cache in FTSimpleLayout #7

Description

@blake-r

Hi.

There are two issues in cache realization in FTSimpleLayout:

  • store pointers to original string, but need to cached string - original can out of scope;
  • no cache invalidating after change layout parameters.

My patch to fix this:

From f33041e830d791cfaee2ef5847584429965efea8 Mon Sep 17 00:00:00 2001
From: Oleg aka Blake-R <blake-r@mail.ru>
Date: Thu, 25 Aug 2011 09:09:13 +0400
Subject: [PATCH] Fix cache store and it's invalidation on change layout
 parameters.

---
 ftgles/src/FTLayout/FTSimpleLayout.cpp   |   60 ++++++++++++++++++++---------
 ftgles/src/FTLayout/FTSimpleLayoutImpl.h |    6 ++-
 2 files changed, 45 insertions(+), 21 deletions(-)

diff --git a/ftgles/src/FTLayout/FTSimpleLayout.cpp b/ftgles/src/FTLayout/FTSimpleLayout.cpp
index ff2ec11..050d231 100755
--- a/ftgles/src/FTLayout/FTSimpleLayout.cpp
+++ b/ftgles/src/FTLayout/FTSimpleLayout.cpp
@@ -81,6 +81,7 @@ void FTSimpleLayout::Render(const wchar_t* string, const int len, FTPoint pos,
 void FTSimpleLayout::SetFont(FTFont *fontInit)
 {
     dynamic_cast<FTSimpleLayoutImpl*>(impl)->currentFont = fontInit;
+    dynamic_cast<FTSimpleLayoutImpl*>(impl)->invalidate();
 }


@@ -93,6 +94,7 @@ FTFont *FTSimpleLayout::GetFont()
 void FTSimpleLayout::SetLineLength(const float LineLength)
 {
     dynamic_cast<FTSimpleLayoutImpl*>(impl)->lineLength = LineLength;
+    dynamic_cast<FTSimpleLayoutImpl*>(impl)->invalidate();
 }


@@ -105,6 +107,7 @@ float FTSimpleLayout::GetLineLength() const
 void FTSimpleLayout::SetAlignment(const FTGL::TextAlignment Alignment)
 {
     dynamic_cast<FTSimpleLayoutImpl*>(impl)->alignment = Alignment;
+    dynamic_cast<FTSimpleLayoutImpl*>(impl)->invalidate();
 }


@@ -117,6 +120,7 @@ FTGL::TextAlignment FTSimpleLayout::GetAlignment() const
 void FTSimpleLayout::SetLineSpacing(const float LineSpacing)
 {
     dynamic_cast<FTSimpleLayoutImpl*>(impl)->lineSpacing = LineSpacing;
+    dynamic_cast<FTSimpleLayoutImpl*>(impl)->invalidate();
 }


@@ -137,6 +141,21 @@ FTSimpleLayoutImpl::FTSimpleLayoutImpl()
     lineLength = 100.0f;
     alignment = FTGL::ALIGN_LEFT;
     lineSpacing = 1.0f;
+   stringCache = NULL;
+   stringCacheCount = 0;
+}
+
+
+FTSimpleLayoutImpl::~FTSimpleLayoutImpl()
+{
+   free(stringCache);
+   stringCache = NULL;
+   stringCacheCount = 0;
+}
+
+
+inline void FTSimpleLayoutImpl::invalidate()
+{
    stringCacheCount = 0;
 }

@@ -209,6 +228,7 @@ inline void FTSimpleLayoutImpl::WrapTextI(const T *buf, const int len,
 {
     FTUnicodeStringItr<T> breakItr(buf);          // points to the last break character
     FTUnicodeStringItr<T> lineStart(buf);         // points to the line start
+   unsigned int new_stringCacheCount = 0;        // length of buffer
     float nextStart = 0.0;     // total width of the current line
     float breakWidth = 0.0;    // width of the line up to the last word break
     float currentWidth = 0.0;  // width of all characters on the current line
@@ -228,31 +248,33 @@ inline void FTSimpleLayoutImpl::WrapTextI(const T *buf, const int len,
     {
        bounds->Invalidate();
     }
-   
+
+   {
+       FTUnicodeStringItr<T> itr(buf);
+       for (; *itr; ++itr) {}
+       new_stringCacheCount = itr.getBufferFromHere() - buf + sizeof(T)/*terminator*/;
+   }
+
    // Check if the incoming string is different to the previously
    // cached string.
-   unsigned int i = 0;
-   for (FTUnicodeStringItr<T> itr(buf); *itr; itr++)
-   {
-       if (i >= stringCacheCount ||
-           stringCache[i++] != (unsigned int)*itr)
-       {
-           refresh = true;
-           break;
-       }
+   if (stringCache && stringCacheCount == new_stringCacheCount) refresh = !!memcmp(stringCache, buf, stringCacheCount);
+   else {
+       refresh = true;
+       stringCacheCount = new_stringCacheCount;
+       if (!stringCache) stringCache = (unsigned char *)malloc(stringCacheCount);
+       else stringCache = (unsigned char *)realloc(stringCache, stringCacheCount);
+       if (!stringCache) throw std::bad_alloc();
    }
-   
+
    if (refresh)
    {
-       stringCacheCount = 0;
+       memcpy(stringCache, buf, stringCacheCount);
         layoutGlyphCache.clear();

        // Scan the input for all characters that need output
        FTUnicodeStringItr<T> prevItr(buf);
        for (FTUnicodeStringItr<T> itr(buf); *itr; prevItr = itr++, charCount++)
-       {
-           stringCache[stringCacheCount++] = (unsigned int)*itr;
-           
+       {   
            // Find the width of the current glyph
            glyphBounds = currentFont->BBox(itr.getBufferFromHere(), 1);
            glyphWidth = glyphBounds.Upper().Xf() - glyphBounds.Lower().Xf();
@@ -296,7 +318,7 @@ inline void FTSimpleLayoutImpl::WrapTextI(const T *buf, const int len,
                }

                layoutGlyphCacheItem_t cacheItem;
-               cacheItem.buf = (T*)lineStart.getBufferFromHere();
+               cacheItem.buf = stringCache + ptrdiff_t(lineStart.getBufferFromHere() - buf);
                cacheItem.charCount = breakCharCount;
                cacheItem.position = FTPoint(position.X(), position.Y(), position.Z());
                cacheItem.remainingWidth = remainingWidth;
@@ -331,7 +353,7 @@ inline void FTSimpleLayoutImpl::WrapTextI(const T *buf, const int len,
                wordLength += advance;
            }
        }
-       
+
        float remainingWidth = lineLength - currentWidth;
        // Render any remaining text on the last line
        // Disable justification for the last row
@@ -339,7 +361,7 @@ inline void FTSimpleLayoutImpl::WrapTextI(const T *buf, const int len,
        {
            alignment = FTGL::ALIGN_LEFT;
            layoutGlyphCacheItem_t cacheItem;
-           cacheItem.buf = (T *)lineStart.getBufferFromHere();
+           cacheItem.buf = stringCache + ptrdiff_t(lineStart.getBufferFromHere() - buf);
            cacheItem.charCount = -1;
            cacheItem.position = FTPoint(position.X(), position.Y(), position.Z());
            cacheItem.penDiff = FTPoint(0,0,0);
@@ -350,7 +372,7 @@ inline void FTSimpleLayoutImpl::WrapTextI(const T *buf, const int len,
        else
        {
            layoutGlyphCacheItem_t cacheItem;
-           cacheItem.buf = (T *)lineStart.getBufferFromHere();
+           cacheItem.buf = stringCache + ptrdiff_t(lineStart.getBufferFromHere() - buf);
            cacheItem.charCount = -1;
            cacheItem.position = FTPoint(position.X(), position.Y(), position.Z());
            cacheItem.penDiff = FTPoint(0,0,0);
diff --git a/ftgles/src/FTLayout/FTSimpleLayoutImpl.h b/ftgles/src/FTLayout/FTSimpleLayoutImpl.h
index 63b56cc..dd84234 100755
--- a/ftgles/src/FTLayout/FTSimpleLayoutImpl.h
+++ b/ftgles/src/FTLayout/FTSimpleLayoutImpl.h
@@ -50,7 +50,7 @@ class FTSimpleLayoutImpl : public FTLayoutImpl
 protected:
    FTSimpleLayoutImpl();

-   virtual ~FTSimpleLayoutImpl() {};
+   virtual ~FTSimpleLayoutImpl();

    virtual FTBBox BBox(const char* string, const int len,
                        FTPoint position);
@@ -211,10 +211,12 @@ private:
     */
     std::list<layoutGlyphCacheItem_t> layoutGlyphCache;

-   unsigned int stringCache[4096];
+   unsigned char * stringCache;

    unsigned int stringCacheCount;
+

+   void invalidate();

    /* Internal generic BBox() implementation */
    template <typename T>
-- 
1.7.6.1

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions