2 * Copyright (c) 2020 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 using System.Collections.Generic;
20 using System.ComponentModel;
25 using Tizen.NUI.BaseComponents;
27 namespace Tizen.NUI.Utility
31 /// This is a class for stroing the text of a page.
33 [EditorBrowsable(EditorBrowsableState.Never)]
34 internal class PageData
36 public string PreviousTag { get; set; }
37 public string EndTag { get; set; }
38 public int StartOffset { get; set; }
39 public int EndOffset { get; set; }
43 /// This is a class that stores information when parsing markup text.
45 [EditorBrowsable(EditorBrowsableState.Never)]
46 internal class TagData
48 public string TagName { get; set; }
49 public string AttributeName { get; set; }
50 public bool IsEndTag { get; set; }
54 /// This is utility class for paging very long text.
56 [EditorBrowsable(EditorBrowsableState.Never)]
57 public class TextPageUtil : Disposable
59 private static char LESS_THAN = '<';
60 private static char GREATER_THAN = '>';
61 private static char EQUAL = '=';
62 private static char QUOTATION_MARK = '\'';
63 private static char SLASH = '/';
64 // private static char BACK_SLASH = '\\';
65 // private static char AMPERSAND = '&';
66 // private static char HASH = '#';
67 // private static char SEMI_COLON = ';';
68 // private static char CHAR_ARRAY_END = '\0';
69 // private static char HEX_CODE = 'x';
70 private static byte WHITE_SPACE = 0x20;
72 private int totalPageCnt;
74 private List<PageData> pageList;
75 private List<TagData> tagList;
76 private StringReader stream;
77 private List<char> characterList;
78 private string pageString;
81 /// When text is inputed, the text is paging in the TextLabe size unit.
82 /// <returns>The total number of pages.</returns>
84 [EditorBrowsable(EditorBrowsableState.Never)]
85 public int SetText(TextLabel label, string str)
87 if (label == null || str == null) return 0;
89 // perform this operation to match the utf32 character used in native Dali.
90 bool previousMarkup = label.EnableMarkup;
91 label.EnableMarkup = false;
93 pageString = label.Text;
94 label.EnableMarkup = previousMarkup;
95 label.MultiLine = true;
96 label.Ellipsis = false;
98 int length = pageString.Length;
99 int remainLength = length;
105 pageList = new List<PageData>();
106 tagList = new List<TagData>();
107 characterList = new List<char>();
109 stream = new StringReader(pageString);
111 RendererParameters textParameters = new RendererParameters();
112 textParameters.Text = pageString;
113 textParameters.HorizontalAlignment = label.HorizontalAlignment;
114 textParameters.VerticalAlignment = label.VerticalAlignment;
115 textParameters.FontFamily = label.FontFamily;
116 textParameters.FontWeight = "";
117 textParameters.FontWidth = "";
118 textParameters.FontSlant = "";
119 textParameters.Layout = TextLayout.MultiLine;
120 textParameters.TextColor = Color.Black;
121 textParameters.FontSize = label.PointSize;
122 textParameters.TextWidth = (uint)label.Size.Width;
123 textParameters.TextHeight = (uint)label.Size.Height;
124 textParameters.EllipsisEnabled = true;
125 textParameters.MarkupEnabled = previousMarkup;
126 textParameters.MinLineSize = label.MinLineSize;
127 textParameters.Padding = label.Padding;
130 Tizen.NUI.PropertyArray cutOffIndexArray = TextUtils.GetLastCharacterIndex(textParameters);
131 uint count = cutOffIndexArray.Count();
132 for (uint i = 0; i < count; i++)
134 cutOffIndexArray.GetElementAt(i).Get(out cutOffIndex); // Gets the last index of text shown on the actual screen.
136 // If markup is enabled, It should parse markup
137 if (label.EnableMarkup)
139 int preOffset = offset;
140 offset = MarkupProcess(offset, cutOffIndex - preOffset);
141 remainLength -= (offset - preOffset);
143 //If markup is not enabled, parsing is not required.
146 PageData pageData = new PageData();
147 pageData.StartOffset = offset;
148 int cnt = (cutOffIndex - offset) < remainLength ? (cutOffIndex - offset) : remainLength;
151 pageData.EndOffset = offset;
152 pageList.Add(pageData);
155 if (offset <= 0 || remainLength <= 0) break;
158 textParameters.Dispose();
159 cutOffIndexArray.Dispose();
165 /// Input the page number returns the text of the page.
166 /// <returns>The text of the page.</returns>
168 [EditorBrowsable(EditorBrowsableState.Never)]
169 public string GetText(int pageNum)
171 if (pageNum > totalPageCnt || pageNum < 1)
173 Tizen.Log.Error("NUI", $"Out of Range total page count : {totalPageCnt}, input page number : {pageNum}\n");
177 List<PageData> dataList = pageList.GetRange(pageNum - 1, 1);
178 foreach (PageData data in dataList)
180 int cnt = data.EndOffset - data.StartOffset;
181 char[] charArray = new char[cnt];
182 pageString.CopyTo(data.StartOffset, charArray, 0, cnt);
183 string pageText = data.PreviousTag + new String(charArray) + data.EndTag;
189 private void SkipWhiteSpace(ref int offset)
192 while ((character = stream.Read()) != -1)
195 if (character == WHITE_SPACE) continue;
200 private bool IsTag(TagData tag, ref int offset)
202 List<char> tagChaList = new List<char>();
205 bool isQuotationOpen = false;
206 bool attributesFound = false;
207 tag.IsEndTag = false;
208 bool isPreviousLessThan = true;
209 bool isPreviousSlash = false;
214 tag.AttributeName = "";
215 // SkipWhiteSpace(ref offset);
216 while ((!isTag) && ((character = stream.Read()) != -1))
219 characterList.Add((char)character);
220 if (!isQuotationOpen && (SLASH == character)) // '/'
222 if (isPreviousLessThan)
228 // if the tag has a '/' it may be an end tag.
229 isPreviousSlash = true;
231 isPreviousLessThan = false;
232 // SkipWhiteSpace(ref offset);
234 else if (GREATER_THAN == character) // '>'
242 if (!attributesFound)
244 tag.TagName = new String(tagChaList.ToArray());
248 tag.AttributeName = new String(tagChaList.ToArray());
251 isPreviousSlash = false;
252 isPreviousLessThan = false;
254 else if (QUOTATION_MARK == character)
256 tagChaList.Add((char)character);
257 isQuotationOpen = !isQuotationOpen;
259 isPreviousSlash = false;
260 isPreviousLessThan = false;
262 else if (WHITE_SPACE >= character || EQUAL == character) // ' ', '='
264 // Let's save tag name.
265 if (!attributesFound)
267 tag.TagName = new String(tagChaList.ToArray());
270 tagChaList.Add((char)character);
271 // If the tag contains white spaces then it may have attributes.
272 if (!isQuotationOpen)
274 attributesFound = true;
279 tagChaList.Add((char)character);
280 isPreviousSlash = false;
281 isPreviousLessThan = false;
288 private int MarkupProcess(int startOffset, int cutOffIndex)
292 int offset = startOffset;
294 characterList.Clear();
295 PageData pageData = new PageData();
297 pageData.StartOffset = offset;
299 // If the markup was previously open, the markup tag should be attached to the front.
301 foreach (TagData data in tagList)
303 tag += "<" + data.TagName + data.AttributeName + ">";
305 pageData.PreviousTag = tag;
309 while ((character = stream.Read()) != -1)
312 characterList.Add((char)character);
314 TagData tagData = new TagData();
316 if (LESS_THAN == character) // '<'
318 isTag = IsTag(tagData, ref offset);
323 if (tagData.IsEndTag)
325 int lastIndex = tagList.Count;
326 tagList.RemoveAt(lastIndex - 1);
330 tagList.Add(tagData);
337 if (count >= cutOffIndex) break;
341 // If the markup was previously open, you should attach the label tag.
343 foreach (TagData data in tagList)
345 tag = "</" + data.TagName + ">" + tag;
347 pageData.EndTag = tag;
349 pageData.EndOffset = offset;
350 pageList.Add(pageData);
352 if (character == -1) offset = -1;