• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 
17 #define LOG_TAG "Minikin"
18 
19 #include "LayoutUtils.h"
20 
21 namespace minikin {
22 
23 const uint16_t CHAR_NBSP = 0x00A0;
24 
25 /*
26  * Determine whether the code unit is a word space for the purposes of
27  * justification.
28  */
isWordSpace(uint16_t code_unit)29 bool isWordSpace(uint16_t code_unit) {
30   return code_unit == ' ' || code_unit == CHAR_NBSP;
31 }
32 
33 /**
34  * For the purpose of layout, a word break is a boundary with no
35  * kerning or complex script processing. This is necessarily a
36  * heuristic, but should be accurate most of the time.
37  */
isWordBreakAfter(uint16_t c)38 static bool isWordBreakAfter(uint16_t c) {
39   if (isWordSpace(c) || (c >= 0x2000 && c <= 0x200a) || c == 0x3000) {
40     // spaces
41     return true;
42   }
43   // Note: kana is not included, as sophisticated fonts may kern kana
44   return false;
45 }
46 
isWordBreakBefore(uint16_t c)47 static bool isWordBreakBefore(uint16_t c) {
48   // CJK ideographs (and yijing hexagram symbols)
49   return isWordBreakAfter(c) || (c >= 0x3400 && c <= 0x9fff);
50 }
51 
52 /**
53  * Return offset of previous word break. It is either < offset or == 0.
54  */
getPrevWordBreakForCache(const uint16_t * chars,size_t offset,size_t len)55 size_t getPrevWordBreakForCache(const uint16_t* chars,
56                                 size_t offset,
57                                 size_t len) {
58   if (offset == 0)
59     return 0;
60   if (offset > len)
61     offset = len;
62   if (isWordBreakBefore(chars[offset - 1])) {
63     return offset - 1;
64   }
65   for (size_t i = offset - 1; i > 0; i--) {
66     if (isWordBreakBefore(chars[i]) || isWordBreakAfter(chars[i - 1])) {
67       return i;
68     }
69   }
70   return 0;
71 }
72 
73 /**
74  * Return offset of next word break. It is either > offset or == len.
75  */
getNextWordBreakForCache(const uint16_t * chars,size_t offset,size_t len)76 size_t getNextWordBreakForCache(const uint16_t* chars,
77                                 size_t offset,
78                                 size_t len) {
79   if (offset >= len)
80     return len;
81   if (isWordBreakAfter(chars[offset])) {
82     return offset + 1;
83   }
84   for (size_t i = offset + 1; i < len; i++) {
85     // No need to check isWordBreakAfter(chars[i - 1]) since it is checked
86     // in previous iteration.  Note that isWordBreakBefore returns true
87     // whenever isWordBreakAfter returns true.
88     if (isWordBreakBefore(chars[i])) {
89       return i;
90     }
91   }
92   return len;
93 }
94 
95 }  // namespace minikin
96