140beb7744a61248de82a6077996c83c14e0122c2Raph Levien/* 240beb7744a61248de82a6077996c83c14e0122c2Raph Levien * Copyright (C) 2015 The Android Open Source Project 340beb7744a61248de82a6077996c83c14e0122c2Raph Levien * 440beb7744a61248de82a6077996c83c14e0122c2Raph Levien * Licensed under the Apache License, Version 2.0 (the "License"); 540beb7744a61248de82a6077996c83c14e0122c2Raph Levien * you may not use this file except in compliance with the License. 640beb7744a61248de82a6077996c83c14e0122c2Raph Levien * You may obtain a copy of the License at 740beb7744a61248de82a6077996c83c14e0122c2Raph Levien * 840beb7744a61248de82a6077996c83c14e0122c2Raph Levien * http://www.apache.org/licenses/LICENSE-2.0 940beb7744a61248de82a6077996c83c14e0122c2Raph Levien * 1040beb7744a61248de82a6077996c83c14e0122c2Raph Levien * Unless required by applicable law or agreed to in writing, software 1140beb7744a61248de82a6077996c83c14e0122c2Raph Levien * distributed under the License is distributed on an "AS IS" BASIS, 1240beb7744a61248de82a6077996c83c14e0122c2Raph Levien * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1340beb7744a61248de82a6077996c83c14e0122c2Raph Levien * See the License for the specific language governing permissions and 1440beb7744a61248de82a6077996c83c14e0122c2Raph Levien * limitations under the License. 1540beb7744a61248de82a6077996c83c14e0122c2Raph Levien */ 1640beb7744a61248de82a6077996c83c14e0122c2Raph Levien 1740beb7744a61248de82a6077996c83c14e0122c2Raph Levien#define LOG_TAG "Minikin" 1840beb7744a61248de82a6077996c83c14e0122c2Raph Levien 1940beb7744a61248de82a6077996c83c14e0122c2Raph Levien#include <cmath> 2040beb7744a61248de82a6077996c83c14e0122c2Raph Levien#include <unicode/uchar.h> 2140beb7744a61248de82a6077996c83c14e0122c2Raph Levien 22555d84c6f98eafcbe677cdcb8e9605760acd8ce5Mark Salyzyn#include <android/log.h> 23555d84c6f98eafcbe677cdcb8e9605760acd8ce5Mark Salyzyn 2440beb7744a61248de82a6077996c83c14e0122c2Raph Levien#include <minikin/GraphemeBreak.h> 2540beb7744a61248de82a6077996c83c14e0122c2Raph Levien#include <minikin/Measurement.h> 2640beb7744a61248de82a6077996c83c14e0122c2Raph Levien 2714e2d136aaef271ba131f917cf5f27baa31ae5adSeigo Nonakanamespace minikin { 2840beb7744a61248de82a6077996c83c14e0122c2Raph Levien 2940beb7744a61248de82a6077996c83c14e0122c2Raph Levien// These could be considered helper methods of layout, but need only be loosely coupled, so 3040beb7744a61248de82a6077996c83c14e0122c2Raph Levien// are separate. 3140beb7744a61248de82a6077996c83c14e0122c2Raph Levien 32ea408fc18e8e78d984ebdf63703da668a15720deKeisuke Kuroyanagistatic float getRunAdvance(const float* advances, const uint16_t* buf, size_t layoutStart, 33ea408fc18e8e78d984ebdf63703da668a15720deKeisuke Kuroyanagi size_t start, size_t count, size_t offset) { 3440beb7744a61248de82a6077996c83c14e0122c2Raph Levien float advance = 0.0f; 3540beb7744a61248de82a6077996c83c14e0122c2Raph Levien size_t lastCluster = start; 3640beb7744a61248de82a6077996c83c14e0122c2Raph Levien float clusterWidth = 0.0f; 3740beb7744a61248de82a6077996c83c14e0122c2Raph Levien for (size_t i = start; i < offset; i++) { 38ea408fc18e8e78d984ebdf63703da668a15720deKeisuke Kuroyanagi float charAdvance = advances[i - layoutStart]; 3940beb7744a61248de82a6077996c83c14e0122c2Raph Levien if (charAdvance != 0.0f) { 4040beb7744a61248de82a6077996c83c14e0122c2Raph Levien advance += charAdvance; 4140beb7744a61248de82a6077996c83c14e0122c2Raph Levien lastCluster = i; 4240beb7744a61248de82a6077996c83c14e0122c2Raph Levien clusterWidth = charAdvance; 4340beb7744a61248de82a6077996c83c14e0122c2Raph Levien } 4440beb7744a61248de82a6077996c83c14e0122c2Raph Levien } 45ea408fc18e8e78d984ebdf63703da668a15720deKeisuke Kuroyanagi if (offset < start + count && advances[offset - layoutStart] == 0.0f) { 4640beb7744a61248de82a6077996c83c14e0122c2Raph Levien // In the middle of a cluster, distribute width of cluster so that each grapheme cluster 4740beb7744a61248de82a6077996c83c14e0122c2Raph Levien // gets an equal share. 4840beb7744a61248de82a6077996c83c14e0122c2Raph Levien // TODO: get caret information out of font when that's available 4940beb7744a61248de82a6077996c83c14e0122c2Raph Levien size_t nextCluster; 5040beb7744a61248de82a6077996c83c14e0122c2Raph Levien for (nextCluster = offset + 1; nextCluster < start + count; nextCluster++) { 51ea408fc18e8e78d984ebdf63703da668a15720deKeisuke Kuroyanagi if (advances[nextCluster - layoutStart] != 0.0f) break; 5240beb7744a61248de82a6077996c83c14e0122c2Raph Levien } 5340beb7744a61248de82a6077996c83c14e0122c2Raph Levien int numGraphemeClusters = 0; 5440beb7744a61248de82a6077996c83c14e0122c2Raph Levien int numGraphemeClustersAfter = 0; 5540beb7744a61248de82a6077996c83c14e0122c2Raph Levien for (size_t i = lastCluster; i < nextCluster; i++) { 5640beb7744a61248de82a6077996c83c14e0122c2Raph Levien bool isAfter = i >= offset; 57b01028d1d7bc3906ef71c72ad985919f79304b5eRoozbeh Pournader if (GraphemeBreak::isGraphemeBreak( 58b01028d1d7bc3906ef71c72ad985919f79304b5eRoozbeh Pournader advances + (start - layoutStart), buf, start, count, i)) { 5940beb7744a61248de82a6077996c83c14e0122c2Raph Levien numGraphemeClusters++; 6040beb7744a61248de82a6077996c83c14e0122c2Raph Levien if (isAfter) { 6140beb7744a61248de82a6077996c83c14e0122c2Raph Levien numGraphemeClustersAfter++; 6240beb7744a61248de82a6077996c83c14e0122c2Raph Levien } 6340beb7744a61248de82a6077996c83c14e0122c2Raph Levien } 6440beb7744a61248de82a6077996c83c14e0122c2Raph Levien } 6540beb7744a61248de82a6077996c83c14e0122c2Raph Levien if (numGraphemeClusters > 0) { 6640beb7744a61248de82a6077996c83c14e0122c2Raph Levien advance -= clusterWidth * numGraphemeClustersAfter / numGraphemeClusters; 6740beb7744a61248de82a6077996c83c14e0122c2Raph Levien } 6840beb7744a61248de82a6077996c83c14e0122c2Raph Levien } 6940beb7744a61248de82a6077996c83c14e0122c2Raph Levien return advance; 7040beb7744a61248de82a6077996c83c14e0122c2Raph Levien} 7140beb7744a61248de82a6077996c83c14e0122c2Raph Levien 72ea408fc18e8e78d984ebdf63703da668a15720deKeisuke Kuroyanagifloat getRunAdvance(const float* advances, const uint16_t* buf, size_t start, size_t count, 734ea1cc82b0e8170d6ab6a7e9ee274c81315cd59eKeisuke Kuroyanagi size_t offset) { 74ea408fc18e8e78d984ebdf63703da668a15720deKeisuke Kuroyanagi return getRunAdvance(advances, buf, start, start, count, offset); 754ea1cc82b0e8170d6ab6a7e9ee274c81315cd59eKeisuke Kuroyanagi} 764ea1cc82b0e8170d6ab6a7e9ee274c81315cd59eKeisuke Kuroyanagi 7740beb7744a61248de82a6077996c83c14e0122c2Raph Levien/** 7840beb7744a61248de82a6077996c83c14e0122c2Raph Levien * Essentially the inverse of getRunAdvance. Compute the value of offset for which the 7940beb7744a61248de82a6077996c83c14e0122c2Raph Levien * measured caret comes closest to the provided advance param, and which is on a grapheme 8040beb7744a61248de82a6077996c83c14e0122c2Raph Levien * cluster boundary. 8140beb7744a61248de82a6077996c83c14e0122c2Raph Levien * 8240beb7744a61248de82a6077996c83c14e0122c2Raph Levien * The actual implementation fast-forwards through clusters to get "close", then does a finer-grain 8340beb7744a61248de82a6077996c83c14e0122c2Raph Levien * search within the cluster and grapheme breaks. 8440beb7744a61248de82a6077996c83c14e0122c2Raph Levien */ 85ea408fc18e8e78d984ebdf63703da668a15720deKeisuke Kuroyanagisize_t getOffsetForAdvance(const float* advances, const uint16_t* buf, size_t start, size_t count, 8640beb7744a61248de82a6077996c83c14e0122c2Raph Levien float advance) { 8740beb7744a61248de82a6077996c83c14e0122c2Raph Levien float x = 0.0f, xLastClusterStart = 0.0f, xSearchStart = 0.0f; 8840beb7744a61248de82a6077996c83c14e0122c2Raph Levien size_t lastClusterStart = start, searchStart = start; 8940beb7744a61248de82a6077996c83c14e0122c2Raph Levien for (size_t i = start; i < start + count; i++) { 90b01028d1d7bc3906ef71c72ad985919f79304b5eRoozbeh Pournader if (GraphemeBreak::isGraphemeBreak(advances, buf, start, count, i)) { 9140beb7744a61248de82a6077996c83c14e0122c2Raph Levien searchStart = lastClusterStart; 9240beb7744a61248de82a6077996c83c14e0122c2Raph Levien xSearchStart = xLastClusterStart; 9340beb7744a61248de82a6077996c83c14e0122c2Raph Levien } 94ea408fc18e8e78d984ebdf63703da668a15720deKeisuke Kuroyanagi float width = advances[i - start]; 9540beb7744a61248de82a6077996c83c14e0122c2Raph Levien if (width != 0.0f) { 9640beb7744a61248de82a6077996c83c14e0122c2Raph Levien lastClusterStart = i; 9740beb7744a61248de82a6077996c83c14e0122c2Raph Levien xLastClusterStart = x; 9840beb7744a61248de82a6077996c83c14e0122c2Raph Levien x += width; 9940beb7744a61248de82a6077996c83c14e0122c2Raph Levien if (x > advance) { 10040beb7744a61248de82a6077996c83c14e0122c2Raph Levien break; 10140beb7744a61248de82a6077996c83c14e0122c2Raph Levien } 10240beb7744a61248de82a6077996c83c14e0122c2Raph Levien } 10340beb7744a61248de82a6077996c83c14e0122c2Raph Levien } 10440beb7744a61248de82a6077996c83c14e0122c2Raph Levien size_t best = searchStart; 10540beb7744a61248de82a6077996c83c14e0122c2Raph Levien float bestDist = FLT_MAX; 10640beb7744a61248de82a6077996c83c14e0122c2Raph Levien for (size_t i = searchStart; i <= start + count; i++) { 107b01028d1d7bc3906ef71c72ad985919f79304b5eRoozbeh Pournader if (GraphemeBreak::isGraphemeBreak(advances, buf, start, count, i)) { 1084ea1cc82b0e8170d6ab6a7e9ee274c81315cd59eKeisuke Kuroyanagi // "getRunAdvance(layout, buf, start, count, i) - advance" but more efficient 109ea408fc18e8e78d984ebdf63703da668a15720deKeisuke Kuroyanagi float delta = getRunAdvance(advances, buf, start, searchStart, count - searchStart, i) 1104ea1cc82b0e8170d6ab6a7e9ee274c81315cd59eKeisuke Kuroyanagi 1114ea1cc82b0e8170d6ab6a7e9ee274c81315cd59eKeisuke Kuroyanagi + xSearchStart - advance; 11240beb7744a61248de82a6077996c83c14e0122c2Raph Levien if (std::abs(delta) < bestDist) { 11340beb7744a61248de82a6077996c83c14e0122c2Raph Levien bestDist = std::abs(delta); 11440beb7744a61248de82a6077996c83c14e0122c2Raph Levien best = i; 11540beb7744a61248de82a6077996c83c14e0122c2Raph Levien } 11640beb7744a61248de82a6077996c83c14e0122c2Raph Levien if (delta >= 0.0f) { 11740beb7744a61248de82a6077996c83c14e0122c2Raph Levien break; 11840beb7744a61248de82a6077996c83c14e0122c2Raph Levien } 11940beb7744a61248de82a6077996c83c14e0122c2Raph Levien } 12040beb7744a61248de82a6077996c83c14e0122c2Raph Levien } 12140beb7744a61248de82a6077996c83c14e0122c2Raph Levien return best; 12240beb7744a61248de82a6077996c83c14e0122c2Raph Levien} 12340beb7744a61248de82a6077996c83c14e0122c2Raph Levien 12414e2d136aaef271ba131f917cf5f27baa31ae5adSeigo Nonaka} // namespace minikin 125