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 ) {
171 Tizen.Log.Error("NUI", $"Out of Range total page count : {totalPageCnt}, input page number : {pageNum}\n");
175 List<PageData> dataList = pageList.GetRange(pageNum-1, 1);
176 foreach(PageData data in dataList)
178 int cnt = data.endOffset - data.startOffset;
179 char[] charArray = new char[cnt];
180 pageString.CopyTo(data.startOffset, charArray, 0, cnt);
181 string pageText = data.previousTag+new String(charArray)+data.endTag;
187 private void SkipWhiteSpace(ref int offset)
190 while( ( character = stream.Read()) != -1)
193 if( character == WHITE_SPACE) continue;
198 private bool IsTag(TagData tag, ref int offset)
200 List<char> tagChaList = new List<char>();
203 bool isQuotationOpen = false;
204 bool attributesFound = false;
205 tag.isEndTag = false;
206 bool isPreviousLessThan = true;
207 bool isPreviousSlash = false;
212 tag.attributeName = "";
213 // SkipWhiteSpace(ref offset);
214 while((!isTag) && ((character = stream.Read()) != -1)) {
216 characterList.Add((char)character);
217 if( !isQuotationOpen && ( SLASH == character ) ) // '/'
219 if (isPreviousLessThan)
225 // if the tag has a '/' it may be an end tag.
226 isPreviousSlash = true;
228 isPreviousLessThan = false;
229 // SkipWhiteSpace(ref offset);
231 else if( GREATER_THAN == character ) // '>'
239 if(!attributesFound) {
240 tag.tagName = new String(tagChaList.ToArray());
242 tag.attributeName = new String(tagChaList.ToArray());
245 isPreviousSlash = false;
246 isPreviousLessThan = false;
248 else if( QUOTATION_MARK == character )
250 tagChaList.Add((char)character);
251 isQuotationOpen = !isQuotationOpen;
253 isPreviousSlash = false;
254 isPreviousLessThan = false;
256 else if( WHITE_SPACE >= character || EQUAL == character ) // ' ', '='
258 // Let's save tag name.
259 if(!attributesFound) {
260 tag.tagName = new String(tagChaList.ToArray());
263 tagChaList.Add((char)character);
264 // If the tag contains white spaces then it may have attributes.
265 if( !isQuotationOpen )
267 attributesFound = true;
272 tagChaList.Add((char)character);
273 isPreviousSlash = false;
274 isPreviousLessThan = false;
281 private int MarkupProcess(int startOffset, int cutOffIndex)
285 int offset = startOffset;
287 characterList.Clear();
288 PageData pageData = new PageData();
290 pageData.startOffset = offset;
292 // If the markup was previously open, the markup tag should be attached to the front.
294 foreach (TagData data in tagList)
296 tag += "<"+data.tagName+data.attributeName+">";
298 pageData.previousTag = tag;
302 while( (character = stream.Read()) != -1 )
305 characterList.Add((char)character);
307 TagData tagData = new TagData();
309 if( LESS_THAN == character ) // '<'
311 isTag = IsTag(tagData, ref offset);
315 if(tagData.isEndTag) {
316 int lastIndex = tagList.Count;
317 tagList.RemoveAt(lastIndex-1);
319 tagList.Add(tagData);
324 if(count >= cutOffIndex) break;
328 // If the markup was previously open, you should attach the label tag.
330 foreach (TagData data in tagList)
332 tag = "</"+data.tagName+">" + tag;
334 pageData.endTag = tag;
336 pageData.endOffset = offset;
337 pageList.Add(pageData);
339 if(character == -1) offset = -1;