14d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann// Copyright 2016 PDFium Authors. All rights reserved.
24d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann// Use of this source code is governed by a BSD-style license that can be
34d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann// found in the LICENSE file.
44d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
54d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
64d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
74d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#include "core/fxge/cfx_facecache.h"
84d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
94d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#include <algorithm>
104d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#include <limits>
114d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#include <memory>
12d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#include <utility>
134d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
14d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#include "core/fxcrt/fx_codepage.h"
15d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#include "core/fxge/cfx_font.h"
164d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#include "core/fxge/cfx_fontmgr.h"
174d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#include "core/fxge/cfx_gemodule.h"
184d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#include "core/fxge/cfx_pathdata.h"
194d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#include "core/fxge/cfx_substfont.h"
204d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#include "core/fxge/fx_freetype.h"
214d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#include "third_party/base/numerics/safe_math.h"
22d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#include "third_party/base/ptr_util.h"
234d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
244d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#if defined _SKIA_SUPPORT_ || _SKIA_SUPPORT_PATHS_
254d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#include "third_party/skia/include/core/SkStream.h"
264d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#include "third_party/skia/include/core/SkTypeface.h"
27d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
28d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#if _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
29d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#include "third_party/skia/include/ports/SkFontMgr.h"
30d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#include "third_party/skia/include/ports/SkFontMgr_empty.h"
31d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#endif
324d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#endif
334d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
344d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmannnamespace {
354d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
364d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmannconstexpr uint32_t kInvalidGlyphIndex = static_cast<uint32_t>(-1);
374d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
38d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmannconstexpr int kMaxGlyphDimension = 2048;
394d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
40d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmannstruct UniqueKeyGen {
41d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  void Generate(int count, ...);
42d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
43d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  char key_[128];
44d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  int key_len_;
45d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann};
46d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
47d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmannvoid UniqueKeyGen::Generate(int count, ...) {
48d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  va_list argList;
49d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  va_start(argList, count);
50d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  for (int i = 0; i < count; i++) {
51d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    int p = va_arg(argList, int);
52d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    reinterpret_cast<uint32_t*>(key_)[i] = p;
534d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  }
54d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  va_end(argList);
55d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  key_len_ = count * sizeof(uint32_t);
564d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann}
57d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
584d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann}  // namespace
594d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
604d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. MoltmannCFX_FaceCache::CFX_FaceCache(FXFT_Face face)
614d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    : m_Face(face)
624d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#if defined _SKIA_SUPPORT_ || _SKIA_SUPPORT_PATHS_
634d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      ,
644d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      m_pTypeface(nullptr)
654d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#endif
664d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann{
674d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann}
684d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
69d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. MoltmannCFX_FaceCache::~CFX_FaceCache() {}
704d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
71d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmannstd::unique_ptr<CFX_GlyphBitmap> CFX_FaceCache::RenderGlyph(
72d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    const CFX_Font* pFont,
73d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    uint32_t glyph_index,
74d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    bool bFontStyle,
75d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    const CFX_Matrix* pMatrix,
76d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    int dest_width,
77d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    int anti_alias) {
784d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  if (!m_Face)
794d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    return nullptr;
804d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
814d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  FXFT_Matrix ft_matrix;
8233357cad1fd1321a2b38d2963e2585f27ce980a2Philip P. Moltmann  ft_matrix.xx = (signed long)(pMatrix->a / 64 * 65536);
8333357cad1fd1321a2b38d2963e2585f27ce980a2Philip P. Moltmann  ft_matrix.xy = (signed long)(pMatrix->c / 64 * 65536);
8433357cad1fd1321a2b38d2963e2585f27ce980a2Philip P. Moltmann  ft_matrix.yx = (signed long)(pMatrix->b / 64 * 65536);
8533357cad1fd1321a2b38d2963e2585f27ce980a2Philip P. Moltmann  ft_matrix.yy = (signed long)(pMatrix->d / 64 * 65536);
864d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  bool bUseCJKSubFont = false;
874d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  const CFX_SubstFont* pSubstFont = pFont->GetSubstFont();
884d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  if (pSubstFont) {
894d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    bUseCJKSubFont = pSubstFont->m_bSubstCJK && bFontStyle;
904d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    int skew = 0;
914d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    if (bUseCJKSubFont)
924d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      skew = pSubstFont->m_bItalicCJK ? -15 : 0;
934d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    else
944d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      skew = pSubstFont->m_ItalicAngle;
954d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    if (skew) {
964d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      // |skew| is nonpositive so |-skew| is used as the index. We need to make
974d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      // sure |skew| != INT_MIN since -INT_MIN is undefined.
984d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      if (skew <= 0 && skew != std::numeric_limits<int>::min() &&
994d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann          static_cast<size_t>(-skew) < CFX_Font::kAngleSkewArraySize) {
1004d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        skew = -CFX_Font::s_AngleSkew[-skew];
1014d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      } else {
1024d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        skew = -58;
1034d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      }
1044d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      if (pFont->IsVertical())
1054d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        ft_matrix.yx += ft_matrix.yy * skew / 100;
1064d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      else
1074d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        ft_matrix.xy -= ft_matrix.xx * skew / 100;
1084d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    }
109d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    if (pSubstFont->m_bFlagMM) {
1104d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      pFont->AdjustMMParams(glyph_index, dest_width,
1114d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                            pFont->GetSubstFont()->m_Weight);
1124d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    }
1134d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  }
1144d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  ScopedFontTransform scoped_transform(m_Face, &ft_matrix);
1154d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  int load_flags = (m_Face->face_flags & FT_FACE_FLAG_SFNT)
1164d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                       ? FXFT_LOAD_NO_BITMAP
1174d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                       : (FXFT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING);
1184d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  int error = FXFT_Load_Glyph(m_Face, glyph_index, load_flags);
1194d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  if (error) {
1204d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    // if an error is returned, try to reload glyphs without hinting.
1214d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    if (load_flags & FT_LOAD_NO_HINTING || load_flags & FT_LOAD_NO_SCALE)
1224d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      return nullptr;
1234d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
1244d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    load_flags |= FT_LOAD_NO_HINTING;
1254d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    error = FXFT_Load_Glyph(m_Face, glyph_index, load_flags);
1264d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
1274d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    if (error)
1284d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      return nullptr;
1294d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  }
1304d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  int weight = 0;
1314d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  if (bUseCJKSubFont)
1324d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    weight = pSubstFont->m_WeightCJK;
1334d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  else
1344d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    weight = pSubstFont ? pSubstFont->m_Weight : 0;
135d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (pSubstFont && !pSubstFont->m_bFlagMM && weight > 400) {
1364d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    uint32_t index = (weight - 400) / 10;
1374d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    if (index >= CFX_Font::kWeightPowArraySize)
1384d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      return nullptr;
1394d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    pdfium::base::CheckedNumeric<signed long> level = 0;
140d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    if (pSubstFont->m_Charset == FX_CHARSET_ShiftJIS)
1414d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      level = CFX_Font::s_WeightPow_SHIFTJIS[index] * 2;
1424d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    else
1434d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      level = CFX_Font::s_WeightPow_11[index];
1444d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
145d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    level = level *
146d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann            (abs(static_cast<int>(ft_matrix.xx)) +
147d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann             abs(static_cast<int>(ft_matrix.xy))) /
1484d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann            36655;
1494d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    FXFT_Outline_Embolden(FXFT_Get_Glyph_Outline(m_Face),
1504d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                          level.ValueOrDefault(0));
1514d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  }
1524d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  FXFT_Library_SetLcdFilter(CFX_GEModule::Get()->GetFontMgr()->GetFTLibrary(),
1534d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                            FT_LCD_FILTER_DEFAULT);
1544d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  error = FXFT_Render_Glyph(m_Face, anti_alias);
1554d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  if (error)
1564d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    return nullptr;
1574d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  int bmwidth = FXFT_Get_Bitmap_Width(FXFT_Get_Glyph_Bitmap(m_Face));
1584d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  int bmheight = FXFT_Get_Bitmap_Rows(FXFT_Get_Glyph_Bitmap(m_Face));
159d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (bmwidth > kMaxGlyphDimension || bmheight > kMaxGlyphDimension)
1604d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    return nullptr;
1614d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  int dib_width = bmwidth;
162d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  auto pGlyphBitmap = pdfium::MakeUnique<CFX_GlyphBitmap>();
163d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  pGlyphBitmap->m_pBitmap->Create(
1644d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      dib_width, bmheight,
1654d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      anti_alias == FXFT_RENDER_MODE_MONO ? FXDIB_1bppMask : FXDIB_8bppMask);
1664d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  pGlyphBitmap->m_Left = FXFT_Get_Glyph_BitmapLeft(m_Face);
1674d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  pGlyphBitmap->m_Top = FXFT_Get_Glyph_BitmapTop(m_Face);
168d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  int dest_pitch = pGlyphBitmap->m_pBitmap->GetPitch();
1694d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  int src_pitch = FXFT_Get_Bitmap_Pitch(FXFT_Get_Glyph_Bitmap(m_Face));
170d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  uint8_t* pDestBuf = pGlyphBitmap->m_pBitmap->GetBuffer();
1714d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  uint8_t* pSrcBuf =
1724d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      (uint8_t*)FXFT_Get_Bitmap_Buffer(FXFT_Get_Glyph_Bitmap(m_Face));
1734d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  if (anti_alias != FXFT_RENDER_MODE_MONO &&
1744d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      FXFT_Get_Bitmap_PixelMode(FXFT_Get_Glyph_Bitmap(m_Face)) ==
1754d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann          FXFT_PIXEL_MODE_MONO) {
1764d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    int bytes = anti_alias == FXFT_RENDER_MODE_LCD ? 3 : 1;
1774d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    for (int i = 0; i < bmheight; i++) {
1784d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      for (int n = 0; n < bmwidth; n++) {
1794d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        uint8_t data =
1804d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann            (pSrcBuf[i * src_pitch + n / 8] & (0x80 >> (n % 8))) ? 255 : 0;
1814d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann        for (int b = 0; b < bytes; b++)
1824d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann          pDestBuf[i * dest_pitch + n * bytes + b] = data;
1834d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      }
1844d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    }
1854d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  } else {
186d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    memset(pDestBuf, 0, dest_pitch * bmheight);
187d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    int rowbytes = std::min(abs(src_pitch), dest_pitch);
188d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    for (int row = 0; row < bmheight; row++)
189d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      memcpy(pDestBuf + row * dest_pitch, pSrcBuf + row * src_pitch, rowbytes);
1904d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  }
1914d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  return pGlyphBitmap;
1924d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann}
1934d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
1944d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmannconst CFX_PathData* CFX_FaceCache::LoadGlyphPath(const CFX_Font* pFont,
1954d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                                                 uint32_t glyph_index,
1964d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                                                 int dest_width) {
197d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (!m_Face || glyph_index == kInvalidGlyphIndex)
1984d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    return nullptr;
1994d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
200d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  const auto* pSubstFont = pFont->GetSubstFont();
201d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  int weight = pSubstFont ? pSubstFont->m_Weight : 0;
202d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  int angle = pSubstFont ? pSubstFont->m_ItalicAngle : 0;
203d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  bool vertical = pSubstFont ? pFont->IsVertical() : false;
204d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  const PathMapKey key =
205d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      std::make_tuple(glyph_index, dest_width, weight, angle, vertical);
2064d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  auto it = m_PathMap.find(key);
2074d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  if (it != m_PathMap.end())
2084d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    return it->second.get();
2094d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
2104d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  CFX_PathData* pGlyphPath = pFont->LoadGlyphPathImpl(glyph_index, dest_width);
2114d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  m_PathMap[key] = std::unique_ptr<CFX_PathData>(pGlyphPath);
2124d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  return pGlyphPath;
2134d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann}
2144d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
2154d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmannconst CFX_GlyphBitmap* CFX_FaceCache::LoadGlyphBitmap(const CFX_Font* pFont,
2164d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                                                      uint32_t glyph_index,
2174d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                                                      bool bFontStyle,
2184d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                                                      const CFX_Matrix* pMatrix,
2194d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                                                      int dest_width,
2204d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                                                      int anti_alias,
2214d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                                                      int& text_flags) {
2224d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  if (glyph_index == kInvalidGlyphIndex)
2234d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    return nullptr;
2244d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
225d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  UniqueKeyGen keygen;
2264d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  int nMatrixA = static_cast<int>(pMatrix->a * 10000);
2274d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  int nMatrixB = static_cast<int>(pMatrix->b * 10000);
2284d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  int nMatrixC = static_cast<int>(pMatrix->c * 10000);
2294d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  int nMatrixD = static_cast<int>(pMatrix->d * 10000);
230d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#if _FX_PLATFORM_ != _FX_PLATFORM_APPLE_
2314d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  if (pFont->GetSubstFont()) {
2324d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    keygen.Generate(9, nMatrixA, nMatrixB, nMatrixC, nMatrixD, dest_width,
2334d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                    anti_alias, pFont->GetSubstFont()->m_Weight,
2344d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                    pFont->GetSubstFont()->m_ItalicAngle, pFont->IsVertical());
2354d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  } else {
2364d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    keygen.Generate(6, nMatrixA, nMatrixB, nMatrixC, nMatrixD, dest_width,
2374d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                    anti_alias);
2384d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  }
2394d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#else
2404d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  if (text_flags & FXTEXT_NO_NATIVETEXT) {
2414d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    if (pFont->GetSubstFont()) {
2424d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      keygen.Generate(9, nMatrixA, nMatrixB, nMatrixC, nMatrixD, dest_width,
2434d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                      anti_alias, pFont->GetSubstFont()->m_Weight,
2444d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                      pFont->GetSubstFont()->m_ItalicAngle,
2454d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                      pFont->IsVertical());
2464d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    } else {
2474d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      keygen.Generate(6, nMatrixA, nMatrixB, nMatrixC, nMatrixD, dest_width,
2484d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                      anti_alias);
2494d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    }
2504d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  } else {
2514d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    if (pFont->GetSubstFont()) {
2524d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      keygen.Generate(10, nMatrixA, nMatrixB, nMatrixC, nMatrixD, dest_width,
2534d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                      anti_alias, pFont->GetSubstFont()->m_Weight,
2544d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                      pFont->GetSubstFont()->m_ItalicAngle, pFont->IsVertical(),
2554d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                      3);
2564d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    } else {
2574d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann      keygen.Generate(7, nMatrixA, nMatrixB, nMatrixC, nMatrixD, dest_width,
2584d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                      anti_alias, 3);
2594d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    }
2604d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  }
2614d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#endif
262d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  ByteString FaceGlyphsKey(keygen.key_, keygen.key_len_);
263d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#if _FX_PLATFORM_ != _FX_PLATFORM_APPLE_ || defined _SKIA_SUPPORT_ || \
2644d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    defined _SKIA_SUPPORT_PATHS_
2654d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  return LookUpGlyphBitmap(pFont, pMatrix, FaceGlyphsKey, glyph_index,
2664d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                           bFontStyle, dest_width, anti_alias);
2674d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#else
2684d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  if (text_flags & FXTEXT_NO_NATIVETEXT) {
2694d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    return LookUpGlyphBitmap(pFont, pMatrix, FaceGlyphsKey, glyph_index,
2704d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                             bFontStyle, dest_width, anti_alias);
2714d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  }
272d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  std::unique_ptr<CFX_GlyphBitmap> pGlyphBitmap;
2734d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  auto it = m_SizeMap.find(FaceGlyphsKey);
2744d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  if (it != m_SizeMap.end()) {
275d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    SizeGlyphCache* pSizeCache = &(it->second);
276d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    auto it2 = pSizeCache->find(glyph_index);
277d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    if (it2 != pSizeCache->end())
278d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      return it2->second.get();
2794d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
2804d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    pGlyphBitmap = RenderGlyph_Nativetext(pFont, glyph_index, pMatrix,
2814d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                                          dest_width, anti_alias);
2824d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    if (pGlyphBitmap) {
283d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      CFX_GlyphBitmap* pResult = pGlyphBitmap.get();
284d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      (*pSizeCache)[glyph_index] = std::move(pGlyphBitmap);
285d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      return pResult;
2864d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    }
2874d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  } else {
2884d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    pGlyphBitmap = RenderGlyph_Nativetext(pFont, glyph_index, pMatrix,
2894d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                                          dest_width, anti_alias);
2904d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    if (pGlyphBitmap) {
291d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      CFX_GlyphBitmap* pResult = pGlyphBitmap.get();
292d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
293d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      SizeGlyphCache cache;
294d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      cache[glyph_index] = std::move(pGlyphBitmap);
295d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
296d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      m_SizeMap[FaceGlyphsKey] = std::move(cache);
297d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      return pResult;
2984d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    }
2994d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  }
3004d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  if (pFont->GetSubstFont()) {
3014d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    keygen.Generate(9, nMatrixA, nMatrixB, nMatrixC, nMatrixD, dest_width,
3024d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                    anti_alias, pFont->GetSubstFont()->m_Weight,
3034d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                    pFont->GetSubstFont()->m_ItalicAngle, pFont->IsVertical());
3044d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  } else {
3054d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    keygen.Generate(6, nMatrixA, nMatrixB, nMatrixC, nMatrixD, dest_width,
3064d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                    anti_alias);
3074d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  }
308d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  ByteString FaceGlyphsKey2(keygen.key_, keygen.key_len_);
3094d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  text_flags |= FXTEXT_NO_NATIVETEXT;
3104d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  return LookUpGlyphBitmap(pFont, pMatrix, FaceGlyphsKey2, glyph_index,
3114d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann                           bFontStyle, dest_width, anti_alias);
3124d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#endif
3134d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann}
3144d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
3154d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#if defined _SKIA_SUPPORT_ || defined _SKIA_SUPPORT_PATHS_
3164d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. MoltmannCFX_TypeFace* CFX_FaceCache::GetDeviceCache(const CFX_Font* pFont) {
3174d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  if (!m_pTypeface) {
318d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    m_pTypeface = SkTypeface::MakeFromStream(
319d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        new SkMemoryStream(pFont->GetFontData(), pFont->GetSize()));
320d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  }
321d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#if _FX_PLATFORM_ == _FX_PLATFORM_WINDOWS_
322d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (!m_pTypeface) {
323d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    sk_sp<SkFontMgr> customMgr(SkFontMgr_New_Custom_Empty());
324d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    m_pTypeface = customMgr->makeFromStream(pdfium::MakeUnique<SkMemoryStream>(
325d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann        pFont->GetFontData(), pFont->GetSize()));
3264d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  }
327d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#endif
328d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  return m_pTypeface.get();
3294d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann}
3304d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#endif
3314d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
332d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann#if _FX_PLATFORM_ != _FX_PLATFORM_APPLE_
3334d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmannvoid CFX_FaceCache::InitPlatform() {}
3344d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann#endif
3354d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
3364d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. MoltmannCFX_GlyphBitmap* CFX_FaceCache::LookUpGlyphBitmap(
3374d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    const CFX_Font* pFont,
3384d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    const CFX_Matrix* pMatrix,
339d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    const ByteString& FaceGlyphsKey,
3404d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    uint32_t glyph_index,
3414d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    bool bFontStyle,
3424d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    int dest_width,
3434d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann    int anti_alias) {
344d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  SizeGlyphCache* pSizeCache;
3454d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  auto it = m_SizeMap.find(FaceGlyphsKey);
3464d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  if (it == m_SizeMap.end()) {
347d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    m_SizeMap[FaceGlyphsKey] = SizeGlyphCache();
348d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    pSizeCache = &(m_SizeMap[FaceGlyphsKey]);
3494d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  } else {
350d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    pSizeCache = &(it->second);
3514d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann  }
3524d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann
353d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  auto it2 = pSizeCache->find(glyph_index);
354d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  if (it2 != pSizeCache->end())
355d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann    return it2->second.get();
356d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann
357d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  std::unique_ptr<CFX_GlyphBitmap> pGlyphBitmap = RenderGlyph(
358d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann      pFont, glyph_index, bFontStyle, pMatrix, dest_width, anti_alias);
359d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  CFX_GlyphBitmap* pResult = pGlyphBitmap.get();
360d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  (*pSizeCache)[glyph_index] = std::move(pGlyphBitmap);
361d904c1ec7e8d1d86ed56f0dd252435d12cd345aePhilip P. Moltmann  return pResult;
3624d3acf4ec42bf6e838f9060103aff98fbf170794Philip P. Moltmann}
363