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
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 static int TEXTPAGE_TEXT_CHUNK = 20000;
74 private int totalPageCnt;
76 private List<PageData> pageList;
77 private List<TagData> tagList;
78 private StringReader stream;
79 private List<char> characterList;
80 private string pageString;
83 /// When text is inputed, the text is paging in the TextLabe size unit.
84 /// <returns>The total number of pages.</returns>
86 [EditorBrowsable(EditorBrowsableState.Never)]
87 public int SetText(TextLabel label, string str)
89 if(str == null) return 0;
91 // perform this operation to match the utf32 character used in native Dali.
92 bool previousMarkup = label.EnableMarkup;
93 label.EnableMarkup = false;
95 pageString = label.Text;
96 label.EnableMarkup = previousMarkup;
97 label.MultiLine = true;
98 label.Ellipsis = false;
100 int length = pageString.Length;
101 int remainLength = length;
106 pageList = new List<PageData>();
107 tagList = new List<TagData>();
108 characterList = new List<char>();
110 stream = new StringReader(pageString);
112 RendererParameters textParameters = new RendererParameters();
113 textParameters.Text = pageString;
114 textParameters.HorizontalAlignment = label.HorizontalAlignment;
115 textParameters.VerticalAlignment = label.VerticalAlignment;
116 textParameters.FontFamily = label.FontFamily;
117 textParameters.FontWeight = "";
118 textParameters.FontWidth = "";
119 textParameters.FontSlant = "";
120 textParameters.Layout = TextLayout.MultiLine;
121 textParameters.TextColor = Color.Black;
122 textParameters.FontSize = label.PointSize;
123 textParameters.TextWidth = (uint)label.Size.Width;
124 textParameters.TextHeight = (uint)label.Size.Height;
125 textParameters.EllipsisEnabled = true;
126 textParameters.MarkupEnabled = previousMarkup;
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 ) break;
162 /// Input the page number returns the text of the page.
163 /// <returns>The text of the page.</returns>
165 [EditorBrowsable(EditorBrowsableState.Never)]
166 public string GetText(int pageNum)
168 if( pageNum > totalPageCnt || pageNum < 1 ) {
169 Tizen.Log.Error("NUI", $"Out of Range total page count : {totalPageCnt}, input page number : {pageNum}\n");
173 List<PageData> dataList = pageList.GetRange(pageNum-1, 1);
174 foreach(PageData data in dataList)
176 int cnt = data.endOffset - data.startOffset;
177 char[] charArray = new char[cnt];
178 pageString.CopyTo(data.startOffset, charArray, 0, cnt);
179 string pageText = data.previousTag+new String(charArray)+data.endTag;
185 private void SkipWhiteSpace(ref int offset)
188 while( ( character = stream.Read()) != -1)
191 if( character == WHITE_SPACE) continue;
196 private bool IsTag(TagData tag, ref int offset)
198 List<char> tagChaList = new List<char>();
201 bool isQuotationOpen = false;
202 bool attributesFound = false;
203 tag.isEndTag = false;
204 bool isPreviousLessThan = true;
205 bool isPreviousSlash = false;
210 tag.attributeName = "";
211 // SkipWhiteSpace(ref offset);
212 while((!isTag) && ((character = stream.Read()) != -1)) {
214 characterList.Add((char)character);
215 if( !isQuotationOpen && ( SLASH == character ) ) // '/'
217 if (isPreviousLessThan)
223 // if the tag has a '/' it may be an end tag.
224 isPreviousSlash = true;
226 isPreviousLessThan = false;
227 // SkipWhiteSpace(ref offset);
229 else if( GREATER_THAN == character ) // '>'
237 if(!attributesFound) {
238 tag.tagName = new String(tagChaList.ToArray());
240 tag.attributeName = new String(tagChaList.ToArray());
243 isPreviousSlash = false;
244 isPreviousLessThan = false;
246 else if( QUOTATION_MARK == character )
248 tagChaList.Add((char)character);
249 isQuotationOpen = !isQuotationOpen;
251 isPreviousSlash = false;
252 isPreviousLessThan = false;
254 else if( WHITE_SPACE >= character || EQUAL == character ) // ' ', '='
256 // Let's save tag name.
257 if(!attributesFound) {
258 tag.tagName = new String(tagChaList.ToArray());
261 tagChaList.Add((char)character);
262 // If the tag contains white spaces then it may have attributes.
263 if( !isQuotationOpen )
265 attributesFound = true;
270 tagChaList.Add((char)character);
271 isPreviousSlash = false;
272 isPreviousLessThan = false;
279 private int MarkupProcess(int startOffset, int cutOffIndex)
283 int offset = startOffset;
285 characterList.Clear();
286 PageData pageData = new PageData();
288 pageData.startOffset = offset;
290 bool isPreviousLessThan = false;
291 bool isPreviousSlash = false;
293 // If the markup was previously open, the markup tag should be attached to the front.
295 foreach (TagData data in tagList)
297 tag += "<"+data.tagName+data.attributeName+">";
299 pageData.previousTag = tag;
303 while( (character = stream.Read()) != -1 )
306 characterList.Add((char)character);
308 TagData tagData = new TagData();
310 if( LESS_THAN == character ) // '<'
312 isTag = IsTag(tagData, ref offset);
316 if(tagData.isEndTag) {
317 int lastIndex = tagList.Count;
318 tagList.RemoveAt(lastIndex-1);
320 tagList.Add(tagData);
325 if(count >= cutOffIndex) break;
329 // If the markup was previously open, you should attach the label tag.
331 foreach (TagData data in tagList)
333 tag = "</"+data.tagName+">" + tag;
335 pageData.endTag = tag;
337 pageData.endOffset = offset;
338 pageList.Add(pageData);
340 if(character == -1) offset = -1;