Add text wrapping hyphen mode support
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / text / layouts / layout-engine.cpp
index fcf5f5e..25f83d1 100644 (file)
@@ -44,11 +44,12 @@ namespace
 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::Concise, true, "LOG_TEXT_LAYOUT");
 #endif
 
 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::Concise, true, "LOG_TEXT_LAYOUT");
 #endif
 
-const float              MAX_FLOAT     = std::numeric_limits<float>::max();
-const CharacterDirection LTR           = false;
-const CharacterDirection RTL           = !LTR;
-const float              LINE_SPACING  = 0.f;
-const float              MIN_LINE_SIZE = 0.f;
+const float              MAX_FLOAT      = std::numeric_limits<float>::max();
+const CharacterDirection LTR            = false;
+const CharacterDirection RTL            = !LTR;
+const float              LINE_SPACING   = 0.f;
+const float              MIN_LINE_SIZE  = 0.f;
+const Character          HYPHEN_UNICODE = 0x002D;
 
 inline bool isEmptyLineAtLast(const Vector<LineRun>& lines, const Vector<LineRun>::Iterator& line)
 {
 
 inline bool isEmptyLineAtLast(const Vector<LineRun>& lines, const Vector<LineRun>::Iterator& line)
 {
@@ -448,7 +449,11 @@ struct Engine::Impl
     const Length totalNumberOfGlyphs = parameters.textModel->mVisualModel->mGlyphs.Count();
 
     const bool isMultiline   = mLayout == MULTI_LINE_BOX;
     const Length totalNumberOfGlyphs = parameters.textModel->mVisualModel->mGlyphs.Count();
 
     const bool isMultiline   = mLayout == MULTI_LINE_BOX;
-    const bool isWordLaidOut = parameters.textModel->mLineWrapMode == Text::LineWrap::WORD;
+    const bool isWordLaidOut = parameters.textModel->mLineWrapMode == Text::LineWrap::WORD ||
+                               (parameters.textModel->mLineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION) ||
+                               (parameters.textModel->mLineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::MIXED);
+    const bool isHyphenMode = parameters.textModel->mLineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::HYPHENATION;
+    const bool isMixedMode  = parameters.textModel->mLineWrapMode == (Text::LineWrap::Mode)DevelText::LineWrap::MIXED;
 
     // The last glyph to be laid-out.
     const GlyphIndex lastGlyphOfParagraphPlusOne = parameters.startGlyphIndex + parameters.numberOfGlyphs;
 
     // The last glyph to be laid-out.
     const GlyphIndex lastGlyphOfParagraphPlusOne = parameters.startGlyphIndex + parameters.numberOfGlyphs;
@@ -486,7 +491,10 @@ struct Engine::Impl
     FontId lastFontId = glyphMetrics.fontId;
     UpdateLineHeight(glyphMetrics, tmpLineLayout);
 
     FontId lastFontId = glyphMetrics.fontId;
     UpdateLineHeight(glyphMetrics, tmpLineLayout);
 
-    bool oneWordLaidOut = false;
+    bool       oneWordLaidOut   = false;
+    bool       oneHyphenLaidOut = false;
+    GlyphIndex hyphenIndex      = 0;
+    GlyphInfo  hyphenGlyph;
 
     for(GlyphIndex glyphIndex = lineLayout.glyphIndex;
         glyphIndex < lastGlyphOfParagraphPlusOne;)
 
     for(GlyphIndex glyphIndex = lineLayout.glyphIndex;
         glyphIndex < lastGlyphOfParagraphPlusOne;)
@@ -565,7 +573,15 @@ struct Engine::Impl
          (tmpLineLayout.length > parameters.boundingBox.width))
       {
         // Current word does not fit in the box's width.
          (tmpLineLayout.length > parameters.boundingBox.width))
       {
         // Current word does not fit in the box's width.
-        if(!oneWordLaidOut || completelyFill)
+        if(((oneHyphenLaidOut && isHyphenMode) ||
+            (!oneWordLaidOut && isMixedMode && oneHyphenLaidOut)) &&
+           !completelyFill)
+        {
+          parameters.textModel->mVisualModel->mHyphen.glyph.PushBack(hyphenGlyph);
+          parameters.textModel->mVisualModel->mHyphen.index.PushBack(hyphenIndex + 1);
+        }
+
+        if((!oneWordLaidOut && !oneHyphenLaidOut) || completelyFill)
         {
           DALI_LOG_INFO(gLogFilter, Debug::Verbose, "  Break the word by character\n");
 
         {
           DALI_LOG_INFO(gLogFilter, Debug::Verbose, "  Break the word by character\n");
 
@@ -608,7 +624,7 @@ struct Engine::Impl
          (TextAbstraction::LINE_MUST_BREAK == lineBreakInfo))
       {
         LineLayout currentLineLayout = lineLayout;
          (TextAbstraction::LINE_MUST_BREAK == lineBreakInfo))
       {
         LineLayout currentLineLayout = lineLayout;
-
+        oneHyphenLaidOut             = false;
         // Must break the line. Update the line layout and return.
         MergeLineLayout(lineLayout, tmpLineLayout);
 
         // Must break the line. Update the line layout and return.
         MergeLineLayout(lineLayout, tmpLineLayout);
 
@@ -631,7 +647,8 @@ struct Engine::Impl
       if(isMultiline &&
          (TextAbstraction::LINE_ALLOW_BREAK == lineBreakInfo))
       {
       if(isMultiline &&
          (TextAbstraction::LINE_ALLOW_BREAK == lineBreakInfo))
       {
-        oneWordLaidOut = isWordLaidOut;
+        oneHyphenLaidOut = false;
+        oneWordLaidOut   = isWordLaidOut;
         DALI_LOG_INFO(gLogFilter, Debug::Verbose, "  One word laid-out\n");
 
         // Current glyph is the last one of the current word.
         DALI_LOG_INFO(gLogFilter, Debug::Verbose, "  One word laid-out\n");
 
         // Current glyph is the last one of the current word.
@@ -641,6 +658,33 @@ struct Engine::Impl
         tmpLineLayout.Clear();
       }
 
         tmpLineLayout.Clear();
       }
 
+      if(isMultiline &&
+         ((isHyphenMode || (!oneWordLaidOut && isMixedMode))) &&
+         (TextAbstraction::LINE_HYPHENATION_BREAK == lineBreakInfo))
+      {
+        hyphenGlyph        = GlyphInfo();
+        hyphenGlyph.fontId = glyphsBuffer[glyphIndex].fontId;
+
+        TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+        hyphenGlyph.index                      = fontClient.GetGlyphIndex(hyphenGlyph.fontId, HYPHEN_UNICODE);
+
+        mMetrics->GetGlyphMetrics(&hyphenGlyph, 1);
+
+        if((tmpLineLayout.length + hyphenGlyph.width) <= parameters.boundingBox.width)
+        {
+          hyphenIndex      = glyphIndex;
+          oneHyphenLaidOut = true;
+
+          DALI_LOG_INFO(gLogFilter, Debug::Verbose, "  One hyphen laid-out\n");
+
+          // Current glyph is the last one of the current word hyphen.
+          // Add the temporal layout to the current one.
+          MergeLineLayout(lineLayout, tmpLineLayout);
+
+          tmpLineLayout.Clear();
+        }
+      }
+
       glyphIndex += numberOfGLyphsInGroup;
     }
 
       glyphIndex += numberOfGLyphsInGroup;
     }
 
@@ -1059,6 +1103,9 @@ struct Engine::Impl
     DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->LayoutText\n");
     DALI_LOG_INFO(gLogFilter, Debug::Verbose, "  box size %f, %f\n", layoutParameters.boundingBox.width, layoutParameters.boundingBox.height);
 
     DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->LayoutText\n");
     DALI_LOG_INFO(gLogFilter, Debug::Verbose, "  box size %f, %f\n", layoutParameters.boundingBox.width, layoutParameters.boundingBox.height);
 
+    layoutParameters.textModel->mVisualModel->mHyphen.glyph.Clear();
+    layoutParameters.textModel->mVisualModel->mHyphen.index.Clear();
+
     Vector<LineRun>& lines = layoutParameters.textModel->mVisualModel->mLines;
 
     if(0u == layoutParameters.numberOfGlyphs)
     Vector<LineRun>& lines = layoutParameters.textModel->mVisualModel->mLines;
 
     if(0u == layoutParameters.numberOfGlyphs)
@@ -1271,6 +1318,17 @@ struct Engine::Impl
 
       if(ellipsis)
       {
 
       if(ellipsis)
       {
+        //clear hyphen from ellipsis line
+        const Length* hyphenIndices = layoutParameters.textModel->mVisualModel->mHyphen.index.Begin();
+        Length        hyphensCount  = layoutParameters.textModel->mVisualModel->mHyphen.glyph.Size();
+
+        while(hyphenIndices && hyphensCount > 0 && hyphenIndices[hyphensCount - 1] >= layout.glyphIndex)
+        {
+          layoutParameters.textModel->mVisualModel->mHyphen.index.Remove(layoutParameters.textModel->mVisualModel->mHyphen.index.Begin() + hyphensCount - 1);
+          layoutParameters.textModel->mVisualModel->mHyphen.glyph.Remove(layoutParameters.textModel->mVisualModel->mHyphen.glyph.Begin() + hyphensCount - 1);
+          hyphensCount--;
+        }
+
         // No more lines to layout.
         break;
       }
         // No more lines to layout.
         break;
       }