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)]
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)]
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;
129 Tizen.NUI.PropertyArray cutOffIndexArray = TextUtils.GetLastCharacterIndex(textParameters);
130 uint count = cutOffIndexArray.Count();
131 for (uint i = 0; i < count; i++)
133 cutOffIndexArray.GetElementAt(i).Get(out cutOffIndex); // Gets the last index of text shown on the actual screen.
135 // If markup is enabled, It should parse markup
136 if (label.EnableMarkup)
138 int preOffset = offset;
139 offset = MarkupProcess(offset, cutOffIndex - preOffset);
140 remainLength -= (offset - preOffset);
142 //If markup is not enabled, parsing is not required.
145 PageData pageData = new PageData();
146 pageData.startOffset = offset;
147 int cnt = (cutOffIndex - offset) < remainLength ? (cutOffIndex - offset) : remainLength;
150 pageData.endOffset = offset;
151 pageList.Add(pageData);
154 if (offset <= 0 || remainLength <= 0) break;
157 textParameters.Dispose();
158 cutOffIndexArray.Dispose();
164 /// Input the page number returns the text of the page.
165 /// <returns>The text of the page.</returns>
167 [EditorBrowsable(EditorBrowsableState.Never)]
168 public string GetText(int pageNum)
170 if (pageNum > totalPageCnt || pageNum < 1)
172 Tizen.Log.Error("NUI", $"Out of Range total page count : {totalPageCnt}, input page number : {pageNum}\n");
176 List<PageData> dataList = pageList.GetRange(pageNum - 1, 1);
177 foreach (PageData data in dataList)
179 int cnt = data.endOffset - data.startOffset;
180 char[] charArray = new char[cnt];
181 pageString.CopyTo(data.startOffset, charArray, 0, cnt);
182 string pageText = data.previousTag + new String(charArray) + data.endTag;
188 private void SkipWhiteSpace(ref int offset)
191 while ((character = stream.Read()) != -1)
194 if (character == WHITE_SPACE) continue;
199 private bool IsTag(TagData tag, ref int offset)
201 List<char> tagChaList = new List<char>();
204 bool isQuotationOpen = false;
205 bool attributesFound = false;
206 tag.isEndTag = false;
207 bool isPreviousLessThan = true;
208 bool isPreviousSlash = false;
213 tag.attributeName = "";
214 // SkipWhiteSpace(ref offset);
215 while ((!isTag) && ((character = stream.Read()) != -1))
218 characterList.Add((char)character);
219 if (!isQuotationOpen && (SLASH == character)) // '/'
221 if (isPreviousLessThan)
227 // if the tag has a '/' it may be an end tag.
228 isPreviousSlash = true;
230 isPreviousLessThan = false;
231 // SkipWhiteSpace(ref offset);
233 else if (GREATER_THAN == character) // '>'
241 if (!attributesFound)
243 tag.tagName = new String(tagChaList.ToArray());
247 tag.attributeName = new String(tagChaList.ToArray());
250 isPreviousSlash = false;
251 isPreviousLessThan = false;
253 else if (QUOTATION_MARK == character)
255 tagChaList.Add((char)character);
256 isQuotationOpen = !isQuotationOpen;
258 isPreviousSlash = false;
259 isPreviousLessThan = false;
261 else if (WHITE_SPACE >= character || EQUAL == character) // ' ', '='
263 // Let's save tag name.
264 if (!attributesFound)
266 tag.tagName = new String(tagChaList.ToArray());
269 tagChaList.Add((char)character);
270 // If the tag contains white spaces then it may have attributes.
271 if (!isQuotationOpen)
273 attributesFound = true;
278 tagChaList.Add((char)character);
279 isPreviousSlash = false;
280 isPreviousLessThan = false;
287 private int MarkupProcess(int startOffset, int cutOffIndex)
291 int offset = startOffset;
293 characterList.Clear();
294 PageData pageData = new PageData();
296 pageData.startOffset = offset;
298 // If the markup was previously open, the markup tag should be attached to the front.
300 foreach (TagData data in tagList)
302 tag += "<" + data.tagName + data.attributeName + ">";
304 pageData.previousTag = tag;
308 while ((character = stream.Read()) != -1)
311 characterList.Add((char)character);
313 TagData tagData = new TagData();
315 if (LESS_THAN == character) // '<'
317 isTag = IsTag(tagData, ref offset);
322 if (tagData.isEndTag)
324 int lastIndex = tagList.Count;
325 tagList.RemoveAt(lastIndex - 1);
329 tagList.Add(tagData);
336 if (count >= cutOffIndex) break;
340 // If the markup was previously open, you should attach the label tag.
342 foreach (TagData data in tagList)
344 tag = "</" + data.tagName + ">" + tag;
346 pageData.endTag = tag;
348 pageData.endOffset = offset;
349 pageList.Add(pageData);
351 if (character == -1) offset = -1;