123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234 |
- // RichTextKit
- // Copyright © 2019-2020 Topten Software. All Rights Reserved.
- //
- // Licensed under the Apache License, Version 2.0 (the "License"); you may
- // not use this product except in compliance with the License. You may obtain
- // a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- // License for the specific language governing permissions and limitations
- // under the License.
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- using Topten.RichTextKit.Utils;
- namespace Topten.RichTextKit
- {
- /// <summary>
- /// Represents a unicode string and all associated attributes
- /// for each character required for the Bidi algorithm
- /// </summary>
- class BidiData
- {
- /// <summary>
- /// Construct a new empty BidiData
- /// </summary>
- public BidiData()
- {
- _types = new Buffer<Directionality>();
- _pairedBracketTypes= new Buffer<PairedBracketType>();
- _pairedBracketValues = new Buffer<int>();
- }
- List<int> _paragraphPositions = new List<int>();
- sbyte _paragraphEmbeddingLevel;
- public sbyte ParagraphEmbeddingLevel => _paragraphEmbeddingLevel;
- bool _hasBrackets;
- public bool HasBrackets => _hasBrackets;
- bool _hasEmbeddings;
- public bool HasEmbeddings => _hasEmbeddings;
- bool _hasIsolates;
- public bool HasIsolates => _hasIsolates;
- /// <summary>
- /// Initialize with an array of Unicode code points
- /// </summary>
- /// <param name="codePoints">The unicode code points to be processed</param>
- /// <param name="paragraphEmbeddingLevel">The paragraph embedding level</param>
- public void Init(Slice<int> codePoints, sbyte paragraphEmbeddingLevel)
- {
- // Set working buffer sizes
- _types.Length = codePoints.Length;
- _pairedBracketTypes.Length = codePoints.Length;
- _pairedBracketValues.Length = codePoints.Length;
- _paragraphPositions.Clear();
- _paragraphEmbeddingLevel = paragraphEmbeddingLevel;
- // Resolve the directionality, paired bracket type and paired bracket values for
- // all code points
- _hasBrackets = false;
- _hasEmbeddings = false;
- _hasIsolates = false;
- for (int i = 0; i < codePoints.Length; i++)
- {
- var bidiData = UnicodeClasses.BidiData(codePoints[i]);
- // Look up directionality
- var dir = (Directionality)(bidiData >> 24);
- _types[i] = dir;
- switch (dir)
- {
- case Directionality.LRE:
- case Directionality.LRO:
- case Directionality.RLE:
- case Directionality.RLO:
- case Directionality.PDF:
- _hasEmbeddings = true;
- break;
- case Directionality.LRI:
- case Directionality.RLI:
- case Directionality.FSI:
- case Directionality.PDI:
- _hasIsolates = true;
- break;
- }
- // Lookup paired bracket types
- var pbt = (PairedBracketType)((bidiData >> 16) & 0xFF);
- _pairedBracketTypes[i] = pbt;
- switch (pbt)
- {
- case PairedBracketType.o:
- _pairedBracketValues[i] = MapCanon((int)(bidiData & 0xFFFF));
- _hasBrackets = true;
- break;
- case PairedBracketType.c:
- _pairedBracketValues[i] = MapCanon(codePoints[i]);
- _hasBrackets = true;
- break;
- }
- /*
- if (_types[i] == RichTextKit.Directionality.B)
- {
- _types[i] = (Directionality)Directionality.WS;
- _paragraphPositions.Add(i);
- }
- */
- }
- // Create slices on work buffers
- Types = _types.AsSlice();
- PairedBracketTypes = _pairedBracketTypes.AsSlice();
- PairedBracketValues = _pairedBracketValues.AsSlice();
- }
- /// <summary>
- /// Map bracket types 0x3008 and 0x3009 to their canonical equivalents
- /// </summary>
- /// <param name="codePoint">The code point to be mapped</param>
- /// <returns>The mapped canonical code point, or the passed code point</returns>
- static int MapCanon(int codePoint)
- {
- if (codePoint == 0x3008)
- return 0x2329;
- if (codePoint == 0x3009)
- return 0x232A;
- else
- return codePoint;
- }
- /// <summary>
- /// Get the length of the data held by the BidiData
- /// </summary>
- public int Length => _types.Length;
- Buffer<Directionality> _types;
- Buffer<PairedBracketType> _pairedBracketTypes;
- Buffer<int> _pairedBracketValues;
- Buffer<Directionality> _savedTypes;
- Buffer<PairedBracketType> _savedPairedBracketTypes;
-
- /// <summary>
- /// Save the Types and PairedBracketTypes of this bididata
- /// </summary>
- /// <remarks>
- /// This is used when processing embedded style runs with
- /// directionality overrides. TextBlock saves the data,
- /// overrides the style runs to neutral, processes the bidi
- /// data for the entire paragraph and then restores this data
- /// before processing the embedded runs.
- /// </remarks>
- public void SaveTypes()
- {
- // Make sure we have a buffer
- if (_savedTypes == null)
- {
- _savedTypes = new Buffer<Directionality>();
- _savedPairedBracketTypes = new Buffer<PairedBracketType>();
- }
- // Capture the types data
- _savedTypes.Clear();
- _savedTypes.Add(_types.AsSlice());
- _savedPairedBracketTypes.Clear();
- _savedPairedBracketTypes.Add(_pairedBracketTypes.AsSlice());
- }
- /// <summary>
- /// Restore the data saved by SaveTypes
- /// </summary>
- public void RestoreTypes()
- {
- _types.Clear();
- _types.Add(_savedTypes.AsSlice());
- _pairedBracketTypes.Clear();
- _pairedBracketTypes.Add(_savedPairedBracketTypes.AsSlice());
- }
- /// <summary>
- /// The directionality of each code point
- /// </summary>
- public Slice<Directionality> Types;
- /// <summary>
- /// The paired bracket type for each code point
- /// </summary>
- public Slice<PairedBracketType> PairedBracketTypes;
- /// <summary>
- /// The paired bracket value for code code point
- /// </summary>
- /// <remarks>
- /// The paired bracket values are the code points
- /// of each character where the opening code point
- /// is replaced with the closing code point for easier
- /// matching. Also, bracket code points are mapped
- /// to their canonical equivalents
- /// </remarks>
- public Slice<int> PairedBracketValues;
- public Buffer<sbyte> _tempLevelBuffer;
- /// <summary>
- /// Gets a temporary level buffer. Used by TextBlock when
- /// resolving style runs with different directionality.
- /// </summary>
- /// <param name="length">Length of the required buffer</param>
- /// <returns>An uninitialized level buffer</returns>
- public Slice<sbyte> GetTempLevelBuffer(int length)
- {
- if (_tempLevelBuffer == null)
- _tempLevelBuffer = new Buffer<sbyte>();
- _tempLevelBuffer.Clear();
- return _tempLevelBuffer.Add(length, false);
- }
- }
- }
|