[haiku-commits] haiku: hrev46009 - src/apps/haiku-depot/textview

  • From: superstippi@xxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Mon, 2 Sep 2013 10:15:34 +0200 (CEST)

hrev46009 adds 6 changesets to branch 'master'
old head: 01f623b00f98bc17544b4ba5df6aa5c1cfab5610
new head: 15a557e69cd82d9ad3c67134c4bc8e48059ed37a
overview: http://cgit.haiku-os.org/haiku/log/?qt=range&q=15a557e+%5E01f623b

----------------------------------------------------------------------------

fcf16d3: HaikuDepot: Fixed spelling of ascent and descent nouns

4710193: HaikuDepot: Work-in-progress on a TextDocument class.
  
   * This is mostly still targeted at the use-case of parsing
     some mark up text and building a static representation
     of the styled document which can be layouted and rendered.
   * Lots of TODOs and almost nothing is tested.

6f1dbba: HaikuDepot: Paragraph: Added Length() method.

621cb2b: HaikuDepot: Fix passing back cloned StyleData objects
  
   * In the methods that create a new style data object
     by cloning the object and changing the respective
     property, returning a Reference to a style data
     object makes it easier on the calling side to deal
     with the same object being returned or a new one.

947ba26: HaikuDepot: Redesign TextStyle as CharacterStyle ...
  
   ... following the example set by ParagraphStyle and
   ParagraphStyleData.

15a557e: HaikuDepot: Re-implemented TextLayout as ParagraphLayout
  
   * Completely unfininished and untested, won't even compile,
     but is not included in the build. The idea being to wrap TextSpan
     objects and split them onto Lines each containing their own
     layouted TextSpan chunks. TextLayout will later be repurposed
     to off-load the layout of individual text paragraphs to
     ParagraphLayouts.

                                      [ Stephan Aßmus <superstippi@xxxxxx> ]

----------------------------------------------------------------------------

18 files changed, 1670 insertions(+), 62 deletions(-)
src/apps/haiku-depot/Jamfile                     |   3 +
src/apps/haiku-depot/textview/CharacterStyle.cpp | 176 ++++++
src/apps/haiku-depot/textview/CharacterStyle.h   |  55 ++
.../haiku-depot/textview/CharacterStyleData.cpp  | 240 ++++++++
.../haiku-depot/textview/CharacterStyleData.h    | 108 ++++
src/apps/haiku-depot/textview/GlyphInfo.h        |  26 +-
src/apps/haiku-depot/textview/Paragraph.cpp      |  13 +
src/apps/haiku-depot/textview/Paragraph.h        |   2 +
.../haiku-depot/textview/ParagraphLayout.cpp     | 596 +++++++++++++++++++
src/apps/haiku-depot/textview/ParagraphLayout.h  | 135 +++++
src/apps/haiku-depot/textview/ParagraphStyle.cpp |  48 +-
src/apps/haiku-depot/textview/ParagraphStyle.h   |   2 +-
.../haiku-depot/textview/ParagraphStyleData.cpp  |  48 +-
.../haiku-depot/textview/ParagraphStyleData.h    |  20 +-
src/apps/haiku-depot/textview/TextDocument.cpp   | 188 ++++++
src/apps/haiku-depot/textview/TextDocument.h     |  66 ++
src/apps/haiku-depot/textview/TextLayout.cpp     |   4 +-
src/apps/haiku-depot/textview/TextLayout.h       |   2 +-

############################################################################

Commit:      fcf16d33e44b2f3e6818ebf91ce5b77691d27bb8
URL:         http://cgit.haiku-os.org/haiku/commit/?id=fcf16d3
Author:      Stephan Aßmus <superstippi@xxxxxx>
Date:        Sat Aug 31 11:55:38 2013 UTC

HaikuDepot: Fixed spelling of ascent and descent nouns

----------------------------------------------------------------------------

diff --git a/src/apps/haiku-depot/textview/GlyphInfo.h 
b/src/apps/haiku-depot/textview/GlyphInfo.h
index 00211b7..74d70b2 100644
--- a/src/apps/haiku-depot/textview/GlyphInfo.h
+++ b/src/apps/haiku-depot/textview/GlyphInfo.h
@@ -16,23 +16,23 @@ public:
                x(0.0f),
                y(0.0f),
                advanceX(0.0f),
-               maxAscend(0.0f),
-               maxDescend(0.0f),
+               maxAscent(0.0f),
+               maxDescent(0.0f),
                lineIndex(0),
                style()
        {
        }
 
        GlyphInfo(uint32 charCode, float x, float y, float advanceX,
-                       float maxAscend, float maxDescend, int lineIndex,
+                       float maxAscent, float maxDescent, int lineIndex,
                        const TextStyleRef& style)
                :
                charCode(charCode),
                x(x),
                y(y),
                advanceX(advanceX),
-               maxAscend(maxAscend),
-               maxDescend(maxDescend),
+               maxAscent(maxAscent),
+               maxDescent(maxDescent),
                lineIndex(lineIndex),
                style(style)
        {
@@ -44,8 +44,8 @@ public:
                x(other.x),
                y(other.y),
                advanceX(other.advanceX),
-               maxAscend(other.maxAscend),
-               maxDescend(other.maxDescend),
+               maxAscent(other.maxAscent),
+               maxDescent(other.maxDescent),
                lineIndex(other.lineIndex),
                style(other.style)
        {
@@ -57,8 +57,8 @@ public:
                x = other.x;
                y = other.y;
                advanceX = other.advanceX;
-               maxAscend = other.maxAscend;
-               maxDescend = other.maxDescend;
+               maxAscent = other.maxAscent;
+               maxDescent = other.maxDescent;
                lineIndex = other.lineIndex;
                style = other.style;
                return *this;
@@ -70,8 +70,8 @@ public:
                        && x == other.x
                        && y == other.y
                        && advanceX == other.advanceX
-                       && maxAscend == other.maxAscend
-                       && maxDescend == other.maxDescend
+                       && maxAscent == other.maxAscent
+                       && maxDescent == other.maxDescent
                        && lineIndex == other.lineIndex
                        && style == other.style;
        }
@@ -88,8 +88,8 @@ public:
        float                                   y;
        float                                   advanceX;
 
-       float                                   maxAscend;
-       float                                   maxDescend;
+       float                                   maxAscent;
+       float                                   maxDescent;
 
        int                                             lineIndex;
 
diff --git a/src/apps/haiku-depot/textview/TextLayout.cpp 
b/src/apps/haiku-depot/textview/TextLayout.cpp
index fe2186b..20eba50 100644
--- a/src/apps/haiku-depot/textview/TextLayout.cpp
+++ b/src/apps/haiku-depot/textview/TextLayout.cpp
@@ -554,8 +554,8 @@ TextLayout::_FinalizeLine(int lineStart, int lineEnd, int 
lineIndex, float y,
        fLineInfos.Add(LineInfo(lineStart, y, lineHeight, maxAscent, 
maxDescent));
 
        for (int i = lineStart; i <= lineEnd; i++) {
-               fGlyphInfoBuffer[i].maxAscend = maxAscent;
-               fGlyphInfoBuffer[i].maxDescend = maxDescent;
+               fGlyphInfoBuffer[i].maxAscent = maxAscent;
+               fGlyphInfoBuffer[i].maxDescent = maxDescent;
                fGlyphInfoBuffer[i].lineIndex = lineIndex;
                fGlyphInfoBuffer[i].y += maxAscent;
        }
diff --git a/src/apps/haiku-depot/textview/TextLayout.h 
b/src/apps/haiku-depot/textview/TextLayout.h
index b697d23..05058b9 100644
--- a/src/apps/haiku-depot/textview/TextLayout.h
+++ b/src/apps/haiku-depot/textview/TextLayout.h
@@ -82,4 +82,4 @@ private:
 
 };
 
-#endif // FILTER_VIEW_H
+#endif // TEXT_LAYOUT_H

############################################################################

Commit:      471019301434314fd49b93fdcb2d0cee7ef865d5
URL:         http://cgit.haiku-os.org/haiku/commit/?id=4710193
Author:      Stephan Aßmus <superstippi@xxxxxx>
Date:        Sat Aug 31 15:48:35 2013 UTC

HaikuDepot: Work-in-progress on a TextDocument class.

 * This is mostly still targeted at the use-case of parsing
   some mark up text and building a static representation
   of the styled document which can be layouted and rendered.
 * Lots of TODOs and almost nothing is tested.

----------------------------------------------------------------------------

diff --git a/src/apps/haiku-depot/textview/TextDocument.cpp 
b/src/apps/haiku-depot/textview/TextDocument.cpp
new file mode 100644
index 0000000..7bb089f
--- /dev/null
+++ b/src/apps/haiku-depot/textview/TextDocument.cpp
@@ -0,0 +1,188 @@
+/*
+ * Copyright 2013, Stephan Aßmus <superstippi@xxxxxx>.
+ * All rights reserved. Distributed under the terms of the MIT License.
+ */
+
+#include "TextDocument.h"
+
+
+TextDocument::TextDocument()
+       :
+       fParagraphs(),
+       fEmptyLastParagraph(),
+       fDefaultTextStyle()
+{
+}
+
+
+TextDocument::TextDocument(const TextStyle& textStyle,
+       const ParagraphStyle& paragraphStyle)
+       :
+       fParagraphs(),
+       fEmptyLastParagraph(paragraphStyle),
+       fDefaultTextStyle(textStyle)
+{
+}
+
+
+TextDocument::TextDocument(const TextDocument& other)
+       :
+       fParagraphs(other.fParagraphs),
+       fEmptyLastParagraph(other.fEmptyLastParagraph),
+       fDefaultTextStyle(other.fDefaultTextStyle)
+{
+}
+
+
+TextDocument&
+TextDocument::operator=(const TextDocument& other)
+{
+       fParagraphs = other.fParagraphs;
+       fEmptyLastParagraph = other.fEmptyLastParagraph;
+       fDefaultTextStyle = other.fDefaultTextStyle;
+
+       return *this;
+}
+
+
+bool
+TextDocument::operator==(const TextDocument& other) const
+{
+       if (this == &other)
+               return true;
+
+       return fEmptyLastParagraph == other.fEmptyLastParagraph
+               && fDefaultTextStyle == other.fDefaultTextStyle
+               && fParagraphs == other.fParagraphs;
+}
+
+
+bool
+TextDocument::operator!=(const TextDocument& other) const
+{
+       return !(*this == other);
+}
+
+
+// #pragma mark -
+
+
+status_t
+TextDocument::Insert(int32 offset, const BString& text)
+{
+       return Insert(offset, text, TextStyleAt(offset));
+}
+
+
+status_t
+TextDocument::Insert(int32 offset, const BString& text, const TextStyle& style)
+{
+       return Insert(offset, text, style, ParagraphStyleAt(offset));
+}
+
+
+status_t
+TextDocument::Insert(int32 offset, const BString& text,
+       const TextStyle& textStyle, const ParagraphStyle& paragraphStyle)
+{
+       return Replace(offset, 0, text, textStyle, paragraphStyle);
+}
+
+
+// #pragma mark -
+
+
+status_t
+TextDocument::Remove(int32 offset, int32 length)
+{
+       // TODO: Implement
+       return B_ERROR;
+}
+
+
+// #pragma mark -
+
+
+status_t
+TextDocument::Replace(int32 offset, int32 length, const BString& text)
+{
+       return Replace(offset, length, text, TextStyleAt(offset));
+}
+
+
+status_t
+TextDocument::Replace(int32 offset, int32 length, const BString& text,
+       const TextStyle& style)
+{
+       return Replace(offset, length, text, style, ParagraphStyleAt(offset));
+}
+
+
+status_t
+TextDocument::Replace(int32 offset, int32 length, const BString& text,
+       const TextStyle& textStyle, const ParagraphStyle& paragraphStyle)
+{
+       // TODO: Implement
+       return B_ERROR;
+}
+
+
+// #pragma mark -
+
+
+const TextStyle&
+TextDocument::TextStyleAt(int32 textOffset) const
+{
+       int32 paragraphOffset;
+       const Paragraph& paragraph = ParagraphAt(textOffset, paragraphOffset);
+
+       textOffset -= paragraphOffset;
+       const TextSpanList& spans = paragraph.TextSpans();
+
+       int32 index = 0;
+       while (index < spans.CountItems()) {
+               const TextSpan& span = spans.ItemAtFast(index);
+               if (textOffset - span.CharCount() < 0)
+                       return span.Style();
+               textOffset -= span.CharCount();
+       }
+
+       // TODO: Document should have a default TextStyle?      
+       return fDefaultTextStyle;
+}
+
+
+const ParagraphStyle&
+TextDocument::ParagraphStyleAt(int32 textOffset) const
+{
+       int32 paragraphOffset;
+       return ParagraphAt(textOffset, paragraphOffset).Style();
+}
+
+
+// #pragma mark -
+
+
+const Paragraph&
+TextDocument::ParagraphAt(int32 textOffset, int32& paragraphOffset) const
+{
+       int32 textLength = 0;
+       paragraphOffset = 0;
+       int32 count = fParagraphs.CountItems();
+       for (int32 i = 0; i < count; i++) {
+               const Paragraph& paragraph = fParagraphs.ItemAtFast(i);
+               paragraphOffset = textLength;
+               if (textLength + paragraph.Length() > textOffset)
+                       return paragraph;
+       }
+       return fEmptyLastParagraph;
+}
+
+
+bool
+TextDocument::Append(const Paragraph& paragraph)
+{
+       return fParagraphs.Add(paragraph);
+}
+
+
diff --git a/src/apps/haiku-depot/textview/TextDocument.h 
b/src/apps/haiku-depot/textview/TextDocument.h
new file mode 100644
index 0000000..542daa3
--- /dev/null
+++ b/src/apps/haiku-depot/textview/TextDocument.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2013, Stephan Aßmus <superstippi@xxxxxx>.
+ * All rights reserved. Distributed under the terms of the MIT License.
+ */
+#ifndef TEXT_DOCUMENT_H
+#define TEXT_DOCUMENT_H
+
+#include "List.h"
+#include "Paragraph.h"
+
+
+typedef List<Paragraph, false> ParagraphList;
+
+
+class TextDocument {
+public:
+                                                               TextDocument();
+                                                               
TextDocument(const TextStyle& textStyle,
+                                                                       const 
ParagraphStyle& paragraphStyle);
+                                                               
TextDocument(const TextDocument& other);
+
+                       TextDocument&           operator=(const TextDocument& 
other);
+                       bool                            operator==(const 
TextDocument& other) const;
+                       bool                            operator!=(const 
TextDocument& other) const;
+
+                       // Text insertion and removing
+                       status_t                        Insert(int32 offset, 
const BString& text);
+                       status_t                        Insert(int32 offset, 
const BString& text,
+                                                                       const 
TextStyle& style);
+                       status_t                        Insert(int32 offset, 
const BString& text,
+                                                                       const 
TextStyle& textStyle,
+                                                                       const 
ParagraphStyle& paragraphStyle);
+
+                       status_t                        Remove(int32 offset, 
int32 length);
+
+                       status_t                        Replace(int32 offset, 
int32 length,
+                                                                       const 
BString& text);
+                       status_t                        Replace(int32 offset, 
int32 length,
+                                                                       const 
BString& text,
+                                                                       const 
TextStyle& style);
+                       status_t                        Replace(int32 offset, 
int32 length,
+                                                                       const 
BString& text,
+                                                                       const 
TextStyle& textStyle,
+                                                                       const 
ParagraphStyle& paragraphStyle);
+
+                       // Style access
+                       const TextStyle&        TextStyleAt(int32 textOffset) 
const;
+                       const ParagraphStyle& ParagraphStyleAt(int32 
textOffset) const;
+
+                       // Paragraph access
+                       const ParagraphList& Paragraphs() const
+                                                                       { 
return fParagraphs; }
+
+                       const Paragraph&        ParagraphAt(int32 textOffset,
+                                                                       int32& 
paragraphOffset) const;
+
+                       bool                            Append(const Paragraph& 
paragraph);
+
+private:
+                       ParagraphList           fParagraphs;
+                       Paragraph                       fEmptyLastParagraph;
+                       TextStyle                       fDefaultTextStyle;
+};
+
+
+#endif // TEXT_DOCUMENT_H

############################################################################

Commit:      6f1dbba1641a1b1ae1c12d7fbcf1f4ec7f5342d3
URL:         http://cgit.haiku-os.org/haiku/commit/?id=6f1dbba
Author:      Stephan Aßmus <superstippi@xxxxxx>
Date:        Mon Sep  2 09:48:36 2013 UTC

HaikuDepot: Paragraph: Added Length() method.

----------------------------------------------------------------------------

diff --git a/src/apps/haiku-depot/textview/Paragraph.cpp 
b/src/apps/haiku-depot/textview/Paragraph.cpp
index be27c7a..b5eede5 100644
--- a/src/apps/haiku-depot/textview/Paragraph.cpp
+++ b/src/apps/haiku-depot/textview/Paragraph.cpp
@@ -123,3 +123,16 @@ Paragraph::Insert(int32 offset, const TextSpan& newSpan)
                && fTextSpans.Add(newSpan, index + 1)
                && fTextSpans.Add(spanAfter, index + 2);
 }
+
+
+int32
+Paragraph::Length() const
+{
+       int32 length = 0;
+       for (int32 i = fTextSpans.CountItems() - 1; i >= 0; i--) {
+               const TextSpan& span = fTextSpans.ItemAtFast(i);
+               length += span.CharCount();
+       }
+       return length;
+}
+
diff --git a/src/apps/haiku-depot/textview/Paragraph.h 
b/src/apps/haiku-depot/textview/Paragraph.h
index fa62821..512189e 100644
--- a/src/apps/haiku-depot/textview/Paragraph.h
+++ b/src/apps/haiku-depot/textview/Paragraph.h
@@ -33,6 +33,8 @@ public:
                        bool                            Append(const TextSpan& 
span);
                        bool                            Insert(int32 offset, 
const TextSpan& span);
 
+                       int32                           Length() const;
+
 private:
                        ParagraphStyle          fStyle;
                        TextSpanList            fTextSpans;

############################################################################

Commit:      621cb2bf13137c3f4084368f80f12f2a1b6d7b76
URL:         http://cgit.haiku-os.org/haiku/commit/?id=621cb2b
Author:      Stephan Aßmus <superstippi@xxxxxx>
Date:        Mon Sep  2 09:49:07 2013 UTC

HaikuDepot: Fix passing back cloned StyleData objects

 * In the methods that create a new style data object
   by cloning the object and changing the respective
   property, returning a Reference to a style data
   object makes it easier on the calling side to deal
   with the same object being returned or a new one.

----------------------------------------------------------------------------

diff --git a/src/apps/haiku-depot/textview/ParagraphStyle.cpp 
b/src/apps/haiku-depot/textview/ParagraphStyle.cpp
index 731dec7..21a96a6 100644
--- a/src/apps/haiku-depot/textview/ParagraphStyle.cpp
+++ b/src/apps/haiku-depot/textview/ParagraphStyle.cpp
@@ -57,48 +57,72 @@ ParagraphStyle::operator!=(const ParagraphStyle& other) 
const
 bool
 ParagraphStyle::SetAlignment(::Alignment alignment)
 {
-       fStyleData.SetTo(fStyleData->SetAlignment(alignment));
-       return fStyleData->Alignment() == alignment;
+       ParagraphStyleDataRef data = fStyleData->SetAlignment(alignment);
+       if (data == fStyleData)
+               return data->Alignment() == alignment;
+
+       fStyleData = data;
+       return true;
 }
 
 
 bool
 ParagraphStyle::SetJustify(bool justify)
 {
-       fStyleData.SetTo(fStyleData->SetJustify(justify));
-       return fStyleData->Justify() == justify;
+       ParagraphStyleDataRef data = fStyleData->SetJustify(justify);
+       if (data == fStyleData)
+               return data->Justify() == justify;
+
+       fStyleData = data;
+       return true;
 }
 
 
 bool
 ParagraphStyle::SetFirstLineInset(float inset)
 {
-       fStyleData.SetTo(fStyleData->SetFirstLineInset(inset));
-       return fStyleData->FirstLineInset() == inset;
+       ParagraphStyleDataRef data = fStyleData->SetFirstLineInset(inset);
+       if (data == fStyleData)
+               return data->FirstLineInset() == inset;
+
+       fStyleData = data;
+       return true;
 }
 
 
 bool
 ParagraphStyle::SetLineInset(float inset)
 {
-       fStyleData.SetTo(fStyleData->SetLineInset(inset));
-       return fStyleData->LineInset() == inset;
+       ParagraphStyleDataRef data = fStyleData->SetLineInset(inset);
+       if (data == fStyleData)
+               return data->LineInset() == inset;
+
+       fStyleData = data;
+       return true;
 }
 
 
 bool
 ParagraphStyle::SetSpacingTop(float spacing)
 {
-       fStyleData.SetTo(fStyleData->SetSpacingTop(spacing));
-       return fStyleData->SpacingTop() == spacing;
+       ParagraphStyleDataRef data = fStyleData->SetSpacingTop(spacing);
+       if (data == fStyleData)
+               return data->SpacingTop() == spacing;
+
+       fStyleData = data;
+       return true;
 }
 
 
 bool
 ParagraphStyle::SetSpacingBottom(float spacing)
 {
-       fStyleData.SetTo(fStyleData->SetSpacingBottom(spacing));
-       return fStyleData->SpacingBottom() == spacing;
+       ParagraphStyleDataRef data = fStyleData->SetSpacingBottom(spacing);
+       if (data == fStyleData)
+               return data->SpacingBottom() == spacing;
+
+       fStyleData = data;
+       return true;
 }
 
 
diff --git a/src/apps/haiku-depot/textview/ParagraphStyle.h 
b/src/apps/haiku-depot/textview/ParagraphStyle.h
index f548db4..8c9de53 100644
--- a/src/apps/haiku-depot/textview/ParagraphStyle.h
+++ b/src/apps/haiku-depot/textview/ParagraphStyle.h
@@ -37,7 +37,7 @@ public:
 
 
 private:
-                       ParagraphDataRef        fStyleData;
+                       ParagraphStyleDataRef fStyleData;
 };
 
 
diff --git a/src/apps/haiku-depot/textview/ParagraphStyleData.cpp 
b/src/apps/haiku-depot/textview/ParagraphStyleData.cpp
index d7f3db0..d943c21 100644
--- a/src/apps/haiku-depot/textview/ParagraphStyleData.cpp
+++ b/src/apps/haiku-depot/textview/ParagraphStyleData.cpp
@@ -58,93 +58,93 @@ ParagraphStyleData::operator!=(const ParagraphStyleData& 
other) const
 }
 
 
-ParagraphStyleData*
+ParagraphStyleDataRef
 ParagraphStyleData::SetAlignment(::Alignment alignment)
 {
        if (fAlignment == alignment)
-               return this;
+               return ParagraphStyleDataRef(this);
 
        ParagraphStyleData* ret = new(std::nothrow) ParagraphStyleData(*this);
        if (ret == NULL)
-               return this;
+               return ParagraphStyleDataRef(this);
 
        ret->fAlignment = alignment;
-       return ret;
+       return ParagraphStyleDataRef(ret, true);
 }
 
 
-ParagraphStyleData*
+ParagraphStyleDataRef
 ParagraphStyleData::SetJustify(bool justify)
 {
        if (fJustify == justify)
-               return this;
+               return ParagraphStyleDataRef(this);
 
        ParagraphStyleData* ret = new(std::nothrow) ParagraphStyleData(*this);
        if (ret == NULL)
-               return this;
+               return ParagraphStyleDataRef(this);
 
        ret->fJustify = justify;
-       return ret;
+       return ParagraphStyleDataRef(ret, true);
 }
 
 
-ParagraphStyleData*
+ParagraphStyleDataRef
 ParagraphStyleData::SetFirstLineInset(float inset)
 {
        if (fFirstLineInset == inset)
-               return this;
+               return ParagraphStyleDataRef(this);
 
        ParagraphStyleData* ret = new(std::nothrow) ParagraphStyleData(*this);
        if (ret == NULL)
-               return this;
+               return ParagraphStyleDataRef(this);
 
        ret->fFirstLineInset = inset;
-       return ret;
+       return ParagraphStyleDataRef(ret, true);
 }
 
 
-ParagraphStyleData*
+ParagraphStyleDataRef
 ParagraphStyleData::SetLineInset(float inset)
 {
        if (fLineInset == inset)
-               return this;
+               return ParagraphStyleDataRef(this);
 
        ParagraphStyleData* ret = new(std::nothrow) ParagraphStyleData(*this);
        if (ret == NULL)
-               return this;
+               return ParagraphStyleDataRef(this);
 
        ret->fLineInset = inset;
-       return ret;
+       return ParagraphStyleDataRef(ret, true);
 }
 
 
-ParagraphStyleData*
+ParagraphStyleDataRef
 ParagraphStyleData::SetSpacingTop(float spacing)
 {
        if (fSpacingTop == spacing)
-               return this;
+               return ParagraphStyleDataRef(this);
 
        ParagraphStyleData* ret = new(std::nothrow) ParagraphStyleData(*this);
        if (ret == NULL)
-               return this;
+               return ParagraphStyleDataRef(this);
 
        ret->fSpacingTop = spacing;
-       return ret;
+       return ParagraphStyleDataRef(ret, true);
 }
 
 
-ParagraphStyleData*
+ParagraphStyleDataRef
 ParagraphStyleData::SetSpacingBottom(float spacing)
 {
        if (fSpacingBottom == spacing)
-               return this;
+               return ParagraphStyleDataRef(this);
 
        ParagraphStyleData* ret = new(std::nothrow) ParagraphStyleData(*this);
        if (ret == NULL)
-               return this;
+               return ParagraphStyleDataRef(this);
 
        ret->fSpacingBottom = spacing;
-       return ret;
+       return ParagraphStyleDataRef(ret, true);
 }
 
 
diff --git a/src/apps/haiku-depot/textview/ParagraphStyleData.h 
b/src/apps/haiku-depot/textview/ParagraphStyleData.h
index 96c9d43..c209643 100644
--- a/src/apps/haiku-depot/textview/ParagraphStyleData.h
+++ b/src/apps/haiku-depot/textview/ParagraphStyleData.h
@@ -14,6 +14,11 @@ enum Alignment {
        ALIGN_RIGHT             = 2,
 };
 
+
+class ParagraphStyleData;
+typedef BReference<ParagraphStyleData> ParagraphStyleDataRef;
+
+
 // You cannot modify a ParagraphStyleData object once it has been
 // created.
 class ParagraphStyleData : public BReferenceable {
@@ -27,27 +32,27 @@ public:
                        bool                            operator!=(
                                                                        const 
ParagraphStyleData& other) const;
 
-                       ParagraphStyleData*     SetAlignment(::Alignment 
alignment);
+                       ParagraphStyleDataRef SetAlignment(::Alignment 
alignment);
        inline  ::Alignment                     Alignment() const
                                                                        { 
return fAlignment; }
 
-                       ParagraphStyleData*     SetJustify(bool justify);
+                       ParagraphStyleDataRef SetJustify(bool justify);
        inline  bool                            Justify() const
                                                                        { 
return fJustify; }
 
-                       ParagraphStyleData*     SetFirstLineInset(float inset);
+                       ParagraphStyleDataRef SetFirstLineInset(float inset);
        inline  float                           FirstLineInset() const
                                                                        { 
return fFirstLineInset; }
 
-                       ParagraphStyleData*     SetLineInset(float inset);
+                       ParagraphStyleDataRef SetLineInset(float inset);
        inline  float                           LineInset() const
                                                                        { 
return fLineInset; }
 
-                       ParagraphStyleData*     SetSpacingTop(float spacing);
+                       ParagraphStyleDataRef SetSpacingTop(float spacing);
        inline  float                           SpacingTop() const
                                                                        { 
return fSpacingTop; }
 
-                       ParagraphStyleData*     SetSpacingBottom(float spacing);
+                       ParagraphStyleDataRef SetSpacingBottom(float spacing);
        inline  float                           SpacingBottom() const
                                                                        { 
return fSpacingBottom; }
 
@@ -66,7 +71,4 @@ private:
 };
 
 
-typedef BReference<ParagraphStyleData> ParagraphDataRef;
-
-
 #endif // PARAGRAPH_STYLE_DATA_H

############################################################################

Commit:      947ba26bd0606f5a5b15bd53cfd85f0f56c06527
URL:         http://cgit.haiku-os.org/haiku/commit/?id=947ba26
Author:      Stephan Aßmus <superstippi@xxxxxx>
Date:        Mon Sep  2 10:04:33 2013 UTC

HaikuDepot: Redesign TextStyle as CharacterStyle ...

 ... following the example set by ParagraphStyle and
 ParagraphStyleData.

----------------------------------------------------------------------------

diff --git a/src/apps/haiku-depot/Jamfile b/src/apps/haiku-depot/Jamfile
index 766f3de..b9ed0aa 100644
--- a/src/apps/haiku-depot/Jamfile
+++ b/src/apps/haiku-depot/Jamfile
@@ -27,9 +27,12 @@ Application HaikuDepot :
        support.cpp
 
        # textview stuff
+       CharacterStyle.cpp
+       CharacterStyleData.cpp
        Paragraph.cpp
        ParagraphStyle.cpp
        ParagraphStyleData.cpp
+       TextDocument.cpp
        TextLayout.cpp
        TextSpan.cpp
        TextStyle.cpp
diff --git a/src/apps/haiku-depot/textview/CharacterStyle.cpp 
b/src/apps/haiku-depot/textview/CharacterStyle.cpp
new file mode 100644
index 0000000..9923bb2
--- /dev/null
+++ b/src/apps/haiku-depot/textview/CharacterStyle.cpp
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2013, Stephan Aßmus <superstippi@xxxxxx>.
+ * All rights reserved. Distributed under the terms of the MIT License.
+ */
+
+#include "CharacterStyle.h"
+
+
+CharacterStyle::CharacterStyle()
+       :
+       fStyleData(new CharacterStyleData(), true)
+{
+}
+
+
+CharacterStyle::CharacterStyle(const CharacterStyle& other)
+       :
+       fStyleData(other.fStyleData)
+{
+}
+
+
+CharacterStyle&
+CharacterStyle::operator=(const CharacterStyle& other)
+{
+       if (this == &other)
+               return *this;
+       
+       fStyleData = other.fStyleData;
+       return *this;
+}
+
+
+bool
+CharacterStyle::operator==(const CharacterStyle& other) const
+{
+       if (this == &other)
+               return true;
+
+       if (fStyleData == other.fStyleData)
+               return true;
+
+       if (fStyleData.Get() != NULL && other.fStyleData.Get() != NULL)
+               return *fStyleData.Get() == *other.fStyleData.Get();
+
+       return false;
+}
+
+
+bool
+CharacterStyle::operator!=(const CharacterStyle& other) const
+{
+       return !(*this == other);
+}
+
+
+bool
+CharacterStyle::SetFont(const BFont& font)
+{
+       CharacterStyleDataRef data = fStyleData->SetFont(font);
+       if (data == fStyleData)
+               return data->Font() == font;
+
+       fStyleData = data;
+       return true;
+}
+
+
+bool
+CharacterStyle::SetAscent(float ascent)
+{
+       CharacterStyleDataRef data = fStyleData->SetAscent(ascent);
+       if (data == fStyleData)
+               return data->Ascent() == ascent;
+
+       fStyleData = data;
+       return true;
+}
+
+
+bool
+CharacterStyle::SetDescent(float descent)
+{
+       CharacterStyleDataRef data = fStyleData->SetDescent(descent);
+       if (data == fStyleData)
+               return data->Descent() == descent;
+
+       fStyleData = data;
+       return true;
+}
+
+
+bool
+CharacterStyle::SetWidth(float width)
+{
+       CharacterStyleDataRef data = fStyleData->SetWidth(width);
+       if (data == fStyleData)
+               return data->Width() == width;
+
+       fStyleData = data;
+       return true;
+}
+
+
+bool
+CharacterStyle::SetForegroundColor(rgb_color color)
+{
+       CharacterStyleDataRef data = fStyleData->SetForegroundColor(color);
+       if (data == fStyleData)
+               return data->ForegroundColor() == color;
+
+       fStyleData = data;
+       return true;
+}
+
+
+bool
+CharacterStyle::SetBackgroundColor(rgb_color color)
+{
+       CharacterStyleDataRef data = fStyleData->SetBackgroundColor(color);
+       if (data == fStyleData)
+               return data->BackgroundColor() == color;
+
+       fStyleData = data;
+       return true;
+}
+
+
+bool
+CharacterStyle::SetStrikeOutColor(rgb_color color)
+{
+       CharacterStyleDataRef data = fStyleData->SetStrikeOutColor(color);
+       if (data == fStyleData)
+               return data->StrikeOutColor() == color;
+
+       fStyleData = data;
+       return true;
+}
+
+
+bool
+CharacterStyle::SetUnderlineColor(rgb_color color)
+{
+       CharacterStyleDataRef data = fStyleData->SetUnderlineColor(color);
+       if (data == fStyleData)
+               return data->UnderlineColor() == color;
+
+       fStyleData = data;
+       return true;
+}
+
+
+bool
+CharacterStyle::SetStrikeOut(uint8 strikeOut)
+{
+       CharacterStyleDataRef data = fStyleData->SetStrikeOut(strikeOut);
+       if (data == fStyleData)
+               return data->StrikeOut() == strikeOut;
+
+       fStyleData = data;
+       return true;
+}
+
+
+bool
+CharacterStyle::SetUnderline(uint8 underline)
+{
+       CharacterStyleDataRef data = fStyleData->SetUnderline(underline);
+       if (data == fStyleData)
+               return data->Underline() == underline;
+
+       fStyleData = data;
+       return true;
+}
+
+
diff --git a/src/apps/haiku-depot/textview/CharacterStyle.h 
b/src/apps/haiku-depot/textview/CharacterStyle.h
new file mode 100644
index 0000000..eb6a7e6
--- /dev/null
+++ b/src/apps/haiku-depot/textview/CharacterStyle.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2013, Stephan Aßmus <superstippi@xxxxxx>.
+ * All rights reserved. Distributed under the terms of the MIT License.
+ */
+#ifndef CHARACTER_STYLE_H
+#define CHARACTER_STYLE_H
+
+#include "CharacterStyleData.h"
+
+
+class CharacterStyle {
+public:
+                                                               
CharacterStyle();
+                                                               
CharacterStyle(const CharacterStyle& other);
+
+                       CharacterStyle&         operator=(const CharacterStyle& 
other);
+                       bool                            operator==(const 
CharacterStyle& other) const;
+                       bool                            operator!=(const 
CharacterStyle& other) const;
+
+                       bool                            SetFont(const BFont& 
font);
+                       const BFont&            Font() const;
+
+                       bool                            SetAscent(float ascent);
+                       float                           Ascent() const;
+
+                       bool                            SetDescent(float 
descent);
+                       float                           Descent() const;
+
+                       bool                            SetWidth(float width);
+                       float                           Width() const;
+
+                       bool                            
SetForegroundColor(rgb_color color);
+                       rgb_color                       ForegroundColor() const;
+
+                       bool                            
SetBackgroundColor(rgb_color color);
+                       rgb_color                       BackgroundColor() const;
+
+                       bool                            
SetStrikeOutColor(rgb_color color);
+                       rgb_color                       StrikeOutColor() const;
+
+                       bool                            
SetUnderlineColor(rgb_color color);
+                       rgb_color                       UnderlineColor() const;
+
+                       bool                            SetStrikeOut(uint8 
strikeOut);
+                       uint8                           StrikeOut() const;
+
+                       bool                            SetUnderline(uint8 
underline);
+                       uint8                           Underline() const;
+
+private:
+                       CharacterStyleDataRef fStyleData;
+};
+
+
+#endif // CHARACTER_STYLE_H
diff --git a/src/apps/haiku-depot/textview/CharacterStyleData.cpp 
b/src/apps/haiku-depot/textview/CharacterStyleData.cpp
new file mode 100644
index 0000000..a5a0401
--- /dev/null
+++ b/src/apps/haiku-depot/textview/CharacterStyleData.cpp
@@ -0,0 +1,240 @@
+/*
+ * Copyright 2013, Stephan Aßmus <superstippi@xxxxxx>.
+ * All rights reserved. Distributed under the terms of the MIT License.
+ */
+
+#include "CharacterStyleData.h"
+
+#include <new>
+
+
+CharacterStyleData::CharacterStyleData()
+       :
+       fFont(),
+
+       fAscent(-1.0f),
+       fDescent(-1.0f),
+       fWidth(-1.0f),
+
+       fGlyphSpacing(0.0f),
+
+       fFgColor((rgb_color){ 0, 0, 0, 255 }),
+       fBgColor((rgb_color){ 255, 255, 255, 255 }),
+       fStrikeOutColor((rgb_color){ 0, 0, 0, 255 }),
+       fUnderlineColor((rgb_color){ 0, 0, 0, 255 }),
+
+       fStrikeOutStyle(STRIKE_OUT_NONE),
+       fUnderlineStyle(UNDERLINE_NONE)
+{
+}
+
+
+CharacterStyleData::CharacterStyleData(const CharacterStyleData& other)
+       :
+       fFont(other.fFont),
+
+       fAscent(other.fAscent),
+       fDescent(other.fDescent),
+       fWidth(other.fWidth),
+
+       fGlyphSpacing(other.fGlyphSpacing),
+
+       fFgColor(other.fFgColor),
+       fBgColor(other.fBgColor),
+       fStrikeOutColor(other.fStrikeOutColor),
+       fUnderlineColor(other.fUnderlineColor),
+
+       fStrikeOutStyle(other.fStrikeOutStyle),
+       fUnderlineStyle(other.fUnderlineStyle)
+{
+}
+
+
+bool
+CharacterStyleData::operator==(const CharacterStyleData& other) const
+{
+       if (this == &other)
+               return true;
+
+       return fFont == other.fFont
+               && fAscent == other.fAscent
+               && fDescent == other.fDescent
+               && fWidth == other.fWidth
+
+               && fGlyphSpacing == other.fGlyphSpacing
+
+               && fFgColor == other.fFgColor
+               && fBgColor == other.fBgColor
+               && fStrikeOutColor == other.fStrikeOutColor
+               && fUnderlineColor == other.fUnderlineColor
+
+               && fStrikeOutStyle == other.fStrikeOutStyle
+               && fUnderlineStyle == other.fUnderlineStyle;
+}
+
+
+bool
+CharacterStyleData::operator!=(const CharacterStyleData& other) const
+{
+       return !(*this == other);
+}
+
+
+CharacterStyleDataRef
+CharacterStyleData::SetFont(const BFont& font)
+{
+       if (fFont == font)
+               return CharacterStyleDataRef(this);
+
+       CharacterStyleData* ret = new(std::nothrow) CharacterStyleData(*this);
+       if (ret == NULL)
+               return CharacterStyleDataRef(this);
+
+       ret->fFont = font;
+       return CharacterStyleDataRef(ret, true);
+}
+
+
+CharacterStyleDataRef
+CharacterStyleData::SetAscent(float ascent)
+{
+       if (fAscent == ascent)
+               return CharacterStyleDataRef(this);
+
+       CharacterStyleData* ret = new(std::nothrow) CharacterStyleData(*this);
+       if (ret == NULL)
+               return CharacterStyleDataRef(this);
+
+       ret->fAscent = ascent;
+       return CharacterStyleDataRef(ret, true);
+}
+
+
+CharacterStyleDataRef
+CharacterStyleData::SetDescent(float descent)
+{
+       if (fDescent == descent)
+               return CharacterStyleDataRef(this);
+
+       CharacterStyleData* ret = new(std::nothrow) CharacterStyleData(*this);
+       if (ret == NULL)
+               return CharacterStyleDataRef(this);
+
+       ret->fDescent = descent;
+       return CharacterStyleDataRef(ret, true);
+}
+
+
+CharacterStyleDataRef
+CharacterStyleData::SetWidth(float width)
+{
+       if (fWidth == width)
+               return CharacterStyleDataRef(this);
+
+       CharacterStyleData* ret = new(std::nothrow) CharacterStyleData(*this);
+       if (ret == NULL)
+               return CharacterStyleDataRef(this);
+
+       ret->fWidth = width;
+       return CharacterStyleDataRef(ret, true);
+}
+
+
+CharacterStyleDataRef
+CharacterStyleData::SetForegroundColor(rgb_color color)
+{
+       if (fFgColor == color)
+               return CharacterStyleDataRef(this);
+
+       CharacterStyleData* ret = new(std::nothrow) CharacterStyleData(*this);
+       if (ret == NULL)
+               return CharacterStyleDataRef(this);
+
+       ret->fFgColor = color;
+       return CharacterStyleDataRef(ret, true);
+}
+
+
+CharacterStyleDataRef
+CharacterStyleData::SetBackgroundColor(rgb_color color)
+{
+       if (fBgColor == color)
+               return CharacterStyleDataRef(this);
+
+       CharacterStyleData* ret = new(std::nothrow) CharacterStyleData(*this);
+       if (ret == NULL)
+               return CharacterStyleDataRef(this);
+
+       ret->fBgColor = color;
+       return CharacterStyleDataRef(ret, true);
+}
+
+
+CharacterStyleDataRef
+CharacterStyleData::SetStrikeOutColor(rgb_color color)
+{
+       if (fStrikeOutColor == color)
+               return CharacterStyleDataRef(this);
+
+       CharacterStyleData* ret = new(std::nothrow) CharacterStyleData(*this);
+       if (ret == NULL)
+               return CharacterStyleDataRef(this);
+
+       ret->fStrikeOutColor = color;
+       return CharacterStyleDataRef(ret, true);
+}
+
+
+CharacterStyleDataRef
+CharacterStyleData::SetUnderlineColor(rgb_color color)
+{
+       if (fUnderlineColor == color)
+               return CharacterStyleDataRef(this);
+
+       CharacterStyleData* ret = new(std::nothrow) CharacterStyleData(*this);
+       if (ret == NULL)
+               return CharacterStyleDataRef(this);
+
+       ret->fUnderlineColor = color;
+       return CharacterStyleDataRef(ret, true);
+}
+
+
+CharacterStyleDataRef
+CharacterStyleData::SetStrikeOut(uint8 strikeOut)
+{
+       if (fStrikeOutStyle == strikeOut)
+               return CharacterStyleDataRef(this);
+
+       CharacterStyleData* ret = new(std::nothrow) CharacterStyleData(*this);
+       if (ret == NULL)
+               return CharacterStyleDataRef(this);
+
+       ret->fStrikeOutStyle = strikeOut;
+       return CharacterStyleDataRef(ret, true);
+}
+
+
+CharacterStyleDataRef
+CharacterStyleData::SetUnderline(uint8 underline)
+{
+       if (fUnderlineStyle == underline)
+               return CharacterStyleDataRef(this);
+
+       CharacterStyleData* ret = new(std::nothrow) CharacterStyleData(*this);
+       if (ret == NULL)
+               return CharacterStyleDataRef(this);
+
+       ret->fUnderlineStyle = underline;
+       return CharacterStyleDataRef(ret, true);
+}
+
+
+// #pragma mark - private
+
+
+CharacterStyleData&
+CharacterStyleData::operator=(const CharacterStyleData& other)
+{
+       return *this;
+}
diff --git a/src/apps/haiku-depot/textview/CharacterStyleData.h 
b/src/apps/haiku-depot/textview/CharacterStyleData.h
new file mode 100644
index 0000000..c445aa8
--- /dev/null
+++ b/src/apps/haiku-depot/textview/CharacterStyleData.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2013, Stephan Aßmus <superstippi@xxxxxx>.
+ * All rights reserved. Distributed under the terms of the MIT License.
+ */
+#ifndef CHARACTER_STYLE_DATA_H
+#define CHARACTER_STYLE_DATA_H
+
+#include <Font.h>
+#include <Referenceable.h>
+
+
+enum {
+       STRIKE_OUT_NONE         = 0,
+       STRIKE_OUT_SINGLE       = 1,
+};
+
+
+enum {
+       UNDERLINE_NONE          = 0,
+       UNDERLINE_SINGLE        = 1,
+       UNDERLINE_DOUBLE        = 2,
+       UNDERLINE_WIGGLE        = 3,
+       UNDERLINE_DOTTED        = 4,
+};
+
+
+class CharacterStyleData;
+typedef BReference<CharacterStyleData> CharacterStyleDataRef;
+
+
+// You cannot modify a CharacterStyleData object once it has been
+// created.
+class CharacterStyleData : public BReferenceable {
+public:
+                                                               
CharacterStyleData();
+                                                               
CharacterStyleData(
+                                                                       const 
CharacterStyleData& other);
+
+                       bool                            operator==(
+                                                                       const 
CharacterStyleData& other) const;
+                       bool                            operator!=(
+                                                                       const 
CharacterStyleData& other) const;
+
+                       CharacterStyleDataRef SetFont(const BFont& font);
+       inline  const BFont&            Font() const
+                                                                       { 
return fFont; }
+
+                       CharacterStyleDataRef SetAscent(float ascent);
+       inline  float                           Ascent() const
+                                                                       { 
return fAscent; }
+
+                       CharacterStyleDataRef SetDescent(float descent);
+       inline  float                           Descent() const
+                                                                       { 
return fDescent; }
+
+                       CharacterStyleDataRef SetWidth(float width);
+       inline  float                           Width() const
+                                                                       { 
return fWidth; }
+
+                       CharacterStyleDataRef SetForegroundColor(rgb_color 
color);
+       inline  rgb_color                       ForegroundColor() const
+                                                                       { 
return fFgColor; }
+
+                       CharacterStyleDataRef SetBackgroundColor(rgb_color 
color);
+       inline  rgb_color                       BackgroundColor() const
+                                                                       { 
return fBgColor; }
+
+                       CharacterStyleDataRef SetStrikeOutColor(rgb_color 
color);
+       inline  rgb_color                       StrikeOutColor() const
+                                                                       { 
return fStrikeOutColor; }
+
+                       CharacterStyleDataRef SetUnderlineColor(rgb_color 
color);
+       inline  rgb_color                       UnderlineColor() const
+                                                                       { 
return fUnderlineColor; }
+
+                       CharacterStyleDataRef SetStrikeOut(uint8 strikeOut);
+       inline  uint8                           StrikeOut() const
+                                                                       { 
return fStrikeOutStyle; }
+
+                       CharacterStyleDataRef SetUnderline(uint8 underline);
+       inline  uint8                           Underline() const
+                                                                       { 
return fUnderlineStyle; }
+
+private:
+                       CharacterStyleData&     operator=(const 
CharacterStyleData& other);
+
+private:
+                       BFont                           fFont;
+               
+                       // The following three values override glyph metrics 
unless -1
+                       float                           fAscent;
+                       float                           fDescent;
+                       float                           fWidth;
+
+                       float                           fGlyphSpacing;
+               
+                       rgb_color                       fFgColor;
+                       rgb_color                       fBgColor;
+                       rgb_color                       fStrikeOutColor;
+                       rgb_color                       fUnderlineColor;
+               
+                       uint8                           fStrikeOutStyle;
+                       uint8                           fUnderlineStyle;
+};
+
+
+
+#endif // CHARACTER_STYLE_DATA_H

############################################################################

Revision:    hrev46009
Commit:      15a557e69cd82d9ad3c67134c4bc8e48059ed37a
URL:         http://cgit.haiku-os.org/haiku/commit/?id=15a557e
Author:      Stephan Aßmus <superstippi@xxxxxx>
Date:        Mon Sep  2 10:09:52 2013 UTC

HaikuDepot: Re-implemented TextLayout as ParagraphLayout

 * Completely unfininished and untested, won't even compile,
   but is not included in the build. The idea being to wrap TextSpan
   objects and split them onto Lines each containing their own
   layouted TextSpan chunks. TextLayout will later be repurposed
   to off-load the layout of individual text paragraphs to
   ParagraphLayouts.

----------------------------------------------------------------------------

diff --git a/src/apps/haiku-depot/textview/ParagraphLayout.cpp 
b/src/apps/haiku-depot/textview/ParagraphLayout.cpp
new file mode 100644
index 0000000..c0ff872
--- /dev/null
+++ b/src/apps/haiku-depot/textview/ParagraphLayout.cpp
@@ -0,0 +1,596 @@
+/*
+ * Copyright 2001-2013, Haiku, Inc. All rights reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *             Stephan Aßmus, superstippi@xxxxxx
+ *             Stefano Ceccherini, stefano.ceccherini@xxxxxxxxx
+ *             Marc Flerackers, mflerackers@xxxxxxxxxx
+ *             Hiroshi Lockheimer (BTextView is based on his STEEngine)
+ *             Oliver Tappe, zooey@xxxxxxxxxxxxxxx
+ */
+
+#include "ParagraphLayout.h"
+
+#include <new>
+#include <stdio.h>
+
+#include <AutoDeleter.h>
+#include <utf8_functions.h>
+#include <View.h>
+
+#include "GlyphInfo.h"
+#include "List.h"
+#include "TextStyle.h"
+
+
+enum {
+       CHAR_CLASS_DEFAULT,
+       CHAR_CLASS_WHITESPACE,
+       CHAR_CLASS_GRAPHICAL,
+       CHAR_CLASS_QUOTE,
+       CHAR_CLASS_PUNCTUATION,
+       CHAR_CLASS_PARENS_OPEN,
+       CHAR_CLASS_PARENS_CLOSE,
+       CHAR_CLASS_END_OF_TEXT
+};
+
+
+inline uint32
+get_char_classification(uint32 charCode)
+{
+       // TODO: Should check against a list of characters containing also
+       // word breakers from other languages.
+
+       switch (charCode) {
+               case '\0':
+                       return CHAR_CLASS_END_OF_TEXT;
+
+               case ' ':
+               case '\t':
+               case '\n':
+                       return CHAR_CLASS_WHITESPACE;
+
+               case '=':
+               case '+':
+               case '@':
+               case '#':
+               case '$':
+               case '%':
+               case '^':
+               case '&':
+               case '*':
+               case '\\':
+               case '|':
+               case '<':
+               case '>':
+               case '/':
+               case '~':
+                       return CHAR_CLASS_GRAPHICAL;
+
+               case '\'':
+               case '"':
+                       return CHAR_CLASS_QUOTE;
+
+               case ',':
+               case '.':
+               case '?':
+               case '!':
+               case ';':
+               case ':':
+               case '-':
+                       return CHAR_CLASS_PUNCTUATION;
+
+               case '(':
+               case '[':
+               case '{':
+                       return CHAR_CLASS_PARENS_OPEN;
+
+               case ')':
+               case ']':
+               case '}':
+                       return CHAR_CLASS_PARENS_CLOSE;
+
+               default:
+                       return CHAR_CLASS_DEFAULT;
+       }
+}
+
+
+inline bool
+can_end_line(const GlyphInfo* buffer, int offset, int count)
+{
+       if (offset == count - 1)
+               return true;
+
+       if (offset < 0 || offset > count)
+               return false;
+
+       uint32 charCode = buffer[offset].charCode;
+       uint32 classification = get_char_classification(charCode);
+
+       // wrapping is always allowed at end of text and at newlines
+       if (classification == CHAR_CLASS_END_OF_TEXT || charCode == '\n')
+               return true;
+
+       uint32 nextCharCode = buffer[offset + 1].charCode;
+       uint32 nextClassification = get_char_classification(nextCharCode);
+
+       // never separate a punctuation char from its preceding word
+       if (classification == CHAR_CLASS_DEFAULT
+               && nextClassification == CHAR_CLASS_PUNCTUATION) {
+               return false;
+       }
+
+       if ((classification == CHAR_CLASS_WHITESPACE
+                       && nextClassification != CHAR_CLASS_WHITESPACE)
+               || (classification != CHAR_CLASS_WHITESPACE
+                       && nextClassification == CHAR_CLASS_WHITESPACE)) {
+               return true;
+       }
+
+       // allow wrapping after whitespace, unless more whitespace (except for
+       // newline) follows
+       if (classification == CHAR_CLASS_WHITESPACE
+               && (nextClassification != CHAR_CLASS_WHITESPACE
+                       || nextCharCode == '\n')) {
+               return true;
+       }
+
+       // allow wrapping after punctuation chars, unless more punctuation, 
closing
+       // parenthesis or quotes follow
+       if (classification == CHAR_CLASS_PUNCTUATION
+               && nextClassification != CHAR_CLASS_PUNCTUATION
+               && nextClassification != CHAR_CLASS_PARENS_CLOSE
+               && nextClassification != CHAR_CLASS_QUOTE) {
+               return true;
+       }
+
+       // allow wrapping after quotes, graphical chars and closing parenthesis 
only
+       // if whitespace follows (not perfect, but seems to do the right thing 
most
+       // of the time)
+       if ((classification == CHAR_CLASS_QUOTE
+                       || classification == CHAR_CLASS_GRAPHICAL
+                       || classification == CHAR_CLASS_PARENS_CLOSE)
+               && nextClassification == CHAR_CLASS_WHITESPACE) {
+               return true;
+       }
+
+       return false;
+}
+
+
+// #pragma mark - ParagraphLayout
+
+
+ParagraphLayout::ParagraphLayout()
+       :
+       fTextSpans(),
+       fWidth(0.0f),
+
+       fLayoutValid(false),
+
+       fGlyphInfoBuffer(NULL),
+       fGlpyhInfoBufferSize(0),
+       fGlyphInfoCount(0),
+
+       fLayoutLines()
+{
+}
+
+
+ParagraphLayout::ParagraphLayout(const Paragraph& paragraph)
+       :
+       fTextSpans(paragraph.TextSpans()),
+       fWidth(other.fWidth),
+
+       fLayoutValid(false),
+
+       fGlyphInfoBuffer(NULL),
+       fGlpyhInfoBufferSize(0),
+       fGlyphInfoCount(0),
+
+       fLayoutLines()
+{
+       _Init();
+}
+
+
+ParagraphLayout::ParagraphLayout(const ParagraphLayout& other)
+       :
+       fTextSpans(other.fTextSpans),
+       fWidth(other.fWidth),
+
+       fLayoutValid(false),
+
+       fGlyphInfoBuffer(NULL),
+       fGlpyhInfoBufferSize(0),
+       fGlyphInfoCount(0),
+
+       fLayoutLines()
+{
+       _Init();
+}
+
+
+ParagraphLayout::~ParagraphLayout()
+{
+       delete[] fGlyphInfoBuffer;
+}
+
+
+void
+ParagraphLayout::SetWidth(float width)
+{
+       if (fWidth != width) {
+               fWidth = width;
+               fLayoutValid = false;
+       }
+}
+
+
+float
+ParagraphLayout::Height()
+{
+       _ValidateLayout();
+
+       float height = 0.0f;
+
+       if (fLayoutLines.CountItems() > 0) {
+               const LayoutLine& lastLine = fLayoutLines.LastItem();
+               height = lastLine.y + lastLine.height;
+       }
+
+       return height;
+}
+
+
+void
+ParagraphLayout::Draw(BView* view, const BPoint& offset)
+{
+       _ValidateLayout();
+       
+       int lineCount = fLayoutLines.CountItems();
+       for (int i = 0; i < lineCount; i++) {
+               const LayoutLine& line = fLayoutLines.ItemAtFast(i);
+               _DrawLine(view, line);
+       }
+}
+
+
+// #pragma mark - private
+
+
+void
+ParagraphLayout::_ValidateLayout()
+{
+       if (!fLayoutValid)
+               _Layout();
+}
+
+
+void
+ParagraphLayout::_Layout()
+{
+       fLayoutLines.Clear();
+
+//     int charCount = fText.CountChars();
+//     if (charCount == 0)
+//             return;
+//     
+//     // Allocate arrays
+//     float* escapementArray = new (std::nothrow) float[charCount];
+//     if (escapementArray == NULL)
+//             return;
+//     ArrayDeleter<float> escapementDeleter(escapementArray);
+//
+//     // Fetch glyph spacing information
+//     fDefaultFont.GetEscapements(fText.String(), charCount, escapementArray);
+//
+//     // Convert to glyph buffer
+//     fGlyphInfoCount = charCount;
+//     fGlyphInfoBuffer = new (std::nothrow) GlyphInfo[fGlyphInfoCount];
+//     
+//     // Init glyph buffer and convert escapement scale
+//     float size = fDefaultFont.Size();
+//     const char* c = fText.String();
+//     for (int i = 0; i < fGlyphInfoCount; i++) {
+//             fGlyphInfoBuffer[i].charCode = UTF8ToCharCode(&c);
+//             escapementArray[i] *= size;
+//     }
+//
+//
+//     float x = fFirstLineInset;
+//     float y = 0.0f;
+//     int lineIndex = 0;
+//     int lineStart = 0;
+//
+//     for (int i = 0; i < fGlyphInfoCount; i++) {
+//             uint32 charClassification = get_char_classification(
+//                     fGlyphInfoBuffer[i].charCode);
+//
+//             float advanceX = 0.0f;
+//             float advanceY = 0.0f;
+//             _GetGlyphAdvance(i, advanceX, advanceY, escapementArray);
+//
+//             bool nextLine = false;
+//             bool lineBreak = false;
+//
+//             if (fGlyphInfoBuffer[i].charCode == '\t') {
+//                     // Figure out tab width, it's the width between the 
last two tab
+//                     // stops.
+//                     float tabWidth = 0.0f;
+//                     if (fTabCount > 0)
+//                             tabWidth = fTabBuffer[fTabCount - 1];
+//                     if (fTabCount > 1)
+//                             tabWidth -= fTabBuffer[fTabCount - 2];
+//
+//                     // Try to find a tab stop that is farther than the 
current x
+//                     // offset
+//                     double tabOffset = 0.0;
+//                     for (unsigned tabIndex = 0; tabIndex < fTabCount; 
tabIndex++) {
+//                             tabOffset = fTabBuffer[tabIndex];
+//                             if (tabOffset > x)
+//                                     break;
+//                     }
+//
+//                     // If no tab stop has been found, make the tab stop a 
multiple of
+//                     // the tab width
+//                     if (tabOffset <= x && tabWidth > 0.0)
+//                             tabOffset = ((int) (x / tabWidth) + 1) * 
tabWidth;
+//
+//                     if (tabOffset - x > 0.0)
+//                             advanceX = tabOffset - x;
+//             }
+//
+//             fGlyphInfoBuffer[i].advanceX = advanceX;
+//
+//             if (fGlyphInfoBuffer[i].charCode == '\n') {
+//                     nextLine = true;
+//                     lineBreak = true;
+//                     fGlyphInfoBuffer[i].x = x;
+//                     fGlyphInfoBuffer[i].y = y;
+//             } else if (fWidth > 0.0f && x + advanceX > fWidth) {
+//                     if (charClassification == CHAR_CLASS_WHITESPACE) {
+//                             advanceX = 0.0f;
+//                     } else if (i > lineStart) {
+//                             nextLine = true;
+//                             // The current glyph extends outside the width, 
we need to wrap
+//                             // to the next line. See what previous offset 
can be the end
+//                             // of the line.
+//                             int lineEnd = i - 1;
+//                             while (lineEnd > lineStart
+//                                     && !can_end_line(fGlyphInfoBuffer, 
lineEnd,
+//                                             fGlyphInfoCount)) {
+//                                     lineEnd--;
+//                             }
+//
+//                             if (lineEnd > lineStart) {
+//                                     // Found a place to perform a line 
break.
+//                                     i = lineEnd + 1;
+//                                     // Adjust the glyph info to point at 
the changed buffer
+//                                     // position
+//                                     _GetGlyphAdvance(i, advanceX, advanceY, 
escapementArray);
+//                             } else {
+//                                     // Just break where we are.
+//                             }
+//                     }
+//             }
+//
+//             if (nextLine) {
+//                     // * Initialize the max ascent/descent of all preceding 
glyph infos
+//                     // on the current/last line
+//                     // * Adjust the baseline offset according to the max 
ascent
+//                     // * Fill in the line index.
+//                     unsigned lineEnd;
+//                     if (lineBreak)
+//                             lineEnd = i;
+//                     else
+//                             lineEnd = i - 1;
+//
+//                     float lineHeight = 0.0;
+//                     _FinalizeLine(lineStart, lineEnd, lineIndex, y,
+//                             lineHeight);
+//
+//                     // Start position of the next line
+//                     x = fLineInset;
+//                     y += lineHeight + fLineSpacing;
+//
+//                     if (lineBreak)
+//                             lineStart = i + 1;
+//                     else
+//                             lineStart = i;
+//
+//                     lineIndex++;
+//             }
+//
+//             if (!lineBreak && i < fGlyphInfoCount) {
+//                     fGlyphInfoBuffer[i].x = x;
+//                     fGlyphInfoBuffer[i].y = y;
+//             }
+//
+//             x += advanceX;
+//             y += advanceY;
+//     }
+//
+//     // The last line may not have been appended and initialized yet.
+//     if (lineStart <= fGlyphInfoCount - 1) {
+//             float lineHeight;
+//             _FinalizeLine(lineStart, fGlyphInfoCount - 1, lineIndex, y, 
lineHeight);
+//     }
+}
+
+
+void
+ParagraphLayout::_Init()
+{
+       delete[] fGlyphInfoBuffer;
+       fGlyphInfoBuffer = NULL;
+       fGlpyhInfoBufferSize = 0;
+       fGlyphInfoCount = 0;
+
+       int spanCount = fTextSpans.CountItems();
+       for (int i = 0; i < spanCount; i++) {
+               const TextSpan& span = fTextSpans.ItemAtFast(i);
+               if (!_AppendGlyphInfos(span)) {
+                       fprintf(stderr, "%p->ParagraphLayout::_Init() - Out of 
memory\n",
+                               this);
+                       return;
+               }
+       }
+}
+
+
+bool
+ParagraphLayout::_AppendGlyphInfos(const TextSpan& span)
+{
+       int charCount = span.CharCount();
+       if (charCount == 0)
+               return true;
+       
+       const BString& text = span.Text();
+       const BFont& font = span.Style().font;
+
+       // Allocate arrays
+       float* escapementArray = new (std::nothrow) float[charCount];
+       if (escapementArray == NULL)
+               return false;
+       ArrayDeleter<float> escapementDeleter(escapementArray);
+
+       // Fetch glyph spacing information
+       font.GetEscapements(text, charCount, escapementArray);
+
+       // Append to glyph buffer and convert escapement scale
+       float size = font.Size();
+       const char* c = text.String();
+       for (int i = 0; i < charCount; i++) {
+               _AppendGlyphInfo(UTF8ToCharCode(&c), );
+               fGlyphInfoBuffer[i].charCode = ;
+               escapementArray[i] *= size;
+       }
+
+}
+
+
+bool
+ParagraphLayout::_AppendGlyphInfo(uint32 charCode, const TextStyleRef& style)
+{
+       // Enlarge buffer if necessary
+       if (fGlyphInfoCount == fGlyphInfoBufferSize) {
+               int size = fGlyphInfoBufferSize + 64;
+
+               GlyphInfo* buffer = (GlyphInfo*) realloc(fGlyphInfoBuffer,
+                       size * sizeof(GlyphInfo));
+               if (buffer == NULL)
+                       return false;
+
+               fGlyphInfoBufferSize = size;
+               fGlyphInfoBuffer = buffer;
+       }
+
+       // Store given information
+       fGlyphInfoBuffer[fGlyphInfoCount].charCode = charCode;
+       fGlyphInfoBuffer[fGlyphInfoCount].glyph = glyph;
+       fGlyphInfoBuffer[fGlyphInfoCount].x = 0;
+       fGlyphInfoBuffer[fGlyphInfoCount].y = 0;
+       fGlyphInfoBuffer[fGlyphInfoCount].advanceX = 0;
+       fGlyphInfoBuffer[fGlyphInfoCount].maxAscend = 0;
+       fGlyphInfoBuffer[fGlyphInfoCount].maxDescend = 0;
+       fGlyphInfoBuffer[fGlyphInfoCount].lineIndex = 0;
+       fGlyphInfoBuffer[fGlyphInfoCount].styleRun = styleRun;
+
+       fGlyphInfoCount++;
+
+       return true;
+}
+
+
+void
+ParagraphLayout::_GetGlyphAdvance(int offset, float& advanceX, float& advanceY,
+       float escapementArray[]) const
+{
+       float additionalGlyphSpacing = 0.0f;
+       if (fGlyphInfoBuffer[offset].style.Get() != NULL)
+               additionalGlyphSpacing = 
fGlyphInfoBuffer[offset].style->glyphSpacing;
+       else
+               additionalGlyphSpacing = fGlyphSpacing;
+
+       if (fGlyphInfoBuffer[offset].style.Get() != NULL
+               && fGlyphInfoBuffer[offset].style->width > 0.0f) {
+               // Use the metrics provided by the TextStyle
+               advanceX = fGlyphInfoBuffer[offset].style->width
+                       + additionalGlyphSpacing;
+       } else {
+               advanceX = escapementArray[offset] + additionalGlyphSpacing;
+               advanceY = 0.0f;
+       }
+}
+
+
+void
+ParagraphLayout::_FinalizeLine(int lineStart, int lineEnd, int lineIndex, 
float y,
+       float& lineHeight)
+{
+       lineHeight = 0.0f;
+       float maxAscent = 0.0f;
+       float maxDescent = 0.0f;
+
+       for (int i = lineStart; i <= lineEnd; i++) {
+               if (fGlyphInfoBuffer[i].style.Get() != NULL) {
+                       if (fGlyphInfoBuffer[i].style->font.Size() > lineHeight)
+                               lineHeight = 
fGlyphInfoBuffer[i].style->font.Size();
+                       if (fGlyphInfoBuffer[i].style->ascent > maxAscent)
+                               maxAscent = fGlyphInfoBuffer[i].style->ascent;
+                       if (fGlyphInfoBuffer[i].style->descent > maxDescent)
+                               maxDescent = fGlyphInfoBuffer[i].style->descent;
+               } else {
+                       if (fDefaultFont.Size() > lineHeight)
+                               lineHeight = fDefaultFont.Size();
+                       if (fAscent > maxAscent)
+                               maxAscent = fAscent;
+                       if (fDescent > maxDescent)
+                               maxDescent = fDescent;
+               }
+       }
+
+       fLayoutLines.Add(LayoutLine(lineStart, y, lineHeight, maxAscent, 
maxDescent));
+
+       for (int i = lineStart; i <= lineEnd; i++) {
+               fGlyphInfoBuffer[i].maxAscent = maxAscent;
+               fGlyphInfoBuffer[i].maxDescent = maxDescent;
+               fGlyphInfoBuffer[i].lineIndex = lineIndex;
+               fGlyphInfoBuffer[i].y += maxAscent;
+       }
+}
+
+
+void
+ParagraphLayout::_DrawLine(BView* view, const LayoutLine& line) const
+{
+       int textOffset = line.textOffset;
+       int spanCount = line.layoutedSpans.CountItems();
+       for (int i = 0; i < spanCount) {
+               const TextSpan& span = line.layoutedSpans.ItemAtFast(i);
+               _DrawSpan(view, span, textOffset);
+               textOffset += span.CharCount();
+       }
+}
+
+
+void
+ParagraphLayout::_DrawSpan(BView* view, const TextSpan& span,
+       int textOffset) const
+{
+       float x = fGlyphInfoBuffer[textOffset].x;
+       float y = fGlyphInfoBuffer[textOffset].y;
+
+       const TextStyle& style = span.Style();
+
+       view->SetFont(&style.font);
+       view->SetHighColor(style.fgColor);
+
+       // TODO: Implement other style properties
+       // TODO: Implement correct glyph spacing
+
+       view->DrawString(span.Text(), BPoint(x, y));
+}
diff --git a/src/apps/haiku-depot/textview/ParagraphLayout.h 
b/src/apps/haiku-depot/textview/ParagraphLayout.h
new file mode 100644
index 0000000..0ff8599
--- /dev/null
+++ b/src/apps/haiku-depot/textview/ParagraphLayout.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2013, Stephan Aßmus <superstippi@xxxxxx>.
+ * All rights reserved. Distributed under the terms of the MIT License.
+ */
+#ifndef PARAGRAPH_LAYOUT_H
+#define PARAGRAPH_LAYOUT_H
+
+#include <Font.h>
+#include <Referenceable.h>
+#include <String.h>
+
+#include "GlyphInfo.h"
+#include "Paragraph.h"
+
+
+class BView;
+
+
+class LayoutLine {
+public:
+       LayoutLine()
+               :
+               textOffset(0),
+               y(0.0f),
+               height(0.0f),
+               maxAscent(0.0f),
+               maxDescent(0.0f)
+       {
+       }
+       
+       LayoutLine(const LayoutLine& other)
+               :
+               textOffset(other.textOffset),
+               y(other.y),
+               height(other.height),
+               maxAscent(other.maxAscent),
+               maxDescent(other.maxDescent),
+               layoutedSpans(other.layoutedSpans)
+       {
+       }
+
+       LayoutLine& operator=(const LayoutLine& other)
+       {
+               textOffset = other.textOffset;
+               y = other.y;
+               height = other.height;
+               maxAscent = other.maxAscent;
+               maxDescent = other.maxDescent;
+               layoutedSpans = other.layoutedSpans;
+               return *this;
+       }
+
+       bool operator==(const LayoutLine& other) const
+       {
+               return textOffset == other.textOffset
+                       && y == other.y
+                       && height == other.height
+                       && maxAscent == other.maxAscent
+                       && maxDescent == other.maxDescent
+                       && layoutedSpans == otner.layoutedSpans;
+       }
+
+       bool operator!=(const LayoutLine& other) const
+       {
+               return !(*this == other);
+       }
+
+public:
+       int                             textOffset;
+       float                   y;
+       float                   height;
+       float                   maxAscent;
+       float                   maxDescent;
+
+       TextSpanList    layoutedSpans;
+};
+
+
+typedef List<LayoutLine, false> LayoutLineList;
+
+
+class ParagraphLayout : public BReferenceable {
+public:
+                                                               
ParagraphLayout();
+                                                               
ParagraphLayout(const Paragraph& paragraph);
+                                                               
ParagraphLayout(const ParagraphLayout& other);
+       virtual                                         ~ParagraphLayout();
+
+                       void                            SetParagraph(const 
::Paragraph& paragraph);
+                       const ::Paragraph&      Paragraph() const
+                                                                       { 
return fParagraph; }
+
+                       void                            SetWidth(float width);
+                       float                           Width() const
+                                                                       { 
return fWidth; }
+
+                       float                           Height();
+                       void                            Draw(BView* view, const 
BPoint& offset);
+
+private:
+                       void                            _ValidateLayout();
+                       void                            _Layout();
+
+                       void                            _Init();
+                       bool                            _AppendGlyphInfos(const 
TextSpan& span);
+                       bool                            _AppendGlyphInfo(uint32 
charCode,
+                                                                       const 
TextStyleRef& span);
+
+                       void                            _GetGlyphAdvance(int 
offset,
+                                                                       float& 
advanceX, float& advanceY,
+                                                                       float 
escapementArray[]) const;
+                       
+                       void                            _FinalizeLine(int 
lineStart, int lineEnd,
+                                                                       int 
lineIndex, float y, float& lineHeight);
+
+                       void                            _DrawLine(BView* view,
+                                                                       const 
LayoutLine& line) const;
+                       void                            _DrawSpan(BView* view, 
const TextSpan& span,
+                                                                       int 
textOffset) const;
+
+private:
+                       TextSpanList            fTextSpans;
+
+                       float                           fWidth;
+                       
+                       bool                            fLayoutValid;
+
+                       GlyphInfo*                      fGlyphInfoBuffer;
+                       int                                     
fGlpyhInfoBufferSize;
+                       int                                     fGlyphInfoCount;
+
+                       LayoutLineList          fLayoutLines;
+};
+
+#endif // PARAGRAPH_LAYOUT_H


Other related posts:

  • » [haiku-commits] haiku: hrev46009 - src/apps/haiku-depot/textview - superstippi