/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */


#include <svdata.hxx>
#include <fontinstance.hxx>
#include <impfontcache.hxx>

#include <PhysicalFontFace.hxx>

// extend std namespace to add custom hash needed for LogicalFontInstance

namespace std
{
    template <> struct hash< pair< sal_UCS4, FontWeight > >
    {
        size_t operator()(const pair< sal_UCS4, FontWeight >& rData) const
        {
            std::size_t seed = 0;
            boost::hash_combine(seed, rData.first);
            boost::hash_combine(seed, rData.second);
            return seed;
        }
    };
}


LogicalFontInstance::LogicalFontInstance(const PhysicalFontFace& rFontFace, const FontSelectPattern& rFontSelData )
    : mxFontMetric( new ImplFontMetricData( rFontSelData ))
    , mpConversion( nullptr )
    , mnLineHeight( 0 )
    , mnOwnOrientation( 0 )
    , mnOrientation( 0 )
    , mbInit( false )
    , mpFontCache( nullptr )
    , m_aFontSelData(rFontSelData)
    , m_pHbFont(nullptr)
    , m_nAveWidthFactor(1.0f)
    , m_pFontFace(&const_cast<PhysicalFontFace&>(rFontFace))
{
}

LogicalFontInstance::~LogicalFontInstance()
{
    mpUnicodeFallbackList.reset();
    mpFontCache = nullptr;
    mxFontMetric = nullptr;

    if (m_pHbFont)
        hb_font_destroy(m_pHbFont);
}

hb_font_t* LogicalFontInstance::InitHbFont(hb_face_t* pHbFace)
{
    assert(pHbFace);
    hb_font_t* pHbFont = hb_font_create(pHbFace);
    unsigned int nUPEM = hb_face_get_upem(pHbFace);
    hb_font_set_scale(pHbFont, nUPEM, nUPEM);
    hb_ot_font_set_funcs(pHbFont);
    // hb_font_t keeps a reference to hb_face_t, so destroy this one.
    hb_face_destroy(pHbFace);
    return pHbFont;
}

int LogicalFontInstance::GetKashidaWidth()
{
    hb_font_t* pHbFont = GetHbFont();
    hb_position_t nWidth = 0;
    hb_codepoint_t nIndex = 0;

    if (hb_font_get_glyph(pHbFont, 0x0640, 0, &nIndex))
    {
        double nXScale = 0;
        GetScale(&nXScale, nullptr);
        nWidth = hb_font_get_glyph_h_advance(pHbFont, nIndex) * nXScale;
    }

    return nWidth;
}

void LogicalFontInstance::GetScale(double* nXScale, double* nYScale)
{
    hb_face_t* pHbFace = hb_font_get_face(GetHbFont());
    unsigned int nUPEM = hb_face_get_upem(pHbFace);

    double nHeight(m_aFontSelData.mnHeight);

    // On Windows, mnWidth is relative to average char width not font height,
    // and we need to keep it that way for GDI to correctly scale the glyphs.
    // Here we compensate for this so that HarfBuzz gives us the correct glyph
    // positions.
    double nWidth(m_aFontSelData.mnWidth ? m_aFontSelData.mnWidth * m_nAveWidthFactor : nHeight);

    if (nYScale)
        *nYScale = nHeight / nUPEM;

    if (nXScale)
        *nXScale = nWidth / nUPEM;
}

void LogicalFontInstance::AddFallbackForUnicode( sal_UCS4 cChar, FontWeight eWeight, const OUString& rFontName )
{
    if( !mpUnicodeFallbackList )
        mpUnicodeFallbackList.reset(new UnicodeFallbackList);
    (*mpUnicodeFallbackList)[ std::pair< sal_UCS4, FontWeight >(cChar,eWeight) ] = rFontName;
}

bool LogicalFontInstance::GetFallbackForUnicode( sal_UCS4 cChar, FontWeight eWeight, OUString* pFontName ) const
{
    if( !mpUnicodeFallbackList )
        return false;

    UnicodeFallbackList::const_iterator it = mpUnicodeFallbackList->find( std::pair< sal_UCS4, FontWeight >(cChar,eWeight) );
    if( it == mpUnicodeFallbackList->end() )
        return false;

    *pFontName = (*it).second;
    return true;
}

void LogicalFontInstance::IgnoreFallbackForUnicode( sal_UCS4 cChar, FontWeight eWeight, const OUString& rFontName )
{
    UnicodeFallbackList::iterator it = mpUnicodeFallbackList->find( std::pair< sal_UCS4,FontWeight >(cChar,eWeight) );
    if( it == mpUnicodeFallbackList->end() )
        return;
    if( (*it).second == rFontName )
        mpUnicodeFallbackList->erase( it );
}

bool LogicalFontInstance::GetGlyphBoundRect(sal_GlyphId nID, tools::Rectangle &rRect, bool bVertical) const
{
    if (mpFontCache && mpFontCache->GetCachedGlyphBoundRect(this, nID, rRect))
        return true;

    bool res = ImplGetGlyphBoundRect(nID, rRect, bVertical);
    if (mpFontCache && res)
        mpFontCache->CacheGlyphBoundRect(this, nID, rRect);
    return res;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
