* Breaking characters 4.x-dev

Fri, 09 Apr 2021 07:32:55 +0300

author
cemkalyoncu
date
Fri, 09 Apr 2021 07:32:55 +0300
branch
4.x-dev
changeset 1646
2ddf30bd71cf
parent 1645
40fdf76f65f7
child 1647
98c554aac82d

* Breaking characters

Source/Gorgon/Graphics/AdvancedPrinter.h file | annotate | diff | comparison | revisions
Testing/Source/Manual/AdvancedText.cpp file | annotate | diff | comparison | revisions
--- a/Source/Gorgon/Graphics/AdvancedPrinter.h	Thu Apr 08 19:02:10 2021 +0300
+++ b/Source/Gorgon/Graphics/AdvancedPrinter.h	Fri Apr 09 07:32:55 2021 +0300
@@ -171,6 +171,9 @@
         /// Appends a line break that does not start a new paragraph.
         AdvancedTextBuilder &LineBreak() { return C2(0x85); }
         
+        /// Appends a zero width breaking space.
+        AdvancedTextBuilder &ZeroWidthSpace() { String::AppendUnicode(text, 0x200b); return *this; }
+        
         /// Resets all formatting instructions.
         AdvancedTextBuilder &ResetFormatting() { return SCI(0x04); }
         
@@ -343,7 +346,7 @@
         
         /// Changes the offset that will be added to each letter. Relative sizing is relative to
         /// character width and line height, the value is in percentage.
-        AdvancedTextBuilder &SetLetterOffset(const Geometry::Point &pixels, const Geometry::Point &rel) { 
+        AdvancedTextBuilder &SetLetterOffset(const Geometry::Point &pixels, const Geometry::Point &rel = {0, 0}) { 
             CSI(0x14); 
             ValAndRel(pixels.X, rel.X); 
             ValAndRel(pixels.Y, rel.Y);
@@ -411,7 +414,8 @@
 
         
         /// Place the requested amount of space horizontally. rel is relative to em width and in 
-        /// percentage. per is relative to wrap width and in basis points (1/10000)
+        /// percentage. per is relative to wrap width and in basis points (1/10000). This space will
+        /// not be breaking. If breaking is desired, you may insert zero width space.
         AdvancedTextBuilder &HorizontalSpace(short pixels, short rel = 0, short per = 0) { CSI(0x40); ValRelAndPer(pixels, rel, per); return ST(); }
         
         /// Place the requested amount of space vertically. rel is relative to line height and in 
@@ -817,6 +821,22 @@
             images.Add(index, image);
         }
         
+        /// Adds breaking glyphs. A line can be wrapped after a breaking letter. Spaces are breaking
+        /// and cannot be removed from the list.
+        void SetBreakingLetters(std::vector<Char> letters) {
+            breakingchars = letters;
+        }
+        
+        /// Returns the list of breaking glyphs. You can change the returned vector.
+        std::vector<Char> &GetBreakingLetters() {
+            return breakingchars;
+        }
+        
+        /// Returns the list of breaking glyphs.
+        const std::vector<Char> &GetBreakingLetters() const {
+            return breakingchars;
+        }
+        
         /// This is the advanced operation which allows user to submit functions that will perform the
         /// rendering. First one is glyph render. It will be given the renderer to be used, the 
         /// second is box renderer, starting point, size, background color, border thickness and 
@@ -837,6 +857,9 @@
             int ind = 0;
 
             
+            std::vector<Glyph> breaking = breakingchars;
+            std::sort(breaking.begin(), breaking.end());
+            
             //state machine
             setvalrel               letterspacing;
             int                     wrapwidth = width; //relative will be calculated instantly
@@ -844,6 +867,8 @@
             setvalrel               indent;
             setvalrel               paragraphspacing;
             setvalrel               linespacing;
+            setvalrel               xoffset;
+            setvalrel               yoffset;
             setval<int>             tabwidth;
             setval<bool>            justify;
             setval<TextAlignment>   align;
@@ -934,17 +959,48 @@
                 case 0x0e: //wrap width
                     wrapwidth = readvalrel(it, end, p, false)(renderer->GetEMSize(), width);
                     break;
-                    
-                case 0x17: {
+                case 0x14: //letter offset
+                    xoffset = readvalrel(it, end, p, true);
+                    yoffset = readvalrel(it, end, p, true);
+                    break;
+                case 0x17: { //set tab width
                     auto val = readvalrelper(it, end, p, false);
                     tabwidth = setval<int>{val.set, val(em, wrapwidth, printer->GetTabWidth())};
                     break;
                 }
-                case 0x40:
+                case 0x23: {
+                    while(p != ST) {
+                        breaking.insert(std::upper_bound(breaking.begin(), breaking.end(), p), p);
+                        MOVEIT();
+                        p = internal::decode_impl(it, end);
+                    }
+                    break;
+                }
+                case 0x24: {
+                    std::vector<Glyph> rem;
+                    while(p != ST) {
+                        rem.insert(std::upper_bound(rem.begin(), rem.end(), p), p);
+                        MOVEIT();
+                        p = internal::decode_impl(it, end);
+                    }
+                    auto rit = rem.begin();
+                    breaking.erase(std::remove_if(breaking.begin(), breaking.end(), [&](auto v) {
+                        while(*rit < v && rit != rem.end())
+                            rit++;
+                        
+                        if(rit == rem.end())
+                            return false;
+                        else
+                            return *rit == v;
+                    }), breaking.end());
+                    break;
+                }
+                case 0x40: //horizontal spacing
                     cur.X += readvalrelper(it, end, p, false)(em, wrapwidth, 0);
                     prev = 0; //no kerning after a spacing like this
+                    
                     break;
-                case 0x41:
+                case 0x41: //vertical spacing
                     cur.Y += readvalrel(it, end, p, true)(height, 0);
                     break;
                 }
@@ -971,6 +1027,8 @@
                     align.set               = false;
                     color.set               = false;
                     tabwidth.set            = false;
+                    xoffset.set             = false;
+                    yoffset.set             = false;
                     changeprinter(&fonts.at(0));
                     baselineoffset = 0.0f;
                 case 0x5:
@@ -1308,7 +1366,7 @@
                 int gw     = 0;
 
                 
-                // **** Wrap check
+                // **** Breaking character check
                 if(internal::isbreaking(g)) {
                     lastbreak = (int)acc.size();
                 }
@@ -1358,15 +1416,12 @@
                     else {
                         gw = (int)internal::defaultspace(g, *renderer);
                     }
-                    
-                    newline = false;
                 }
                 else if(g != '\t') {
                     gw = renderer->GetCursorAdvance(g);
-                    
-                    newline = false;
                 }
                 
+                newline = false;
 
                 // **** Accumulate
                 cur.X += hspace;
@@ -1375,15 +1430,15 @@
                     g = 0xffff; //dont try to render
                 
                 if(baselineoffset != 0) {
-                    acc.push_back({g, renderer, cur, {0,0}, color(printer->GetColor()),
-                        gw,
+                    acc.push_back({g, renderer, cur, {xoffset(em, 0), yoffset(em, 0)}, 
+                        color(printer->GetColor()), gw,
                         (int)std::round(baseline*(1+baselineoffset)), 
                         (int)std::round(height + baseline*fabs(baselineoffset))
                     });
                 }
                 else {
-                    acc.push_back({g, renderer, cur, {0,0}, color(printer->GetColor()), 
-                        gw, baseline, height
+                    acc.push_back({g, renderer, cur, {xoffset(em, 0), yoffset(em, 0)}, 
+                        color(printer->GetColor()), gw, baseline, height
                     });
                 }
                 
@@ -1417,6 +1472,12 @@
                     
                     doline(0);
                 }
+                
+                auto br = std::lower_bound(breaking.begin(), breaking.end(), g);
+                if(br != breaking.end() && *br == g) {
+                    lastbreak = (int)acc.size();
+                }
+
             }
             
             if(!acc.empty())
@@ -1748,6 +1809,8 @@
         
         /// Indexed background colors
         std::map<Byte, RGBA> backcolors;
+        
+        std::vector<Glyph> breakingchars;
     };
     
 } }
--- a/Testing/Source/Manual/AdvancedText.cpp	Thu Apr 08 19:02:10 2021 +0300
+++ b/Testing/Source/Manual/AdvancedText.cpp	Fri Apr 09 07:32:55 2021 +0300
@@ -43,7 +43,7 @@
            .UseDefaultFont()
            .DefaultLetterSpacing()
            .SetColor(2, 171)
-           .Append("text. ")
+           .Append("t.ext. ")
            .ResetFormatting()
            .Append("e = mc")
            .UseSubscript()
@@ -61,7 +61,24 @@
            .SetTabWidth(0, 0, 2500)
            .Append("Not a\tnew\tparagraph. Just a line break\n")
            .UseItalicFont()
-           .Append("New\tparagraph")
+           .Append("New\tparagraph ")
+           .Append("D")
+           .SetLetterOffset({0,2})
+           .Append("a")
+           .SetLetterOffset({0,4})
+           .Append("n")
+           .SetLetterOffset({0,5})
+           .Append("c")
+           .SetLetterOffset({0,6})
+           .Append("i")
+           .SetLetterOffset({0,5})
+           .Append("n")
+           .SetLetterOffset({0,4})
+           .Append("g")
+           .SetLetterOffset({0,2})
+           .Append(".")
+           .SetLetterOffset({0,0})
+           .Append(".")
     ;
     
     auto &reg = (Gorgon::Widgets::SimpleGenerator&)Gorgon::Widgets::Registry::Active();
@@ -73,6 +90,8 @@
     printer.RegisterFont(Graphics::NamedFont::Small, reg.InfoFont);
     printer.RegisterFont(Graphics::NamedFont::Script, reg.SmallFont);
     
+    printer.GetBreakingLetters().push_back('.');
+    
     printer.RegisterColor(2, Gorgon::Graphics::Color::Red, Gorgon::Graphics::Color::LightYellow);
     
     l.Draw(reg.Background.Regular);

mercurial