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