OLD | NEW |
1 // Copyright 2014 PDFium Authors. All rights reserved. | 1 // Copyright 2014 PDFium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com | 5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com |
6 | 6 |
7 #include "../../../include/fpdfapi/fpdf_module.h" | 7 #include "../../../include/fpdfapi/fpdf_module.h" |
8 #include "../../../include/fpdfapi/fpdf_page.h" | 8 #include "../../../include/fpdfapi/fpdf_page.h" |
9 #include "../../../include/fpdfapi/fpdf_resource.h" | 9 #include "../../../include/fpdfapi/fpdf_resource.h" |
10 #include "../../../include/fxge/fx_freetype.h" | 10 #include "../../../include/fxge/fx_freetype.h" |
(...skipping 1112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1123 void CPDF_CIDFont::GetCharBBox(FX_DWORD charcode, FX_RECT& rect, int level) { | 1123 void CPDF_CIDFont::GetCharBBox(FX_DWORD charcode, FX_RECT& rect, int level) { |
1124 if (charcode < 256 && m_CharBBox[charcode].Right != -1) { | 1124 if (charcode < 256 && m_CharBBox[charcode].Right != -1) { |
1125 rect.bottom = m_CharBBox[charcode].Bottom; | 1125 rect.bottom = m_CharBBox[charcode].Bottom; |
1126 rect.left = m_CharBBox[charcode].Left; | 1126 rect.left = m_CharBBox[charcode].Left; |
1127 rect.right = m_CharBBox[charcode].Right; | 1127 rect.right = m_CharBBox[charcode].Right; |
1128 rect.top = m_CharBBox[charcode].Top; | 1128 rect.top = m_CharBBox[charcode].Top; |
1129 return; | 1129 return; |
1130 } | 1130 } |
1131 FX_BOOL bVert = FALSE; | 1131 FX_BOOL bVert = FALSE; |
1132 int glyph_index = GlyphFromCharCode(charcode, &bVert); | 1132 int glyph_index = GlyphFromCharCode(charcode, &bVert); |
1133 if (m_Font.m_Face == NULL) { | 1133 FXFT_Face face = m_Font.GetFace(); |
1134 rect = FX_RECT(0, 0, 0, 0); | 1134 if (face) { |
1135 } else { | |
1136 rect.left = rect.bottom = rect.right = rect.top = 0; | 1135 rect.left = rect.bottom = rect.right = rect.top = 0; |
1137 FXFT_Face face = m_Font.m_Face; | |
1138 if (FXFT_Is_Face_Tricky(face)) { | 1136 if (FXFT_Is_Face_Tricky(face)) { |
1139 int err = FXFT_Load_Glyph(face, glyph_index, | 1137 int err = FXFT_Load_Glyph(face, glyph_index, |
1140 FXFT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH); | 1138 FXFT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH); |
1141 if (!err) { | 1139 if (!err) { |
1142 FXFT_BBox cbox; | 1140 FXFT_BBox cbox; |
1143 FXFT_Glyph glyph; | 1141 FXFT_Glyph glyph; |
1144 err = FXFT_Get_Glyph(((FXFT_Face)face)->glyph, &glyph); | 1142 err = FXFT_Get_Glyph(((FXFT_Face)face)->glyph, &glyph); |
1145 if (!err) { | 1143 if (!err) { |
1146 FXFT_Glyph_Get_CBox(glyph, FXFT_GLYPH_BBOX_PIXELS, &cbox); | 1144 FXFT_Glyph_Get_CBox(glyph, FXFT_GLYPH_BBOX_PIXELS, &cbox); |
1147 int pixel_size_x = ((FXFT_Face)face)->size->metrics.x_ppem; | 1145 int pixel_size_x = ((FXFT_Face)face)->size->metrics.x_ppem; |
(...skipping 25 matching lines...) Expand all Loading... |
1173 rect.right = TT2PDF( | 1171 rect.right = TT2PDF( |
1174 FXFT_Get_Glyph_HoriBearingX(face) + FXFT_Get_Glyph_Width(face), | 1172 FXFT_Get_Glyph_HoriBearingX(face) + FXFT_Get_Glyph_Width(face), |
1175 face); | 1173 face); |
1176 rect.top = TT2PDF(FXFT_Get_Glyph_HoriBearingY(face), face); | 1174 rect.top = TT2PDF(FXFT_Get_Glyph_HoriBearingY(face), face); |
1177 rect.top += rect.top / 64; | 1175 rect.top += rect.top / 64; |
1178 rect.bottom = TT2PDF( | 1176 rect.bottom = TT2PDF( |
1179 FXFT_Get_Glyph_HoriBearingY(face) - FXFT_Get_Glyph_Height(face), | 1177 FXFT_Get_Glyph_HoriBearingY(face) - FXFT_Get_Glyph_Height(face), |
1180 face); | 1178 face); |
1181 } | 1179 } |
1182 } | 1180 } |
| 1181 } else { |
| 1182 rect = FX_RECT(0, 0, 0, 0); |
1183 } | 1183 } |
1184 if (m_pFontFile == NULL && m_Charset == CIDSET_JAPAN1) { | 1184 if (m_pFontFile == NULL && m_Charset == CIDSET_JAPAN1) { |
1185 FX_WORD CID = CIDFromCharCode(charcode); | 1185 FX_WORD CID = CIDFromCharCode(charcode); |
1186 const uint8_t* pTransform = GetCIDTransform(CID); | 1186 const uint8_t* pTransform = GetCIDTransform(CID); |
1187 if (pTransform && !bVert) { | 1187 if (pTransform && !bVert) { |
1188 CFX_AffineMatrix matrix(_CIDTransformToFloat(pTransform[0]), | 1188 CFX_AffineMatrix matrix(_CIDTransformToFloat(pTransform[0]), |
1189 _CIDTransformToFloat(pTransform[1]), | 1189 _CIDTransformToFloat(pTransform[1]), |
1190 _CIDTransformToFloat(pTransform[2]), | 1190 _CIDTransformToFloat(pTransform[2]), |
1191 _CIDTransformToFloat(pTransform[3]), | 1191 _CIDTransformToFloat(pTransform[3]), |
1192 _CIDTransformToFloat(pTransform[4]) * 1000, | 1192 _CIDTransformToFloat(pTransform[4]) * 1000, |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1249 break; | 1249 break; |
1250 } | 1250 } |
1251 } | 1251 } |
1252 vx = (short)dwWidth / 2; | 1252 vx = (short)dwWidth / 2; |
1253 vy = (short)m_DefaultVY; | 1253 vy = (short)m_DefaultVY; |
1254 } | 1254 } |
1255 int CPDF_CIDFont::GetGlyphIndex(FX_DWORD unicode, FX_BOOL* pVertGlyph) { | 1255 int CPDF_CIDFont::GetGlyphIndex(FX_DWORD unicode, FX_BOOL* pVertGlyph) { |
1256 if (pVertGlyph) { | 1256 if (pVertGlyph) { |
1257 *pVertGlyph = FALSE; | 1257 *pVertGlyph = FALSE; |
1258 } | 1258 } |
1259 int index = FXFT_Get_Char_Index(m_Font.m_Face, unicode); | 1259 FXFT_Face face = m_Font.GetFace(); |
| 1260 int index = FXFT_Get_Char_Index(face, unicode); |
1260 if (unicode == 0x2502) { | 1261 if (unicode == 0x2502) { |
1261 return index; | 1262 return index; |
1262 } | 1263 } |
1263 if (index && IsVertWriting()) { | 1264 if (index && IsVertWriting()) { |
1264 if (m_pTTGSUBTable) { | 1265 if (m_pTTGSUBTable) { |
1265 TT_uint32_t vindex = 0; | 1266 TT_uint32_t vindex = 0; |
1266 m_pTTGSUBTable->GetVerticalGlyph(index, &vindex); | 1267 m_pTTGSUBTable->GetVerticalGlyph(index, &vindex); |
1267 if (vindex) { | 1268 if (vindex) { |
1268 index = vindex; | 1269 index = vindex; |
1269 if (pVertGlyph) { | 1270 if (pVertGlyph) { |
1270 *pVertGlyph = TRUE; | 1271 *pVertGlyph = TRUE; |
1271 } | 1272 } |
1272 } | 1273 } |
1273 return index; | 1274 return index; |
1274 } | 1275 } |
1275 if (NULL == m_Font.m_pGsubData) { | 1276 if (!m_Font.GetSubData()) { |
1276 unsigned long length = 0; | 1277 unsigned long length = 0; |
1277 int error = FXFT_Load_Sfnt_Table( | 1278 int error = FXFT_Load_Sfnt_Table(face, FT_MAKE_TAG('G', 'S', 'U', 'B'), 0, |
1278 m_Font.m_Face, FT_MAKE_TAG('G', 'S', 'U', 'B'), 0, NULL, &length); | 1279 NULL, &length); |
1279 if (!error) { | 1280 if (!error) { |
1280 m_Font.m_pGsubData = (unsigned char*)FX_Alloc(uint8_t, length); | 1281 m_Font.SetSubData((uint8_t*)FX_Alloc(uint8_t, length)); |
1281 } | 1282 } |
1282 } | 1283 } |
1283 int error = | 1284 int error = FXFT_Load_Sfnt_Table(face, FT_MAKE_TAG('G', 'S', 'U', 'B'), 0, |
1284 FXFT_Load_Sfnt_Table(m_Font.m_Face, FT_MAKE_TAG('G', 'S', 'U', 'B'), 0, | 1285 m_Font.GetSubData(), NULL); |
1285 m_Font.m_pGsubData, NULL); | 1286 if (!error && m_Font.GetSubData()) { |
1286 if (!error && m_Font.m_pGsubData) { | |
1287 m_pTTGSUBTable = new CFX_CTTGSUBTable; | 1287 m_pTTGSUBTable = new CFX_CTTGSUBTable; |
1288 m_pTTGSUBTable->LoadGSUBTable((FT_Bytes)m_Font.m_pGsubData); | 1288 m_pTTGSUBTable->LoadGSUBTable((FT_Bytes)m_Font.GetSubData()); |
1289 TT_uint32_t vindex = 0; | 1289 TT_uint32_t vindex = 0; |
1290 m_pTTGSUBTable->GetVerticalGlyph(index, &vindex); | 1290 m_pTTGSUBTable->GetVerticalGlyph(index, &vindex); |
1291 if (vindex) { | 1291 if (vindex) { |
1292 index = vindex; | 1292 index = vindex; |
1293 if (pVertGlyph) { | 1293 if (pVertGlyph) { |
1294 *pVertGlyph = TRUE; | 1294 *pVertGlyph = TRUE; |
1295 } | 1295 } |
1296 } | 1296 } |
1297 } | 1297 } |
1298 return index; | 1298 return index; |
(...skipping 27 matching lines...) Expand all Loading... |
1326 if (cid && m_pCID2UnicodeMap && m_pCID2UnicodeMap->IsLoaded()) { | 1326 if (cid && m_pCID2UnicodeMap && m_pCID2UnicodeMap->IsLoaded()) { |
1327 unicode = m_pCID2UnicodeMap->UnicodeFromCID(cid); | 1327 unicode = m_pCID2UnicodeMap->UnicodeFromCID(cid); |
1328 } | 1328 } |
1329 if (unicode == 0) { | 1329 if (unicode == 0) { |
1330 unicode = _UnicodeFromCharCode(charcode); | 1330 unicode = _UnicodeFromCharCode(charcode); |
1331 } | 1331 } |
1332 if (unicode == 0 && !(m_Flags & PDFFONT_SYMBOLIC)) { | 1332 if (unicode == 0 && !(m_Flags & PDFFONT_SYMBOLIC)) { |
1333 unicode = UnicodeFromCharCode(charcode).GetAt(0); | 1333 unicode = UnicodeFromCharCode(charcode).GetAt(0); |
1334 } | 1334 } |
1335 } | 1335 } |
| 1336 FXFT_Face face = m_Font.GetFace(); |
1336 if (unicode == 0) { | 1337 if (unicode == 0) { |
1337 if (!m_bAdobeCourierStd) { | 1338 if (!m_bAdobeCourierStd) { |
1338 return charcode == 0 ? -1 : (int)charcode; | 1339 return charcode == 0 ? -1 : (int)charcode; |
1339 } | 1340 } |
1340 charcode += 31; | 1341 charcode += 31; |
1341 int index = 0, iBaseEncoding; | 1342 int index = 0, iBaseEncoding; |
1342 FX_BOOL bMSUnicode = FT_UseTTCharmap(m_Font.m_Face, 3, 1); | 1343 FX_BOOL bMSUnicode = FT_UseTTCharmap(face, 3, 1); |
1343 FX_BOOL bMacRoman = FALSE; | 1344 FX_BOOL bMacRoman = FALSE; |
1344 if (!bMSUnicode) { | 1345 if (!bMSUnicode) { |
1345 bMacRoman = FT_UseTTCharmap(m_Font.m_Face, 1, 0); | 1346 bMacRoman = FT_UseTTCharmap(face, 1, 0); |
1346 } | 1347 } |
1347 iBaseEncoding = PDFFONT_ENCODING_STANDARD; | 1348 iBaseEncoding = PDFFONT_ENCODING_STANDARD; |
1348 if (bMSUnicode) { | 1349 if (bMSUnicode) { |
1349 iBaseEncoding = PDFFONT_ENCODING_WINANSI; | 1350 iBaseEncoding = PDFFONT_ENCODING_WINANSI; |
1350 } else if (bMacRoman) { | 1351 } else if (bMacRoman) { |
1351 iBaseEncoding = PDFFONT_ENCODING_MACROMAN; | 1352 iBaseEncoding = PDFFONT_ENCODING_MACROMAN; |
1352 } | 1353 } |
1353 const FX_CHAR* name = GetAdobeCharName(iBaseEncoding, NULL, charcode); | 1354 const FX_CHAR* name = GetAdobeCharName(iBaseEncoding, NULL, charcode); |
1354 if (name == NULL) { | 1355 if (name == NULL) { |
1355 return charcode == 0 ? -1 : (int)charcode; | 1356 return charcode == 0 ? -1 : (int)charcode; |
1356 } | 1357 } |
1357 FX_WORD unicode = PDF_UnicodeFromAdobeName(name); | 1358 FX_WORD unicode = PDF_UnicodeFromAdobeName(name); |
1358 if (unicode) { | 1359 if (unicode) { |
1359 if (bMSUnicode) { | 1360 if (bMSUnicode) { |
1360 index = FXFT_Get_Char_Index(m_Font.m_Face, unicode); | 1361 index = FXFT_Get_Char_Index(face, unicode); |
1361 } else if (bMacRoman) { | 1362 } else if (bMacRoman) { |
1362 FX_DWORD maccode = | 1363 FX_DWORD maccode = |
1363 FT_CharCodeFromUnicode(FXFT_ENCODING_APPLE_ROMAN, unicode); | 1364 FT_CharCodeFromUnicode(FXFT_ENCODING_APPLE_ROMAN, unicode); |
1364 index = !maccode ? FXFT_Get_Name_Index(m_Font.m_Face, (char*)name) | 1365 index = !maccode ? FXFT_Get_Name_Index(face, (char*)name) |
1365 : FXFT_Get_Char_Index(m_Font.m_Face, maccode); | 1366 : FXFT_Get_Char_Index(face, maccode); |
1366 } else { | 1367 } else { |
1367 return FXFT_Get_Char_Index(m_Font.m_Face, unicode); | 1368 return FXFT_Get_Char_Index(face, unicode); |
1368 } | 1369 } |
1369 } else { | 1370 } else { |
1370 return charcode == 0 ? -1 : (int)charcode; | 1371 return charcode == 0 ? -1 : (int)charcode; |
1371 } | 1372 } |
1372 if (index == 0 || index == 0xffff) { | 1373 if (index == 0 || index == 0xffff) { |
1373 return charcode == 0 ? -1 : (int)charcode; | 1374 return charcode == 0 ? -1 : (int)charcode; |
1374 } | 1375 } |
1375 return index; | 1376 return index; |
1376 } | 1377 } |
1377 if (m_Charset == CIDSET_JAPAN1) { | 1378 if (m_Charset == CIDSET_JAPAN1) { |
1378 if (unicode == '\\') { | 1379 if (unicode == '\\') { |
1379 unicode = '/'; | 1380 unicode = '/'; |
1380 } | 1381 } |
1381 #if _FXM_PLATFORM_ != _FXM_PLATFORM_APPLE_ | 1382 #if _FXM_PLATFORM_ != _FXM_PLATFORM_APPLE_ |
1382 else if (unicode == 0xa5) { | 1383 else if (unicode == 0xa5) { |
1383 unicode = 0x5c; | 1384 unicode = 0x5c; |
1384 } | 1385 } |
1385 #endif | 1386 #endif |
1386 } | 1387 } |
1387 if (m_Font.m_Face == NULL) { | 1388 if (!face) |
1388 return unicode; | 1389 return unicode; |
1389 } | 1390 |
1390 int err = FXFT_Select_Charmap(m_Font.m_Face, FXFT_ENCODING_UNICODE); | 1391 int err = FXFT_Select_Charmap(face, FXFT_ENCODING_UNICODE); |
1391 if (err != 0) { | 1392 if (err != 0) { |
1392 int i; | 1393 int i; |
1393 for (i = 0; i < FXFT_Get_Face_CharmapCount(m_Font.m_Face); i++) { | 1394 for (i = 0; i < FXFT_Get_Face_CharmapCount(face); i++) { |
1394 FX_DWORD ret = FT_CharCodeFromUnicode( | 1395 FX_DWORD ret = FT_CharCodeFromUnicode( |
1395 FXFT_Get_Charmap_Encoding(FXFT_Get_Face_Charmaps(m_Font.m_Face)[i]), | 1396 FXFT_Get_Charmap_Encoding(FXFT_Get_Face_Charmaps(face)[i]), |
1396 (FX_WCHAR)charcode); | 1397 (FX_WCHAR)charcode); |
1397 if (ret == 0) { | 1398 if (ret == 0) { |
1398 continue; | 1399 continue; |
1399 } | 1400 } |
1400 FXFT_Set_Charmap(m_Font.m_Face, | 1401 FXFT_Set_Charmap(face, FXFT_Get_Face_Charmaps(face)[i]); |
1401 FXFT_Get_Face_Charmaps(m_Font.m_Face)[i]); | |
1402 unicode = (FX_WCHAR)ret; | 1402 unicode = (FX_WCHAR)ret; |
1403 break; | 1403 break; |
1404 } | 1404 } |
1405 if (i == FXFT_Get_Face_CharmapCount(m_Font.m_Face) && i) { | 1405 if (i == FXFT_Get_Face_CharmapCount(face) && i) { |
1406 FXFT_Set_Charmap(m_Font.m_Face, | 1406 FXFT_Set_Charmap(face, FXFT_Get_Face_Charmaps(face)[0]); |
1407 FXFT_Get_Face_Charmaps(m_Font.m_Face)[0]); | |
1408 unicode = (FX_WCHAR)charcode; | 1407 unicode = (FX_WCHAR)charcode; |
1409 } | 1408 } |
1410 } | 1409 } |
1411 if (FXFT_Get_Face_Charmap(m_Font.m_Face)) { | 1410 if (FXFT_Get_Face_Charmap(face)) { |
1412 int index = GetGlyphIndex(unicode, pVertGlyph); | 1411 int index = GetGlyphIndex(unicode, pVertGlyph); |
1413 if (index == 0) { | 1412 if (index == 0) |
1414 return -1; | 1413 return -1; |
1415 } | |
1416 return index; | 1414 return index; |
1417 } | 1415 } |
1418 return unicode; | 1416 return unicode; |
1419 } | 1417 } |
1420 if (m_Font.m_Face == NULL) { | 1418 if (!m_Font.GetFace()) |
1421 return -1; | 1419 return -1; |
1422 } | 1420 |
1423 FX_WORD cid = CIDFromCharCode(charcode); | 1421 FX_WORD cid = CIDFromCharCode(charcode); |
1424 if (m_bType1) { | 1422 if (m_bType1) { |
1425 if (NULL == m_pCIDToGIDMap) { | 1423 if (!m_pCIDToGIDMap) { |
1426 return cid; | 1424 return cid; |
1427 } | 1425 } |
1428 } else { | 1426 } else { |
1429 if (m_pCIDToGIDMap == NULL) { | 1427 if (!m_pCIDToGIDMap) { |
1430 if (m_pFontFile && m_pCMap->m_pMapping == NULL) { | 1428 if (m_pFontFile && !m_pCMap->m_pMapping) |
| 1429 return cid; |
| 1430 if (m_pCMap->m_Coding == CIDCODING_UNKNOWN || |
| 1431 !FXFT_Get_Face_Charmap(m_Font.GetFace())) { |
1431 return cid; | 1432 return cid; |
1432 } | 1433 } |
1433 if (m_pCMap->m_Coding == CIDCODING_UNKNOWN || | 1434 if (FXFT_Get_Charmap_Encoding(FXFT_Get_Face_Charmap(m_Font.GetFace())) == |
1434 FXFT_Get_Face_Charmap(m_Font.m_Face) == NULL) { | |
1435 return cid; | |
1436 } | |
1437 if (FXFT_Get_Charmap_Encoding(FXFT_Get_Face_Charmap(m_Font.m_Face)) == | |
1438 FXFT_ENCODING_UNICODE) { | 1435 FXFT_ENCODING_UNICODE) { |
1439 CFX_WideString unicode_str = UnicodeFromCharCode(charcode); | 1436 CFX_WideString unicode_str = UnicodeFromCharCode(charcode); |
1440 if (unicode_str.IsEmpty()) { | 1437 if (unicode_str.IsEmpty()) { |
1441 return -1; | 1438 return -1; |
1442 } | 1439 } |
1443 charcode = unicode_str.GetAt(0); | 1440 charcode = unicode_str.GetAt(0); |
1444 } | 1441 } |
1445 return GetGlyphIndex(charcode, pVertGlyph); | 1442 return GetGlyphIndex(charcode, pVertGlyph); |
1446 } | 1443 } |
1447 } | 1444 } |
1448 FX_DWORD byte_pos = cid * 2; | 1445 FX_DWORD byte_pos = cid * 2; |
1449 if (byte_pos + 2 > m_pCIDToGIDMap->GetSize()) { | 1446 if (byte_pos + 2 > m_pCIDToGIDMap->GetSize()) |
1450 return -1; | 1447 return -1; |
1451 } | 1448 |
1452 const uint8_t* pdata = m_pCIDToGIDMap->GetData() + byte_pos; | 1449 const uint8_t* pdata = m_pCIDToGIDMap->GetData() + byte_pos; |
1453 return pdata[0] * 256 + pdata[1]; | 1450 return pdata[0] * 256 + pdata[1]; |
1454 } | 1451 } |
1455 FX_DWORD CPDF_CIDFont::GetNextChar(const FX_CHAR* pString, | 1452 FX_DWORD CPDF_CIDFont::GetNextChar(const FX_CHAR* pString, |
1456 int nStrLen, | 1453 int nStrLen, |
1457 int& offset) const { | 1454 int& offset) const { |
1458 return m_pCMap->GetNextChar(pString, nStrLen, offset); | 1455 return m_pCMap->GetNextChar(pString, nStrLen, offset); |
1459 } | 1456 } |
1460 int CPDF_CIDFont::GetCharSize(FX_DWORD charcode) const { | 1457 int CPDF_CIDFont::GetCharSize(FX_DWORD charcode) const { |
1461 return m_pCMap->GetCharSize(charcode); | 1458 return m_pCMap->GetCharSize(charcode); |
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1650 if (middlecode > CID) { | 1647 if (middlecode > CID) { |
1651 end = middle - 1; | 1648 end = middle - 1; |
1652 } else if (middlecode < CID) { | 1649 } else if (middlecode < CID) { |
1653 begin = middle + 1; | 1650 begin = middle + 1; |
1654 } else { | 1651 } else { |
1655 return &Japan1_VertCIDs[middle].a; | 1652 return &Japan1_VertCIDs[middle].a; |
1656 } | 1653 } |
1657 } | 1654 } |
1658 return NULL; | 1655 return NULL; |
1659 } | 1656 } |
OLD | NEW |