1 /*
   2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   3  *
   4  * This code is free software; you can redistribute it and/or modify it
   5  * under the terms of the GNU General Public License version 2 only, as
   6  * published by the Free Software Foundation.  Oracle designates this
   7  * particular file as subject to the "Classpath" exception as provided
   8  * by Oracle in the LICENSE file that accompanied this code.
   9  *
  10  * This code is distributed in the hope that it will be useful, but WITHOUT
  11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  13  * version 2 for more details (a copy is included in the LICENSE file that
  14  * accompanied this code).
  15  *
  16  * You should have received a copy of the GNU General Public License version
  17  * 2 along with this work; if not, write to the Free Software Foundation,
  18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  19  *
  20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  21  * or visit www.oracle.com if you need additional information or have any
  22  * questions.
  23  */
  24 
  25 // This file is available under and governed by the GNU General Public
  26 // License version 2 only, as published by the Free Software Foundation.
  27 // However, the following notice accompanied the original version of this
  28 // file:
  29 //
  30 /*
  31  * Copyright © 2010,2012  Google, Inc.
  32  *
  33  *  This is part of HarfBuzz, a text shaping library.
  34  *
  35  * Permission is hereby granted, without written agreement and without
  36  * license or royalty fees, to use, copy, modify, and distribute this
  37  * software and its documentation for any purpose, provided that the
  38  * above copyright notice and the following two paragraphs appear in
  39  * all copies of this software.
  40  *
  41  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
  42  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
  43  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
  44  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
  45  * DAMAGE.
  46  *
  47  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
  48  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  49  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  50  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  51  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  52  *
  53  * Google Author(s): Behdad Esfahbod
  54  */
  55 
  56 #include "hb-ot-shape-complex-private.hh"
  57 
  58 
  59 static bool
  60 compose_hebrew (const hb_ot_shape_normalize_context_t *c,
  61                 hb_codepoint_t  a,
  62                 hb_codepoint_t  b,
  63                 hb_codepoint_t *ab)
  64 {
  65   /* Hebrew presentation-form shaping.
  66    * https://bugzilla.mozilla.org/show_bug.cgi?id=728866
  67    * Hebrew presentation forms with dagesh, for characters U+05D0..05EA;
  68    * Note that some letters do not have a dagesh presForm encoded.
  69    */
  70   static const hb_codepoint_t sDageshForms[0x05EAu - 0x05D0u + 1] = {
  71     0xFB30u, /* ALEF */
  72     0xFB31u, /* BET */
  73     0xFB32u, /* GIMEL */
  74     0xFB33u, /* DALET */
  75     0xFB34u, /* HE */
  76     0xFB35u, /* VAV */
  77     0xFB36u, /* ZAYIN */
  78     0x0000u, /* HET */
  79     0xFB38u, /* TET */
  80     0xFB39u, /* YOD */
  81     0xFB3Au, /* FINAL KAF */
  82     0xFB3Bu, /* KAF */
  83     0xFB3Cu, /* LAMED */
  84     0x0000u, /* FINAL MEM */
  85     0xFB3Eu, /* MEM */
  86     0x0000u, /* FINAL NUN */
  87     0xFB40u, /* NUN */
  88     0xFB41u, /* SAMEKH */
  89     0x0000u, /* AYIN */
  90     0xFB43u, /* FINAL PE */
  91     0xFB44u, /* PE */
  92     0x0000u, /* FINAL TSADI */
  93     0xFB46u, /* TSADI */
  94     0xFB47u, /* QOF */
  95     0xFB48u, /* RESH */
  96     0xFB49u, /* SHIN */
  97     0xFB4Au /* TAV */
  98   };
  99 
 100   bool found = c->unicode->compose (a, b, ab);
 101 
 102   if (!found && !c->plan->has_mark)
 103   {
 104       /* Special-case Hebrew presentation forms that are excluded from
 105        * standard normalization, but wanted for old fonts. */
 106       switch (b) {
 107       case 0x05B4u: /* HIRIQ */
 108           if (a == 0x05D9u) { /* YOD */
 109               *ab = 0xFB1Du;
 110               found = true;
 111           }
 112           break;
 113       case 0x05B7u: /* patah */
 114           if (a == 0x05F2u) { /* YIDDISH YOD YOD */
 115               *ab = 0xFB1Fu;
 116               found = true;
 117           } else if (a == 0x05D0u) { /* ALEF */
 118               *ab = 0xFB2Eu;
 119               found = true;
 120           }
 121           break;
 122       case 0x05B8u: /* QAMATS */
 123           if (a == 0x05D0u) { /* ALEF */
 124               *ab = 0xFB2Fu;
 125               found = true;
 126           }
 127           break;
 128       case 0x05B9u: /* HOLAM */
 129           if (a == 0x05D5u) { /* VAV */
 130               *ab = 0xFB4Bu;
 131               found = true;
 132           }
 133           break;
 134       case 0x05BCu: /* DAGESH */
 135           if (a >= 0x05D0u && a <= 0x05EAu) {
 136               *ab = sDageshForms[a - 0x05D0u];
 137               found = (*ab != 0);
 138           } else if (a == 0xFB2Au) { /* SHIN WITH SHIN DOT */
 139               *ab = 0xFB2Cu;
 140               found = true;
 141           } else if (a == 0xFB2Bu) { /* SHIN WITH SIN DOT */
 142               *ab = 0xFB2Du;
 143               found = true;
 144           }
 145           break;
 146       case 0x05BFu: /* RAFE */
 147           switch (a) {
 148           case 0x05D1u: /* BET */
 149               *ab = 0xFB4Cu;
 150               found = true;
 151               break;
 152           case 0x05DBu: /* KAF */
 153               *ab = 0xFB4Du;
 154               found = true;
 155               break;
 156           case 0x05E4u: /* PE */
 157               *ab = 0xFB4Eu;
 158               found = true;
 159               break;
 160           }
 161           break;
 162       case 0x05C1u: /* SHIN DOT */
 163           if (a == 0x05E9u) { /* SHIN */
 164               *ab = 0xFB2Au;
 165               found = true;
 166           } else if (a == 0xFB49u) { /* SHIN WITH DAGESH */
 167               *ab = 0xFB2Cu;
 168               found = true;
 169           }
 170           break;
 171       case 0x05C2u: /* SIN DOT */
 172           if (a == 0x05E9u) { /* SHIN */
 173               *ab = 0xFB2Bu;
 174               found = true;
 175           } else if (a == 0xFB49u) { /* SHIN WITH DAGESH */
 176               *ab = 0xFB2Du;
 177               found = true;
 178           }
 179           break;
 180       }
 181   }
 182 
 183   return found;
 184 }
 185 
 186 
 187 const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hebrew =
 188 {
 189   "hebrew",
 190   NULL, /* collect_features */
 191   NULL, /* override_features */
 192   NULL, /* data_create */
 193   NULL, /* data_destroy */
 194   NULL, /* preprocess_text */
 195   HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
 196   NULL, /* decompose */
 197   compose_hebrew,
 198   NULL, /* setup_masks */
 199   HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
 200   true, /* fallback_position */
 201 };