download.lst | 3 editeng/source/editeng/impedit3.cxx | 6 external/graphite/StaticLibrary_graphite.mk | 9 external/graphite/UnpackedTarball_graphite.mk | 4 external/graphite/graphite2.issue1115.patch.1 | 6 external/graphite/graphite2.win64.patch.1 | 34 - external/graphite/ubsan.patch | 51 + vcl/inc/graphite_layout.hxx | 10 vcl/source/fontsubset/sft.cxx | 3 vcl/source/gdi/pdfwriter_impl.cxx | 15 vcl/source/glyphs/graphite_layout.cxx | 799 +++++++++----------------- vcl/win/source/gdi/winlayout.cxx | 15 12 files changed, 396 insertions(+), 559 deletions(-)
New commits: commit d2ef084eb0e26b5ee18133269249e7a80efb23d6 Author: Caolán McNamara <caol...@redhat.com> Date: Mon Jun 29 12:26:16 2015 +0200 update graphite to 1.3.5 (cherry picked from commit c64ea526dc71da6e3aad188ac71e58047ed74b5a) and sync the various upgrade patches together Change-Id: I3287d51430d7a0901dd8bbf2458b845bcf92a8d2 Reviewed-on: https://gerrit.libreoffice.org/22210 Reviewed-by: Miklos Vajna <vmik...@collabora.co.uk> Tested-by: Miklos Vajna <vmik...@collabora.co.uk> diff --git a/download.lst b/download.lst index bc94112..9e16272 100644 --- a/download.lst +++ b/download.lst @@ -59,8 +59,7 @@ export FREEHAND_TARBALL := libfreehand-0.1.1.tar.bz2 export FREETYPE_TARBALL := dbf2caca1d3afd410a29217a9809d397-freetype-2.4.8.tar.bz2 export GLEW_TARBALL := 594eb47b4b1210e25438d51825404d5a-glew-1.10.0.zip export GLM_TARBALL := bae83fa5dc7f081768daace6e199adc3-glm-0.9.4.6-libreoffice.zip -export GRAPHITE_MD5SUM := 2ef839348fe28e3b923bf8cced440227 -export GRAPHITE_TARBALL := graphite2-1.2.4.tgz +export GRAPHITE_TARBALL := 28935e208c311761c29983c739db08d8-graphite2-minimal-1.3.5.tgz export HARFBUZZ_MD5SUM := 0e27e531f4c4acff601ebff0957755c2 export HARFBUZZ_TARBALL := harfbuzz-0.9.40.tar.bz2 export HSQLDB_TARBALL := 17410483b5b5f267aa18b7e00b65e6e0-hsqldb_1_8_0.zip diff --git a/editeng/source/editeng/impedit3.cxx b/editeng/source/editeng/impedit3.cxx index 98e3d51..5df7e5e 100644 --- a/editeng/source/editeng/impedit3.cxx +++ b/editeng/source/editeng/impedit3.cxx @@ -714,6 +714,8 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY ) EditLine aSaveLine( *pLine ); SvxFont aTmpFont( pNode->GetCharAttribs().GetDefFont() ); + ImplInitLayoutMode( GetRefDevice(), nPara, nIndex ); + bool bCalcCharPositions = true; boost::scoped_array<long> pBuf(new long[ pNode->Len() ]); @@ -1038,6 +1040,8 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY ) aTmpFont.SetPhysFont( GetRefDevice() ); ImplInitDigitMode(GetRefDevice(), aTmpFont.GetLanguage()); + pPortion->SetRightToLeft( GetRightToLeft( nPara, nTmpPos+1 ) ); + if ( bCalcCharPositions || !pPortion->HasValidSize() ) { pPortion->GetSize() = aTmpFont.QuickGetTextSize( GetRefDevice(), pParaPortion->GetNode()->GetString(), nTmpPos, pPortion->GetLen(), pBuf.get() ); @@ -1069,8 +1073,6 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY ) nTmpWidth += pPortion->GetSize().Width(); - pPortion->SetRightToLeft( GetRightToLeft( nPara, nTmpPos+1 ) ); - sal_Int32 _nPortionEnd = nTmpPos + pPortion->GetLen(); if( bScriptSpace && ( _nPortionEnd < pNode->Len() ) && ( nTmpWidth < nXWidth ) && IsScriptChange( EditPaM( pNode, _nPortionEnd ) ) ) { diff --git a/external/graphite/StaticLibrary_graphite.mk b/external/graphite/StaticLibrary_graphite.mk index de3950f..ddbf995 100644 --- a/external/graphite/StaticLibrary_graphite.mk +++ b/external/graphite/StaticLibrary_graphite.mk @@ -19,8 +19,8 @@ $(eval $(call gb_StaticLibrary_set_include,graphite,\ )) $(eval $(call gb_StaticLibrary_add_defs,graphite,\ - -DDISABLE_TRACING \ - -DGR2_STATIC \ + -DGRAPHITE2_NTRACING \ + -DGRAPHITE2_STATIC \ )) ifeq ($(COM),GCC) @@ -43,19 +43,22 @@ $(eval $(call gb_StaticLibrary_add_generated_cxxobjects,graphite,\ UnpackedTarball/graphite/src/gr_segment \ UnpackedTarball/graphite/src/gr_slot \ UnpackedTarball/graphite/src/json \ - UnpackedTarball/graphite/src/Bidi \ UnpackedTarball/graphite/src/CachedFace \ UnpackedTarball/graphite/src/CmapCache \ UnpackedTarball/graphite/src/Code \ + UnpackedTarball/graphite/src/Collider \ + UnpackedTarball/graphite/src/Decompressor \ UnpackedTarball/graphite/src/Face \ UnpackedTarball/graphite/src/FeatureMap \ UnpackedTarball/graphite/src/FileFace \ UnpackedTarball/graphite/src/Font \ UnpackedTarball/graphite/src/GlyphCache \ UnpackedTarball/graphite/src/GlyphFace \ + UnpackedTarball/graphite/src/Intervals \ UnpackedTarball/graphite/src/Justifier \ UnpackedTarball/graphite/src/NameTable \ UnpackedTarball/graphite/src/Pass \ + UnpackedTarball/graphite/src/Position \ UnpackedTarball/graphite/src/SegCache \ UnpackedTarball/graphite/src/SegCacheEntry \ UnpackedTarball/graphite/src/SegCacheStore \ diff --git a/external/graphite/UnpackedTarball_graphite.mk b/external/graphite/UnpackedTarball_graphite.mk index c7fa86e..a162d17 100644 --- a/external/graphite/UnpackedTarball_graphite.mk +++ b/external/graphite/UnpackedTarball_graphite.mk @@ -11,10 +11,12 @@ $(eval $(call gb_UnpackedTarball_UnpackedTarball,graphite)) $(eval $(call gb_UnpackedTarball_set_tarball,graphite,$(GRAPHITE_TARBALL))) -# http://projects.palaso.org/issues/1115 +$(eval $(call gb_UnpackedTarball_set_patchlevel,graphite,0)) + $(eval $(call gb_UnpackedTarball_add_patches,graphite,\ external/graphite/graphite2.issue1115.patch.1 \ external/graphite/graphite2.win64.patch.1 \ + external/graphite/ubsan.patch \ )) # vim: set noet sw=4 ts=4: diff --git a/external/graphite/graphite2.issue1115.patch.1 b/external/graphite/graphite2.issue1115.patch.1 index f19c8a3..454114b 100644 --- a/external/graphite/graphite2.issue1115.patch.1 +++ b/external/graphite/graphite2.issue1115.patch.1 @@ -1,6 +1,6 @@ --- graphite/src/Code.cpp +++ graphite/src/Code.cpp -@@ -169,8 +169,8 @@ Machine::Code::Code(bool is_constraint, +@@ -175,8 +175,8 @@ Machine::Code::Code(bool is_constraint, bytecode_end, pre_context, rule_length, @@ -11,7 +11,7 @@ face.numFeatures(), {1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,255, -@@ -178,7 +178,7 @@ Machine::Code::Code(bool is_constraint, +@@ -184,7 +184,7 @@ Machine::Code::Code(bool is_constraint, 1,1,1,1,1,1,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, @@ -19,4 +19,4 @@ + 0,0,0,0,0,0,0, static_cast<byte>(silf.numUser())} }; - decoder dec(lims, *this); + decoder dec(lims, *this, pt); diff --git a/external/graphite/graphite2.win64.patch.1 b/external/graphite/graphite2.win64.patch.1 index 6bf8c88..e7c36c6 100644 --- a/external/graphite/graphite2.win64.patch.1 +++ b/external/graphite/graphite2.win64.patch.1 @@ -1,7 +1,20 @@ +diff -ur graphite.org/src/inc/Main.h graphite/src/inc/Main.h +--- graphite.org/src/inc/Main.h 2015-09-07 20:09:25.572279671 +0700 +--- graphite/src/inc/Main.h 2015-09-07 20:09:25.572279671 +0700 +@@ -25,6 +25,9 @@ + of the License or (at your option) any later version. + */ + #pragma once ++#ifdef _WIN32 ++#pragma warning(disable: 4510 4610) ++#endif + + #include <cstdlib> + #include "graphite2/Types.h" diff -ur graphite.org/src/inc/json.h graphite/src/inc/json.h --- graphite.org/src/inc/json.h 2015-02-03 14:49:24.408101900 +0100 +++ graphite/src/inc/json.h 2015-02-03 14:50:59.697552200 +0100 -@@ -78,6 +78,9 @@ +@@ -85,6 +85,9 @@ json & operator << (string) throw(); json & operator << (number) throw(); json & operator << (integer) throw(); @@ -14,8 +27,7 @@ diff -ur graphite.org/src/inc/json.h graphite/src/inc/json.h diff -ur graphite.org/src/json.cpp graphite/src/json.cpp --- graphite.org/src/json.cpp 2015-02-03 14:49:24.409102000 +0100 +++ graphite/src/json.cpp 2015-02-03 14:50:49.814986900 +0100 -@@ -119,6 +119,9 @@ - json & json::operator << (json::number f) throw() { context(seq); fprintf(_stream, "%g", f); return *this; } +@@ -134,5 +134,8 @@ json & json::operator << (json::integer d) throw() { context(seq); fprintf(_stream, "%ld", d); return *this; } json & json::operator << (long unsigned d) throw() { context(seq); fprintf(_stream, "%ld", d); return *this; } +#ifdef _WIN64 @@ -27,17 +39,17 @@ diff -ur graphite.org/src/json.cpp graphite/src/json.cpp diff -ur graphite.org/src/Pass.cpp graphite/src/Pass.cpp --- graphite.org/src/Pass.cpp 2015-02-03 14:49:24.413102200 +0100 +++ graphite/src/Pass.cpp 2015-02-03 14:50:37.873303900 +0100 -@@ -466,7 +466,7 @@ - { - if (r->rule->preContext > fsm.slots.context()) continue; - *fsm.dbgout << json::flat << json::object -- << "id" << r->rule - m_rules -+ << "id" << static_cast<size_t>(r->rule - m_rules) +@@ -544,7 +544,7 @@ + if (r->rule->preContext > fsm.slots.context()) + continue; + *fsm.dbgout << json::flat << json::object +- << "id" << r->rule - m_rules ++ << "id" << static_cast<size_t>(r->rule - m_rules) << "failed" << true << "input" << json::flat << json::object << "start" << objectid(dslot(&fsm.slots.segment, input_slot(fsm.slots, -r->rule->preContext))) -@@ -480,7 +480,7 @@ - void Pass::dumpRuleEventOutput(const FiniteStateMachine & fsm, const Rule & r, Slot * const last_slot) const +@@ -558,7 +558,7 @@ + void Pass::dumpRuleEventOutput(const FiniteStateMachine & fsm, Machine & m, const Rule & r, Slot * const last_slot) const { *fsm.dbgout << json::item << json::flat << json::object - << "id" << &r - m_rules diff --git a/external/graphite/ubsan.patch b/external/graphite/ubsan.patch new file mode 100644 index 0000000..b1617b1 --- /dev/null +++ b/external/graphite/ubsan.patch @@ -0,0 +1,51 @@ +--- src/Pass.cpp ++++ src/Pass.cpp +@@ -294,7 +294,7 @@ + s->rules = begin; + s->rules_end = (end - begin <= FiniteStateMachine::MAX_RULES)? end : + begin + FiniteStateMachine::MAX_RULES; +- qsort(begin, end - begin, sizeof(RuleEntry), &cmpRuleEntry); ++ if (end != begin) qsort(begin, end - begin, sizeof(RuleEntry), &cmpRuleEntry); + } + + return true; +--- src/gr_face.cpp ++++ src/gr_face.cpp +@@ -87,7 +87,7 @@ + + Face *res = new Face(appFaceHandle, *ops); + if (res && load_face(*res, faceOptions)) +- return static_cast<gr_face *>(res); ++ return reinterpret_cast<gr_face *>(res); + + delete res; + return 0; +@@ -195,7 +195,7 @@ + + void gr_face_destroy(gr_face *face) + { +- delete face; ++ delete static_cast<Face *>(face); + } + + +--- src/gr_font.cpp ++++ src/gr_font.cpp +@@ -50,7 +50,7 @@ + if (face == 0) return 0; + + Font * const res = new Font(ppm, *face, appFontHandle, font_ops); +- return static_cast<gr_font*>(res); ++ return reinterpret_cast<gr_font*>(res); + } + + gr_font* gr_make_font_with_advance_fn(float ppm/*pixels per em*/, const void* appFontHandle/*non-NULL*/, gr_advance_fn getAdvance, const gr_face * face/*needed for scaling*/) +@@ -61,7 +61,7 @@ + + void gr_font_destroy(gr_font *font) + { +- delete font; ++ delete static_cast<Font *>(font); + } + + diff --git a/vcl/inc/graphite_layout.hxx b/vcl/inc/graphite_layout.hxx index 55d0d67..b97b351 100644 --- a/vcl/inc/graphite_layout.hxx +++ b/vcl/inc/graphite_layout.hxx @@ -93,9 +93,10 @@ public: private: const gr_face * mpFace; // not owned by layout gr_font * mpFont; // not owned by layout - int mnSegCharOffset; // relative to ImplLayoutArgs::mpStr + unsigned int mnSegCharOffset; // relative to ImplLayoutArgs::mpStr long mnWidth; std::vector<int> mvChar2BaseGlyph; + std::vector<int> mvChar2Glyph; std::vector<int> mvGlyph2Char; std::vector<int> mvCharDxs; std::vector<int> mvCharBreaks; @@ -109,8 +110,6 @@ public: // used by upper layers virtual bool LayoutText( ImplLayoutArgs& ) SAL_OVERRIDE; // first step of layout // split into two stages to allow dc to be restored on the segment - gr_segment * CreateSegment(ImplLayoutArgs& rArgs); - bool LayoutGlyphs(ImplLayoutArgs& rArgs, gr_segment * pSegment); virtual void AdjustLayout( ImplLayoutArgs& ) SAL_OVERRIDE; // adjusting positions @@ -145,13 +144,14 @@ public: static const int EXTRA_CONTEXT_LENGTH; private: void expandOrCondense(ImplLayoutArgs &rArgs); - void fillFrom(gr_segment * rSeg, ImplLayoutArgs & rArgs, float fScaling); + void fillFrom(gr_segment * rSeg, ImplLayoutArgs & rArgs, float fScaling, bool bRtl, int firstCharOffset); float append(gr_segment * pSeg, ImplLayoutArgs & rArgs, const gr_slot * pSlot, float gOrigin, float nextGlyphOrigin, float fScaling, - long & rDXOffset, bool bIsBase, int baseChar); + long & rDXOffset, bool bIsBase, int baseChar, int baseGlyph, bool bRtl); + unsigned int ScanFwdForChar(int &findChar, bool fallback) const; }; #endif // INCLUDED_VCL_INC_GRAPHITE_LAYOUT_HXX diff --git a/vcl/source/fontsubset/sft.cxx b/vcl/source/fontsubset/sft.cxx index 6758df2..fe4abe7 100644 --- a/vcl/source/fontsubset/sft.cxx +++ b/vcl/source/fontsubset/sft.cxx @@ -1770,6 +1770,9 @@ int GetTTGlyphComponents(TrueTypeFont *ttf, sal_uInt32 glyphID, std::vector< sal const sal_uInt8* glyf = getTable(ttf, O_glyf); const sal_uInt8* ptr = glyf + ttf->goffsets[glyphID]; + const sal_uInt8* nptr = glyf + ttf->goffsets[glyphID+1]; + if (nptr <= ptr) + return 0; glyphlist.push_back( glyphID ); diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx index f2974a2..44d1f45 100644 --- a/vcl/source/gdi/pdfwriter_impl.cxx +++ b/vcl/source/gdi/pdfwriter_impl.cxx @@ -9006,22 +9006,27 @@ void PDFWriterImpl::drawLayout( SalLayout& rLayout, const OUString& rText, bool else if( pCharPosAry[i] >= nMinCharPos && pCharPosAry[i] <= nMaxCharPos ) { int nChars = 1; - aUnicodes.push_back( rText[ pCharPosAry[i] ] ); pUnicodesPerGlyph[i] = 1; // try to handle ligatures and such if( i < nGlyphs-1 ) { nChars = pCharPosAry[i+1] - pCharPosAry[i]; + int start = pCharPosAry[i]; // #i115618# fix for simple RTL+CTL cases - // TODO: sanitize for RTL ligatures, more complex CTL, etc. + // supports RTL ligatures. TODO: more complex CTL, etc. if( nChars < 0 ) + { nChars = -nChars; - else if( nChars == 0 ) + start = pCharPosAry[i+1] + 1; + } + else if (nChars == 0) nChars = 1; pUnicodesPerGlyph[i] = nChars; - for( int n = 1; n < nChars; n++ ) - aUnicodes.push_back( rText[ pCharPosAry[i] + n ] ); + for( int n = 0; n < nChars; n++ ) + aUnicodes.push_back( rText[ start + n ] ); } + else + aUnicodes.push_back( rText[ pCharPosAry[i] ] ); // #i36691# hack that is needed because currently the pGlyphs[] // argument is ignored for embeddable fonts and so the layout // engine's glyph work is ignored (i.e. char mirroring) diff --git a/vcl/source/glyphs/graphite_layout.cxx b/vcl/source/glyphs/graphite_layout.cxx index a4aa99c..db50a22 100644 --- a/vcl/source/glyphs/graphite_layout.cxx +++ b/vcl/source/glyphs/graphite_layout.cxx @@ -27,7 +27,7 @@ #undef NDEBUG #endif -// #define GRLAYOUT_DEBUG 1 +//#define GRLAYOUT_DEBUG 1 #include <algorithm> #include <cassert> @@ -89,23 +89,6 @@ namespace return !(b > i) && i < e; } - int findSameDirLimit(const sal_Unicode* buffer, int charCount, bool rtl) - { - UErrorCode status = U_ZERO_ERROR; - UBiDi *ubidi = ubidi_openSized(charCount, 0, &status); - int limit = 0; - ubidi_setPara(ubidi, reinterpret_cast<const UChar *>(buffer), charCount, - (rtl)?UBIDI_DEFAULT_RTL:UBIDI_DEFAULT_LTR, NULL, &status); - UBiDiLevel level = 0; - ubidi_getLogicalRun(ubidi, 0, &limit, &level); - ubidi_close(ubidi); - if ((rtl && !(level & 1)) || (!rtl && (level & 1))) - { - limit = 0; - } - return limit; - } - template <typename T> T maximum(T a, T b) { @@ -125,43 +108,21 @@ namespace // o Querying clustering relationships. // o manipulations that affect neighouring glyphs. -const int GraphiteLayout::EXTRA_CONTEXT_LENGTH = 10; +const int GraphiteLayout::EXTRA_CONTEXT_LENGTH = 32; -// find first slot of cluster and first slot of subsequent cluster -static void findFirstClusterSlot(const gr_slot* base, gr_slot const** first, gr_slot const** after, int * firstChar, int * lastChar, bool bRtl) +const gr_slot *get_next_base(const gr_slot *slot, bool bRtl) { - if (gr_slot_attached_to(base) == NULL) - { - *first = base; - *after = (bRtl)? gr_slot_prev_in_segment(base) : - gr_slot_next_in_segment(base); - *firstChar = gr_slot_before(base); - *lastChar = gr_slot_after(base); - } - const gr_slot * attachment = gr_slot_first_attachment(base); - while (attachment) - { - if (gr_slot_origin_X(*first) > gr_slot_origin_X(attachment)) - *first = attachment; - const gr_slot* attachmentNext = (bRtl)? - gr_slot_prev_in_segment(attachment) : gr_slot_next_in_segment(attachment); - if (attachmentNext) - { - if (*after && (gr_slot_origin_X(*after) < gr_slot_origin_X(attachmentNext))) - *after = attachmentNext; - } - else - { - *after = NULL; - } - if (gr_slot_before(attachment) < *firstChar) - *firstChar = gr_slot_before(attachment); - if (gr_slot_after(attachment) > *lastChar) - *lastChar = gr_slot_after(attachment); - if (gr_slot_first_attachment(attachment)) - findFirstClusterSlot(attachment, first, after, firstChar, lastChar, bRtl); - attachment = gr_slot_next_sibling_attachment(attachment); - } + for ( ; slot; slot = bRtl ? gr_slot_prev_in_segment(slot) : gr_slot_next_in_segment(slot)) + if (!gr_slot_attached_to(slot) || gr_slot_can_insert_before(slot)) + break; + return slot; +} + +bool isWhite(sal_Unicode nChar) +{ + if (nChar <= 0x0020 || nChar == 0x00A0 || (nChar >= 0x2000 && nChar <= 0x200F) || nChar == 0x3000) + return true; + return false; } // The Graphite glyph stream is really a sequence of glyph attachment trees @@ -169,202 +130,131 @@ static void findFirstClusterSlot(const gr_slot* base, gr_slot const** first, gr_ // finds each non-attached base glyph and calls append to record them as a // sequence of clusters. void -GraphiteLayout::fillFrom(gr_segment * pSegment, ImplLayoutArgs &rArgs, float fScaling) +GraphiteLayout::fillFrom(gr_segment * pSegment, ImplLayoutArgs &rArgs, float fScaling, bool bRtl, int lastCharPos) { - bool bRtl(rArgs.mnFlags & SalLayoutFlags::BiDiRtl); - int nCharRequested = rArgs.mnEndCharPos - rArgs.mnMinCharPos; - int nChar = gr_seg_n_cinfo(pSegment); float fMinX = gr_seg_advance_X(pSegment); float fMaxX = 0.0f; long nDxOffset = 0; // from dropped glyphs - int nFirstCharInCluster = 0; - int nLastCharInCluster = 0; + int origNumGlyphs = mvGlyphs.size(); unsigned int nGlyphs = gr_seg_n_slots(pSegment); - mvGlyph2Char.assign(nGlyphs, -1); - mvGlyphs.reserve(nGlyphs); - - if (bRtl) + mvGlyph2Char.resize(mvGlyph2Char.size() + nGlyphs, -1); + mvGlyphs.reserve(mvGlyphs.size() + nGlyphs); + int clusterStart = -1; + int clusterFirstChar = -1; + const gr_slot *nextBaseSlot; + const sal_Unicode *pStr = rArgs.mpStr; + int firstChar; + + if (!nGlyphs || lastCharPos - mnSegCharOffset == 0) return; + const gr_slot* baseSlot = bRtl ? gr_seg_last_slot(pSegment) : gr_seg_first_slot(pSegment); + // find first base + while (baseSlot && gr_slot_attached_to(baseSlot) != NULL && !gr_slot_can_insert_before(baseSlot)) + baseSlot = bRtl ? gr_slot_prev_in_segment(baseSlot) : gr_slot_next_in_segment(baseSlot); + assert(baseSlot); + int nextChar = gr_cinfo_base(gr_seg_cinfo(pSegment, gr_slot_before(baseSlot))) + mnSegCharOffset; + float thisBoundary = 0.; + float nextBoundary = gr_slot_origin_X(baseSlot); + // now loop over bases + for ( ; baseSlot; baseSlot = nextBaseSlot) { - const gr_slot* baseSlot = gr_seg_last_slot(pSegment); - // find first base - while (baseSlot && (gr_slot_attached_to(baseSlot) != NULL)) - baseSlot = gr_slot_prev_in_segment(baseSlot); - int iChar = nChar - 1; - int iNextChar = nChar - 1; - bool reordered = false; - int nBaseGlyphIndex = 0; - // now loop over bases - while (baseSlot) + firstChar = nextChar; + thisBoundary = nextBoundary; + nextBaseSlot = get_next_base(bRtl ? gr_slot_prev_in_segment(baseSlot) : gr_slot_next_in_segment(baseSlot), bRtl); + nextChar = nextBaseSlot ? gr_cinfo_base(gr_seg_cinfo(pSegment, gr_slot_before(nextBaseSlot))) + mnSegCharOffset : -1; + nextBoundary = nextBaseSlot ? gr_slot_origin_X(nextBaseSlot) : gr_seg_advance_X(pSegment); + + if (firstChar < mnMinCharPos || firstChar >= mnEndCharPos) { - bool bCluster = !reordered; - const gr_slot * clusterFirst = NULL; - const gr_slot * clusterAfter = NULL; - int firstChar = -1; - int lastChar = -1; - findFirstClusterSlot(baseSlot, &clusterFirst, &clusterAfter, &firstChar, &lastChar, bRtl); - iNextChar = minimum<int>(firstChar, iNextChar); - if (bCluster) - { - nBaseGlyphIndex = mvGlyphs.size(); - mvGlyph2Char[nBaseGlyphIndex] = iChar + mnSegCharOffset; - nFirstCharInCluster = firstChar; - nLastCharInCluster = lastChar; - } - else - { - mvGlyph2Char[mvGlyphs.size()] = firstChar + mnSegCharOffset; - nFirstCharInCluster = minimum<int>(firstChar, nFirstCharInCluster); - nLastCharInCluster = maximum<int>(firstChar, nLastCharInCluster); - } - float leftBoundary = gr_slot_origin_X(clusterFirst); - float rightBoundary = (clusterAfter)? - gr_slot_origin_X(clusterAfter) : gr_seg_advance_X(pSegment); - if ( - lastChar < iChar && clusterAfter && - (gr_cinfo_after(gr_seg_cinfo(pSegment, iChar)) > - static_cast<int>(gr_slot_index(clusterAfter))) - ) - { - reordered = true; - } - else - { - reordered = false; - iChar = iNextChar - 1; - } - if (mnSegCharOffset + nFirstCharInCluster >= mnMinCharPos && - mnSegCharOffset + nFirstCharInCluster < mnEndCharPos) - { - fMinX = minimum<float>(fMinX, leftBoundary); - fMaxX = maximum<float>(fMaxX, rightBoundary); - if (!reordered) - { - for (int i = nFirstCharInCluster; i <= nLastCharInCluster; i++) - { - if (mnSegCharOffset + i >= mnEndCharPos) - break; - // from the point of view of the dx array, the xpos is - // the origin of the first glyph of the cluster rtl - mvCharDxs[mnSegCharOffset + i - mnMinCharPos] = - static_cast<int>(leftBoundary * fScaling) + nDxOffset; - mvCharBreaks[mnSegCharOffset + i - mnMinCharPos] = gr_cinfo_break_weight(gr_seg_cinfo(pSegment, i)); - } - mvChar2BaseGlyph[mnSegCharOffset + nFirstCharInCluster - mnMinCharPos] = nBaseGlyphIndex; - } - append(pSegment, rArgs, baseSlot, gr_slot_origin_X(baseSlot), rightBoundary, fScaling, - nDxOffset, bCluster, mnSegCharOffset + firstChar); - } - if (mnSegCharOffset + nLastCharInCluster < mnMinCharPos) - break; - baseSlot = gr_slot_next_sibling_attachment(baseSlot); + // handle clipping of diacritic from base + nextBaseSlot = bRtl ? gr_slot_prev_in_segment(baseSlot) : gr_slot_next_in_segment(baseSlot); + nextBoundary = nextBaseSlot ? gr_slot_origin_X(nextBaseSlot) : gr_seg_advance_X(pSegment); + nextChar = nextBaseSlot ? gr_cinfo_base(gr_seg_cinfo(pSegment, gr_slot_before(nextBaseSlot))) + mnSegCharOffset : -1; + continue; } - } - else - { - const gr_slot* baseSlot = gr_seg_first_slot(pSegment); - // find first base - while (baseSlot && (gr_slot_attached_to(baseSlot) != NULL)) - baseSlot = gr_slot_next_in_segment(baseSlot); - int iChar = 0; // relative to segment - int iNextChar = 0; - bool reordered = false; - int nBaseGlyphIndex = 0; - // now loop over bases - while (baseSlot) + // handle reordered clusters. Presumes reordered glyphs have monotonic opposite char index until the cluster base. + bool isReordered = (nextBaseSlot && ((bRtl != (gr_cinfo_base(gr_seg_cinfo(pSegment, gr_slot_before(nextBaseSlot))) < firstChar - mnSegCharOffset)) + || gr_cinfo_base(gr_seg_cinfo(pSegment, gr_slot_before(nextBaseSlot))) == firstChar - mnSegCharOffset)); + if (clusterStart >= 0 && !isReordered) // we hit the base (end) of a reordered cluster { - bool bCluster = !reordered; - const gr_slot * clusterFirst = NULL; - const gr_slot * clusterAfter = NULL; - int firstChar = -1; - int lastChar = -1; - findFirstClusterSlot(baseSlot, &clusterFirst, &clusterAfter, &firstChar, &lastChar, bRtl); - iNextChar = maximum<int>(lastChar, iNextChar); - if (bCluster) - { - nBaseGlyphIndex = mvGlyphs.size(); - mvGlyph2Char[nBaseGlyphIndex] = iChar + mnSegCharOffset; - nFirstCharInCluster = firstChar; - nLastCharInCluster = lastChar; - } - else - { - mvGlyph2Char[mvGlyphs.size()] = firstChar + mnSegCharOffset; - nFirstCharInCluster = minimum<int>(firstChar, nFirstCharInCluster); - nLastCharInCluster = maximum<int>(lastChar, nLastCharInCluster); - } - if ( - firstChar > iChar && - (gr_cinfo_before(gr_seg_cinfo(pSegment, iChar)) > - static_cast<int>(gr_slot_index(clusterFirst))) - ) + int clusterEnd = mvGlyphs.size(); + for (int i = clusterStart; i < clusterEnd; ++i) + mvGlyph2Char[i] = firstChar; + if (bRtl) { - reordered = true; + for ( ; clusterFirstChar < firstChar; ++clusterFirstChar) + if (clusterFirstChar >= mnMinCharPos && clusterFirstChar < mnEndCharPos) + { + mvChar2BaseGlyph[clusterFirstChar - mnMinCharPos] = clusterStart; // lowest glyphItem index + mvCharDxs[clusterFirstChar - mnMinCharPos] = static_cast<int>(thisBoundary * fScaling) + mnWidth + nDxOffset; + } } else { - reordered = false; - iChar = iNextChar + 1; - } - float leftBoundary = gr_slot_origin_X(clusterFirst); - float rightBoundary = (clusterAfter)? - gr_slot_origin_X(clusterAfter) : gr_seg_advance_X(pSegment); - int bFirstChar = gr_cinfo_base(gr_seg_cinfo(pSegment, nFirstCharInCluster)); - if (mnSegCharOffset + bFirstChar >= mnMinCharPos && - mnSegCharOffset + bFirstChar < mnEndCharPos) - { - fMinX = minimum<float>(fMinX, leftBoundary); - fMaxX = maximum<float>(fMaxX, rightBoundary); - if (!reordered) - { - for (int i = nFirstCharInCluster; i <= nLastCharInCluster; i++) + for ( ; clusterFirstChar > firstChar; --clusterFirstChar) + if (clusterFirstChar < mnEndCharPos && clusterFirstChar >= mnMinCharPos) { - int ibase = gr_cinfo_base(gr_seg_cinfo(pSegment, i)); - if (mnSegCharOffset + ibase >= mnEndCharPos) - break; - // from the point of view of the dx array, the xpos is - // the origin of the first glyph of the next cluster ltr - mvCharDxs[mnSegCharOffset + ibase - mnMinCharPos] = - static_cast<int>(rightBoundary * fScaling) + nDxOffset; - mvCharBreaks[mnSegCharOffset + ibase - mnMinCharPos] = gr_cinfo_break_weight(gr_seg_cinfo(pSegment, i)); + mvChar2BaseGlyph[clusterFirstChar - mnMinCharPos] = clusterStart; + mvCharDxs[clusterFirstChar - mnMinCharPos] = static_cast<int>(nextBoundary * fScaling) + mnWidth + nDxOffset; } - // only set mvChar2BaseGlyph for first character of cluster - mvChar2BaseGlyph[mnSegCharOffset + bFirstChar - mnMinCharPos] = nBaseGlyphIndex; - } - append(pSegment, rArgs, baseSlot, gr_slot_origin_X(baseSlot), rightBoundary, fScaling, - nDxOffset, true, mnSegCharOffset + firstChar); } - if (mnSegCharOffset + bFirstChar >= mnEndCharPos) - break; - baseSlot = gr_slot_next_sibling_attachment(baseSlot); + clusterStart = -1; + clusterFirstChar = -1; + } + else if (clusterStart < 0 && isReordered) // we hit the start of a reordered cluster + { + clusterStart = mvGlyphs.size(); + clusterFirstChar = firstChar; + } + + int baseGlyph = mvGlyphs.size(); + int scaledGlyphPos = round_to_long(gr_slot_origin_X(baseSlot) * fScaling) + mnWidth + nDxOffset; + if (mvChar2Glyph[firstChar - mnMinCharPos] == -1 || mvGlyphs[mvChar2Glyph[firstChar - mnMinCharPos]].maLinearPos.X() < scaledGlyphPos) + { + mvChar2Glyph[firstChar - mnMinCharPos] = mvGlyphs.size(); + mvCharDxs[firstChar - mnMinCharPos] = static_cast<int>((bRtl ? thisBoundary : nextBoundary) * fScaling) + mnWidth + nDxOffset; + mvChar2BaseGlyph[firstChar - mnMinCharPos] = baseGlyph; + mvCharBreaks[firstChar - mnMinCharPos] = gr_cinfo_break_weight(gr_seg_cinfo(pSegment, gr_slot_before(baseSlot))); } + mvGlyph2Char[baseGlyph] = firstChar; + append(pSegment, rArgs, baseSlot, thisBoundary, nextBoundary, fScaling, nDxOffset, true, firstChar, baseGlyph, bRtl); + if (thisBoundary < fMinX) fMinX = thisBoundary; + if (nextBoundary > fMaxX && (nextChar < mnMinCharPos || nextChar >= mnEndCharPos || !isWhite(pStr[nextChar]) || fMaxX <= 0.0f)) + fMaxX = nextBoundary; } + long nXOffset = round_to_long(fMinX * fScaling); - mnWidth = round_to_long(fMaxX * fScaling) - nXOffset + nDxOffset; - if (mnWidth < 0) - { - // This can happen when there was no base inside the range - mnWidth = 0; - } + long nXEnd = round_to_long(fMaxX * fScaling); + int nCharRequested = minimum<int>(lastCharPos, mnEndCharPos) - mnMinCharPos; + int firstCharOffset = maximum<int>(mnSegCharOffset, mnMinCharPos) - mnMinCharPos; // fill up non-base char dx with cluster widths from previous base glyph if (bRtl) { if (mvCharDxs[nCharRequested-1] == -1) - mvCharDxs[nCharRequested-1] = 0; + mvCharDxs[nCharRequested-1] = nXEnd - nXOffset + mnWidth + nDxOffset; else - mvCharDxs[nCharRequested-1] -= nXOffset; - for (int i = nCharRequested - 2; i >= 0; i--) + mvCharDxs[nCharRequested-1] = nXEnd - mvCharDxs[nCharRequested-1] + 2 * (mnWidth + nDxOffset); +#ifdef GRLAYOUT_DEBUG + fprintf(grLog(),"%d,%d ", nCharRequested - 1, (int)mvCharDxs[nCharRequested-1]); +#endif + for (int i = nCharRequested - 2; i >= firstCharOffset; i--) { if (mvCharDxs[i] == -1) mvCharDxs[i] = mvCharDxs[i+1]; - else mvCharDxs[i] -= nXOffset; + else mvCharDxs[i] = nXEnd - mvCharDxs[i] + 2 * (mnWidth + nDxOffset); +#ifdef GRLAYOUT_DEBUG + fprintf(grLog(),"%d,%d ", (int)i, (int)mvCharDxs[i]); +#endif } } else { - if (mvCharDxs[0] == -1) - mvCharDxs[0] = 0; + if (mvCharDxs[firstCharOffset] == -1) + mvCharDxs[firstCharOffset] = 0; else - mvCharDxs[0] -= nXOffset; - for (int i = 1; i < nCharRequested; i++) + mvCharDxs[firstCharOffset] -= nXOffset; +#ifdef GRLAYOUT_DEBUG + fprintf(grLog(),"%d,%d ", firstCharOffset, (int)mvCharDxs[firstCharOffset]); +#endif + for (int i = firstCharOffset + 1; i < nCharRequested; i++) { if (mvCharDxs[i] == -1) mvCharDxs[i] = mvCharDxs[i-1]; else mvCharDxs[i] -= nXOffset; @@ -376,11 +266,17 @@ GraphiteLayout::fillFrom(gr_segment * pSegment, ImplLayoutArgs &rArgs, float fSc // remove offset due to context if there is one if (nXOffset != 0) { - for (size_t i = 0; i < mvGlyphs.size(); i++) + for (size_t i = origNumGlyphs; i < mvGlyphs.size(); i++) mvGlyphs[i].maLinearPos.X() -= nXOffset; } + mnWidth += nXEnd - nXOffset + nDxOffset; + if (mnWidth < 0) + { + // This can happen when there was no base inside the range + mnWidth = 0; + } #ifdef GRLAYOUT_DEBUG - fprintf(grLog(), "fillFrom %" SAL_PRI_SIZET "u glyphs offset %ld width %ld\n", mvGlyphs.size(), nXOffset, mnWidth); + fprintf(grLog(), "fillFrom %" SAL_PRI_SIZET "u glyphs offset %ld width %ld for %d\n", mvGlyphs.size(), nXOffset, mnWidth, nCharRequested); #endif } @@ -389,37 +285,29 @@ GraphiteLayout::fillFrom(gr_segment * pSegment, ImplLayoutArgs &rArgs, float fSc float GraphiteLayout::append(gr_segment *pSeg, ImplLayoutArgs &rArgs, const gr_slot * gi, float gOrigin, float nextGlyphOrigin, float scaling, long & rDXOffset, - bool bIsBase, int baseChar) + bool bIsBase, int baseChar, int baseGlyph, bool bRtl) { - bool bRtl(rArgs.mnFlags & SalLayoutFlags::BiDiRtl); - float nextOrigin; assert(gi); - assert(gr_slot_before(gi) <= gr_slot_after(gi)); - int firstChar = gr_slot_before(gi) + mnSegCharOffset; + // assert(gr_slot_before(gi) <= gr_slot_after(gi)); + int firstChar = gr_cinfo_base(gr_seg_cinfo(pSeg, gr_slot_before(gi))) + mnSegCharOffset; assert(mvGlyphs.size() < mvGlyph2Char.size()); - if (!bIsBase) mvGlyph2Char[mvGlyphs.size()] = baseChar;//firstChar; - // is the next glyph attached or in the next cluster? - //glyph_set_range_t iAttached = gi.attachedClusterGlyphs(); - const gr_slot * pFirstAttached = gr_slot_first_attachment(gi); - const gr_slot * pNextSibling = gr_slot_next_sibling_attachment(gi); - if (pFirstAttached) - nextOrigin = gr_slot_origin_X(pFirstAttached); - else if (!bIsBase && pNextSibling) - nextOrigin = gr_slot_origin_X(pNextSibling); - else - nextOrigin = nextGlyphOrigin; + if (firstChar < mnMinCharPos || firstChar >= mnEndCharPos) + return nextGlyphOrigin; + long glyphId = gr_slot_gid(gi); long deltaOffset = 0; - int scaledGlyphPos = round_to_long(gr_slot_origin_X(gi) * scaling); - int glyphWidth = round_to_long((nextOrigin - gOrigin) * scaling); -// if (glyphWidth < 0) -// { -// nextOrigin = gOrigin; -// glyphWidth = 0; -// } + int scaledGlyphPos = round_to_long(gr_slot_origin_X(gi) * scaling) + mnWidth + rDXOffset; + int glyphWidth = round_to_long((nextGlyphOrigin - gOrigin) * scaling); + if (!bIsBase) + { + mvChar2BaseGlyph[firstChar - mnMinCharPos] = baseGlyph; + mvCharDxs[firstChar - mnMinCharPos] = mvCharDxs[baseChar - mnMinCharPos]; + mvCharBreaks[firstChar - mnMinCharPos] = gr_cinfo_break_weight(gr_seg_cinfo(pSeg, gr_slot_before(gi))); + } + #ifdef GRLAYOUT_DEBUG - fprintf(grLog(),"c%d g%ld,X%d W%d nX%f ", firstChar, glyphId, - (int)(gr_slot_origin_X(gi) * scaling), glyphWidth, nextOrigin * scaling); + fprintf(grLog(),"c%d g%ld,X%d W%d nX%f @%d=%d ", firstChar, glyphId, + scaledGlyphPos, glyphWidth, nextGlyphOrigin * scaling, mvChar2Glyph[firstChar-mnMinCharPos], mvCharDxs[firstChar-mnMinCharPos]); #endif if (glyphId == 0) { @@ -449,11 +337,12 @@ GraphiteLayout::append(gr_segment *pSeg, ImplLayoutArgs &rArgs, } // append this glyph. Set the cluster flag if this glyph is attached to another long nGlyphFlags = bIsBase ? 0 : GlyphItem::IS_IN_CLUSTER; + if (gr_slot_attached_to(gi)) + nGlyphFlags |= GlyphItem::IS_DIACRITIC; nGlyphFlags |= (bRtl)? GlyphItem::IS_RTL_GLYPH : 0; GlyphItem aGlyphItem(mvGlyphs.size(), glyphId, - Point(scaledGlyphPos + rDXOffset, - round_to_long((-gr_slot_origin_Y(gi) * scaling))), + Point(scaledGlyphPos, round_to_long((-gr_slot_origin_Y(gi) * scaling))), nGlyphFlags, glyphWidth); if (glyphId != static_cast<long>(GF_DROPPED)) @@ -464,9 +353,10 @@ GraphiteLayout::append(gr_segment *pSeg, ImplLayoutArgs &rArgs, rDXOffset += deltaOffset; // Recursively append all the attached glyphs. - float cOrigin = nextOrigin; + float cOrigin = nextGlyphOrigin; for (const gr_slot * agi = gr_slot_first_attachment(gi); agi != NULL; agi = gr_slot_next_sibling_attachment(agi)) - cOrigin = append(pSeg, rArgs, agi, cOrigin, nextGlyphOrigin, scaling, rDXOffset, false, baseChar); + if (!gr_slot_can_insert_before(agi)) + cOrigin = append(pSeg, rArgs, agi, cOrigin, nextGlyphOrigin, scaling, rDXOffset, false, baseChar, baseGlyph, bRtl); return cOrigin; } @@ -500,6 +390,7 @@ void GraphiteLayout::clear() mvGlyphs.clear(); mvCharDxs.clear(); mvChar2BaseGlyph.clear(); + mvChar2Glyph.clear(); mvGlyph2Char.clear(); // Reset the state to the empty state. @@ -510,170 +401,61 @@ void GraphiteLayout::clear() // This method shouldn't be called on windows, since it needs the dc reset bool GraphiteLayout::LayoutText(ImplLayoutArgs & rArgs) { + clear(); bool success = true; - if (rArgs.mnMinCharPos < rArgs.mnEndCharPos) - { - gr_segment * pSegment = CreateSegment(rArgs); - if (!pSegment) - return false; - success = LayoutGlyphs(rArgs, pSegment); - if (pSegment) - { - gr_seg_destroy(pSegment); - pSegment = NULL; - } - } - else - { - clear(); - } - return success; -} - -gr_segment * GraphiteLayout::CreateSegment(ImplLayoutArgs& rArgs) -{ - assert(rArgs.mnLength >= 0); - - gr_segment * pSegment = NULL; - + if (rArgs.mnMinCharPos >= rArgs.mnEndCharPos) + return success; // Set the SalLayouts values to be the initial ones. SalLayout::AdjustLayout(rArgs); // TODO check if this is needed if (mnUnitsPerPixel > 1) mfScaling = 1.0f / mnUnitsPerPixel; + mvCharDxs.assign(mnEndCharPos - mnMinCharPos, -1); + mvChar2BaseGlyph.assign(mnEndCharPos - mnMinCharPos, -1); + mvChar2Glyph.assign(mnEndCharPos - mnMinCharPos, -1); + mvCharBreaks.assign(mnEndCharPos - mnMinCharPos, 0); - // Clear out any previous buffers - clear(); - bool bRtl(mnLayoutFlags & SalLayoutFlags::BiDiRtl); - try +#ifdef GRLAYOUT_DEBUG + fprintf(grLog(), "New Graphite LayoutText\n"); +#endif + success = false; + while (true) { - // Don't set RTL if font doesn't support it otherwise it forces rtl on - // everything - //if (bRtl && (mrFont.getSupportedScriptDirections() & gr::kfsdcHorizRtl)) - // maLayout.setRightToLeft(bRtl); - - // Context is often needed beyond the specified end, however, we don't - // want it if there has been a direction change, since it is hard - // to tell between reordering within one direction and multi-directional - // text. Extra context, can also cause problems with ligatures stradling - // a hyphenation point, so disable if CTL is disabled. - mnSegCharOffset = rArgs.mnMinCharPos; - int limit = rArgs.mnEndCharPos; - if (!(SalLayoutFlags::ComplexDisabled & rArgs.mnFlags)) - { - const int nSegCharMin = maximum<int>(0, mnMinCharPos - EXTRA_CONTEXT_LENGTH); - const int nSegCharLimit = minimum(rArgs.mnLength, mnEndCharPos + EXTRA_CONTEXT_LENGTH); - if (nSegCharMin < mnSegCharOffset) - { - int sameDirEnd = findSameDirLimit(rArgs.mpStr + nSegCharMin, - rArgs.mnEndCharPos - nSegCharMin, bRtl); - if (sameDirEnd == rArgs.mnEndCharPos) - mnSegCharOffset = nSegCharMin; - } - if (nSegCharLimit > limit) - { - limit += findSameDirLimit(rArgs.mpStr + rArgs.mnEndCharPos, - nSegCharLimit - rArgs.mnEndCharPos, bRtl); - } - } + int nBidiMinRunPos, nBidiEndRunPos; + bool bRightToLeft; + if (!rArgs.GetNextRun(&nBidiMinRunPos, &nBidiEndRunPos, &bRightToLeft)) + break; - size_t numchars = gr_count_unicode_characters(gr_utf16, rArgs.mpStr + mnSegCharOffset, - rArgs.mpStr + (rArgs.mnLength > limit + 64 ? limit + 64 : rArgs.mnLength), NULL); - static com::sun::star::uno::Reference< com::sun::star::i18n::XCharacterClassification > xCharClass; - if ( !xCharClass.is() ) - xCharClass = vcl::unohelper::CreateCharacterClassification(); - size_t numchars2 = rArgs.mnEndCharPos - mnSegCharOffset; // fdo#52540, fdo#68313, fdo#70666 avoid bad ligature replacement, fdo#88051 layout problem - if (numchars > numchars2 && (rArgs.mpStr[mnSegCharOffset + numchars2] == '\t' || - xCharClass->getType(rArgs.mpStr + mnSegCharOffset, numchars2 + 1) == ::com::sun::star::i18n::UnicodeType::LOWERCASE_LETTER)) - { - numchars = numchars2; - } - if (mpFeatures) - pSegment = gr_make_seg(mpFont, mpFace, 0, mpFeatures->values(), gr_utf16, - rArgs.mpStr + mnSegCharOffset, numchars, bRtl); - else - pSegment = gr_make_seg(mpFont, mpFace, 0, NULL, gr_utf16, - rArgs.mpStr + mnSegCharOffset, numchars, bRtl); + if (nBidiEndRunPos < mnMinCharPos || nBidiMinRunPos >= mnEndCharPos) + continue; + + if (nBidiMinRunPos == mnMinCharPos) + nBidiMinRunPos = maximum<int>(0, nBidiMinRunPos - EXTRA_CONTEXT_LENGTH); + if (nBidiEndRunPos == mnEndCharPos) + nBidiEndRunPos = minimum<int>(rArgs.mnLength, nBidiEndRunPos + EXTRA_CONTEXT_LENGTH); + size_t numchars = gr_count_unicode_characters(gr_utf16, rArgs.mpStr + nBidiMinRunPos, + rArgs.mpStr + nBidiEndRunPos, NULL); + gr_segment * pSegment = gr_make_seg(mpFont, mpFace, 0, mpFeatures ? mpFeatures->values() : NULL, + gr_utf16, rArgs.mpStr + nBidiMinRunPos, numchars, 2 | int(bRightToLeft)); - //pSegment = new gr::RangeSegment((gr::Font *)&mrFont, mpTextSrc, &maLayout, mnMinCharPos, limit); if (pSegment != NULL) { + success = true; + mnSegCharOffset = nBidiMinRunPos; #ifdef GRLAYOUT_DEBUG - fprintf(grLog(),"Gr::LayoutText %d-%d, context %d, len %d, numchars %" SAL_PRI_SIZET "u, rtl %d scaling %f:", rArgs.mnMinCharPos, - rArgs.mnEndCharPos, limit, rArgs.mnLength, numchars, bRtl, mfScaling); - for (int i = mnSegCharOffset; i < limit; ++i) + fprintf(grLog(),"Gr::LayoutText %d-%d, context %d-%d, len %d, numchars %" SAL_PRI_SIZET "u, rtl %d scaling %f:", + rArgs.mnMinCharPos, rArgs.mnEndCharPos, + nBidiMinRunPos, nBidiEndRunPos, + rArgs.mnLength, numchars, bRightToLeft, mfScaling); + for (int i = mnSegCharOffset; i < nBidiEndRunPos; ++i) fprintf(grLog(), " %04X", rArgs.mpStr[i]); fprintf(grLog(), "\n"); #endif - } - else - { -#ifdef GRLAYOUT_DEBUG - fprintf(grLog(), "Gr::LayoutText failed: "); - for (int i = mnMinCharPos; i < limit; i++) - { - fprintf(grLog(), "%04x ", rArgs.mpStr[i]); - } - fprintf(grLog(), "\n"); -#endif - clear(); - return NULL; - } - } - catch (...) - { - clear(); // destroy the text source and any partially built segments. - return NULL; - } - return pSegment; -} - -bool GraphiteLayout::LayoutGlyphs(ImplLayoutArgs& rArgs, gr_segment * pSegment) -{ - // Calculate the initial character dxs. - mvCharDxs.assign(mnEndCharPos - mnMinCharPos, -1); - mvChar2BaseGlyph.assign(mnEndCharPos - mnMinCharPos, -1); - mvCharBreaks.assign(mnEndCharPos - mnMinCharPos, 0); - mnWidth = 0; - if (mvCharDxs.size() > 0) - { - // Discover all the clusters. - try - { - bool bRtl(mnLayoutFlags & SalLayoutFlags::BiDiRtl); - fillFrom(pSegment, rArgs, mfScaling); - - if (bRtl) - { - // not needed for adjacent differences, but for mouse clicks to char - std::transform(mvCharDxs.begin(), mvCharDxs.end(), mvCharDxs.begin(), - std::bind1st(std::minus<long>(), mnWidth)); - // fixup last dx to ensure it always equals the width - mvCharDxs[mvCharDxs.size() - 1] = mnWidth; - } - } - catch (const std::exception &e) - { -#ifdef GRLAYOUT_DEBUG - fprintf(grLog(),"LayoutGlyphs failed %s\n", e.what()); -#else - (void)e; -#endif - return false; - } - catch (...) - { -#ifdef GRLAYOUT_DEBUG - fprintf(grLog(),"LayoutGlyphs failed with exception"); -#endif - return false; + fillFrom(pSegment, rArgs, mfScaling, bRightToLeft, nBidiEndRunPos); + gr_seg_destroy(pSegment); } } - else - { - mnWidth = 0; - } - return true; + return success; } sal_Int32 GraphiteLayout::GetTextBreak(DeviceCoordinate maxmnWidth, DeviceCoordinate char_extra, int factor) const @@ -695,12 +477,12 @@ sal_Int32 GraphiteLayout::GetTextBreak(DeviceCoordinate maxmnWidth, DeviceCoordi { nWidth += char_extra; if (nWidth > maxmnWidth) break; - if (mvChar2BaseGlyph[i] != -1) + int gi = mvChar2BaseGlyph[i]; + if (gi != -1) { - if ( + if (!mvGlyphs[gi].IsDiacritic() && (mvCharBreaks[i] > -35 || (mvCharBreaks[i-1] > 0 && mvCharBreaks[i-1] < 35)) && - (mvCharBreaks[i-1] < 35 || (mvCharBreaks[i] < 0 && mvCharBreaks[i] > -35)) - ) + (mvCharBreaks[i-1] < 35 || (mvCharBreaks[i] < 0 && mvCharBreaks[i] > -35))) { nLastBreak = static_cast<int>(i); wLastBreak = nWidth; @@ -755,10 +537,6 @@ DeviceCoordinate GraphiteLayout::FillDXArray( DeviceCoordinate* pDXArray ) const fprintf(grLog(),"%d,%d,%ld ", (int)i, (int)mvCharDxs[i], pDXArray[i]); #endif } - //std::adjacent_difference(mvCharDxs.begin(), mvCharDxs.end(), pDXArray); - //for (size_t i = 0; i < mvCharDxs.size(); i++) - // fprintf(grLog(),"%d,%d,%d ", (int)i, (int)mvCharDxs[i], pDXArray[i]); - //fprintf(grLog(),"FillDX %ld,%d\n", mnWidth, std::accumulate(pDXArray, pDXArray + mvCharDxs.size(), 0)); } #ifdef GRLAYOUT_DEBUG fprintf(grLog(),"FillDXArray %d-%d=%g\n", mnMinCharPos, mnEndCharPos, (double)mnWidth); @@ -769,7 +547,7 @@ DeviceCoordinate GraphiteLayout::FillDXArray( DeviceCoordinate* pDXArray ) const void GraphiteLayout::AdjustLayout(ImplLayoutArgs& rArgs) { SalLayout::AdjustLayout(rArgs); - if(rArgs.mpDXArray) + if(rArgs.mpDXArray && mvGlyphs.size()) { std::vector<int> vDeltaWidths(mvGlyphs.size(), 0); ApplyDXArray(rArgs, vDeltaWidths); @@ -817,11 +595,14 @@ void GraphiteLayout::expandOrCondense(ImplLayoutArgs &rArgs) int nClusterCount = 0; for (size_t j = 0; j < mvGlyphs.size(); j++) { - if (mvGlyphs[j].IsClusterStart()) + if (mvGlyphs[j].IsClusterStart() && !mvGlyphs[j].IsDiacritic()) { ++nClusterCount; } } +#ifdef GRLAYOUT_DEBUG + fprintf(grLog(), "Expand by width %f for %ld clusters\n", nDeltaWidth, nClusterCount); +#endif if (nClusterCount > 1) { float fExtraPerCluster = static_cast<float>(nDeltaWidth) / static_cast<float>(nClusterCount - 1); @@ -829,7 +610,7 @@ void GraphiteLayout::expandOrCondense(ImplLayoutArgs &rArgs) int nOffset = 0; for (size_t i = 0; i < mvGlyphs.size(); i++) { - if (mvGlyphs[i].IsClusterStart()) + if (mvGlyphs[i].IsClusterStart() && !mvGlyphs[i].IsDiacritic()) { nOffset = static_cast<int>(fExtraPerCluster * nCluster); int nCharIndex = mvGlyph2Char[i]; @@ -882,134 +663,126 @@ void GraphiteLayout::expandOrCondense(ImplLayoutArgs &rArgs) mnWidth = rArgs.mnLayoutWidth; } +unsigned int GraphiteLayout::ScanFwdForChar(int &findChar, bool fallback) const +{ + int res = mvChar2Glyph[findChar - mnMinCharPos]; + int done = 3; + while (res == -1 && --done) + { + if (fallback) + { + for (++findChar; findChar - mnMinCharPos < int(mvChar2Glyph.size()); ++findChar) + if ((res = mvChar2Glyph[findChar - mnMinCharPos]) != -1) + return res; + } + else + { + for (--findChar; findChar >= mnMinCharPos; --findChar) + if ((res = mvChar2Glyph[findChar - mnMinCharPos]) != -1) + return res; + } + fallback = !fallback; + } + return unsigned(res); +} + void GraphiteLayout::ApplyDXArray(ImplLayoutArgs &args, std::vector<int> & rDeltaWidth) { - const size_t nChars = args.mnEndCharPos - args.mnMinCharPos; - if (nChars == 0) return; + bool bRtl(mnLayoutFlags & SalLayoutFlags::BiDiRtl); + int startChar = args.mnMinCharPos < mnMinCharPos ? mnMinCharPos : args.mnMinCharPos; + int endChar = args.mnEndCharPos >= mnEndCharPos ? mnEndCharPos - 1 : args.mnEndCharPos; + unsigned int startGi = ScanFwdForChar(startChar, !bRtl); + unsigned int endGi = ScanFwdForChar(endChar, bRtl); + int nChars = endChar - startChar + 1; + if (nChars <= 0) return; + if (startGi > endGi) + { + unsigned int temp = endGi; + endGi = startGi; + startGi = temp; + } + ++endGi; #ifdef GRLAYOUT_DEBUG for (size_t iDx = 0; iDx < mvCharDxs.size(); iDx++) fprintf(grLog(),"%d,%d,%ld ", (int)iDx, (int)mvCharDxs[iDx], args.mpDXArray[iDx]); - fprintf(grLog(),"ApplyDx\n"); + fprintf(grLog(),"ApplyDx %d-%d=%d-%d\n", startChar, endChar, startGi, endGi); #endif - bool bRtl(mnLayoutFlags & SalLayoutFlags::BiDiRtl); - int nXOffset = 0; - if (bRtl) - { - nXOffset = args.mpDXArray[nChars - 1] - mvCharDxs[nChars - 1]; - } - int nPrevClusterGlyph = (bRtl)? (signed)mvGlyphs.size() : -1; - int nPrevClusterLastChar = -1; - for (size_t i = 0; i < nChars; i++) + + for (unsigned int i = startGi; i < endGi; ++i) { - int nChar2Base = mvChar2BaseGlyph[i]; - if ((nChar2Base > -1) && (nChar2Base != nPrevClusterGlyph)) + // calculate visual cluster bounds + int firstChar = mvGlyph2Char[i]; + unsigned int nBaseGlyph = mvChar2BaseGlyph[firstChar - mnMinCharPos]; + while (nBaseGlyph == ~0U && i < endGi) { - assert((nChar2Base > -1) && (nChar2Base < (signed)mvGlyphs.size())); - GlyphItem & gi = mvGlyphs[nChar2Base]; - if (!gi.IsClusterStart()) - continue; - - // find last glyph of this cluster - size_t j = i + 1; - int nLastChar = i; - int nLastGlyph = nChar2Base; - for (; j < nChars; j++) + ++i; + firstChar = mvGlyph2Char[i]; + nBaseGlyph = unsigned(mvChar2BaseGlyph[firstChar - mnMinCharPos]); + } + int lastChar = firstChar; + unsigned int nLastGlyph = i; + // firstGlyph = i + for ( ; nLastGlyph < endGi; nLastGlyph++) + { + int thisChar = mvGlyph2Char[nLastGlyph]; + if (thisChar == -1) continue; + if (unsigned(mvChar2BaseGlyph[thisChar - mnMinCharPos]) != nBaseGlyph) { - const int nChar2BaseJ = mvChar2BaseGlyph[j]; - assert((nChar2BaseJ >= -1) && (nChar2BaseJ < (signed)mvGlyphs.size())); - if (nChar2BaseJ != -1 ) - { - nLastGlyph = nChar2BaseJ + ((bRtl)? +1 : -1); - nLastChar = j - 1; + if (!mvGlyphs[nLastGlyph].IsDiacritic()) break; - } - } - if (nLastGlyph < 0) - { - nLastGlyph = nChar2Base; - } - // Its harder to find the last glyph rtl, since the first of - // cluster is still on the left so we need to search towards - // the previous cluster to the right - if (bRtl) - { - nLastGlyph = nChar2Base; - while (nLastGlyph + 1 < (signed)mvGlyphs.size() && - !mvGlyphs[nLastGlyph+1].IsClusterStart()) - { - ++nLastGlyph; - } - } - if (j == nChars) - { - nLastChar = nChars - 1; - if (!bRtl) nLastGlyph = mvGlyphs.size() - 1; - } - int nBaseCount = 0; - // count bases within cluster - may be more than 1 with reordering - for (int k = nChar2Base; k <= nLastGlyph; k++) - { - if (mvGlyphs[k].IsClusterStart()) ++nBaseCount; - } - assert((nLastChar > -1) && (nLastChar < (signed)nChars)); - long nNewClusterWidth = args.mpDXArray[nLastChar]; - long nOrigClusterWidth = mvCharDxs[nLastChar]; - long nDGlyphOrigin = 0; - if (nPrevClusterLastChar > - 1) - { - assert(nPrevClusterLastChar < (signed)nChars); - nNewClusterWidth -= args.mpDXArray[nPrevClusterLastChar]; - nOrigClusterWidth -= mvCharDxs[nPrevClusterLastChar]; - nDGlyphOrigin = args.mpDXArray[nPrevClusterLastChar] - mvCharDxs[nPrevClusterLastChar]; - } - long nDWidth = nNewClusterWidth - nOrigClusterWidth; -#ifdef GRLAYOUT_DEBUG - fprintf(grLog(), "c%lu last glyph %d/%lu\n", i, nLastGlyph, mvGlyphs.size()); -#endif - assert((nLastGlyph > -1) && (nLastGlyph < (signed)mvGlyphs.size())); - mvGlyphs[nLastGlyph].mnNewWidth += nDWidth; - if (gi.maGlyphId != GF_DROPPED) - mvGlyphs[nLastGlyph].mnNewWidth += nDWidth; - else - nDGlyphOrigin += nDWidth; - long nDOriginPerBase = (nBaseCount > 0)? nDWidth / nBaseCount : 0; - nBaseCount = -1; - // update glyph positions - if (bRtl) - { - for (int n = nChar2Base; n <= nLastGlyph; n++) - { - if (mvGlyphs[n].IsClusterStart()) ++nBaseCount; - assert((n > - 1) && (n < (signed)mvGlyphs.size())); - mvGlyphs[n].maLinearPos.X() += -(nDGlyphOrigin + nDOriginPerBase * nBaseCount) + nXOffset; - } - } - else - { - for (int n = nChar2Base; n <= nLastGlyph; n++) - { - if (mvGlyphs[n].IsClusterStart()) ++nBaseCount; - assert((n > - 1) && (n < (signed)mvGlyphs.size())); - mvGlyphs[n].maLinearPos.X() += nDGlyphOrigin + (nDOriginPerBase * nBaseCount) + nXOffset; - } + else + nBaseGlyph = mvChar2BaseGlyph[thisChar - mnMinCharPos]; } - rDeltaWidth[nChar2Base] = nDWidth; + if (thisChar > lastChar) lastChar = thisChar; + if (thisChar < firstChar) firstChar = thisChar; + } + + // calculate visual cluster widths + if (lastChar > args.mnEndCharPos) lastChar = args.mnEndCharPos; + if (firstChar < args.mnMinCharPos) firstChar = args.mnMinCharPos; + long nOrigClusterWidth = mvCharDxs[lastChar - mnMinCharPos]; + long nNewClusterWidth = args.mpDXArray[lastChar - args.mnMinCharPos]; + long nDGlyphOrigin = 0; + if (firstChar > args.mnMinCharPos) + { + //nNewClusterWidth -= args.mpDXArray[firstChar - args.mnMinCharPos]; + //nOrigClusterWidth -= mvCharDxs[firstChar - mnMinCharPos]; + nDGlyphOrigin = args.mpDXArray[firstChar - args.mnMinCharPos - 1] + - mvCharDxs[firstChar - mnMinCharPos - 1]; + } + + // update visual cluster + long nDWidth = nNewClusterWidth - nOrigClusterWidth; + if (firstChar >= args.mnMinCharPos) + for (int n = firstChar; n <= lastChar; ++n) + if (n > mnMinCharPos && mvCharDxs[n - mnMinCharPos - 1] != -1) + mvCharDxs[n - mnMinCharPos - 1] += nDGlyphOrigin; // + nDWidth; + for (unsigned int n = i; n < nLastGlyph; n++) + //mvGlyphs[n].maLinearPos.X() += (nDGlyphOrigin + nDWidth) * (bRtl ? -1 : 1); + mvGlyphs[n].maLinearPos.X() += nDGlyphOrigin * (bRtl ? -1 : 1); + + rDeltaWidth[nBaseGlyph] = nDWidth; #ifdef GRLAYOUT_DEBUG - fprintf(grLog(),"c%d g%d-%d dW%ld-%ld=%ld dX%ld x%ld\t", (int)i, nChar2Base, nLastGlyph, nNewClusterWidth, nOrigClusterWidth, nDWidth, nDGlyphOrigin, mvGlyphs[nChar2Base].maLinearPos.X()); + fprintf(grLog(),"c%d=%d g%d-%d dW%ld-%ld=%ld dX%ld x%ld @%d=%d\n", firstChar, lastChar, i, nLastGlyph, nNewClusterWidth, nOrigClusterWidth, nDWidth, nDGlyphOrigin, mvGlyphs[i].maLinearPos.X(), mvCharDxs[lastChar - mnMinCharPos], args.mpDXArray[lastChar - args.mnMinCharPos]); #endif - nPrevClusterGlyph = nChar2Base; - nPrevClusterLastChar = nLastChar; - i = nLastChar; - } + i = nLastGlyph - 1; + if (i >= endGi - 1) + mnWidth += nDGlyphOrigin + nDWidth; } // Update the dx vector with the new values. std::copy(args.mpDXArray, args.mpDXArray + nChars, mvCharDxs.begin() + (args.mnMinCharPos - mnMinCharPos)); + //args.mpDXArray[0] = 0; #ifdef GRLAYOUT_DEBUG fprintf(grLog(),"ApplyDx %ld(%ld)\n", args.mpDXArray[nChars - 1], mnWidth); #endif - mnWidth = args.mpDXArray[nChars - 1]; + if (bRtl) + { + int diff = mvGlyphs[0].maLinearPos.X(); + for (size_t i = 0; i < mvGlyphs.size(); ++i) + mvGlyphs[i].maLinearPos.X() -= diff; + } } void GraphiteLayout::kashidaJustify(std::vector<int>& rDeltaWidths, sal_GlyphId nKashidaIndex, int nKashidaWidth) diff --git a/vcl/win/source/gdi/winlayout.cxx b/vcl/win/source/gdi/winlayout.cxx index d1515a1..261e1b0 100644 --- a/vcl/win/source/gdi/winlayout.cxx +++ b/vcl/win/source/gdi/winlayout.cxx @@ -2374,11 +2374,6 @@ GraphiteWinLayout::~GraphiteWinLayout() bool GraphiteWinLayout::LayoutText( ImplLayoutArgs & args) { - if (args.mnMinCharPos >= args.mnEndCharPos) - { - maImpl.clear(); - return true; - } HFONT hUnRotatedFont = 0; if (args.mnOrientation) { @@ -2392,15 +2387,7 @@ bool GraphiteWinLayout::LayoutText( ImplLayoutArgs & args) } WinLayout::AdjustLayout(args); maImpl.SetFontScale(WinLayout::mfFontScale); - gr_segment * pSegment = maImpl.CreateSegment(args); - bool bSucceeded = false; - if (pSegment) - { - // replace the DC on the font within the segment - // create glyph vectors - bSucceeded = maImpl.LayoutGlyphs(args, pSegment); - gr_seg_destroy(pSegment); - } + bool bSucceeded = maImpl.LayoutText(args); if (args.mnOrientation) { // restore the rotated font
_______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits