From e0fdb0cd053024e36f58664bcc710a01598e40a4 Mon Sep 17 00:00:00 2001 From: Mirek Fidler Date: Tue, 22 Jul 2025 09:27:44 +0200 Subject: [PATCH] Draw: Fast cached HasCodepoint for TTF (now used for character replacements), Diagram: Triangle, upptst --- uppsrc/Core/src.tpp/ValueCache_en-us.tpp | 17 ++++++++ uppsrc/Draw/Draw.h | 1 + uppsrc/Draw/FontCR.cpp | 30 ++++++++++++- uppsrc/Painter/RenderChar.cpp | 3 +- uppsrc/RichText/Diagram.h | 2 + uppsrc/RichText/DiagramShape.cpp | 22 +++++++++- upptst/FontSymbols/FontSymbols.upp | 9 ++++ upptst/FontSymbols/main.cpp | 54 ++++++++++++++++++++++++ 8 files changed, 135 insertions(+), 3 deletions(-) create mode 100644 upptst/FontSymbols/FontSymbols.upp create mode 100644 upptst/FontSymbols/main.cpp diff --git a/uppsrc/Core/src.tpp/ValueCache_en-us.tpp b/uppsrc/Core/src.tpp/ValueCache_en-us.tpp index 0d6184333..ef7fcdbeb 100644 --- a/uppsrc/Core/src.tpp/ValueCache_en-us.tpp +++ b/uppsrc/Core/src.tpp/ValueCache_en-us.tpp @@ -38,8 +38,25 @@ ValueMaker`::Make to obtain the Value and stores it to the cache. Note that this function allows full reentrancy (from various threads as well as recursive calls (through Make method) in single thread&] +[s2; &] +[s4;%- &] +[s5;:Upp`:`:MakeValue`(const K`&`,const M`&`):%- [@(0.0.255) template] +<[@(0.0.255) class] K, [@(0.0.255) class] M> Value [* MakeValue]([@(0.0.255) const] +K[@(0.0.255) `&] [*@3 k], [@(0.0.255) const] M[@(0.0.255) `&] [*@3 m])&] +[s2; This is similar to variant with ValueMaker, however virtual +methods Key and Make are substituted with lambdas [%-*@3 k] and +[%-*@3 m].&] [s3; &] [s4;%- &] +[s5;:Upp`:`:MakeValueTL`(const K`&`,const M`&`):%- [@(0.0.255) template] +<[@(0.0.255) class] K, [@(0.0.255) class] M> Value [* MakeValueTL]([@(0.0.255) const] +K[@(0.0.255) `&] [*@3 k], [@(0.0.255) const] M[@(0.0.255) `&] [*@3 m])&] +[s2; Similar to MakeValue([%-*@3 k], [%-*@3 m]) but adds smaller per`-thread +cache, which is then accessed without mutex, making the operation +faster. This can have speed advantage in very specific cases +`- use with caution and benchmark.&] +[s3;%- &] +[s4;%- &] [s5;:Upp`:`:IsValueCacheActive`(`):%- [@(0.0.255) bool]_[* IsValueCacheActive]()&] [s2; Returns true if it is still possible to use Value Cache. This special function is intended to solve destruction conflicts at diff --git a/uppsrc/Draw/Draw.h b/uppsrc/Draw/Draw.h index 2f6c04924..d1ea89896 100644 --- a/uppsrc/Draw/Draw.h +++ b/uppsrc/Draw/Draw.h @@ -992,6 +992,7 @@ enum { bool ReadCmap(const char *ptr, int count, Event range, dword flags = 0); bool ReadCmap(Font font, Event range, dword flags = 0); bool GetPanoseNumber(Font font, byte *panose); +bool HasCodepoint(Font font, int c); } diff --git a/uppsrc/Draw/FontCR.cpp b/uppsrc/Draw/FontCR.cpp index 5b0aaa3d3..ea86f68d2 100644 --- a/uppsrc/Draw/FontCR.cpp +++ b/uppsrc/Draw/FontCR.cpp @@ -322,6 +322,33 @@ bool GetPanoseNumber(Font font, byte *panose) return true; } +bool HasCodepoint(Font font, int c) +{ + Value v = MakeValue( + [&] { + StringBuffer h; + RawCat(h, font); + return (String)h; + }, + [&](Value& v) { + Vector>& ranges = CreateRawValue>>(v); + ReadCmap(font, [&](int start, int end, int) { + if(ranges.GetCount() && ranges.Top().b + 1 == start) // often we get sequence like { 1, 2 }, { 3, 4 } - optimize by joining + ranges.Top().b = end; + else + ranges.Add({ start, end }); + }); + ranges.Shrink(); + return ranges.GetCount() * sizeof(Tuple); + } + ); + const Vector>& ranges = v.To>>(); + for(Tuple r : ranges) + if(c >= r.a && c <= r.b) + return true; + return false; +} + struct sFontMetricsReplacement { Font src; Font dst; @@ -430,7 +457,8 @@ bool Replace(Font fnt, int chr, Font& rfnt) StableIndexSort(distance, candidate); for(int fi : candidate) { f.Face(fi); - if(IsNormal_nc(f, chr)) { + if(HasCodepoint(f, chr)) { +// if(IsNormal_nc(f, chr)) { int a = fnt.GetAscent(); int d = fnt.GetDescent(); static WString apple_kbd = "⌘⌃⇧⌥"; // do not make these smaller it looks ugly... diff --git a/uppsrc/Painter/RenderChar.cpp b/uppsrc/Painter/RenderChar.cpp index 0742232dc..a124c7834 100644 --- a/uppsrc/Painter/RenderChar.cpp +++ b/uppsrc/Painter/RenderChar.cpp @@ -68,7 +68,8 @@ void ApproximateChar(LinearPathConsumer& t, Pointf at, int ch, Font fnt, double gp.move = gp.pos = Null; gp.tolerance = tolerance; PaintCharacter(gp, Pointf(0, 0), ch, fnt); - int sz = gp.glyph.GetCount() * 4; + int sz = gp.glyph.GetCount() * sizeof(float); + gp.glyph.Shrink(); v = RawPickToValue(pick(gp.glyph)); return sz; }); diff --git a/uppsrc/RichText/Diagram.h b/uppsrc/RichText/Diagram.h index 5906fc1c9..514d8936e 100644 --- a/uppsrc/RichText/Diagram.h +++ b/uppsrc/RichText/Diagram.h @@ -25,6 +25,8 @@ struct DiagramItem : Point2 { SHAPE_DIAMOND, SHAPE_OVAL, SHAPE_PARALLELOGRAM, + SHAPE_TRIANGLE, + SHAPE_ITRIANGLE, SHAPE_ARROWLEFT, SHAPE_ARROWRIGHT, SHAPE_ARROWHORZ, diff --git a/uppsrc/RichText/DiagramShape.cpp b/uppsrc/RichText/DiagramShape.cpp index 18a62f4ee..253c032cc 100644 --- a/uppsrc/RichText/DiagramShape.cpp +++ b/uppsrc/RichText/DiagramShape.cpp @@ -4,6 +4,7 @@ namespace Upp { Index DiagramItem::Shape = { "line", "rect", "round_rect", "ellipse", "diamond", "oval", "parallelogram", + "triangle1", "triangle2", "arrow_left", "arrow_right", "arrow_horz", "arrow_down", "arrow_up", "arrow_vert", }; @@ -174,7 +175,26 @@ void DiagramItem::Paint(Painter& w, dword style, const Index *conn) cons w.Move(r.left + r.Width() / 6, r.top).Line(r.right, r.top) .Line(r.right - r.Width() / 6, r.bottom).Line(r.left, r.bottom).Close(); break; - case SHAPE_ARROWLEFT: { + case SHAPE_TRIANGLE: { + text_rect.left += int(r.Width() / 4); + text_rect.right -= int(r.Width() / 4); + text_rect.top += int(r.Width() / 3); + w.Move(r.left + r.Width() / 2, r.top) + .Line(r.right, r.bottom) + .Line(r.left, r.bottom) + .Close(); + } + break; + case SHAPE_ITRIANGLE: { + text_rect.left += int(r.Width() / 4); + text_rect.right -= int(r.Width() / 4); + text_rect.bottom -= int(r.Width() / 3); + w.Move(r.left + r.Width() / 2, r.bottom) + .Line(r.right, r.top) + .Line(r.left, r.top) + .Close(); + } + break; case SHAPE_ARROWLEFT: { double a = r.left + arrow_width; text_rect.left += int(arrow_width / 3); w.Move(r.left, r.top + r.Height() / 2) diff --git a/upptst/FontSymbols/FontSymbols.upp b/upptst/FontSymbols/FontSymbols.upp new file mode 100644 index 000000000..5872304d3 --- /dev/null +++ b/upptst/FontSymbols/FontSymbols.upp @@ -0,0 +1,9 @@ +uses + CtrlLib; + +file + main.cpp; + +mainconfig + "" = "GUI"; + diff --git a/upptst/FontSymbols/main.cpp b/upptst/FontSymbols/main.cpp new file mode 100644 index 000000000..7832cc9df --- /dev/null +++ b/upptst/FontSymbols/main.cpp @@ -0,0 +1,54 @@ +#include + +using namespace Upp; + +struct SymbolRanges { + int from; + int to; + const char *text; +} symbol_ranges[] = { + 0x2190, 0x21FF, "Arrows", + 0x2200, 0x22FF, "Mathematical Operators", + 0x2300, 0x23FF, "Miscellaneous Technical", + 0x2400, 0x243F, "Control Pictures", + 0x2440, 0x245F, "Optical Character Recognition", + 0x2460, 0x24FF, "Enclosed Alphanumerics", + 0x2500, 0x257F, "Box Drawing", + 0x2580, 0x259F, "Block Elements", + 0x25A0, 0x25FF, "Geometric Shapes", + 0x2600, 0x26FF, "Miscellaneous Symbols", + 0x2700, 0x27BF, "Dingbats", + 0x27C0, 0x27EF, "Miscellaneous Mathematical Symbols-A", + 0x27F0, 0x27FF, "Supplemental Arrows-A", + 0x2800, 0x28FF, "Braille Patterns", + 0x2900, 0x297F, "Supplemental Arrows-B", + 0x2980, 0x29FF, "Miscellaneous Mathematical Symbols-B", + 0x2A00, 0x2AFF, "Supplemental Mathematical Operators", + 0x2B00, 0x2BFF, "Miscellaneous Symbols and Arrows", + 0x1F300, 0x1F5FF, "Miscellaneous Symbols and Pictographs", + 0x1F600, 0x1F64F, "Emoticons", + 0x1F650, 0x1F67F, "Ornamental Dingbats", + 0x1F680, 0x1F6FF, "Transport and Map Symbols", + 0x1F700, 0x1F77F, "Alchemical Symbols", + 0x1F780, 0x1F7FF, "Geometric Shapes Extended", + 0x1F800, 0x1F8FF, "Supplemental Arrows-C", + 0x1F900, 0x1F9FF, "Supplemental Symbols and Pictographs", + 0x1FA00, 0x1FA6F, "Chess Symbols", + 0x1FA70, 0x1FAFF, "Symbols and Pictographs Extended-A", + 0x1F000, 0x1F02F, "Mahjong Tiles", + 0x1F030, 0x1F09F, "Domino Tiles", + 0x1F0A0, 0x1F0FF, "Playing Cards", +}; + +GUI_APP_MAIN +{ + String qtf; + for(auto& sr : symbol_ranges) { + qtf << sr.text << ":&[3 "; + for(int i = sr.from; i <= sr.to; i++) { + qtf << WString(i, 1) << " "; + } + qtf << "&&"; + } + PromptOK(qtf); +}