1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd.. All rights reserved. 3cb93a386Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4cb93a386Sopenharmony_ci * you may not use this file except in compliance with the License. 5cb93a386Sopenharmony_ci * You may obtain a copy of the License at 6cb93a386Sopenharmony_ci * 7cb93a386Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8cb93a386Sopenharmony_ci * 9cb93a386Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10cb93a386Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11cb93a386Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12cb93a386Sopenharmony_ci * See the License for the specific language governing permissions and 13cb93a386Sopenharmony_ci * limitations under the License. 14cb93a386Sopenharmony_ci */ 15cb93a386Sopenharmony_ci 16cb93a386Sopenharmony_ci#include "modules/skparagraph/src/ParagraphImpl.h" 17cb93a386Sopenharmony_ci#include "modules/skparagraph/src/TextTabAlign.h" 18cb93a386Sopenharmony_ci#include "log.h" 19cb93a386Sopenharmony_ci 20cb93a386Sopenharmony_cinamespace skia { 21cb93a386Sopenharmony_cinamespace textlayout { 22cb93a386Sopenharmony_ci 23cb93a386Sopenharmony_ciTextTabAlign::TextTabFuncs TextTabAlign::fTextTabFuncsTable[TextTabAlign::textAlignCount] = { 24cb93a386Sopenharmony_ci { 25cb93a386Sopenharmony_ci &TextTabAlign::leftAlignProcessTab, 26cb93a386Sopenharmony_ci &TextTabAlign::leftAlignProcessEndofWord, 27cb93a386Sopenharmony_ci &TextTabAlign::leftAlignProcessEndofLine, 28cb93a386Sopenharmony_ci &TextTabAlign::leftAlignProcessCluster 29cb93a386Sopenharmony_ci }, 30cb93a386Sopenharmony_ci { 31cb93a386Sopenharmony_ci &TextTabAlign::rightAlignProcessTab, 32cb93a386Sopenharmony_ci &TextTabAlign::rightAlignProcessEndofWord, 33cb93a386Sopenharmony_ci &TextTabAlign::rightAlignProcessEndofLine, 34cb93a386Sopenharmony_ci &TextTabAlign::rightAlignProcessCluster 35cb93a386Sopenharmony_ci }, 36cb93a386Sopenharmony_ci { 37cb93a386Sopenharmony_ci &TextTabAlign::centerAlignProcessTab, 38cb93a386Sopenharmony_ci &TextTabAlign::centerAlignProcessEndofWord, 39cb93a386Sopenharmony_ci &TextTabAlign::centerAlignProcessEndofLine, 40cb93a386Sopenharmony_ci &TextTabAlign::centerAlignProcessCluster 41cb93a386Sopenharmony_ci }, 42cb93a386Sopenharmony_ci}; 43cb93a386Sopenharmony_ci 44cb93a386Sopenharmony_civoid TextTabAlign::init(SkScalar maxWidth, Cluster* endOfClusters) 45cb93a386Sopenharmony_ci{ 46cb93a386Sopenharmony_ci fMaxWidth = maxWidth; 47cb93a386Sopenharmony_ci fEndOfClusters = endOfClusters; 48cb93a386Sopenharmony_ci if (fTabPosition < 1.0 || fTabAlignMode < TextAlign::kLeft || TextAlign::kCenter < fTabAlignMode || 49cb93a386Sopenharmony_ci endOfClusters == nullptr) { 50cb93a386Sopenharmony_ci return; 51cb93a386Sopenharmony_ci } 52cb93a386Sopenharmony_ci fMaxTabIndex = fMaxWidth / fTabPosition; 53cb93a386Sopenharmony_ci 54cb93a386Sopenharmony_ci // If textAlign is configured, textTabAlign does not take effect 55cb93a386Sopenharmony_ci if (endOfClusters->getOwner()->paragraphStyle().getTextAlign() != TextAlign::kStart) { 56cb93a386Sopenharmony_ci TEXT_LOGD("textAlign is configured, textTabAlign does not take effect"); 57cb93a386Sopenharmony_ci return; 58cb93a386Sopenharmony_ci } 59cb93a386Sopenharmony_ci 60cb93a386Sopenharmony_ci // If ellipsis is configured, textTabAlign does not take effect 61cb93a386Sopenharmony_ci if (endOfClusters->getOwner()->paragraphStyle().ellipsized()) { 62cb93a386Sopenharmony_ci TEXT_LOGD("ellipsis is configured, textTabAlign does not take effect"); 63cb93a386Sopenharmony_ci return; 64cb93a386Sopenharmony_ci } 65cb93a386Sopenharmony_ci 66cb93a386Sopenharmony_ci TextAlign tabAlignMode = fTabAlignMode; 67cb93a386Sopenharmony_ci if (endOfClusters->getOwner()->paragraphStyle().getTextDirection() == TextDirection::kRtl) { 68cb93a386Sopenharmony_ci if (tabAlignMode == TextAlign::kLeft) { 69cb93a386Sopenharmony_ci tabAlignMode = TextAlign::kRight; 70cb93a386Sopenharmony_ci } else if (tabAlignMode == TextAlign::kRight) { 71cb93a386Sopenharmony_ci tabAlignMode = TextAlign::kLeft; 72cb93a386Sopenharmony_ci } 73cb93a386Sopenharmony_ci } 74cb93a386Sopenharmony_ci fTextTabFuncs = &(fTextTabFuncsTable[static_cast<size_t>(tabAlignMode)]); 75cb93a386Sopenharmony_ci} 76cb93a386Sopenharmony_ci 77cb93a386Sopenharmony_civoid TextTabAlign::expendTabCluster(SkScalar width) 78cb93a386Sopenharmony_ci{ 79cb93a386Sopenharmony_ci fTabCluster->run().extendClusterWidth(fTabCluster, width); 80cb93a386Sopenharmony_ci TEXT_LOGD("tabCluster(%zu, %zu) expend %f", fTabCluster->textRange().start, fTabCluster->textRange().end, width); 81cb93a386Sopenharmony_ci} 82cb93a386Sopenharmony_ci 83cb93a386Sopenharmony_cibool TextTabAlign::leftAlignProcessTab(TextWrapper::TextStretch& words, TextWrapper::TextStretch& clusters, 84cb93a386Sopenharmony_ci Cluster* currentCluster, SkScalar totalFakeSpacing) 85cb93a386Sopenharmony_ci{ 86cb93a386Sopenharmony_ci fAlreadyInTab = true; 87cb93a386Sopenharmony_ci fTabCluster = currentCluster; 88cb93a386Sopenharmony_ci fTabBlockEnd = fTabCluster; 89cb93a386Sopenharmony_ci fTabStartPos = words.width() + clusters.width() + totalFakeSpacing; 90cb93a386Sopenharmony_ci do { 91cb93a386Sopenharmony_ci fTabIndex++; 92cb93a386Sopenharmony_ci } while ((fTabPosition * fTabIndex) < fTabStartPos); 93cb93a386Sopenharmony_ci 94cb93a386Sopenharmony_ci if (fTabIndex > fMaxTabIndex) { 95cb93a386Sopenharmony_ci expendTabCluster(0 - fTabCluster->width()); 96cb93a386Sopenharmony_ci clusters.extend(currentCluster); 97cb93a386Sopenharmony_ci words.extend(clusters); 98cb93a386Sopenharmony_ci return true; 99cb93a386Sopenharmony_ci } 100cb93a386Sopenharmony_ci 101cb93a386Sopenharmony_ci fTabEndPos = fTabStartPos; 102cb93a386Sopenharmony_ci fTabShift = fTabPosition * fTabIndex - fTabStartPos; 103cb93a386Sopenharmony_ci expendTabCluster(fTabShift - fTabCluster->width()); 104cb93a386Sopenharmony_ci return false; 105cb93a386Sopenharmony_ci} 106cb93a386Sopenharmony_ci 107cb93a386Sopenharmony_cibool TextTabAlign::leftAlignProcessEndofWord(TextWrapper::TextStretch& words, TextWrapper::TextStretch& clusters, 108cb93a386Sopenharmony_ci Cluster* currentCluster, SkScalar totalFakeSpacing) 109cb93a386Sopenharmony_ci{ 110cb93a386Sopenharmony_ci if (fAlreadyInTab) { 111cb93a386Sopenharmony_ci fTabBlockEnd = currentCluster; 112cb93a386Sopenharmony_ci } 113cb93a386Sopenharmony_ci return false; 114cb93a386Sopenharmony_ci} 115cb93a386Sopenharmony_ci 116cb93a386Sopenharmony_cibool TextTabAlign::leftAlignProcessEndofLine(TextWrapper::TextStretch& words, TextWrapper::TextStretch& clusters, 117cb93a386Sopenharmony_ci Cluster* currentCluster, SkScalar totalFakeSpacing) 118cb93a386Sopenharmony_ci{ 119cb93a386Sopenharmony_ci if (fAlreadyInTab && (fTabBlockEnd == fTabCluster)) { 120cb93a386Sopenharmony_ci words.shiftWidth(0 - fTabCluster->width()); 121cb93a386Sopenharmony_ci expendTabCluster(0 - fTabCluster->width()); 122cb93a386Sopenharmony_ci } 123cb93a386Sopenharmony_ci return false; 124cb93a386Sopenharmony_ci} 125cb93a386Sopenharmony_ci 126cb93a386Sopenharmony_cibool TextTabAlign::leftAlignProcessCluster(TextWrapper::TextStretch& words, TextWrapper::TextStretch& clusters, 127cb93a386Sopenharmony_ci Cluster* currentCluster, SkScalar totalFakeSpacing) 128cb93a386Sopenharmony_ci{ 129cb93a386Sopenharmony_ci if (fAlreadyInTab && (currentCluster->getOwner()->getWordBreakType() == WordBreakType::BREAK_ALL)) { 130cb93a386Sopenharmony_ci fTabBlockEnd = currentCluster; 131cb93a386Sopenharmony_ci } 132cb93a386Sopenharmony_ci return false; 133cb93a386Sopenharmony_ci} 134cb93a386Sopenharmony_ci 135cb93a386Sopenharmony_civoid TextTabAlign::rightAlignProcessTabBlockEnd(TextWrapper::TextStretch& words, TextWrapper::TextStretch& clusters) 136cb93a386Sopenharmony_ci{ 137cb93a386Sopenharmony_ci if ((fTabBlockEnd != fTabCluster) && ((fTabPosition * fTabIndex) > fTabEndPos)) { 138cb93a386Sopenharmony_ci fTabShift = fTabPosition * fTabIndex - fTabEndPos; 139cb93a386Sopenharmony_ci expendTabCluster(fTabShift); 140cb93a386Sopenharmony_ci words.shiftWidth(fTabShift); 141cb93a386Sopenharmony_ci } 142cb93a386Sopenharmony_ci} 143cb93a386Sopenharmony_ci 144cb93a386Sopenharmony_cibool TextTabAlign::rightAlignProcessTab(TextWrapper::TextStretch& words, TextWrapper::TextStretch& clusters, 145cb93a386Sopenharmony_ci Cluster* currentCluster, SkScalar totalFakeSpacing) 146cb93a386Sopenharmony_ci{ 147cb93a386Sopenharmony_ci if (fAlreadyInTab) { 148cb93a386Sopenharmony_ci fTabBlockEnd = currentCluster; 149cb93a386Sopenharmony_ci fTabEndPos = words.width() + clusters.width() + totalFakeSpacing; 150cb93a386Sopenharmony_ci rightAlignProcessTabBlockEnd(words, clusters); 151cb93a386Sopenharmony_ci } 152cb93a386Sopenharmony_ci 153cb93a386Sopenharmony_ci fAlreadyInTab = true; 154cb93a386Sopenharmony_ci fTabCluster = currentCluster; 155cb93a386Sopenharmony_ci fTabBlockEnd = fTabCluster; 156cb93a386Sopenharmony_ci expendTabCluster(0 - fTabCluster->width()); 157cb93a386Sopenharmony_ci 158cb93a386Sopenharmony_ci fTabStartPos = words.width() + clusters.width() + totalFakeSpacing; 159cb93a386Sopenharmony_ci do { 160cb93a386Sopenharmony_ci fTabIndex++; 161cb93a386Sopenharmony_ci } while ((fTabPosition * fTabIndex) < fTabStartPos); 162cb93a386Sopenharmony_ci 163cb93a386Sopenharmony_ci if (fTabIndex > fMaxTabIndex) { 164cb93a386Sopenharmony_ci clusters.extend(currentCluster); 165cb93a386Sopenharmony_ci words.extend(clusters); 166cb93a386Sopenharmony_ci return true; 167cb93a386Sopenharmony_ci } 168cb93a386Sopenharmony_ci fTabEndPos = fTabStartPos; 169cb93a386Sopenharmony_ci return false; 170cb93a386Sopenharmony_ci} 171cb93a386Sopenharmony_ci 172cb93a386Sopenharmony_cibool TextTabAlign::rightAlignProcessEndofWord(TextWrapper::TextStretch& words, TextWrapper::TextStretch& clusters, 173cb93a386Sopenharmony_ci Cluster* currentCluster, SkScalar totalFakeSpacing) 174cb93a386Sopenharmony_ci{ 175cb93a386Sopenharmony_ci if (!fAlreadyInTab) { 176cb93a386Sopenharmony_ci return false; 177cb93a386Sopenharmony_ci } 178cb93a386Sopenharmony_ci 179cb93a386Sopenharmony_ci fTabEndPos = words.width() + clusters.width() + totalFakeSpacing; 180cb93a386Sopenharmony_ci fTabBlockEnd = currentCluster; 181cb93a386Sopenharmony_ci if (currentCluster + 1 == fEndOfClusters) { 182cb93a386Sopenharmony_ci rightAlignProcessTabBlockEnd(words, clusters); 183cb93a386Sopenharmony_ci return false; 184cb93a386Sopenharmony_ci } 185cb93a386Sopenharmony_ci 186cb93a386Sopenharmony_ci if (currentCluster->isHardBreak()) { 187cb93a386Sopenharmony_ci fTabEndPos -= currentCluster->width(); 188cb93a386Sopenharmony_ci return rightAlignProcessEndofLine(words, clusters, currentCluster, totalFakeSpacing); 189cb93a386Sopenharmony_ci } 190cb93a386Sopenharmony_ci 191cb93a386Sopenharmony_ci return false; 192cb93a386Sopenharmony_ci} 193cb93a386Sopenharmony_ci 194cb93a386Sopenharmony_cibool TextTabAlign::rightAlignProcessEndofLine(TextWrapper::TextStretch& words, TextWrapper::TextStretch& clusters, 195cb93a386Sopenharmony_ci Cluster* currentCluster, SkScalar totalFakeSpacing) 196cb93a386Sopenharmony_ci{ 197cb93a386Sopenharmony_ci if (!fAlreadyInTab) { 198cb93a386Sopenharmony_ci return false; 199cb93a386Sopenharmony_ci } 200cb93a386Sopenharmony_ci 201cb93a386Sopenharmony_ci rightAlignProcessTabBlockEnd(words, clusters); 202cb93a386Sopenharmony_ci return false; 203cb93a386Sopenharmony_ci} 204cb93a386Sopenharmony_ci 205cb93a386Sopenharmony_cibool TextTabAlign::rightAlignProcessCluster(TextWrapper::TextStretch& words, TextWrapper::TextStretch& clusters, 206cb93a386Sopenharmony_ci Cluster* currentCluster, SkScalar totalFakeSpacing) 207cb93a386Sopenharmony_ci{ 208cb93a386Sopenharmony_ci if (fAlreadyInTab && (currentCluster->getOwner()->getWordBreakType() == WordBreakType::BREAK_ALL)) { 209cb93a386Sopenharmony_ci fTabEndPos = words.width() + clusters.width() + totalFakeSpacing; 210cb93a386Sopenharmony_ci fTabBlockEnd = currentCluster; 211cb93a386Sopenharmony_ci } 212cb93a386Sopenharmony_ci 213cb93a386Sopenharmony_ci return false; 214cb93a386Sopenharmony_ci} 215cb93a386Sopenharmony_ci 216cb93a386Sopenharmony_cibool TextTabAlign::centerAlignProcessTabBlockEnd(TextWrapper::TextStretch& words, TextWrapper::TextStretch& clusters) 217cb93a386Sopenharmony_ci{ 218cb93a386Sopenharmony_ci if ((fTabPosition * fTabIndex + ((fTabEndPos - fTabStartPos) / 2)) > fMaxWidth) { 219cb93a386Sopenharmony_ci return true; 220cb93a386Sopenharmony_ci } 221cb93a386Sopenharmony_ci 222cb93a386Sopenharmony_ci if ((fTabBlockEnd != fTabCluster) && 223cb93a386Sopenharmony_ci ((fTabPosition * fTabIndex) > (fTabStartPos + ((fTabEndPos - fTabStartPos) / 2)))) { 224cb93a386Sopenharmony_ci fTabShift = fTabPosition * fTabIndex - (fTabStartPos + ((fTabEndPos - fTabStartPos) / 2)); 225cb93a386Sopenharmony_ci expendTabCluster(fTabShift); 226cb93a386Sopenharmony_ci words.shiftWidth(fTabShift); 227cb93a386Sopenharmony_ci } 228cb93a386Sopenharmony_ci return false; 229cb93a386Sopenharmony_ci} 230cb93a386Sopenharmony_ci 231cb93a386Sopenharmony_cibool TextTabAlign::centerAlignProcessTab(TextWrapper::TextStretch& words, TextWrapper::TextStretch& clusters, 232cb93a386Sopenharmony_ci Cluster* currentCluster, SkScalar totalFakeSpacing) 233cb93a386Sopenharmony_ci{ 234cb93a386Sopenharmony_ci if (fAlreadyInTab) { 235cb93a386Sopenharmony_ci fTabBlockEnd = currentCluster; 236cb93a386Sopenharmony_ci fTabEndPos = words.width() + clusters.width() + totalFakeSpacing; 237cb93a386Sopenharmony_ci if (centerAlignProcessTabBlockEnd(words, clusters)) { 238cb93a386Sopenharmony_ci clusters.extend(currentCluster); 239cb93a386Sopenharmony_ci return true; 240cb93a386Sopenharmony_ci } 241cb93a386Sopenharmony_ci } 242cb93a386Sopenharmony_ci 243cb93a386Sopenharmony_ci fAlreadyInTab = true; 244cb93a386Sopenharmony_ci fTabCluster = currentCluster; 245cb93a386Sopenharmony_ci fTabBlockEnd = fTabCluster; 246cb93a386Sopenharmony_ci expendTabCluster(0 - fTabCluster->width()); 247cb93a386Sopenharmony_ci 248cb93a386Sopenharmony_ci fTabStartPos = words.width() + clusters.width() + totalFakeSpacing; 249cb93a386Sopenharmony_ci do { 250cb93a386Sopenharmony_ci fTabIndex++; 251cb93a386Sopenharmony_ci } while ((fTabPosition * fTabIndex) < fTabStartPos); 252cb93a386Sopenharmony_ci 253cb93a386Sopenharmony_ci if (fTabIndex > fMaxTabIndex) { 254cb93a386Sopenharmony_ci clusters.extend(currentCluster); 255cb93a386Sopenharmony_ci words.extend(clusters); 256cb93a386Sopenharmony_ci return true; 257cb93a386Sopenharmony_ci } 258cb93a386Sopenharmony_ci 259cb93a386Sopenharmony_ci fTabEndPos = fTabStartPos; 260cb93a386Sopenharmony_ci return false; 261cb93a386Sopenharmony_ci} 262cb93a386Sopenharmony_ci 263cb93a386Sopenharmony_cibool TextTabAlign::centerAlignProcessEndofWord(TextWrapper::TextStretch& words, TextWrapper::TextStretch& clusters, 264cb93a386Sopenharmony_ci Cluster* currentCluster, SkScalar totalFakeSpacing) 265cb93a386Sopenharmony_ci{ 266cb93a386Sopenharmony_ci if (!fAlreadyInTab) { 267cb93a386Sopenharmony_ci return false; 268cb93a386Sopenharmony_ci } 269cb93a386Sopenharmony_ci 270cb93a386Sopenharmony_ci SkScalar tabEndPosTmp = words.width() + clusters.width() + totalFakeSpacing; 271cb93a386Sopenharmony_ci if ((fTabPosition * fTabIndex + ((tabEndPosTmp - fTabStartPos) / 2)) > fMaxWidth) { 272cb93a386Sopenharmony_ci centerAlignProcessTabBlockEnd(words, clusters); 273cb93a386Sopenharmony_ci return true; 274cb93a386Sopenharmony_ci } 275cb93a386Sopenharmony_ci 276cb93a386Sopenharmony_ci fTabEndPos = tabEndPosTmp; 277cb93a386Sopenharmony_ci fTabBlockEnd = currentCluster; 278cb93a386Sopenharmony_ci 279cb93a386Sopenharmony_ci if (currentCluster + 1 == fEndOfClusters) { 280cb93a386Sopenharmony_ci return centerAlignProcessTabBlockEnd(words, clusters); 281cb93a386Sopenharmony_ci } 282cb93a386Sopenharmony_ci 283cb93a386Sopenharmony_ci if (currentCluster->isHardBreak()) { 284cb93a386Sopenharmony_ci fTabEndPos -= currentCluster->width(); 285cb93a386Sopenharmony_ci return centerAlignProcessEndofLine(words, clusters, currentCluster, totalFakeSpacing); 286cb93a386Sopenharmony_ci } 287cb93a386Sopenharmony_ci 288cb93a386Sopenharmony_ci return false; 289cb93a386Sopenharmony_ci} 290cb93a386Sopenharmony_ci 291cb93a386Sopenharmony_cibool TextTabAlign::centerAlignProcessEndofLine(TextWrapper::TextStretch& words, TextWrapper::TextStretch& clusters, 292cb93a386Sopenharmony_ci Cluster* currentCluster, SkScalar totalFakeSpacing) 293cb93a386Sopenharmony_ci{ 294cb93a386Sopenharmony_ci if (!fAlreadyInTab) { 295cb93a386Sopenharmony_ci return false; 296cb93a386Sopenharmony_ci } 297cb93a386Sopenharmony_ci 298cb93a386Sopenharmony_ci centerAlignProcessTabBlockEnd(words, clusters); 299cb93a386Sopenharmony_ci return false; 300cb93a386Sopenharmony_ci} 301cb93a386Sopenharmony_ci 302cb93a386Sopenharmony_cibool TextTabAlign::centerAlignProcessCluster(TextWrapper::TextStretch& words, TextWrapper::TextStretch& clusters, 303cb93a386Sopenharmony_ci Cluster* currentCluster, SkScalar totalFakeSpacing) 304cb93a386Sopenharmony_ci{ 305cb93a386Sopenharmony_ci if ((!fAlreadyInTab) || (currentCluster->getOwner()->getWordBreakType() != WordBreakType::BREAK_ALL)) { 306cb93a386Sopenharmony_ci return false; 307cb93a386Sopenharmony_ci } 308cb93a386Sopenharmony_ci 309cb93a386Sopenharmony_ci SkScalar tabEndPosTmp = words.width() + clusters.width() + totalFakeSpacing; 310cb93a386Sopenharmony_ci if (((tabEndPosTmp - fTabStartPos) / 2) > (fMaxWidth - fTabPosition * fTabIndex)) { 311cb93a386Sopenharmony_ci centerAlignProcessTabBlockEnd(words, clusters); 312cb93a386Sopenharmony_ci return true; 313cb93a386Sopenharmony_ci } 314cb93a386Sopenharmony_ci 315cb93a386Sopenharmony_ci fTabEndPos = tabEndPosTmp; 316cb93a386Sopenharmony_ci fTabBlockEnd = currentCluster; 317cb93a386Sopenharmony_ci return false; 318cb93a386Sopenharmony_ci} 319cb93a386Sopenharmony_ci 320cb93a386Sopenharmony_ci} // namespace textlayout 321cb93a386Sopenharmony_ci} // namespace skia