Markup procesor. Color 98/53798/10
authorVictor Cebollada <v.cebollada@samsung.com>
Tue, 15 Dec 2015 11:46:59 +0000 (11:46 +0000)
committerVictor Cebollada <v.cebollada@samsung.com>
Thu, 17 Dec 2015 11:20:33 +0000 (11:20 +0000)
Change-Id: I112a2492c0b6e2f20e864015d9f14ae3ae92d762
Signed-off-by: Victor Cebollada <v.cebollada@samsung.com>
23 files changed:
dali-toolkit/internal/controls/text-controls/text-field-impl.cpp
dali-toolkit/internal/file.list
dali-toolkit/internal/text/color-run.h [new file with mode: 0644]
dali-toolkit/internal/text/color-segmentation.cpp [new file with mode: 0644]
dali-toolkit/internal/text/color-segmentation.h [new file with mode: 0644]
dali-toolkit/internal/text/input-style.h [new file with mode: 0644]
dali-toolkit/internal/text/logical-model-impl.cpp
dali-toolkit/internal/text/logical-model-impl.h
dali-toolkit/internal/text/markup-processor-color.cpp [new file with mode: 0644]
dali-toolkit/internal/text/markup-processor-color.h [new file with mode: 0644]
dali-toolkit/internal/text/markup-processor-helper-functions.cpp
dali-toolkit/internal/text/markup-processor-helper-functions.h
dali-toolkit/internal/text/markup-processor.cpp
dali-toolkit/internal/text/markup-processor.h
dali-toolkit/internal/text/segmentation.cpp
dali-toolkit/internal/text/text-controller-impl.cpp
dali-toolkit/internal/text/text-controller-impl.h
dali-toolkit/internal/text/text-controller.cpp
dali-toolkit/internal/text/text-controller.h
dali-toolkit/internal/text/text-style-run-container.h [new file with mode: 0644]
dali-toolkit/internal/text/text-view.cpp
dali-toolkit/internal/text/visual-model-impl.h
dali-toolkit/public-api/controls/text-controls/text-field.h

index c078a25..d15d488 100644 (file)
@@ -97,6 +97,7 @@ DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "horizontalAlignment",
 DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "verticalAlignment",                    STRING,    VERTICAL_ALIGNMENT                   )
 DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "textColor",                            VECTOR4,   TEXT_COLOR                           )
 DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "placeholderTextColor",                 VECTOR4,   PLACEHOLDER_TEXT_COLOR               )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "inputColor",                           VECTOR4,   INPUT_COLOR                          )
 DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "shadowOffset",                         VECTOR2,   SHADOW_OFFSET                        )
 DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "shadowColor",                          VECTOR4,   SHADOW_COLOR                         )
 DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "primaryCursorColor",                   VECTOR4,   PRIMARY_CURSOR_COLOR                 )
@@ -291,6 +292,7 @@ void TextField::SetProperty( BaseObject* object, Property::Index index, const Pr
           if( impl.mController->GetTextColor() != textColor )
           {
             impl.mController->SetTextColor( textColor );
+            impl.mController->SetInputColor( textColor );
             impl.mRenderer.Reset();
           }
         }
@@ -311,6 +313,17 @@ void TextField::SetProperty( BaseObject* object, Property::Index index, const Pr
         }
         break;
       }
+      case Toolkit::TextField::Property::INPUT_COLOR:
+      {
+        if( impl.mController )
+        {
+          const Vector4 inputColor = value.Get< Vector4 >();
+          DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p INPUT_COLOR %f,%f,%f,%f\n", impl.mController.Get(), inputColor.r, inputColor.g, inputColor.b, inputColor.a );
+
+          impl.mController->SetInputColor( inputColor );
+        }
+        break;
+      }
       case Toolkit::TextField::Property::SHADOW_OFFSET:
       {
         if( impl.mController )
@@ -683,6 +696,14 @@ Property::Value TextField::GetProperty( BaseObject* object, Property::Index inde
         }
         break;
       }
+      case Toolkit::TextField::Property::INPUT_COLOR:
+      {
+        if( impl.mController )
+        {
+          value = impl.mController->GetInputColor();
+        }
+        break;
+      }
       case Toolkit::TextField::Property::SHADOW_OFFSET:
       {
         if ( impl.mController )
index 0cc5763..6a8f4dc 100644 (file)
@@ -83,8 +83,10 @@ toolkit_src_files = \
    $(toolkit_src_dir)/text/bidirectional-support.cpp \
    $(toolkit_src_dir)/text/character-set-conversion.cpp \
    $(toolkit_src_dir)/text/clipping/text-clipper.cpp \
+   $(toolkit_src_dir)/text/color-segmentation.cpp \
    $(toolkit_src_dir)/text/logical-model-impl.cpp \
    $(toolkit_src_dir)/text/markup-processor.cpp \
+   $(toolkit_src_dir)/text/markup-processor-color.cpp \
    $(toolkit_src_dir)/text/markup-processor-helper-functions.cpp \
    $(toolkit_src_dir)/text/multi-language-support.cpp \
    $(toolkit_src_dir)/text/segmentation.cpp \
diff --git a/dali-toolkit/internal/text/color-run.h b/dali-toolkit/internal/text/color-run.h
new file mode 100644 (file)
index 0000000..860ec7b
--- /dev/null
@@ -0,0 +1,58 @@
+#ifndef __DALI_TOOLKIT_TEXT_COLOR_RUN_H__
+#define __DALI_TOOLKIT_TEXT_COLOR_RUN_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/math/vector4.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/character-run.h>
+#include <dali-toolkit/internal/text/glyph-run.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+/**
+ * @brief Run of characters with the same color.
+ */
+struct ColorRun
+{
+  CharacterRun characterRun; ///< The initial character index and the number of characters of the run.
+  Vector4      color;        ///< The color of the characters.
+};
+
+struct ColorGlyphRun
+{
+  GlyphRun glyphRun; ///< The initial glyph index and the number of glyphs of the run.
+  Vector4  color;    ///< The color of the glyphs.
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // __DALI_TOOLKIT_TEXT_COLOR_RUN_H__
diff --git a/dali-toolkit/internal/text/color-segmentation.cpp b/dali-toolkit/internal/text/color-segmentation.cpp
new file mode 100644 (file)
index 0000000..9169225
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// FILE HEADER
+#include <dali-toolkit/internal/text/color-segmentation.h>
+
+// EXTERNAL INCLUDES
+
+// INTERNAL INCLUDES
+
+#include <iostream>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+void SetColorSegmentationInfo( const Vector<ColorRun>& characterColorRuns,
+                               const Vector<GlyphIndex>& charactersToGlyph,
+                               const Vector<Length>& glyphsPerCharacter,
+                               Vector<ColorGlyphRun>& glyphColorRuns )
+{
+  const VectorBase::SizeType numberOfColorRuns = characterColorRuns.Count();
+
+  if( 0u == numberOfColorRuns )
+  {
+    // Nothing to do.
+    return;
+  }
+
+  // Resize the color runs for the glyphs.
+  glyphColorRuns.Resize( numberOfColorRuns );
+
+  // Get pointers to the buffers.
+  ColorGlyphRun* glyphColorRunsBuffer = glyphColorRuns.Begin();
+  const GlyphIndex* const charactersToGlyphBuffer = charactersToGlyph.Begin();
+  const Length* const glyphsPerCharacterBuffer = glyphsPerCharacter.Begin();
+
+  // Convert from characters to glyphs.
+  Length index = 0u;
+  for( Vector<ColorRun>::ConstIterator it = characterColorRuns.Begin(),
+         endIt = characterColorRuns.End();
+       it != endIt;
+       ++it, ++index )
+  {
+    const ColorRun& colorRun = *it;
+
+    if( 0u < colorRun.characterRun.numberOfCharacters )
+    {
+      // Get the next color glyph run.
+      ColorGlyphRun& colorGlyphRun = *( glyphColorRunsBuffer + index );
+      colorGlyphRun.color = colorRun.color;
+
+      // Convert the color run index from character to glyph.
+      colorGlyphRun.glyphRun.glyphIndex = *( charactersToGlyphBuffer + colorRun.characterRun.characterIndex );
+
+      // Get the index to the last character of the run.
+      const CharacterIndex lastIndex = colorRun.characterRun.characterIndex + colorRun.characterRun.numberOfCharacters - 1u;
+
+      // Calculate the number of glyphs.
+      colorGlyphRun.glyphRun.numberOfGlyphs = *( charactersToGlyphBuffer + lastIndex ) + *( glyphsPerCharacterBuffer + lastIndex ) - colorGlyphRun.glyphRun.glyphIndex;
+    }
+  }
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/color-segmentation.h b/dali-toolkit/internal/text/color-segmentation.h
new file mode 100644 (file)
index 0000000..9e52de1
--- /dev/null
@@ -0,0 +1,57 @@
+#ifndef __DALI_TOOLKIT_TEXT_COLOR_SEGMENTATION_H__
+#define __DALI_TOOLKIT_TEXT_COLOR_SEGMENTATION_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-vector.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/color-run.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+class LogicalModel;
+
+/**
+ * @brief Creates color glyph runs.
+ *
+ * @param[in] characterColorRuns The color runs in characters (set in the mark-up string).
+ * @param[in] charactersToGlyph Conversion table from characters to glyphs.
+ * @param[in] glyphsPerCharacter Table with the number of glyphs for each character.
+ * @param[out] glyphColorRuns The color runs in glyphs.
+ */
+void SetColorSegmentationInfo( const Vector<ColorRun>& characterColorRuns,
+                               const Vector<GlyphIndex>& charactersToGlyph,
+                               const Vector<Length>& glyphsPerCharacter,
+                               Vector<ColorGlyphRun>& glyphColorRuns );
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // __DALI_TOOLKIT_TEXT_COLOR_SEGMENTATION_H__
diff --git a/dali-toolkit/internal/text/input-style.h b/dali-toolkit/internal/text/input-style.h
new file mode 100644 (file)
index 0000000..cd562ec
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef __DALI_TOOLKIT_TEXT_INPUT_STYLE_H__
+#define __DALI_TOOLKIT_TEXT_INPUT_STYLE_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/math/vector4.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+/**
+ * The input text's style.
+ */
+struct InputStyle
+{
+Vector4 textColor;
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // __DALI_TOOLKIT_TEXT_INPUT_STYLE_H__
index e8e906f..10b2a49 100644 (file)
 // CLASS HEADER
 #include <dali-toolkit/internal/text/logical-model-impl.h>
 
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/input-style.h>
+#include <dali-toolkit/internal/text/text-style-run-container.h>
+
 namespace Dali
 {
 
@@ -241,6 +245,51 @@ CharacterIndex LogicalModel::GetLogicalCharacterIndex( CharacterIndex visualChar
   return *( mVisualToLogicalMap.Begin() + visualCharacterIndex );
 }
 
+void LogicalModel::UpdateTextStyleRuns( CharacterIndex index, int numberOfCharacters )
+{
+  const Length totalNumberOfCharacters = mText.Count();
+
+  // Process the color runs.
+  Vector<ColorRun> removedColorRuns;
+  UpdateCharacterRuns<ColorRun>( index,
+                                 numberOfCharacters,
+                                 totalNumberOfCharacters,
+                                 mColorRuns,
+                                 removedColorRuns );
+}
+
+void LogicalModel::RetrieveStyle( CharacterIndex index, InputStyle& style )
+{
+  unsigned int runIndex = 0u;
+  unsigned int lastRunIndex = 0u;
+  bool overriden = false;
+
+  // Set the text color.
+  for( Vector<ColorRun>::ConstIterator it = mColorRuns.Begin(),
+         endIt = mColorRuns.End();
+       it != endIt;
+       ++it, ++runIndex )
+  {
+    const ColorRun& colorRun = *it;
+
+    if( ( colorRun.characterRun.characterIndex <= index ) &&
+        ( index < colorRun.characterRun.characterIndex + colorRun.characterRun.numberOfCharacters ) )
+    {
+      lastRunIndex = runIndex;
+      overriden = true;
+    }
+  }
+
+  // Set the text's color if it's overriden.
+  if( overriden )
+  {
+    style.textColor = ( *( mColorRuns.Begin() + lastRunIndex ) ).color;
+  }
+
+  runIndex = 0u;
+  overriden = false;
+}
+
 LogicalModel::~LogicalModel()
 {
 }
index 43ef817..6842cf6 100644 (file)
@@ -26,6 +26,7 @@
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/text/bidirectional-line-info-run.h>
 #include <dali-toolkit/internal/text/bidirectional-paragraph-info-run.h>
+#include <dali-toolkit/internal/text/color-run.h>
 #include <dali-toolkit/internal/text/font-run.h>
 #include <dali-toolkit/internal/text/script-run.h>
 
@@ -40,6 +41,7 @@ namespace Text
 
 class LogicalModel;
 typedef IntrusivePtr<LogicalModel> LogicalModelPtr;
+struct InputStyle;
 
 /**
  * @brief A logical text model contains layout independent information.
@@ -106,6 +108,22 @@ public:
    */
   CharacterIndex GetLogicalCharacterIndex( CharacterIndex visualCharacterIndex ) const;
 
+  /**
+   * @brief Updates the text's style runs with the added or removed text.
+   *
+   * @param[in] index The character's index.
+   * @param[in] numberOfCharacters The number of characters added or removed. If the value is negative the characters are removed.
+   */
+  void UpdateTextStyleRuns( CharacterIndex index, int numberOfCharacters );
+
+  /**
+   * @brief Retrieves the text's style for the given character index.
+   *
+   * @param[in] index The character index.
+   * @param[out] style The text's style in the given style.
+   */
+  void RetrieveStyle( CharacterIndex index, InputStyle& style );
+
 protected:
 
   /**
@@ -131,6 +149,7 @@ public:
   Vector<Character>                     mText;
   Vector<ScriptRun>                     mScriptRuns;
   Vector<FontRun>                       mFontRuns;
+  Vector<ColorRun>                      mColorRuns;
   Vector<LineBreakInfo>                 mLineBreakInfo;
   Vector<WordBreakInfo>                 mWordBreakInfo;
   Vector<BidirectionalParagraphInfoRun> mBidirectionalParagraphInfo;
diff --git a/dali-toolkit/internal/text/markup-processor-color.cpp b/dali-toolkit/internal/text/markup-processor-color.cpp
new file mode 100644 (file)
index 0000000..2fd826d
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// FILE HEADER
+#include <dali-toolkit/internal/text/markup-processor-color.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-vector.h>
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/color-run.h>
+#include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+namespace
+{
+const std::string XHTML_VALUE_ATTRIBUTE("value");
+}
+
+void ProcessColorTag( const Tag& tag, ColorRun& colorRun )
+{
+  for( Vector<Attribute>::ConstIterator it = tag.attributes.Begin(),
+         endIt = tag.attributes.End();
+       it != endIt;
+       ++it )
+  {
+    const Attribute& attribute( *it );
+    if( TokenComparison( XHTML_VALUE_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength ) )
+    {
+      ColorStringToVector4( attribute.valueBuffer, attribute.valueLength, colorRun.color );
+    }
+  }
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/text/markup-processor-color.h b/dali-toolkit/internal/text/markup-processor-color.h
new file mode 100644 (file)
index 0000000..bf3ea20
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef __DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_COLOR_H__
+#define __DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_COLOR_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+struct Tag;
+struct ColorRun;
+
+/**
+ * @brief Retrieves the color value from the tag and sets it to the color run.
+ *
+ * @param[in] tag The color tag and its attributes.
+ * @param[in,out] colorRun The color run.
+ */
+void ProcessColorTag( const Tag& tag, ColorRun& colorRun );
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // __DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_COLOR_H__
index 122335e..c460747 100644 (file)
 // FILE HEADER
 #include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
 
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/constants.h>
+#include <stdlib.h>
+
 namespace Dali
 {
 
@@ -32,6 +36,20 @@ namespace
 const char WHITE_SPACE       = 0x20; // ASCII value of the white space.
 const char LAST_UPPER_CASE   = 0x5b; // ASCII value of the one after the last upper case character (Z).
 const char TO_LOWER_CASE     = 32;   // Value to add to a upper case character to transform it into a lower case.
+
+const char WEB_COLOR_TOKEN( '#' );
+const char* const HEX_COLOR_TOKEN( "0x" );
+const char* const ALPHA_ONE( "FF" );
+
+const std::string BLACK_COLOR( "black" );
+const std::string WHITE_COLOR( "white" );
+const std::string RED_COLOR( "red" );
+const std::string GREEN_COLOR( "green" );
+const std::string BLUE_COLOR( "blue" );
+const std::string YELLOW_COLOR( "yellow" );
+const std::string MAGENTA_COLOR( "magenta" );
+const std::string CYAN_COLOR( "cyan" );
+const std::string TRANSPARENT_COLOR( "transparent" );
 }
 
 bool TokenComparison( const std::string& string1, const char* const stringBuffer2, Length length )
@@ -63,6 +81,80 @@ void SkipWhiteSpace( const char*& markupStringBuffer,
   for( ; ( WHITE_SPACE >= *markupStringBuffer ) && ( markupStringBuffer < markupStringEndBuffer ); ++markupStringBuffer );
 }
 
+unsigned int StringToHex( const char* const uintStr )
+{
+  return static_cast<unsigned int>( strtoul( uintStr, NULL, 16 ) );
+}
+
+void UintColorToVector4( unsigned int color, Vector4& retColor )
+{
+  retColor.a = static_cast<float>( ( color & 0xFF000000 ) >> 24u ) / 255.f;
+  retColor.r = static_cast<float>( ( color & 0x00FF0000 ) >> 16u ) / 255.f;
+  retColor.g = static_cast<float>( ( color & 0x0000FF00 ) >> 8u ) / 255.f;
+  retColor.b = static_cast<float>( color & 0x000000FF ) / 255.f;
+}
+
+void ColorStringToVector4( const char* const colorStr, Length length, Vector4& retColor )
+{
+  if( WEB_COLOR_TOKEN == *colorStr )
+  {
+    std::string webColor( colorStr + 1u, length - 1u );
+    if( 4u == length )                      // 3 component web color #F00 (red)
+    {
+      webColor.insert( 2u, &( webColor[2] ), 1u );
+      webColor.insert( 1u, &( webColor[1] ), 1u );
+      webColor.insert( 0u, &( webColor[0] ), 1u );
+      webColor.insert( 0u, ALPHA_ONE );
+    }
+    else if( 7u == length )                 // 6 component web color #FF0000 (red)
+    {
+      webColor.insert( 0u, ALPHA_ONE );
+    }
+
+    UintColorToVector4( StringToHex( webColor.c_str() ), retColor );
+  }
+  else if( TokenComparison( HEX_COLOR_TOKEN, colorStr, 2u ) )
+  {
+    UintColorToVector4( StringToHex( colorStr + 2u ), retColor );
+  }
+  else if( TokenComparison( BLACK_COLOR, colorStr, length ) )
+  {
+    retColor = Color::BLACK;
+  }
+  else if( TokenComparison( WHITE_COLOR, colorStr, length ) )
+  {
+    retColor = Color::WHITE;
+  }
+  else if( TokenComparison( RED_COLOR, colorStr, length ) )
+  {
+    retColor = Color::RED;
+  }
+  else if( TokenComparison( GREEN_COLOR, colorStr, length ) )
+  {
+    retColor = Color::GREEN;
+  }
+  else if( TokenComparison( BLUE_COLOR, colorStr, length ) )
+  {
+    retColor = Color::BLUE;
+  }
+  else if( TokenComparison( YELLOW_COLOR, colorStr, length ) )
+  {
+    retColor = Color::YELLOW;
+  }
+  else if( TokenComparison( MAGENTA_COLOR, colorStr, length ) )
+  {
+    retColor = Color::MAGENTA;
+  }
+  else if( TokenComparison( CYAN_COLOR, colorStr, length ) )
+  {
+    retColor = Color::CYAN;
+  }
+  else if( TokenComparison( TRANSPARENT_COLOR, colorStr, length ) )
+  {
+    retColor = Color::TRANSPARENT;
+  }
+}
+
 } // namespace Text
 
 } // namespace Toolkit
index cf494d2..5934467 100644 (file)
@@ -28,6 +28,8 @@
 namespace Dali
 {
 
+struct Vector4;
+
 namespace Toolkit
 {
 
@@ -82,6 +84,35 @@ bool TokenComparison( const std::string& string1, const char* const stringBuffer
 void SkipWhiteSpace( const char*& markupStringBuffer,
                      const char* const markupStringEndBuffer );
 
+/**
+ * @brief Converts a string into an hexadecimal unsigned int.
+ *
+ * @param[in] uintStr An hexadecimal unsigned int packed inside a string.
+ *
+ * @return The hexadecimal value.
+ */
+unsigned int StringToHex( const char* const uintStr );
+
+/**
+ * @brief Converts an ARGB color packed in 4 byte unsigned int into a Vector4 color used in Dali.
+ *
+ * @param[in] color An ARGB color packed in an unsigned int.
+ * @param[out] retColor A Vector4 with the converted color.
+ */
+void UintColorToVector4( unsigned int color, Vector4& retColor );
+
+/**
+ * @brief Converts a color packed inside a string into an ARGB Vector4 color.
+ *
+ * The string color could be in hexadecimal ( 0xFF0000FF ), webcolor ( #0000FF or #00F ) or some constant values:
+ * black, white, red, green, blue, yellow, magenta, cyan, transparent.
+ *
+ * @param[in] colorStr A color packed inside a string.
+ * @param[in] length The length of the color string.
+ * @param[out] retColor A color packed inside a Vector4.
+ */
+void ColorStringToVector4( const char* const colorStr, Length length, Vector4& retColor );
+
 } // namespace Text
 
 } // namespace Toolkit
index 84707ad..51a1efb 100644 (file)
@@ -20,6 +20,7 @@
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/text/character-set-conversion.h>
+#include <dali-toolkit/internal/text/markup-processor-color.h>
 #include <dali-toolkit/internal/text/markup-processor-helper-functions.h>
 
 namespace Dali
@@ -58,6 +59,50 @@ const char WHITE_SPACE       = 0x20; // ASCII value of the white space.
 
 const unsigned int MAX_NUM_OF_ATTRIBUTES =  5u; ///< The font tag has the 'family', 'size' 'weight', 'width' and 'slant' attrubutes.
 
+const unsigned int DEFAULT_VECTOR_SIZE   = 16u; ///< Default size of run vectors.
+
+/**
+ * @brief Struct used to retrieve the style runs from the mark-up string.
+ */
+struct StyleStack
+{
+  typedef VectorBase::SizeType RunIndex;
+
+  Vector<RunIndex>  stack;    ///< Use a vector as a style stack. Stores the indices pointing where the run is stored inside the logical model.
+  unsigned int topIndex; ///< Points the top of the stack.
+
+  StyleStack()
+  : stack(),
+    topIndex( 0u )
+  {
+    stack.Resize( DEFAULT_VECTOR_SIZE );
+  }
+
+  void Push( RunIndex index )
+  {
+    // Check if there is space inside the style stack.
+    const VectorBase::SizeType size = stack.Count();
+    if( topIndex >= size )
+    {
+      // Resize the style stack.
+      stack.Resize( 2u * size );
+    }
+
+    // Set the run index in the top of the stack.
+    *( stack.Begin() + topIndex ) = index;
+
+    // Reposition the pointer to the top of the stack.
+    ++topIndex;
+  }
+
+  RunIndex Pop()
+  {
+    // Pop the top of the stack.
+    --topIndex;
+    return *( stack.Begin() + topIndex );
+  }
+};
+
 /**
  * @brief Splits the tag string into the tag name and its attributes.
  *
@@ -297,6 +342,15 @@ void ProcessMarkupString( const std::string& markupString, MarkupProcessData& ma
   const Length markupStringSize = markupString.size();
   markupProcessData.markupProcessedText.reserve( markupStringSize );
 
+  // Stores a struct with the index to the first character of the run, the type of run and its parameters.
+  StyleStack styleStack;
+
+  // Points the next free position in the vector of runs.
+  StyleStack::RunIndex colorRunIndex = 0u;
+
+  // Give an initial default value to the model's vectors.
+  markupProcessData.colorRuns.Reserve( DEFAULT_VECTOR_SIZE );
+
   // Get the mark-up string buffer.
   const char* markupStringBuffer = markupString.c_str();
   const char* const markupStringEndBuffer = markupStringBuffer + markupStringSize;
@@ -314,10 +368,29 @@ void ProcessMarkupString( const std::string& markupString, MarkupProcessData& ma
         if( !tag.isEndTag )
         {
           // Create a new color run.
+          ColorRun colorRun;
+          colorRun.characterRun.numberOfCharacters = 0u;
+
+          // Set the start character index.
+          colorRun.characterRun.characterIndex = characterIndex;
+
+          // Fill the run with the attributes.
+          ProcessColorTag( tag, colorRun );
+
+          // Push the color run in the logical model.
+          markupProcessData.colorRuns.PushBack( colorRun );
+
+          // Push the index of the run into the stack.
+          styleStack.Push( colorRunIndex );
+
+          // Point the next color run.
+          ++colorRunIndex;
         }
         else
         {
           // Pop the top of the stack and set the number of characters of the run.
+          ColorRun& colorRun = *( markupProcessData.colorRuns.Begin() + styleStack.Pop() );
+          colorRun.characterRun.numberOfCharacters = characterIndex - colorRun.characterRun.characterIndex;
         }
       } // <color></color>
       else if( TokenComparison( XHTML_I_TAG, tag.buffer, tag.length ) )
@@ -437,6 +510,14 @@ void ProcessMarkupString( const std::string& markupString, MarkupProcessData& ma
   }
 
   // Resize the model's vectors.
+  if( 0u == colorRunIndex )
+  {
+    markupProcessData.colorRuns.Clear();
+  }
+  else
+  {
+    markupProcessData.colorRuns.Resize( colorRunIndex );
+  }
 }
 
 } // namespace Text
index 86ec1a6..966622e 100644 (file)
  */
 
 // EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-vector.h>
 #include <string>
 
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/color-run.h>
+
 namespace Dali
 {
 
@@ -35,11 +39,14 @@ namespace Text
  */
 struct MarkupProcessData
 {
-  MarkupProcessData()
-  : markupProcessedText()
+  MarkupProcessData( Vector<ColorRun>& colorRuns )
+  : colorRuns( colorRuns ),
+    markupProcessedText()
   {}
 
-  std::string markupProcessedText;
+  Vector<ColorRun>&           colorRuns;
+
+  std::string                 markupProcessedText;
 };
 
 /**
index 466991b..a7c7135 100644 (file)
@@ -15,7 +15,7 @@
  *
  */
 
-// CLASS HEADER
+// FILE HEADER
 #include <dali-toolkit/internal/text/segmentation.h>
 
 // EXTERNAL INCLUDES
index a86688d..bc85e95 100644 (file)
@@ -25,6 +25,7 @@
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/text/bidirectional-support.h>
 #include <dali-toolkit/internal/text/character-set-conversion.h>
+#include <dali-toolkit/internal/text/color-segmentation.h>
 #include <dali-toolkit/internal/text/multi-language-support.h>
 #include <dali-toolkit/internal/text/segmentation.h>
 #include <dali-toolkit/internal/text/shaper.h>
@@ -132,7 +133,8 @@ EventData::EventData( DecoratorPtr decorator )
   mUpdateRightSelectionPosition( false ),
   mScrollAfterUpdatePosition( false ),
   mScrollAfterDelete( false ),
-  mAllTextSelected( false )
+  mAllTextSelected( false ),
+  mUpdateInputStyle( false )
 {
   mImfManager = ImfManager::Get();
 }
@@ -287,6 +289,20 @@ bool Controller::Impl::ProcessInputEvents()
     }
   }
 
+  if( mEventData->mUpdateInputStyle )
+  {
+    // Set the default style first.
+    RetrieveDefaultInputStyle( mEventData->mInputStyle );
+
+    // Get the character index from the cursor index.
+    const CharacterIndex styleIndex = ( mEventData->mPrimaryCursorPosition > 0u ) ? mEventData->mPrimaryCursorPosition - 1u : 0u;
+
+    // Retrieve the style from the style runs stored in the logical model.
+    mLogicalModel->RetrieveStyle( styleIndex, mEventData->mInputStyle );
+
+    mEventData->mUpdateInputStyle = false;
+  }
+
   mEventData->mEventQueue.clear();
 
   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::ProcessInputEvents\n" );
@@ -481,6 +497,30 @@ void Controller::Impl::UpdateModel( OperationsMask operationsRequired )
   }
 }
 
+bool Controller::Impl::UpdateModelStyle( OperationsMask operationsRequired )
+{
+  bool updated = false;
+
+  if( COLOR & operationsRequired )
+  {
+    // Set the color runs in glyphs.
+    SetColorSegmentationInfo( mLogicalModel->mColorRuns,
+                              mVisualModel->mCharactersToGlyph,
+                              mVisualModel->mGlyphsPerCharacter,
+                              mVisualModel->mColorRuns );
+
+    updated = true;
+  }
+
+  return updated;
+}
+
+void Controller::Impl::RetrieveDefaultInputStyle( InputStyle& inputStyle )
+{
+  // Set the default text's color.
+  inputStyle.textColor = mTextColor;
+}
+
 void Controller::Impl::GetDefaultFonts( Vector<FontRun>& fonts, Length numberOfCharacters )
 {
   if( mFontDefaults )
@@ -549,6 +589,7 @@ void Controller::Impl::OnCursorKeyEvent( const Event& event )
   }
 
   mEventData->mUpdateCursorPosition = true;
+  mEventData->mUpdateInputStyle = true;
   mEventData->mScrollAfterUpdatePosition = true;
 }
 
@@ -578,6 +619,7 @@ void Controller::Impl::OnTapEvent( const Event& event )
 
       mEventData->mUpdateCursorPosition = true;
       mEventData->mScrollAfterUpdatePosition = true;
+      mEventData->mUpdateInputStyle = true;
 
       // Notify the cursor position to the imf manager.
       if( mEventData->mImfManager )
@@ -709,6 +751,7 @@ void Controller::Impl::OnHandleEvent( const Event& event )
     if( Event::GRAB_HANDLE_EVENT == event.type )
     {
       mEventData->mUpdateCursorPosition = true;
+      mEventData->mUpdateInputStyle = true;
 
       if ( !IsClipboardEmpty() )
       {
@@ -795,6 +838,7 @@ void Controller::Impl::OnHandleEvent( const Event& event )
       mEventData->mUpdateCursorPosition = mEventData->mPrimaryCursorPosition != handlePosition;
       mEventData->mScrollAfterUpdatePosition = mEventData->mUpdateCursorPosition;
       mEventData->mPrimaryCursorPosition = handlePosition;
+      mEventData->mUpdateInputStyle = mEventData->mUpdateCursorPosition;
     }
     else if( leftSelectionHandleEvent || rightSelectionHandleEvent )
     {
@@ -914,6 +958,11 @@ void Controller::Impl::RetrieveSelection( std::string& selectedText, bool delete
 
     if( deleteAfterRetrieval ) // Only delete text if copied successfully
     {
+      // Set as input style the style of the first deleted character.
+      mLogicalModel->RetrieveStyle( startOfSelectedText, mEventData->mInputStyle );
+
+      mLogicalModel->UpdateTextStyleRuns( startOfSelectedText, -static_cast<int>( lengthOfSelectedText ) );
+
       // Delete text between handles
       Vector<Character>& currentText = mLogicalModel->mText;
 
index 190549c..3ae0c7f 100644 (file)
@@ -23,6 +23,7 @@
 #include <dali/devel-api/text-abstraction/font-client.h>
 
 // INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/input-style.h>
 #include <dali-toolkit/internal/text/layouts/layout-engine.h>
 #include <dali-toolkit/internal/text/logical-model-impl.h>
 #include <dali-toolkit/internal/text/text-controller.h>
@@ -133,6 +134,8 @@ struct EventData
    */
   std::vector<Event> mEventQueue;              ///< The queue of touch events etc.
 
+  InputStyle         mInputStyle;              ///< The style to be set to the new inputed text.
+
   /**
    * 0,0 means that the top-left corner of the layout matches the top-left corner of the UI control.
    * Typically this will have a negative value with scrolling occurs.
@@ -163,6 +166,7 @@ struct EventData
   bool mScrollAfterUpdatePosition       : 1;   ///< Whether to scroll after the cursor position is updated.
   bool mScrollAfterDelete               : 1;   ///< Whether to scroll after delete characters.
   bool mAllTextSelected                 : 1;   ///< True if the selection handles are selecting all the text.
+  bool mUpdateInputStyle                : 1;   ///< Whether to update the input style after moving the cursor.
 };
 
 struct ModifyEvent
@@ -355,9 +359,35 @@ struct Controller::Impl
     return !result; // // If NumberOfItems greater than 0, return false
   }
 
+  /**
+   * @brief Updates the logical and visual models.
+   *
+   * When text or style changes the model is set with some operations pending.
+   * When i.e. the text's size or a relayout is required this method is called
+   * with a given @p operationsRequired parameter. The operations required are
+   * matched with the operations pending to perform the minimum number of operations.
+   *
+   * @param[in] operationsRequired The operations required.
+   */
   void UpdateModel( OperationsMask operationsRequired );
 
   /**
+   * @brief Updates the style runs in the visual model when the text's styles changes.
+   *
+   * @param[in] operationsRequired The operations required.
+   *
+   * @return @e true if the model has been modified.
+   */
+  bool UpdateModelStyle( OperationsMask operationsRequired );
+
+  /**
+   * @brief Retreieves the default style.
+   *
+   * @param[out] inputStyle The default style.
+   */
+  void RetrieveDefaultInputStyle( InputStyle& inputStyle );
+
+  /**
    * @brief Retrieve the default fonts.
    *
    * @param[out] fonts The default font family, style and point sizes.
index 27f5cbf..e273f01 100644 (file)
@@ -91,9 +91,12 @@ void Controller::SetText( const std::string& text )
   // Reset keyboard as text changed
   mImpl->ResetImfManager();
 
-  // Remove the previously set text
+  // Remove the previously set text and style.
   ResetText();
 
+  // Remove the style.
+  ClearStyleData();
+
   CharacterIndex lastCursorIndex = 0u;
 
   if( mImpl->mEventData )
@@ -110,7 +113,7 @@ void Controller::SetText( const std::string& text )
 
   if( !text.empty() )
   {
-    MarkupProcessData markupProcessData;
+    MarkupProcessData markupProcessData( mImpl->mLogicalModel->mColorRuns );
 
     Length textSize = 0u;
     const uint8_t* utf8 = NULL;
@@ -489,6 +492,20 @@ bool Controller::RemoveText( int cursorOffset, int numberOfChars )
 
     if( ( cursorIndex + numberOfChars ) <= currentText.Count() )
     {
+      // Update the input style and remove the text's style before removing the text.
+      if( mImpl->mEventData )
+      {
+        // Set first the default input style.
+        mImpl->RetrieveDefaultInputStyle( mImpl->mEventData->mInputStyle );
+
+        // Update the input style.
+        mImpl->mLogicalModel->RetrieveStyle( cursorIndex, mImpl->mEventData->mInputStyle );
+
+        // Remove the text's style before removing the text.
+        mImpl->mLogicalModel->UpdateTextStyleRuns( cursorIndex, -numberOfChars );
+      }
+
+      // Remove the characters.
       Vector<Character>::Iterator first = currentText.Begin() + cursorIndex;
       Vector<Character>::Iterator last  = first + numberOfChars;
 
@@ -589,6 +606,48 @@ float Controller::GetUnderlineHeight() const
   return mImpl->mVisualModel->GetUnderlineHeight();
 }
 
+void Controller::SetInputColor( const Vector4& color )
+{
+  if( mImpl->mEventData )
+  {
+    mImpl->mEventData->mInputStyle.textColor = color;
+
+    if( EventData::SELECTING == mImpl->mEventData->mState )
+    {
+      const bool handlesCrossed = mImpl->mEventData->mLeftSelectionPosition > mImpl->mEventData->mRightSelectionPosition;
+
+      // Get start and end position of selection
+      const CharacterIndex startOfSelectedText = handlesCrossed ? mImpl->mEventData->mRightSelectionPosition : mImpl->mEventData->mLeftSelectionPosition;
+      const Length lengthOfSelectedText = ( handlesCrossed ? mImpl->mEventData->mLeftSelectionPosition : mImpl->mEventData->mRightSelectionPosition ) - startOfSelectedText;
+
+      // Add the color run.
+      const VectorBase::SizeType numberOfRuns = mImpl->mLogicalModel->mColorRuns.Count();
+      mImpl->mLogicalModel->mColorRuns.Resize( numberOfRuns + 1u );
+
+      ColorRun& colorRun = *( mImpl->mLogicalModel->mColorRuns.Begin() + numberOfRuns );
+      colorRun.color = color;
+      colorRun.characterRun.characterIndex = startOfSelectedText;
+      colorRun.characterRun.numberOfCharacters = lengthOfSelectedText;
+
+      // Request to relayout.
+      mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | COLOR );
+      mImpl->RequestRelayout();
+    }
+  }
+}
+
+const Vector4& Controller::GetInputColor() const
+{
+  if( mImpl->mEventData )
+  {
+    return mImpl->mEventData->mInputStyle.textColor;
+  }
+
+  // Return the default text's color if there is no EventData.
+  return mImpl->mTextColor;
+
+}
+
 void Controller::SetEnableCursorBlink( bool enable )
 {
   DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "TextInput disabled" );
@@ -759,7 +818,7 @@ bool Controller::Relayout( const Size& size )
   {
     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "new size (previous size %f,%f)\n", mImpl->mVisualModel->mControlSize.width, mImpl->mVisualModel->mControlSize.height );
 
-    // Operations that need to be done if the size changes.
+    // Layout operations that need to be done if the size changes.
     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
                                                              LAYOUT                    |
                                                              ALIGN                     |
@@ -769,14 +828,28 @@ bool Controller::Relayout( const Size& size )
     mImpl->mVisualModel->mControlSize = size;
   }
 
-  // Make sure the model is up-to-date before layouting
+  // Whether there are modify events.
+  const bool isModifyEventsEmpty = 0u == mImpl->mModifyEvents.Count();
+
+  // Make sure the model is up-to-date before layouting.
   ProcessModifyEvents();
   mImpl->UpdateModel( mImpl->mOperationsPending );
 
+  // Style operations that need to be done if the text is modified.
+  if( !isModifyEventsEmpty )
+  {
+    mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
+                                                             COLOR );
+  }
+
+  // Apply the style runs if text is modified.
+  bool updated = mImpl->UpdateModelStyle( mImpl->mOperationsPending );
+
+  // Layout the text.
   Size layoutSize;
-  bool updated = DoRelayout( mImpl->mVisualModel->mControlSize,
-                             mImpl->mOperationsPending,
-                             layoutSize );
+  updated = DoRelayout( mImpl->mVisualModel->mControlSize,
+                        mImpl->mOperationsPending,
+                        layoutSize ) || updated;
 
   // Do not re-do any operation until something changes.
   mImpl->mOperationsPending = NO_OPERATION;
@@ -1473,6 +1546,35 @@ void Controller::InsertText( const std::string& text, Controller::InsertType typ
     // The cursor position.
     CharacterIndex& cursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
 
+    // Update the text's style.
+    if( mImpl->mEventData )
+    {
+      // Updates the text style runs.
+      mImpl->mLogicalModel->UpdateTextStyleRuns( cursorIndex, maxSizeOfNewText );
+
+      // Get the character index from the cursor index.
+      const CharacterIndex styleIndex = ( cursorIndex > 0u ) ? cursorIndex - 1u : 0u;
+
+      // Retrieve the text's style for the given index.
+      InputStyle style;
+      mImpl->mLogicalModel->RetrieveStyle( styleIndex, style );
+
+      // Whether to add a new text color run.
+      const bool addColorRun = style.textColor != mImpl->mEventData->mInputStyle.textColor;
+
+      // Add style runs.
+      if( addColorRun )
+      {
+        const VectorBase::SizeType numberOfRuns = mImpl->mLogicalModel->mColorRuns.Count();
+        mImpl->mLogicalModel->mColorRuns.Resize( numberOfRuns + 1u );
+
+        ColorRun& colorRun = *( mImpl->mLogicalModel->mColorRuns.Begin() + numberOfRuns );
+        colorRun.color = mImpl->mEventData->mInputStyle.textColor;
+        colorRun.characterRun.characterIndex = cursorIndex;
+        colorRun.characterRun.numberOfCharacters = maxSizeOfNewText;
+      }
+    }
+
     // Insert at current cursor position.
     Vector<Character>& modifyText = mImpl->mLogicalModel->mText;
 
@@ -2080,6 +2182,7 @@ void Controller::ClearModelData()
   mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
   mImpl->mVisualModel->mGlyphPositions.Clear();
   mImpl->mVisualModel->mLines.Clear();
+  mImpl->mVisualModel->mColorRuns.Clear();
   mImpl->mVisualModel->ClearCaches();
 }
 
@@ -2097,6 +2200,11 @@ void Controller::ClearFontData()
   mImpl->mVisualModel->ClearCaches();
 }
 
+void Controller::ClearStyleData()
+{
+  mImpl->mLogicalModel->mColorRuns.Clear();
+}
+
 Controller::Controller( ControlInterface& controlInterface )
 : mImpl( NULL )
 {
index 0955431..058719e 100644 (file)
@@ -85,6 +85,7 @@ public:
     UPDATE_ACTUAL_SIZE = 0x0200,
     REORDER            = 0x0400,
     ALIGN              = 0x0800,
+    COLOR              = 0x1000,
     ALL_OPERATIONS     = 0xFFFF
   };
 
@@ -383,6 +384,20 @@ public:
   float GetUnderlineHeight() const;
 
   /**
+   * @brief Sets the input text's color.
+   *
+   * @param[in] color The input text's color.
+   */
+  void SetInputColor( const Vector4& color );
+
+  /**
+   * @brief Retrieves the input text's color.
+   *
+   * @return The input text's color.
+   */
+  const Vector4& GetInputColor() const;
+
+  /**
    * @brief Called to enable/disable cursor blink.
    *
    * @note Only editable controls should calls this.
@@ -680,6 +695,11 @@ private:
   void ClearFontData();
 
   /**
+   * @brief Helper to clear text's style data.
+   */
+  void ClearStyleData();
+
+  /**
    * @brief Private constructor.
    */
   Controller( ControlInterface& controlInterface );
diff --git a/dali-toolkit/internal/text/text-style-run-container.h b/dali-toolkit/internal/text/text-style-run-container.h
new file mode 100644 (file)
index 0000000..e35ccea
--- /dev/null
@@ -0,0 +1,177 @@
+#ifndef __DALI_TOOLKIT_TEXT_STYLE_RUN_CONTAINER_H__
+#define __DALI_TOOLKIT_TEXT_STYLE_RUN_CONTAINER_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali-toolkit/internal/text/character-run.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+/**
+ * @brief Updates the number of characters and the character index of the text's style runs.
+ *
+ * If the @p numberOfCharacters is a negative value, it means the number of characters that are removed starting from the @p index.
+ *
+ * It deletes runs if all their characters are removed.
+ *
+ * @param[in] index Index to the first character updated.
+ * @param[in] numberOfCharacters The number of characters to be updated.
+ * @param[in] totalNumberOfCharacters Total number of characters of the text.
+ * @param[in,out] runs The text's style runs.
+ * @param[out] removedRuns The text's style removed runs.
+ */
+template< typename T >
+void UpdateCharacterRuns( CharacterIndex index,
+                          int numberOfCharacters,
+                          Length totalNumberOfCharacters,
+                          Vector<T>& runs,
+                          Vector<T>& removedRuns )
+{
+  if( 0 > numberOfCharacters )
+  {
+    // Remove characters.
+    const Length numberOfRemovedCharacters = -numberOfCharacters;
+
+    if( ( 0u == index ) && ( numberOfRemovedCharacters == totalNumberOfCharacters ) )
+    {
+      // Set the removed runs.
+      removedRuns = runs;
+
+      // All characters are removed.
+      runs.Clear();
+
+      // Nothing else to do.
+      return;
+    }
+
+    const VectorBase::SizeType size = runs.Count();
+    // Temporary vector used to remove runs.
+    Vector<T> tempRuns;
+    // Reserve some space for the temporary vector.
+    tempRuns.Reserve( size );
+    removedRuns.Reserve( size );
+
+    // Whether any run has to be removed.
+    bool runsRemoved = false;
+
+    // Index to the last character added/removed.
+    const CharacterIndex lastIndex = index + numberOfRemovedCharacters - 1u;
+
+    // Update the style runs
+    for( typename Vector<T>::Iterator it = runs.Begin(),
+           endIt = runs.End();
+         it != endIt;
+         ++it )
+    {
+      T& run = *it;
+
+      const CharacterIndex lastRunIndex = run.characterRun.characterIndex + run.characterRun.numberOfCharacters - 1u;
+
+      if( lastRunIndex < index )
+      {
+        // The style run is not affected by the removed text.
+        tempRuns.PushBack( run );
+        continue;
+      }
+
+      if( ( index <= run.characterRun.characterIndex ) &&
+          ( lastIndex >= lastRunIndex ) )
+      {
+        // Add the removed run into the vector.
+        removedRuns.PushBack( run );
+
+        // All the characters are removed.
+        runsRemoved = true;
+      }
+      else
+      {
+        if( lastIndex < run.characterRun.characterIndex )
+        {
+          // Just move the character index.
+          run.characterRun.characterIndex -= numberOfRemovedCharacters;
+        }
+        else
+        {
+          if( run.characterRun.characterIndex < index )
+          {
+            // Remove characters starting from a character within the run.
+            run.characterRun.numberOfCharacters -= std::min( numberOfRemovedCharacters, 1u + lastRunIndex - index );
+          }
+          else
+          {
+            // Remove characters starting from a character located before the first index of the run.
+            run.characterRun.numberOfCharacters -= 1u + lastIndex - run.characterRun.characterIndex;
+            run.characterRun.characterIndex = index;
+          }
+        }
+
+        tempRuns.PushBack( run );
+      }
+    }
+
+    // Copy the temporary vector if there are runs removed.
+    if( runsRemoved )
+    {
+      runs = tempRuns;
+    }
+  }
+  else
+  {
+    // Add characters.
+
+    // Update the style runs
+    for( typename Vector<T>::Iterator it = runs.Begin(),
+           endIt = runs.End();
+         it != endIt;
+         ++it )
+    {
+      T& run = *it;
+
+      // Update the number of characters of the style run.
+
+      if( ( 0u == index ) && ( 0u == run.characterRun.characterIndex ) )
+      {
+        run.characterRun.numberOfCharacters += numberOfCharacters;
+      }
+      else if( index <= run.characterRun.characterIndex )
+      {
+        run.characterRun.characterIndex += numberOfCharacters;
+      }
+      else if( index <= run.characterRun.characterIndex + run.characterRun.numberOfCharacters )
+      {
+        run.characterRun.numberOfCharacters += numberOfCharacters;
+      }
+    }
+  }
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // __DALI_TOOLKIT_TEXT_STYLE_RUN_CONTAINER_H__
index 88ab012..2921700 100644 (file)
@@ -122,6 +122,30 @@ Length View::GetGlyphs( GlyphInfo* glyphs,
                                                 glyphIndex,
                                                 numberOfLaidOutGlyphs );
 
+        // Set the colors.
+        const GlyphIndex lastLaidOutGlyphIndex = glyphIndex + numberOfLaidOutGlyphs;
+
+        for( Vector<ColorGlyphRun>::ConstIterator it = mImpl->mVisualModel->mColorRuns.Begin(),
+               endIt = mImpl->mVisualModel->mColorRuns.End();
+             it != endIt;
+             ++it )
+        {
+          const ColorGlyphRun& colorGlyphRun = *it;
+          const GlyphIndex lastGlyphIndex = colorGlyphRun.glyphRun.glyphIndex + colorGlyphRun.glyphRun.numberOfGlyphs;
+
+          if( ( colorGlyphRun.glyphRun.glyphIndex < lastLaidOutGlyphIndex ) &&
+              ( glyphIndex < lastGlyphIndex ) )
+          {
+            for( GlyphIndex index = glyphIndex < colorGlyphRun.glyphRun.glyphIndex ? colorGlyphRun.glyphRun.glyphIndex : glyphIndex,
+                   endIndex = lastLaidOutGlyphIndex < lastGlyphIndex ? lastLaidOutGlyphIndex : lastGlyphIndex;
+                 index < endIndex;
+                 ++index )
+            {
+              *( glyphColors + index - glyphIndex ) = colorGlyphRun.color;
+            }
+          }
+        }
+
         // Get the lines for the given range of glyphs.
         // The lines contain the alignment offset which needs to be added to the glyph's position.
         LineIndex firstLine = 0u;
index 52d2d31..ca579e1 100644 (file)
@@ -27,6 +27,7 @@
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/text/line-run.h>
+#include <dali-toolkit/internal/text/color-run.h>
 
 namespace Dali
 {
@@ -301,6 +302,7 @@ public:
   Vector<Vector2>        mGlyphPositions;       ///< For each glyph, the position.
   Vector<LineRun>        mLines;                ///< The laid out lines.
   Vector<GlyphRun>       mUnderlineRuns;        ///< Runs of glyphs that are underlined.
+  Vector<ColorGlyphRun>  mColorRuns;            ///< Runs of glyphs with the same color.
 
   Vector2                mControlSize;           ///< The size of the UI control the decorator is adding it's decorations to.
   Vector4                mTextColor;            ///< The text color
index f4642cf..7332e92 100644 (file)
@@ -79,6 +79,7 @@ public:
       VERTICAL_ALIGNMENT,                       ///< name "verticalAlignment",                   The line vertical alignment,                                              type STRING,  values   "TOP",   "CENTER",   "BOTTOM"
       TEXT_COLOR,                               ///< name "textColor",                           The text color,                                                           type VECTOR4
       PLACEHOLDER_TEXT_COLOR,                   ///< name "placeholderTextColor",                The placeholder-text color,                                               type VECTOR4
+      INPUT_COLOR,                              ///< name "inputColor",                          The color of the new input text,                                          type VECTOR4
       SHADOW_OFFSET,                            ///< name "shadowOffset",                        The drop shadow offset 0 indicates no shadow,                             type VECTOR2
       SHADOW_COLOR,                             ///< name "shadowColor",                         The color of a drop shadow,                                               type VECTOR4
       PRIMARY_CURSOR_COLOR,                     ///< name "primaryCursorColor",                  The color to apply to the primary cursor,                                 type VECTOR4