javauis/lcdui_akn/lcdui/src/CMIDFont.cpp
author Pat Downey <patd@symbian.org>
Wed, 01 Sep 2010 12:33:18 +0100
branchRCL_3
changeset 66 2455ef1f5bbc
parent 19 04becd199f91
permissions -rw-r--r--
Revert incorrect RCL_3 drop: Revision: v2.2.11 Kit: 201035

/*
* Copyright (c) 2003-2008 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:  Implementation of CMIDFont for series 60
*
*/


#include <eikenv.h>
#include <coemain.h>
#include <barsread.h>
#include <lcdui.rsg>
#include <fontids.hrh>
#include <gulfont.h>
// API used when font is created
#include <AknUtils.h>
#include <aknenv.h>
// API from CAknLayoutFont related to fonts
#include <AknLayoutFont.h>
#include <j2me/jdebug.h>
#include <aknlayoutscalable_avkon.cdl.h> // for layout data

#include "CMIDFont.h"
// API used for checking graphic scaling related parameters
#include "CMIDMenuHandler.h"
#include "CMIDUIManager.h"

// Indexes for the font size table below
enum TColumnIndexes
{
    EIndexScreenWidth  = 0,
    EIndexScreenHeight = 1,
    EIndexSmallFont    = 2,
    EIndexMediumFont   = 3,
    EIndexLargeFont    = 4,
    EResolutionCount   = 6
};

// Table including the font sizes for known S60 resolutions
// The order of the numbers in one table row:
// 1. screen width
// 2. screen height
// 3. small font height
// 4. medium font height
// 5. large font heigth
// This table must be updated when new resolutions become available in S60.
const TInt KFontSizes[EResolutionCount][5] =
{
    { 176, 208, 13, 15, 17 }, // Low
    { 240, 320, 19, 21, 24 }, // QVGA
    { 320, 480, 25, 28, 32 }, // HVGA
    { 352, 416, 26, 30, 34 }, // Double
    { 360, 640, 24, 27, 30 }, // nHD
    { 480, 640, 32, 36, 41 }  // VGA
};

// Constant for calculating the font heights when in graphic scaling case
// the original MIDlet resolution is smaller than any known S60 resolution.
// These are the averages of screen width / font height ratios of
// Low, QVGA, Double and HVGA resolutions.
const TReal KSmallFontRatioToScreenWidth  = 13.13;
const TReal KMediumFontRatioToScreenWidth = 11.58;
const TReal KLargeFontRatioToScreenWidth  = 10.18;

// Minimum font height. This is used as font height if calculated font
// height would be smaller than this.
const TInt KMinFontHeight = 11;

// Default value of iScalingFactor.
const TReal KNonScaled = 1.0;

// Zero size (0, 0).
#define KZeroSize ::TSize()

MMIDFont* CMIDFont::NewL(TUint aStyle, TUint aSize, TInt aFace,
                         CMIDUIManager* aUIManager, TBool aIsFreeSizeFont)
{
    CMIDFont* font = new(ELeave) CMIDFont(aUIManager);
    CleanupStack::PushL(font);
    font->ConstructL(aStyle, aSize, aFace, aIsFreeSizeFont);
    CleanupStack::Pop(font);
    return font;
}

CMIDFont::CMIDFont(CMIDUIManager* aUIManager)
        : iUIManager(aUIManager), iScalingFactor(KNonScaled)
{
}

/**
 * @return the MIDP font height - including external leading.
 */
TInt CMIDFont::Height()
{
    const CAknLayoutFont* layFont =  CAknLayoutFont::AsCAknLayoutFontOrNull(Font());
    // We are using only CAknLayoutFonts, so panic is raised if the layFont is null.
    ASSERT(layFont);
    return layFont->TextPaneHeight();
}

/**
 * @return vertical distance from top of font to the baseline.
 */
TInt CMIDFont::Baseline()
{
    return Font()->FontMaxAscent();
}

TInt CMIDFont::Width(const TDesC& aString)
{
    return Font()->TextWidthInPixels(aString);
}

CMIDFont::~CMIDFont()
{
    const CAknLayoutFont* layFont =  CAknLayoutFont::AsCAknLayoutFontOrNull(iFont);
    if (layFont)
    {
        delete layFont;
        iFont = NULL;
    }
}

void CMIDFont::ConstructL(TUint aStyle, TUint aSize, TInt /*aFace*/,
                          TBool aIsFreeSizeFont)
{
    // Ensure that menu handler exists. It will be needed later.
    iUIManager->OpenMenuHandlerL();

    // saving of flag iUnderline
    iUnderlined = aStyle & EUnderlined;

    // We don't need underline flag in aStyle.
    aStyle &= ~EUnderlined;

    // saving of size of font
    iSize = aSize;

    // saving iIsFreeSizeFont flag
    iIsFreeSizeFont = aIsFreeSizeFont;

    // saving of iBold flag
    if (aStyle & EBold)
    {
        iBold = ETrue;
    }
    else
    {
        iBold = EFalse;
    }

    // saving of iItalic flag
    if (aStyle & EItalic)
    {
        iItalic = ETrue;
    }
    else
    {
        iItalic = EFalse;
    }

    // seting of orginal size and scaling factor.
    SetOrigFontHeight();

    // checking of this is really resizible font
    if (iIsFreeSizeFont)
    {
        // In case of font with custom height simply set the same value as in iSize
        iPaneHeight = aSize;
    }
    else
    {
        // If is not downscaling on and this is not freely resizible font, then we use predefined size of font.
        iPaneHeight = GetTextPaneHeight(ETrue);
    }

    iFont = NULL;

    // creating of new iFont
    CreateNewFont();
}

const CFont* CMIDFont::DefaultFont(const TDefaultId& aId)
{
    if (aId == EDefaultTextId)
    {
        return AknLayoutUtils::FontFromId(
                   AknLayoutScalable_Avkon::form2_mdip_string_pane_t1(1,0).Font(), NULL);
    }
    else if (aId == EDefaultLabelId)
    {
        return AknLayoutUtils::FontFromId(
                   AknLayoutScalable_Avkon::form2_midp_label_pane_t1(0).Font(), NULL);
    }
    else
    {
        ASSERT(0); // unsupported default font id
        return NULL;
    }
}

// deprecated, use DefaultFont(EDefaultLabelId)
const CFont* CMIDFont::DefaultLabelFont()
{
    return DefaultFont(EDefaultLabelId);
}

/**
 * Returns iFont that is a pointer to CFont object.
 * Parameter aHighLevelUIComponent indicates whether this method has been called
 * from a non-high level ui component (Graphics), or a high level UI component (List, StringItem, etc.).
 */
CFont* CMIDFont::Font(TBool aHighLevelComponent)
{
    TBool useScaling = !aHighLevelComponent;

    TInt paneHeight;
    if (iIsFreeSizeFont)
    {
        // free size font is independent on resolution, so it should not be
        // re-created if resolution is changed
        paneHeight = iPaneHeight;
    }
    else
    {
        // standard font depends on resolution, if resolution is changed
        // pane height is changed too
        paneHeight = GetTextPaneHeight(useScaling);
    }

    // Check if the font size has changed e.g. because of the dynamic
    // resolution change. If so re-create the font.
    if (iPaneHeight != paneHeight)
    {
        iPaneHeight = paneHeight;
        CreateNewFont();
    }

    if (iFont)
    {
        return iFont;
    }
    else
    {
        // returns the default font if font creation has failed
        return const_cast<CFont*>(CMIDFont::DefaultFont(EDefaultTextId));
    }

}

/**
 * CreteNewFont function creates a new iFont object.
 * Font specification attributes are retrieved from the class member variables.
 */
void CMIDFont::CreateNewFont()
{
    // delete existing iFont object
    const CAknLayoutFont* layFont =  CAknLayoutFont::AsCAknLayoutFontOrNull(iFont);
    if (layFont)
    {
        delete layFont;
        iFont = NULL;
    }

    // init spec
    TAknFontSpecification spec(EAknLogicalFontSecondaryFont);
    // size
    spec.SetTextPaneHeight(iPaneHeight);
    // italic
    if (iItalic)
        spec.SetPosture(EPostureItalic);
    // bold
    if (iBold)
        spec.SetWeight(EStrokeWeightBold);

    TInt err = 0;
    DEBUG("CMIDFont::CreateNewFont - calling CreateLayoutFontFromSpecificationL");
    TRAP(err, iFont = AknLayoutUtils::CreateLayoutFontFromSpecificationL(spec));   // Now owned by the client code
    if (err != KErrNone)
    {
        DEBUG_INT("CMIDFont::CreateNewFont - Exception from AknLayoutUtils::CreateLayoutFontFromSpecificationL. Error = %d", err);
    }
}

TBool CMIDFont::IsUnderlined() const
{
    return iUnderlined;
}

void CMIDFont::Dispose()
{
    delete this;
}


/**
 * This function returns the height of the text pane for the current font size.
 * The text pane height value is retrieved from the LAF.
 * If the aScaling is true and graphic scaling is effective in current device screen,
 * the font height in the original MIDlet resolution is returned.
 */
TInt CMIDFont::GetTextPaneHeight(TBool aScaling)
{
    // iOrigFontHeight > 0 only when orignial MIDlet resolution has been defined in .jad
    if (aScaling && iOrigFontHeight > 0 &&
            iUIManager->GetMenuHandler()->IsScalingEffectiveInCurrentScreen())
    {
        return iOrigFontHeight;
    }

    TInt paneHeight;
    if (iSize == MMIDFont::ESmall)
    {
        //Small size is retrieved from the form item label LAF
        paneHeight = AknLayoutScalable_Avkon::form2_midp_label_pane_t1(0).H();
    }
    else if (iSize == MMIDFont::ELarge)
    {
        paneHeight = AknLayoutScalable_Avkon::form2_mdip_string_pane_t1(2,0).H();
    }
    else // EMedium
    {
        paneHeight = AknLayoutScalable_Avkon::form2_mdip_string_pane_t1(1,0).H();
    }

    return paneHeight;
}


void CMIDFont::SetOrigFontHeight()
{
    iOrigFontHeight = 0;

    if (!iUIManager->GetMenuHandler()->IsScalingEnabled())
    {
        return;
    }

    ::TSize origResolution =
        iUIManager->GetMenuHandler()->GetScalingParameterOrgMIDletScrSize();

    // ensure that resolution is in portrait orientation
    ::TSize resolution(Min(origResolution.iWidth, origResolution.iHeight),
                       Max(origResolution.iWidth, origResolution.iHeight));

    TInt fontSizeIndex = 0;
    switch (iSize)
    {
    case MMIDFont::ESmall:
        fontSizeIndex = EIndexSmallFont;
        break;
    case MMIDFont::EMedium:
        fontSizeIndex = EIndexMediumFont;
        break;
    case MMIDFont::ELarge:
        fontSizeIndex = EIndexLargeFont;
        break;
    default:
        break;
    }

    // These indexes are for the case that original resolution is not a known
    // resolution and font height needs to be calculated based on the font heights
    // in KFontSizes table.
    TInt smallerResolutionIndex = KErrNotFound;
    TInt biggerResolutionIndex = KErrNotFound;

    for (TInt i = 0; i < EResolutionCount && biggerResolutionIndex == KErrNotFound; ++i)
    {
        if (KFontSizes[i][EIndexScreenWidth] == resolution.iWidth)
        {
            iOrigFontHeight = KFontSizes[i][fontSizeIndex];
            return;
        }

        if (KFontSizes[i][EIndexScreenWidth] < resolution.iWidth)
        {
            smallerResolutionIndex = i;
        }
        else if (KFontSizes[i][EIndexScreenWidth] > resolution.iWidth &&
                 biggerResolutionIndex == KErrNotFound)
        {
            biggerResolutionIndex = i;
        }
    }

    // Orig resolution is not a known S60 resolution, need to calculate an estimate for
    // original font height based on the screen width of the original resolution.
    if (iOrigFontHeight == 0)
    {
        // First check if the original MIDlet resolution is smaller than any known
        // S60 resolution. If so, the original font height estimate is calculated
        // by using the KXXXFontRatioToScreenWidth constants.
        if (smallerResolutionIndex == KErrNotFound)
        {
            TReal fontSizeRatio = KSmallFontRatioToScreenWidth;

            switch (iSize)
            {
            case MMIDFont::ESmall:
                fontSizeRatio = KSmallFontRatioToScreenWidth;
                break;
            case MMIDFont::EMedium:
                fontSizeRatio = KMediumFontRatioToScreenWidth;
                break;
            case MMIDFont::ELarge:
                fontSizeRatio = KLargeFontRatioToScreenWidth;
                break;
            default:
                break;
            }

            iOrigFontHeight = TReal(resolution.iWidth) / fontSizeRatio;
            iOrigFontHeight = Max(KMinFontHeight, iOrigFontHeight);
        }
        else if (biggerResolutionIndex == KErrNotFound)
        {
            // Original screen width is bigger than the highest resolution in the KFontSizes table.
            // Use the font size defined for the highest resolution in the table.
            iOrigFontHeight = KFontSizes[EResolutionCount - 1][fontSizeIndex];
        }
        else
        {
            // The screen width of the original MIDlet resolution is between 2 known S60 screen
            // widths. Calculate estimate for font height based on the heights of the 2 known resolutions.
            TReal fontHeightDelta = KFontSizes[biggerResolutionIndex][fontSizeIndex] -
                                    KFontSizes[smallerResolutionIndex][fontSizeIndex];

            TReal screenWidthDelta = KFontSizes[biggerResolutionIndex][EIndexScreenWidth] -
                                     KFontSizes[smallerResolutionIndex][EIndexScreenWidth];

            TReal origScreenWidthDelta = resolution.iWidth -
                                         KFontSizes[smallerResolutionIndex][EIndexScreenWidth];

            iOrigFontHeight = KFontSizes[smallerResolutionIndex][fontSizeIndex] +
                              ((origScreenWidthDelta / screenWidthDelta) *
                               fontHeightDelta);
        }
    }
}

/**
 * @return ETrue if font is bold, EFalse if not.
 */
TBool CMIDFont::IsBold()
{
    return iBold;
}

/**
 * @return ETrue if font is italic, EFalse if not.
 */
TBool CMIDFont::IsItalic()
{
    return iItalic;
}
// End of File