<commit_before>/*
* Copyright (c) 2010 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: Retrieves the character map for each of the numeric keys.
*/

// INCLUDE FILES
#include "cpcskeymap.h"
#include <QChar>
#include <QString>

#if defined(USE_ORBIT_KEYMAP)
#include <hbinputkeymap.h>
#include <hbinputkeymapfactory.h>
#endif // #if defined(USE_ORBIT_KEYMAP)

// This macro suppresses log writes
//#define NO_PRED_SEARCH_LOGS
#include "predictivesearchlog.h"

const QChar KSpaceChar = ' ';

// Separator character stored in predictive search table columns
const QChar KSeparatorChar = ' ';

// ============================== MEMBER FUNCTIONS ============================

// ----------------------------------------------------------------------------
// CPcsKeyMap::~CPcsKeyMap
// ----------------------------------------------------------------------------
CPcsKeyMap::~CPcsKeyMap()
    {
    PRINT(_L("Enter CPcsKeyMap::~CPcsKeyMap"));
    PRINT(_L("End CPcsKeyMap::~CPcsKeyMap"));
    }

// ----------------------------------------------------------------------------
// CPcsKeyMap::GetMappedStringL
// ----------------------------------------------------------------------------
HBufC* CPcsKeyMap::GetMappedStringL(const TDesC& aSource) const
    {
    PRINT1(_L("Enter CPcsKeyMap::GetMappedStringL input '%S'"), &aSource);

	QString source((QChar*)aSource.Ptr(), aSource.Length());
	QString result;
	TInt err(KErrNone);
	QT_TRYCATCH_ERROR(err, result = GetMappedString(source));
	User::LeaveIfError(err);

    HBufC* destination = HBufC::NewL(result.length());
	destination->Des().Copy(result.utf16());

    PRINT1(_L("End CPcsKeyMap::GetMappedStringL result '%S'"), destination);
    return destination;
    }

// ----------------------------------------------------------------------------
// CPcsKeyMap::GetMappedString
// ----------------------------------------------------------------------------
QString CPcsKeyMap::GetMappedString(QString aSource) const
	{
#if defined(WRITE_PRED_SEARCH_LOGS)
	const int KLogLength = 30;
	TBuf<KLogLength> log(aSource.left(KLogLength).utf16());
	PRINT1(_L("Enter CPcsKeyMap::GetMappedString input '%S'"), &log);
#endif

	QString destination;
	TBool skipHashStar = DetermineSpecialCharBehaviour(aSource);
	TInt length = aSource.length();

    for (int i = 0; i < length; ++i)
        {
        if (aSource[i] == KSpaceChar)
            {
            destination.append(KSeparatorChar);
            }
        else
			{
			QChar ch(0);
#if defined(USE_ORBIT_KEYMAP)
            ch = MappedKeyForChar(aSource[i]);
#else
            ch = UseHardcodedKeyMap(aSource[i]);
#endif
			if (!ShouldSkipChar(ch, skipHashStar))
				{
				destination.append(ch);
				}
			}
		}
#if defined(WRITE_PRED_SEARCH_LOGS)
	log = destination.left(KLogLength).utf16();
	PRINT1(_L("End CPcsKeyMap::GetMappedString result '%S'"), &log);
#endif
    return destination;
	}

// ----------------------------------------------------------------------------
// CPcsKeyMap::GetNumericLimitsL
// In order to speed up the execution, caller should convert search pattern
// with a one call to CPcsKeyMap::GetMappedStringL() and then pass the tokens
// to CPcsKeyMap::GetNumericLimitsL().
// So it is expected that aString contains only certain characters.
// ----------------------------------------------------------------------------
TInt CPcsKeyMap::GetNumericLimits(QString aString,
								  QString& aLowerLimit,
								  QString& aUpperLimit) const
	{
	PRINT(_L("CPcsKeyMap::GetNumericLimits"));
	if (aString.length() > iMaxKeysStoredInDb)
		{
		QString truncated = aString.left(iMaxKeysStoredInDb);
		aString = truncated;
		}

	TInt err = ComputeValue(aString, EFalse, aLowerLimit);
	if (err == KErrNone)
		{
		err = ComputeValue(aString, ETrue, aUpperLimit);
		}
	PRINT1(_L("End CPcsKeyMap::GetNumericLimits ret=%d"), err);
	return err;
	}

#if defined(USE_ORBIT_KEYMAP)
// ----------------------------------------------------------------------------
// CPcsKeyMap::Separator
// ----------------------------------------------------------------------------
QChar CPcsKeyMap::Separator() const
    {
    return KSeparatorChar;
    }

// ----------------------------------------------------------------------------
// CPcsKeyMap::SetHardcodedCharacters
// Default implementation selects only the current default language.
// ----------------------------------------------------------------------------
QList<HbInputLanguage> CPcsKeyMap::SelectLanguages()
	{
	QList<HbInputLanguage> languages;
	HbInputLanguage inputLanguage(QLocale::system().language());
	languages << inputLanguage;
	return languages;
	}

// ----------------------------------------------------------------------------
// CPcsKeyMap::SetHardcodedCharacters
// Default implementation does nothing
// ----------------------------------------------------------------------------
void CPcsKeyMap::SetHardcodedCharacters()
	{
	}
#endif // #if defined(USE_ORBIT_KEYMAP)

// ----------------------------------------------------------------------------
// CPcsKeyMap::DetermineSpecialCharBehaviour
// Default implementation
// ----------------------------------------------------------------------------
TBool CPcsKeyMap::DetermineSpecialCharBehaviour(QString /*aSource*/) const
	{
	return EFalse;
	}

// ----------------------------------------------------------------------------
// CPcsKeyMap::ShouldSkipChar
// Default implementation
// ----------------------------------------------------------------------------
TBool CPcsKeyMap::ShouldSkipChar(QChar /*aChar*/, TBool /*aSkipHashStar*/) const
	{
	return EFalse;
	}

// ----------------------------------------------------------------------------
// CPcsKeyMap::ConstructL
// ----------------------------------------------------------------------------
#if defined(USE_ORBIT_KEYMAP)
void CPcsKeyMap::ConstructL(HbKeyboardType aKeyboardType)
#else
void CPcsKeyMap::ConstructL()
#endif
	{
	PRINT(_L("Enter CPcsKeyMap::ConstructL"));

#if defined(USE_ORBIT_KEYMAP)
	TInt err(KErrNone);
	QT_TRYCATCH_ERROR(err,
		{
		InitKeyMappings();
		SetHardcodedCharacters();
		ConstructLanguageMappings(aKeyboardType);
		});
	if (err != KErrNone)
        {
        PRINT1(_L("CPcsKeyMap::ConstructL exception, err=%d"), err);
        User::Leave(err);
        }
#endif

	PRINT(_L("End CPcsKeyMap::ConstructL"));
	}

// ----------------------------------------------------------------------------
// CPcsKeyMap::CPcsKeyMap
// ----------------------------------------------------------------------------
#if defined(USE_ORBIT_KEYMAP)
CPcsKeyMap::CPcsKeyMap(TInt aAmountOfKeys,
					   QChar aPadChar,
					   TInt aMaxKeysStoredInDb) :
	iKeyMapping(),
	iAmountOfKeys(aAmountOfKeys),
	iPadChar(aPadChar),
	iMaxKeysStoredInDb(aMaxKeysStoredInDb)
	{
	}
#else // #if defined(USE_ORBIT_KEYMAP)
CPcsKeyMap::CPcsKeyMap(TInt /*aAmountOfKeys*/,
					   QChar /*aPadChar*/,
					   TInt aMaxKeysStoredInDb) :
	iMaxKeysStoredInDb(aMaxKeysStoredInDb)
	{
	}
#endif // #if defined(USE_ORBIT_KEYMAP)

#if defined(USE_ORBIT_KEYMAP)
// ----------------------------------------------------------------------------
// CPcsKeyMap::InitKeyMappings
// Put string for each key into iKeyMapping.
// ----------------------------------------------------------------------------
void CPcsKeyMap::InitKeyMappings()
	{
    PRINT(_L("Enter CPcsKeyMap::InitKeyMappings"));

	for (TInt i = 0; i < iAmountOfKeys; ++i)
        {
        iKeyMapping << QString("");
        }
	}

// ----------------------------------------------------------------------------
// CPcsKeyMap::ConstructLanguageMappings
// Fetch keymap for selected languages.
// Currently QWERTY keymaps do not map digits ('0'..'9') to any key, even with
// HbModifierChrPressed and HbModifierFnPressed modifiers.
// ----------------------------------------------------------------------------
void CPcsKeyMap::ConstructLanguageMappings(HbKeyboardType aKeyboardType)
	{
    PRINT(_L("Enter CPcsKeyMap::ConstructLanguageMappings"));

#if defined(WRITE_PRED_SEARCH_LOGS)
    TInt count(0);
#endif

	QList<HbInputLanguage> languages = SelectLanguages();
    PRINT1(_L("build keymap from %d language(s)"), languages.count());

	TInt languageCount = languages.size();
	for (TInt lang = 0; lang < languageCount; ++lang)
		{
        PRINT2(_L("(%d) handle language %d"), lang, languages[lang].language());
		if (IsLanguageSupported(languages[lang].language()))
			{
			PRINT2(_L("Constructing keymap for lang=%d,var=%d"),
				   languages[lang].language(),
				   languages[lang].variant());
			// Gets ownership of keymap
			const HbKeymap* keymap =
			    HbKeymapFactory::instance()->keymap(languages[lang],
                                                    HbKeymapFactory::NoCaching);
			if (keymap)
			    {
#if defined(WRITE_PRED_SEARCH_LOGS)
                count +=
#endif
                ReadKeymapCharacters(aKeyboardType, *keymap);
				delete keymap;
			    }
			else
                {
                PRINT(_L("CPcsKeyMap::ContructKeyboardMapping keymap not found"));
                }
			}
		}

#if defined(WRITE_PRED_SEARCH_LOGS)
    PRINT1(_L("End CPcsKeyMap::ConstructLanguageMappings keymap has %d chars"), count);
#endif
	}

// ----------------------------------------------------------------------------
// CPcsKeyMap::IsLanguageSupported
// ----------------------------------------------------------------------------
TBool CPcsKeyMap::IsLanguageSupported(QLocale::Language aLanguage) const
	{
	return (aLanguage != QLocale::Japanese && aLanguage != QLocale::Chinese);
	}

// ----------------------------------------------------------------------------
// CPcsKeyMap::MappedKeyForChar
// Loop all QStrings of iKeyMapping to find one containing the character.
// If the character is not mapped, use pad character.
// ----------------------------------------------------------------------------
const QChar CPcsKeyMap::MappedKeyForChar(const QChar aChar) const
	{
    for (TInt index = 0; index < iAmountOfKeys; ++index)
        {
        if (iKeyMapping[index].contains(aChar))
            {
			return ArrayIndexToMappedChar(index);
            }
        }

#if _DEBUG
	TUint ch = aChar.unicode();
	PRINT2(_L("CPcsKeyMap::MappedKeyForChar no mapping for char '%c' (0x%x)"),
		   ch, ch);
#endif
	return iPadChar;
    }

// ----------------------------------------------------------------------------
// CPcsKeyMap::ReadKeymapCharacters
// ----------------------------------------------------------------------------
TInt CPcsKeyMap::ReadKeymapCharacters(HbKeyboardType aKeyboardType,
                                      const HbKeymap& aKeymap)
    {
    PRINT(_L("Enter CPcsKeyMap::ReadKeymapCharacters"));

    TInt count(0);

    for (TInt key = 0; key < iAmountOfKeys; ++key)
        {
        PRINT1(_L("handle key(enum value %d)"), key); // test
        const HbMappedKey* mappedKey = aKeymap.keyForIndex(aKeyboardType, key);
        // 12-key: Most languages don't have mapping for EKeyStar, EKeyHash.
        // QWERTY: Different languages have different amount of keys,
        // so mappedKey can be NULL.
        if (mappedKey)
            {
            const QString lowerCase = mappedKey->characters(HbModifierNone); // "abc2.."
            const QString upperCase = mappedKey->characters(HbModifierShiftPressed); // "ABC2.."
            const QString charsForKey = lowerCase + upperCase;

            // Filter out duplicate characters
            for (TInt i = charsForKey.length() - 1; i >= 0 ; --i)
                {
                QChar ch = charsForKey[i];
                if (!iKeyMapping[key].contains(ch) &&
                    !iHardcodedChars.contains(ch))
                    {
#if defined(WRITE_PRED_SEARCH_LOGS)
                    char ascChar = ch.toAscii();
                    TChar logChar(ArrayIndexToMappedChar(key).unicode());

                    if (ascChar == 0) // ch can't be represented in ASCII
                        {
                        PRINT2(_L("CPcsKeyMap: map key(%c) <-> char=0x%x"),
                               logChar, ch);
                        }
                    else
                        {
                        PRINT3(_L("CPcsKeyMap: map key(%c) <-> char='%c'(0x%x)"),
                               logChar,
                               ascChar,
                               ascChar);
                        }
                    ++count;
#endif // #if defined(WRITE_PRED_SEARCH_LOGS)
                    iKeyMapping[key] += ch;
                    }
                }
            }
        }

    PRINT(_L("End CPcsKeyMap::ReadKeymapCharacters"));
    return count;
    }
#endif // #if defined(USE_ORBIT_KEYMAP)

// End of file
<commit_msg>Revert using old Orbit API, so allow compilation on pre-wk32 environment<commit_after>/*
* Copyright (c) 2010 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: Retrieves the character map for each of the numeric keys.
*/

// INCLUDE FILES
#include "cpcskeymap.h"
#include <QChar>
#include <QString>

#if defined(USE_ORBIT_KEYMAP)
#include <hbinputkeymap.h>
#include <hbinputkeymapfactory.h>
#endif // #if defined(USE_ORBIT_KEYMAP)

// This macro suppresses log writes
//#define NO_PRED_SEARCH_LOGS
#include "predictivesearchlog.h"

const QChar KSpaceChar = ' ';

// Separator character stored in predictive search table columns
const QChar KSeparatorChar = ' ';

// Code using the new API (wk32 onwards) is put here. Remove old API code
// when wk30 is no longer used.
// #define NEW_KEYMAP_FACTORY_API

// ============================== MEMBER FUNCTIONS ============================

// ----------------------------------------------------------------------------
// CPcsKeyMap::~CPcsKeyMap
// ----------------------------------------------------------------------------
CPcsKeyMap::~CPcsKeyMap()
    {
    PRINT(_L("Enter CPcsKeyMap::~CPcsKeyMap"));
    PRINT(_L("End CPcsKeyMap::~CPcsKeyMap"));
    }

// ----------------------------------------------------------------------------
// CPcsKeyMap::GetMappedStringL
// ----------------------------------------------------------------------------
HBufC* CPcsKeyMap::GetMappedStringL(const TDesC& aSource) const
    {
    PRINT1(_L("Enter CPcsKeyMap::GetMappedStringL input '%S'"), &aSource);

	QString source((QChar*)aSource.Ptr(), aSource.Length());
	QString result;
	TInt err(KErrNone);
	QT_TRYCATCH_ERROR(err, result = GetMappedString(source));
	User::LeaveIfError(err);

    HBufC* destination = HBufC::NewL(result.length());
	destination->Des().Copy(result.utf16());

    PRINT1(_L("End CPcsKeyMap::GetMappedStringL result '%S'"), destination);
    return destination;
    }

// ----------------------------------------------------------------------------
// CPcsKeyMap::GetMappedString
// ----------------------------------------------------------------------------
QString CPcsKeyMap::GetMappedString(QString aSource) const
	{
#if defined(WRITE_PRED_SEARCH_LOGS)
	const int KLogLength = 30;
	TBuf<KLogLength> log(aSource.left(KLogLength).utf16());
	PRINT1(_L("Enter CPcsKeyMap::GetMappedString input '%S'"), &log);
#endif

	QString destination;
	TBool skipHashStar = DetermineSpecialCharBehaviour(aSource);
	TInt length = aSource.length();

    for (int i = 0; i < length; ++i)
        {
        if (aSource[i] == KSpaceChar)
            {
            destination.append(KSeparatorChar);
            }
        else
			{
			QChar ch(0);
#if defined(USE_ORBIT_KEYMAP)
            ch = MappedKeyForChar(aSource[i]);
#else
            ch = UseHardcodedKeyMap(aSource[i]);
#endif
			if (!ShouldSkipChar(ch, skipHashStar))
				{
				destination.append(ch);
				}
			}
		}
#if defined(WRITE_PRED_SEARCH_LOGS)
	log = destination.left(KLogLength).utf16();
	PRINT1(_L("End CPcsKeyMap::GetMappedString result '%S'"), &log);
#endif
    return destination;
	}

// ----------------------------------------------------------------------------
// CPcsKeyMap::GetNumericLimitsL
// In order to speed up the execution, caller should convert search pattern
// with a one call to CPcsKeyMap::GetMappedStringL() and then pass the tokens
// to CPcsKeyMap::GetNumericLimitsL().
// So it is expected that aString contains only certain characters.
// ----------------------------------------------------------------------------
TInt CPcsKeyMap::GetNumericLimits(QString aString,
								  QString& aLowerLimit,
								  QString& aUpperLimit) const
	{
	PRINT(_L("CPcsKeyMap::GetNumericLimits"));
	if (aString.length() > iMaxKeysStoredInDb)
		{
		QString truncated = aString.left(iMaxKeysStoredInDb);
		aString = truncated;
		}

	TInt err = ComputeValue(aString, EFalse, aLowerLimit);
	if (err == KErrNone)
		{
		err = ComputeValue(aString, ETrue, aUpperLimit);
		}
	PRINT1(_L("End CPcsKeyMap::GetNumericLimits ret=%d"), err);
	return err;
	}

#if defined(USE_ORBIT_KEYMAP)
// ----------------------------------------------------------------------------
// CPcsKeyMap::Separator
// ----------------------------------------------------------------------------
QChar CPcsKeyMap::Separator() const
    {
    return KSeparatorChar;
    }

// ----------------------------------------------------------------------------
// CPcsKeyMap::SetHardcodedCharacters
// Default implementation selects only the current default language.
// ----------------------------------------------------------------------------
QList<HbInputLanguage> CPcsKeyMap::SelectLanguages()
	{
	QList<HbInputLanguage> languages;
	HbInputLanguage inputLanguage(QLocale::system().language());
	languages << inputLanguage;
	return languages;
	}

// ----------------------------------------------------------------------------
// CPcsKeyMap::SetHardcodedCharacters
// Default implementation does nothing
// ----------------------------------------------------------------------------
void CPcsKeyMap::SetHardcodedCharacters()
	{
	}
#endif // #if defined(USE_ORBIT_KEYMAP)

// ----------------------------------------------------------------------------
// CPcsKeyMap::DetermineSpecialCharBehaviour
// Default implementation
// ----------------------------------------------------------------------------
TBool CPcsKeyMap::DetermineSpecialCharBehaviour(QString /*aSource*/) const
	{
	return EFalse;
	}

// ----------------------------------------------------------------------------
// CPcsKeyMap::ShouldSkipChar
// Default implementation
// ----------------------------------------------------------------------------
TBool CPcsKeyMap::ShouldSkipChar(QChar /*aChar*/, TBool /*aSkipHashStar*/) const
	{
	return EFalse;
	}

// ----------------------------------------------------------------------------
// CPcsKeyMap::ConstructL
// ----------------------------------------------------------------------------
#if defined(USE_ORBIT_KEYMAP)
void CPcsKeyMap::ConstructL(HbKeyboardType aKeyboardType)
#else
void CPcsKeyMap::ConstructL()
#endif
	{
	PRINT(_L("Enter CPcsKeyMap::ConstructL"));

#if defined(USE_ORBIT_KEYMAP)
	TInt err(KErrNone);
	QT_TRYCATCH_ERROR(err,
		{
		InitKeyMappings();
		SetHardcodedCharacters();
		ConstructLanguageMappings(aKeyboardType);
		});
	if (err != KErrNone)
        {
        PRINT1(_L("CPcsKeyMap::ConstructL exception, err=%d"), err);
        User::Leave(err);
        }
#endif

	PRINT(_L("End CPcsKeyMap::ConstructL"));
	}

// ----------------------------------------------------------------------------
// CPcsKeyMap::CPcsKeyMap
// ----------------------------------------------------------------------------
#if defined(USE_ORBIT_KEYMAP)
CPcsKeyMap::CPcsKeyMap(TInt aAmountOfKeys,
					   QChar aPadChar,
					   TInt aMaxKeysStoredInDb) :
	iKeyMapping(),
	iAmountOfKeys(aAmountOfKeys),
	iPadChar(aPadChar),
	iMaxKeysStoredInDb(aMaxKeysStoredInDb)
	{
	}
#else // #if defined(USE_ORBIT_KEYMAP)
CPcsKeyMap::CPcsKeyMap(TInt /*aAmountOfKeys*/,
					   QChar /*aPadChar*/,
					   TInt aMaxKeysStoredInDb) :
	iMaxKeysStoredInDb(aMaxKeysStoredInDb)
	{
	}
#endif // #if defined(USE_ORBIT_KEYMAP)

#if defined(USE_ORBIT_KEYMAP)
// ----------------------------------------------------------------------------
// CPcsKeyMap::InitKeyMappings
// Put string for each key into iKeyMapping.
// ----------------------------------------------------------------------------
void CPcsKeyMap::InitKeyMappings()
	{
    PRINT(_L("Enter CPcsKeyMap::InitKeyMappings"));

	for (TInt i = 0; i < iAmountOfKeys; ++i)
        {
        iKeyMapping << QString("");
        }
	}

// ----------------------------------------------------------------------------
// CPcsKeyMap::ConstructLanguageMappings
// Fetch keymap for selected languages.
// Currently QWERTY keymaps do not map digits ('0'..'9') to any key, even with
// HbModifierChrPressed and HbModifierFnPressed modifiers.
// ----------------------------------------------------------------------------
void CPcsKeyMap::ConstructLanguageMappings(HbKeyboardType aKeyboardType)
	{
    PRINT(_L("Enter CPcsKeyMap::ConstructLanguageMappings"));

#if defined(WRITE_PRED_SEARCH_LOGS)
    TInt count(0);
#endif

	QList<HbInputLanguage> languages = SelectLanguages();
    PRINT1(_L("build keymap from %d language(s)"), languages.count());

	TInt languageCount = languages.size();
#if !defined(NEW_KEYMAP_FACTORY_API)
	// Latest SDKs have so many keymaps contact server runs out of stack.
	// So limit the amount of keymaps.
	const TInt KMaxKeymapCount = 10;
	if (languageCount > KMaxKeymapCount)
	    {
        languageCount = KMaxKeymapCount;
	    }
#endif

	for (TInt lang = 0; lang < languageCount; ++lang)
		{
        PRINT2(_L("(%d) handle language %d"), lang, languages[lang].language());
		if (IsLanguageSupported(languages[lang].language()))
			{
			PRINT2(_L("Constructing keymap for lang=%d,var=%d"),
				   languages[lang].language(),
				   languages[lang].variant());
#if defined(NEW_KEYMAP_FACTORY_API)
			// Gets ownership of keymap
			const HbKeymap* keymap =
			    HbKeymapFactory::instance()->keymap(languages[lang],
                                                    HbKeymapFactory::NoCaching);
#else
			// Does not get ownership of keymap
			const HbKeymap* keymap =
				HbKeymapFactory::instance()->keymap(languages[lang].language(),
                                                    languages[lang].variant());
#endif
			if (keymap)
			    {
#if defined(WRITE_PRED_SEARCH_LOGS)
                count +=
#endif
                ReadKeymapCharacters(aKeyboardType, *keymap);

#if defined(NEW_KEYMAP_FACTORY_API)
				delete keymap;
#endif
			    }
			else
                {
                PRINT(_L("CPcsKeyMap::ContructKeyboardMapping keymap not found"));
                }
			}
		}

#if defined(WRITE_PRED_SEARCH_LOGS)
    PRINT1(_L("End CPcsKeyMap::ConstructLanguageMappings keymap has %d chars"), count);
#endif
	}

// ----------------------------------------------------------------------------
// CPcsKeyMap::IsLanguageSupported
// ----------------------------------------------------------------------------
TBool CPcsKeyMap::IsLanguageSupported(QLocale::Language aLanguage) const
	{
	return (aLanguage != QLocale::Japanese && aLanguage != QLocale::Chinese);
	}

// ----------------------------------------------------------------------------
// CPcsKeyMap::MappedKeyForChar
// Loop all QStrings of iKeyMapping to find one containing the character.
// If the character is not mapped, use pad character.
// ----------------------------------------------------------------------------
const QChar CPcsKeyMap::MappedKeyForChar(const QChar aChar) const
	{
    for (TInt index = 0; index < iAmountOfKeys; ++index)
        {
        if (iKeyMapping[index].contains(aChar))
            {
			return ArrayIndexToMappedChar(index);
            }
        }

#if _DEBUG
	TUint ch = aChar.unicode();
	PRINT2(_L("CPcsKeyMap::MappedKeyForChar no mapping for char '%c' (0x%x)"),
		   ch, ch);
#endif
	return iPadChar;
    }

// ----------------------------------------------------------------------------
// CPcsKeyMap::ReadKeymapCharacters
// ----------------------------------------------------------------------------
TInt CPcsKeyMap::ReadKeymapCharacters(HbKeyboardType aKeyboardType,
                                      const HbKeymap& aKeymap)
    {
    PRINT(_L("Enter CPcsKeyMap::ReadKeymapCharacters"));

    TInt count(0);

    for (TInt key = 0; key < iAmountOfKeys; ++key)
        {
        PRINT1(_L("handle key(enum value %d)"), key); // test
        const HbMappedKey* mappedKey = aKeymap.keyForIndex(aKeyboardType, key);
        // 12-key: Most languages don't have mapping for EKeyStar, EKeyHash.
        // QWERTY: Different languages have different amount of keys,
        // so mappedKey can be NULL.
        if (mappedKey)
            {
            const QString lowerCase = mappedKey->characters(HbModifierNone); // "abc2.."
            const QString upperCase = mappedKey->characters(HbModifierShiftPressed); // "ABC2.."
            const QString charsForKey = lowerCase + upperCase;

            // Filter out duplicate characters
            for (TInt i = charsForKey.length() - 1; i >= 0 ; --i)
                {
                QChar ch = charsForKey[i];
                if (!iKeyMapping[key].contains(ch) &&
                    !iHardcodedChars.contains(ch))
                    {
#if defined(WRITE_PRED_SEARCH_LOGS)
                    char ascChar = ch.toAscii();
                    TChar logChar(ArrayIndexToMappedChar(key).unicode());

                    if (ascChar == 0) // ch can't be represented in ASCII
                        {
                        PRINT2(_L("CPcsKeyMap: map key(%c) <-> char=0x%x"),
                               logChar, ch);
                        }
                    else
                        {
                        PRINT3(_L("CPcsKeyMap: map key(%c) <-> char='%c'(0x%x)"),
                               logChar,
                               ascChar,
                               ascChar);
                        }
                    ++count;
#endif // #if defined(WRITE_PRED_SEARCH_LOGS)
                    iKeyMapping[key] += ch;
                    }
                }
            }
        }

    PRINT(_L("End CPcsKeyMap::ReadKeymapCharacters"));
    return count;
    }
#endif // #if defined(USE_ORBIT_KEYMAP)

// End of file
<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * Licensed 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
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <thrift/conformance/cpp2/AnyRegistry.h>

#include <folly/io/Cursor.h>
#include <thrift/conformance/cpp2/Any.h>

namespace apache::thrift::conformance {

bool AnyRegistry::registerType(const std::type_info& typeInfo, AnyType type) {
  return registerTypeImpl(typeInfo, std::move(type)) != nullptr;
}

bool AnyRegistry::registerSerializer(
    const std::type_info& type,
    const AnySerializer* serializer) {
  return registerSerializerImpl(
      serializer, &registry_.at(std::type_index(type)));
}

bool AnyRegistry::registerSerializer(
    const std::type_info& type,
    std::unique_ptr<AnySerializer> serializer) {
  return registerSerializerImpl(
      std::move(serializer), &registry_.at(std::type_index(type)));
}

std::string_view AnyRegistry::getTypeName(const std::type_info& type) const {
  const auto* entry = getTypeEntry(type);
  if (entry == nullptr) {
    return {};
  }
  return entry->type.get_name();
}

const AnySerializer* AnyRegistry::getSerializer(
    const std::type_info& type,
    const Protocol& protocol) const {
  return getSerializer(getTypeEntry(type), protocol);
}

const AnySerializer* AnyRegistry::getSerializer(
    std::string_view name,
    const Protocol& protocol) const {
  return getSerializer(getTypeEntry(name), protocol);
}

Any AnyRegistry::store(any_ref value, const Protocol& protocol) const {
  if (value.type() == typeid(Any)) {
    // Use the Any specific overload.
    return store(any_cast<const Any&>(value), protocol);
  }

  const auto* entry = getTypeEntry(value.type());
  const auto* serializer = getSerializer(entry, protocol);
  if (serializer == nullptr) {
    folly::throw_exception<std::bad_any_cast>();
  }

  folly::IOBufQueue queue(folly::IOBufQueue::cacheChainLength());
  // Allocate 16KB at a time; leave some room for the IOBuf overhead
  constexpr size_t kDesiredGrowth = (1 << 14) - 64;
  serializer->encode(value, folly::io::QueueAppender(&queue, kDesiredGrowth));

  Any result;
  result.set_type(entry->type.get_name());
  if (protocol.isCustom()) {
    result.customProtocol_ref() = protocol.custom();
  } else {
    result.protocol_ref() = protocol.standard();
  }
  result.data_ref() = queue.moveAsValue();
  return result;
}

Any AnyRegistry::store(const Any& value, const Protocol& protocol) const {
  if (hasProtocol(value, protocol)) {
    return value;
  }
  return store(load(value), protocol);
}

void AnyRegistry::load(const Any& value, any_ref out) const {
  // TODO(afuller): Add support for type_id.
  if (!value.type_ref().has_value()) {
    folly::throw_exception<std::bad_any_cast>();
  }
  const auto* entry = getTypeEntry(*value.type_ref());
  const auto* serializer = getSerializer(entry, getProtocol(value));
  if (serializer == nullptr) {
    folly::throw_exception<std::bad_any_cast>();
  }
  folly::io::Cursor cursor(&*value.data_ref());
  serializer->decode(entry->typeInfo, cursor, out);
}

std::any AnyRegistry::load(const Any& value) const {
  std::any out;
  load(value, out);
  return out;
}

auto AnyRegistry::registerTypeImpl(const std::type_info& typeInfo, AnyType type)
    -> TypeEntry* {
  if (!checkNameAvailability(type)) {
    return nullptr;
  }

  auto result = registry_.emplace(
      std::type_index(typeInfo), TypeEntry(typeInfo, std::move(type)));
  if (!result.second) {
    return nullptr;
  }

  indexType(&result.first->second);
  return &result.first->second;
}

bool AnyRegistry::registerSerializerImpl(
    const AnySerializer* serializer,
    TypeEntry* entry) {
  if (serializer == nullptr) {
    return false;
  }
  return entry->serializers.emplace(serializer->getProtocol(), serializer)
      .second;
}

bool AnyRegistry::registerSerializerImpl(
    std::unique_ptr<AnySerializer> serializer,
    TypeEntry* entry) {
  if (!registerSerializerImpl(serializer.get(), entry)) {
    return false;
  }
  ownedSerializers_.emplace_front(std::move(serializer));
  return true;
}

bool AnyRegistry::checkNameAvailability(std::string_view name) const {
  return !name.empty() && !nameIndex_.contains(name);
}

bool AnyRegistry::checkNameAvailability(const AnyType& type) const {
  // Ensure name and all aliases are availabile.
  if (!checkNameAvailability(*type.name_ref())) {
    return false;
  }
  for (const auto& alias : *type.aliases_ref()) {
    if (!checkNameAvailability(alias)) {
      return false;
    }
  }
  return true;
}

void AnyRegistry::indexName(std::string_view name, TypeEntry* entry) {
  auto res = nameIndex_.emplace(name, entry);
  assert(res.second);
  // TODO(afuller): Also index under typeId.
}

void AnyRegistry::indexType(TypeEntry* entry) {
  indexName(*entry->type.name_ref(), entry);
  for (const auto& alias : *entry->type.aliases_ref()) {
    indexName(alias, entry);
  }
}

auto AnyRegistry::getTypeEntry(std::string_view name) const
    -> const TypeEntry* {
  auto itr = nameIndex_.find(name);
  if (itr == nameIndex_.end()) {
    return nullptr;
  }
  return itr->second;
}

auto AnyRegistry::getTypeEntry(const std::type_index& index) const
    -> const TypeEntry* {
  auto itr = registry_.find(index);
  if (itr == registry_.end()) {
    return nullptr;
  }
  return &itr->second;
}

const AnySerializer* AnyRegistry::getSerializer(
    const TypeEntry* entry,
    const Protocol& protocol) const {
  if (entry == nullptr) {
    return nullptr;
  }

  auto itr = entry->serializers.find(protocol);
  if (itr == entry->serializers.end()) {
    return nullptr;
  }
  return itr->second;
}

} // namespace apache::thrift::conformance
<commit_msg>Fix @mode/opt compile bug<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * Licensed 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
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <thrift/conformance/cpp2/AnyRegistry.h>

#include <folly/CppAttributes.h>
#include <folly/io/Cursor.h>
#include <thrift/conformance/cpp2/Any.h>

namespace apache::thrift::conformance {

bool AnyRegistry::registerType(const std::type_info& typeInfo, AnyType type) {
  return registerTypeImpl(typeInfo, std::move(type)) != nullptr;
}

bool AnyRegistry::registerSerializer(
    const std::type_info& type,
    const AnySerializer* serializer) {
  return registerSerializerImpl(
      serializer, &registry_.at(std::type_index(type)));
}

bool AnyRegistry::registerSerializer(
    const std::type_info& type,
    std::unique_ptr<AnySerializer> serializer) {
  return registerSerializerImpl(
      std::move(serializer), &registry_.at(std::type_index(type)));
}

std::string_view AnyRegistry::getTypeName(const std::type_info& type) const {
  const auto* entry = getTypeEntry(type);
  if (entry == nullptr) {
    return {};
  }
  return entry->type.get_name();
}

const AnySerializer* AnyRegistry::getSerializer(
    const std::type_info& type,
    const Protocol& protocol) const {
  return getSerializer(getTypeEntry(type), protocol);
}

const AnySerializer* AnyRegistry::getSerializer(
    std::string_view name,
    const Protocol& protocol) const {
  return getSerializer(getTypeEntry(name), protocol);
}

Any AnyRegistry::store(any_ref value, const Protocol& protocol) const {
  if (value.type() == typeid(Any)) {
    // Use the Any specific overload.
    return store(any_cast<const Any&>(value), protocol);
  }

  const auto* entry = getTypeEntry(value.type());
  const auto* serializer = getSerializer(entry, protocol);
  if (serializer == nullptr) {
    folly::throw_exception<std::bad_any_cast>();
  }

  folly::IOBufQueue queue(folly::IOBufQueue::cacheChainLength());
  // Allocate 16KB at a time; leave some room for the IOBuf overhead
  constexpr size_t kDesiredGrowth = (1 << 14) - 64;
  serializer->encode(value, folly::io::QueueAppender(&queue, kDesiredGrowth));

  Any result;
  result.set_type(entry->type.get_name());
  if (protocol.isCustom()) {
    result.customProtocol_ref() = protocol.custom();
  } else {
    result.protocol_ref() = protocol.standard();
  }
  result.data_ref() = queue.moveAsValue();
  return result;
}

Any AnyRegistry::store(const Any& value, const Protocol& protocol) const {
  if (hasProtocol(value, protocol)) {
    return value;
  }
  return store(load(value), protocol);
}

void AnyRegistry::load(const Any& value, any_ref out) const {
  // TODO(afuller): Add support for type_id.
  if (!value.type_ref().has_value()) {
    folly::throw_exception<std::bad_any_cast>();
  }
  const auto* entry = getTypeEntry(*value.type_ref());
  const auto* serializer = getSerializer(entry, getProtocol(value));
  if (serializer == nullptr) {
    folly::throw_exception<std::bad_any_cast>();
  }
  folly::io::Cursor cursor(&*value.data_ref());
  serializer->decode(entry->typeInfo, cursor, out);
}

std::any AnyRegistry::load(const Any& value) const {
  std::any out;
  load(value, out);
  return out;
}

auto AnyRegistry::registerTypeImpl(const std::type_info& typeInfo, AnyType type)
    -> TypeEntry* {
  if (!checkNameAvailability(type)) {
    return nullptr;
  }

  auto result = registry_.emplace(
      std::type_index(typeInfo), TypeEntry(typeInfo, std::move(type)));
  if (!result.second) {
    return nullptr;
  }

  indexType(&result.first->second);
  return &result.first->second;
}

bool AnyRegistry::registerSerializerImpl(
    const AnySerializer* serializer,
    TypeEntry* entry) {
  if (serializer == nullptr) {
    return false;
  }
  return entry->serializers.emplace(serializer->getProtocol(), serializer)
      .second;
}

bool AnyRegistry::registerSerializerImpl(
    std::unique_ptr<AnySerializer> serializer,
    TypeEntry* entry) {
  if (!registerSerializerImpl(serializer.get(), entry)) {
    return false;
  }
  ownedSerializers_.emplace_front(std::move(serializer));
  return true;
}

bool AnyRegistry::checkNameAvailability(std::string_view name) const {
  return !name.empty() && !nameIndex_.contains(name);
}

bool AnyRegistry::checkNameAvailability(const AnyType& type) const {
  // Ensure name and all aliases are availabile.
  if (!checkNameAvailability(*type.name_ref())) {
    return false;
  }
  for (const auto& alias : *type.aliases_ref()) {
    if (!checkNameAvailability(alias)) {
      return false;
    }
  }
  return true;
}

void AnyRegistry::indexName(std::string_view name, TypeEntry* entry) {
  FOLLY_MAYBE_UNUSED auto res = nameIndex_.emplace(name, entry);
  assert(res.second);
  // TODO(afuller): Also index under typeId.
}

void AnyRegistry::indexType(TypeEntry* entry) {
  indexName(*entry->type.name_ref(), entry);
  for (const auto& alias : *entry->type.aliases_ref()) {
    indexName(alias, entry);
  }
}

auto AnyRegistry::getTypeEntry(std::string_view name) const
    -> const TypeEntry* {
  auto itr = nameIndex_.find(name);
  if (itr == nameIndex_.end()) {
    return nullptr;
  }
  return itr->second;
}

auto AnyRegistry::getTypeEntry(const std::type_index& index) const
    -> const TypeEntry* {
  auto itr = registry_.find(index);
  if (itr == registry_.end()) {
    return nullptr;
  }
  return &itr->second;
}

const AnySerializer* AnyRegistry::getSerializer(
    const TypeEntry* entry,
    const Protocol& protocol) const {
  if (entry == nullptr) {
    return nullptr;
  }

  auto itr = entry->serializers.find(protocol);
  if (itr == entry->serializers.end()) {
    return nullptr;
  }
  return itr->second;
}

} // namespace apache::thrift::conformance
<|endoftext|>


<commit_before>/* -*- 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 <stdio.h>
#include <string.h>
#include <dlfcn.h>
#include <cxxabi.h>
#include <boost/unordered_map.hpp>

#include <rtl/strbuf.hxx>
#include <rtl/ustrbuf.hxx>
#include <osl/diagnose.h>
#include <osl/mutex.hxx>

#include <com/sun/star/uno/genfunc.hxx>
#include <typelib/typedescription.hxx>
#include <uno/any2.h>

#include "share.hxx"

using namespace ::std;
using namespace ::osl;
using namespace ::com::sun::star::uno;
using namespace ::__cxxabiv1;

namespace CPPU_CURRENT_NAMESPACE
{

void dummy_can_throw_anything( char const * )
{
}

static OUString toUNOname( char const * p )
{
#if defined BRIDGES_DEBUG
    char const * start = p;
#endif

    // example: N3com3sun4star4lang24IllegalArgumentExceptionE

    OUStringBuffer buf( 64 );
    OSL_ASSERT( 'N' == *p );
    ++p; // skip N

    while ('E' != *p)
    {
        // read chars count
        long n = (*p++ - '0');
        while ('0' <= *p && '9' >= *p)
        {
            n *= 10;
            n += (*p++ - '0');
        }
        buf.appendAscii( p, n );
        p += n;
        if ('E' != *p)
            buf.append( '.' );
    }

#if defined BRIDGES_DEBUG
    OUString ret( buf.makeStringAndClear() );
    OString c_ret( OUStringToOString( ret, RTL_TEXTENCODING_ASCII_US ) );
    fprintf( stderr, "> toUNOname(): %s => %s\n", start, c_ret.getStr() );
    return ret;
#else
    return buf.makeStringAndClear();
#endif
}

class RTTI
{
    typedef boost::unordered_map< OUString, type_info *, OUStringHash > t_rtti_map;

    Mutex m_mutex;
    t_rtti_map m_rttis;
    t_rtti_map m_generatedRttis;

    void * m_hApp;

public:
    RTTI();
    ~RTTI();

    type_info * getRTTI( typelib_CompoundTypeDescription * );
};

RTTI::RTTI()
    : m_hApp( dlopen( 0, RTLD_LAZY ) )
{
}

RTTI::~RTTI()
{
    dlclose( m_hApp );
}

type_info * RTTI::getRTTI( typelib_CompoundTypeDescription *pTypeDescr )
{
    type_info * rtti;

    OUString const & unoName = *(OUString const *)&pTypeDescr->aBase.pTypeName;

    MutexGuard guard( m_mutex );
    t_rtti_map::const_iterator iFind( m_rttis.find( unoName ) );
    if (iFind == m_rttis.end())
    {
        // RTTI symbol
        OStringBuffer buf( 64 );
        buf.append( "_ZTIN" );
        sal_Int32 index = 0;
        do
        {
            OUString token( unoName.getToken( 0, '.', index ) );
            buf.append( token.getLength() );
            OString c_token( OUStringToOString( token, RTL_TEXTENCODING_ASCII_US ) );
            buf.append( c_token );
        }
        while (index >= 0);
        buf.append( 'E' );

        OString symName( buf.makeStringAndClear() );
        rtti = (type_info *)dlsym( m_hApp, symName.getStr() );

        if (rtti)
        {
            pair< t_rtti_map::iterator, bool > insertion(
                m_rttis.insert( t_rtti_map::value_type( unoName, rtti ) ) );
            OSL_ENSURE( insertion.second, "### inserting new rtti failed?!" );
        }
        else
        {
            // try to lookup the symbol in the generated rtti map
            t_rtti_map::const_iterator iiFind( m_generatedRttis.find( unoName ) );
            if (iiFind == m_generatedRttis.end())
            {
                // we must generate it !
                // symbol and rtti-name is nearly identical,
                // the symbol is prefixed with _ZTI
                char const * rttiName = symName.getStr() +4;
#if defined BRIDGES_DEBUG
                fprintf( stderr,"generated rtti for %s\n", rttiName );
#endif
                if (pTypeDescr->pBaseTypeDescription)
                {
                    // ensure availability of base
                    type_info * base_rtti = getRTTI(
                        (typelib_CompoundTypeDescription *)pTypeDescr->pBaseTypeDescription );
                    rtti = new __si_class_type_info(
                        strdup( rttiName ), (__class_type_info *)base_rtti );
                }
                else
                {
                    // this class has no base class
                    rtti = new __class_type_info( strdup( rttiName ) );
                }

                pair< t_rtti_map::iterator, bool > insertion(
                    m_generatedRttis.insert( t_rtti_map::value_type( unoName, rtti ) ) );
                OSL_ENSURE( insertion.second, "### inserting new generated rtti failed?!" );
            }
            else // taking already generated rtti
            {
                rtti = iiFind->second;
            }
        }
    }
    else
    {
        rtti = iFind->second;
    }

    return rtti;
}

static void deleteException( void * pExc )
{
    __cxa_exception const * header = ((__cxa_exception const *)pExc - 1);
    typelib_TypeDescription * pTD = 0;
    OUString unoName( toUNOname( header->exceptionType->name() ) );
    ::typelib_typedescription_getByName( &pTD, unoName.pData );
    OSL_ENSURE( pTD, "### unknown exception type! leaving out destruction => leaking!!!" );
    if (pTD)
    {
        ::uno_destructData( pExc, pTD, cpp_release );
        ::typelib_typedescription_release( pTD );
    }
}

void raiseException( uno_Any * pUnoExc, uno_Mapping * pUno2Cpp )
{
#if defined BRIDGES_DEBUG
    OString cstr(
        OUStringToOString(
            *reinterpret_cast< OUString const * >( &pUnoExc->pType->pTypeName ),
            RTL_TEXTENCODING_ASCII_US ) );
    fprintf( stderr, "> uno exception occurred: %s\n", cstr.getStr() );
#endif
    void * pCppExc;
    type_info * rtti;

    {
    // construct cpp exception object
    typelib_TypeDescription * pTypeDescr = 0;
    TYPELIB_DANGER_GET( &pTypeDescr, pUnoExc->pType );
    OSL_ASSERT( pTypeDescr );
    if (! pTypeDescr)
    {
        throw RuntimeException(
            OUString("cannot get typedescription for type ") +
            *reinterpret_cast< OUString const * >( &pUnoExc->pType->pTypeName ) );
    }

    pCppExc = __cxa_allocate_exception( pTypeDescr->nSize );
    ::uno_copyAndConvertData( pCppExc, pUnoExc->pData, pTypeDescr, pUno2Cpp );

    // destruct uno exception
    ::uno_any_destruct( pUnoExc, 0 );
    // avoiding locked counts
    static RTTI * s_rtti = 0;
    if (! s_rtti)
    {
        MutexGuard guard( Mutex::getGlobalMutex() );
        if (! s_rtti)
        {
#ifdef LEAK_STATIC_DATA
            s_rtti = new RTTI();
#else
            static RTTI rtti_data;
            s_rtti = &rtti_data;
#endif
        }
    }
    rtti = (type_info *)s_rtti->getRTTI( (typelib_CompoundTypeDescription *) pTypeDescr );
    TYPELIB_DANGER_RELEASE( pTypeDescr );
    OSL_ENSURE( rtti, "### no rtti for throwing exception!" );
    if (! rtti)
    {
        throw RuntimeException(
            OUString("no rtti for type ") +
            *reinterpret_cast< OUString const * >( &pUnoExc->pType->pTypeName ),
             );
    }
    }

    __cxa_throw( pCppExc, rtti, deleteException );
}

void fillUnoException( __cxa_exception * header, uno_Any * pUnoExc, uno_Mapping * pCpp2Uno )
{
    if (! header)
    {
        RuntimeException aRE( "no exception header!" );
        Type const & rType = ::getCppuType( &aRE );
        uno_type_any_constructAndConvert( pUnoExc, &aRE, rType.getTypeLibType(), pCpp2Uno );
#if defined _DEBUG
        OString cstr( OUStringToOString( aRE.Message, RTL_TEXTENCODING_ASCII_US ) );
        OSL_FAIL( cstr.getStr() );
#endif
        return;
    }

    typelib_TypeDescription * pExcTypeDescr = 0;
    OUString unoName( toUNOname( header->exceptionType->name() ) );
#if defined BRIDGES_DEBUG
    OString cstr_unoName( OUStringToOString( unoName, RTL_TEXTENCODING_ASCII_US ) );
    fprintf( stderr, "> c++ exception occurred: %s\n", cstr_unoName.getStr() );
#endif
    typelib_typedescription_getByName( &pExcTypeDescr, unoName.pData );
    if (0 == pExcTypeDescr)
    {
        RuntimeException aRE( OUString("exception type not found: ") + unoName );
        Type const & rType = ::getCppuType( &aRE );
        uno_type_any_constructAndConvert( pUnoExc, &aRE, rType.getTypeLibType(), pCpp2Uno );
#if defined _DEBUG
        OString cstr( OUStringToOString( aRE.Message, RTL_TEXTENCODING_ASCII_US ) );
        OSL_FAIL( cstr.getStr() );
#endif
    }
    else
    {
        // construct uno exception any
        uno_any_constructAndConvert( pUnoExc, header->adjustedPtr, pExcTypeDescr, pCpp2Uno );
        typelib_typedescription_release( pExcTypeDescr );
    }
}

}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>fix sparc build<commit_after>/* -*- 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 <stdio.h>
#include <string.h>
#include <dlfcn.h>
#include <cxxabi.h>
#include <boost/unordered_map.hpp>

#include <rtl/strbuf.hxx>
#include <rtl/ustrbuf.hxx>
#include <osl/diagnose.h>
#include <osl/mutex.hxx>

#include <com/sun/star/uno/genfunc.hxx>
#include <typelib/typedescription.hxx>
#include <uno/any2.h>

#include "share.hxx"

using namespace ::std;
using namespace ::osl;
using namespace ::com::sun::star::uno;
using namespace ::__cxxabiv1;

namespace CPPU_CURRENT_NAMESPACE
{

void dummy_can_throw_anything( char const * )
{
}

static OUString toUNOname( char const * p )
{
#if defined BRIDGES_DEBUG
    char const * start = p;
#endif

    // example: N3com3sun4star4lang24IllegalArgumentExceptionE

    OUStringBuffer buf( 64 );
    OSL_ASSERT( 'N' == *p );
    ++p; // skip N

    while ('E' != *p)
    {
        // read chars count
        long n = (*p++ - '0');
        while ('0' <= *p && '9' >= *p)
        {
            n *= 10;
            n += (*p++ - '0');
        }
        buf.appendAscii( p, n );
        p += n;
        if ('E' != *p)
            buf.append( '.' );
    }

#if defined BRIDGES_DEBUG
    OUString ret( buf.makeStringAndClear() );
    OString c_ret( OUStringToOString( ret, RTL_TEXTENCODING_ASCII_US ) );
    fprintf( stderr, "> toUNOname(): %s => %s\n", start, c_ret.getStr() );
    return ret;
#else
    return buf.makeStringAndClear();
#endif
}

class RTTI
{
    typedef boost::unordered_map< OUString, type_info *, OUStringHash > t_rtti_map;

    Mutex m_mutex;
    t_rtti_map m_rttis;
    t_rtti_map m_generatedRttis;

    void * m_hApp;

public:
    RTTI();
    ~RTTI();

    type_info * getRTTI( typelib_CompoundTypeDescription * );
};

RTTI::RTTI()
    : m_hApp( dlopen( 0, RTLD_LAZY ) )
{
}

RTTI::~RTTI()
{
    dlclose( m_hApp );
}

type_info * RTTI::getRTTI( typelib_CompoundTypeDescription *pTypeDescr )
{
    type_info * rtti;

    OUString const & unoName = *(OUString const *)&pTypeDescr->aBase.pTypeName;

    MutexGuard guard( m_mutex );
    t_rtti_map::const_iterator iFind( m_rttis.find( unoName ) );
    if (iFind == m_rttis.end())
    {
        // RTTI symbol
        OStringBuffer buf( 64 );
        buf.append( "_ZTIN" );
        sal_Int32 index = 0;
        do
        {
            OUString token( unoName.getToken( 0, '.', index ) );
            buf.append( token.getLength() );
            OString c_token( OUStringToOString( token, RTL_TEXTENCODING_ASCII_US ) );
            buf.append( c_token );
        }
        while (index >= 0);
        buf.append( 'E' );

        OString symName( buf.makeStringAndClear() );
        rtti = (type_info *)dlsym( m_hApp, symName.getStr() );

        if (rtti)
        {
            pair< t_rtti_map::iterator, bool > insertion(
                m_rttis.insert( t_rtti_map::value_type( unoName, rtti ) ) );
            OSL_ENSURE( insertion.second, "### inserting new rtti failed?!" );
        }
        else
        {
            // try to lookup the symbol in the generated rtti map
            t_rtti_map::const_iterator iiFind( m_generatedRttis.find( unoName ) );
            if (iiFind == m_generatedRttis.end())
            {
                // we must generate it !
                // symbol and rtti-name is nearly identical,
                // the symbol is prefixed with _ZTI
                char const * rttiName = symName.getStr() +4;
#if defined BRIDGES_DEBUG
                fprintf( stderr,"generated rtti for %s\n", rttiName );
#endif
                if (pTypeDescr->pBaseTypeDescription)
                {
                    // ensure availability of base
                    type_info * base_rtti = getRTTI(
                        (typelib_CompoundTypeDescription *)pTypeDescr->pBaseTypeDescription );
                    rtti = new __si_class_type_info(
                        strdup( rttiName ), (__class_type_info *)base_rtti );
                }
                else
                {
                    // this class has no base class
                    rtti = new __class_type_info( strdup( rttiName ) );
                }

                pair< t_rtti_map::iterator, bool > insertion(
                    m_generatedRttis.insert( t_rtti_map::value_type( unoName, rtti ) ) );
                OSL_ENSURE( insertion.second, "### inserting new generated rtti failed?!" );
            }
            else // taking already generated rtti
            {
                rtti = iiFind->second;
            }
        }
    }
    else
    {
        rtti = iFind->second;
    }

    return rtti;
}

static void deleteException( void * pExc )
{
    __cxa_exception const * header = ((__cxa_exception const *)pExc - 1);
    typelib_TypeDescription * pTD = 0;
    OUString unoName( toUNOname( header->exceptionType->name() ) );
    ::typelib_typedescription_getByName( &pTD, unoName.pData );
    OSL_ENSURE( pTD, "### unknown exception type! leaving out destruction => leaking!!!" );
    if (pTD)
    {
        ::uno_destructData( pExc, pTD, cpp_release );
        ::typelib_typedescription_release( pTD );
    }
}

void raiseException( uno_Any * pUnoExc, uno_Mapping * pUno2Cpp )
{
#if defined BRIDGES_DEBUG
    OString cstr(
        OUStringToOString(
            *reinterpret_cast< OUString const * >( &pUnoExc->pType->pTypeName ),
            RTL_TEXTENCODING_ASCII_US ) );
    fprintf( stderr, "> uno exception occurred: %s\n", cstr.getStr() );
#endif
    void * pCppExc;
    type_info * rtti;

    {
    // construct cpp exception object
    typelib_TypeDescription * pTypeDescr = 0;
    TYPELIB_DANGER_GET( &pTypeDescr, pUnoExc->pType );
    OSL_ASSERT( pTypeDescr );
    if (! pTypeDescr)
    {
        throw RuntimeException(
            OUString("cannot get typedescription for type ") +
            *reinterpret_cast< OUString const * >( &pUnoExc->pType->pTypeName ) );
    }

    pCppExc = __cxa_allocate_exception( pTypeDescr->nSize );
    ::uno_copyAndConvertData( pCppExc, pUnoExc->pData, pTypeDescr, pUno2Cpp );

    // destruct uno exception
    ::uno_any_destruct( pUnoExc, 0 );
    // avoiding locked counts
    static RTTI * s_rtti = 0;
    if (! s_rtti)
    {
        MutexGuard guard( Mutex::getGlobalMutex() );
        if (! s_rtti)
        {
#ifdef LEAK_STATIC_DATA
            s_rtti = new RTTI();
#else
            static RTTI rtti_data;
            s_rtti = &rtti_data;
#endif
        }
    }
    rtti = (type_info *)s_rtti->getRTTI( (typelib_CompoundTypeDescription *) pTypeDescr );
    TYPELIB_DANGER_RELEASE( pTypeDescr );
    OSL_ENSURE( rtti, "### no rtti for throwing exception!" );
    if (! rtti)
    {
        throw RuntimeException(
            OUString("no rtti for type ") +
            *reinterpret_cast< OUString const * >( &pUnoExc->pType->pTypeName )
             );
    }
    }

    __cxa_throw( pCppExc, rtti, deleteException );
}

void fillUnoException( __cxa_exception * header, uno_Any * pUnoExc, uno_Mapping * pCpp2Uno )
{
    if (! header)
    {
        RuntimeException aRE( "no exception header!" );
        Type const & rType = ::getCppuType( &aRE );
        uno_type_any_constructAndConvert( pUnoExc, &aRE, rType.getTypeLibType(), pCpp2Uno );
#if defined _DEBUG
        OString cstr( OUStringToOString( aRE.Message, RTL_TEXTENCODING_ASCII_US ) );
        OSL_FAIL( cstr.getStr() );
#endif
        return;
    }

    typelib_TypeDescription * pExcTypeDescr = 0;
    OUString unoName( toUNOname( header->exceptionType->name() ) );
#if defined BRIDGES_DEBUG
    OString cstr_unoName( OUStringToOString( unoName, RTL_TEXTENCODING_ASCII_US ) );
    fprintf( stderr, "> c++ exception occurred: %s\n", cstr_unoName.getStr() );
#endif
    typelib_typedescription_getByName( &pExcTypeDescr, unoName.pData );
    if (0 == pExcTypeDescr)
    {
        RuntimeException aRE( OUString("exception type not found: ") + unoName );
        Type const & rType = ::getCppuType( &aRE );
        uno_type_any_constructAndConvert( pUnoExc, &aRE, rType.getTypeLibType(), pCpp2Uno );
#if defined _DEBUG
        OString cstr( OUStringToOString( aRE.Message, RTL_TEXTENCODING_ASCII_US ) );
        OSL_FAIL( cstr.getStr() );
#endif
    }
    else
    {
        // construct uno exception any
        uno_any_constructAndConvert( pUnoExc, header->adjustedPtr, pExcTypeDescr, pCpp2Uno );
        typelib_typedescription_release( pExcTypeDescr );
    }
}

}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>#include "Action.h"

Action::Action(const int _action):
action(_action)
{}

Action::Execute()
{}
<commit_msg>added comparison operator<commit_after>#include "Action.h"

Action::Action(const int _action):
action(_action)
{}

Action::Execute()
{
  //call stored function
}

bool operator==(const Action& a1) const
{
  return action==target.action;
}
<|endoftext|>


<commit_before>#ifndef DUNE_STUFF_MATH_HH
#define DUNE_STUFF_MATH_HH

#include <vector>
#include <limits>
#include <algorithm>
#include <cstring>
#include <iostream>
#include "static_assert.hh"
#include <boost/static_assert.hpp>
#include <boost/fusion/include/void.hpp>
#include <boost/format.hpp>
#include <boost/accumulators/accumulators.hpp>
#include <boost/accumulators/statistics/stats.hpp>
#include <boost/accumulators/statistics/max.hpp>
#include <boost/accumulators/statistics/min.hpp>
#include <boost/accumulators/statistics/mean.hpp>

#include <dune/common/deprecated.hh>

namespace Stuff {

/** \todo DOCME **/
template <class SomeRangeType, class OtherRangeType >
static double colonProduct(    const SomeRangeType& arg1,
						const OtherRangeType& arg2 )
{
	dune_static_assert( SomeRangeType::cols == SomeRangeType::rows
			&& OtherRangeType::cols == OtherRangeType::rows
			&& int(OtherRangeType::cols) == int(SomeRangeType::rows), "RangeTypes_dont_fit" );

	double ret = 0.0;
	// iterators
	typedef typename SomeRangeType::ConstRowIterator
		ConstRowIteratorType;
	typedef typename SomeRangeType::row_type::ConstIterator
		ConstIteratorType;
	ConstRowIteratorType arg1RowItEnd = arg1.end();
	ConstRowIteratorType arg2RowItEnd = arg2.end();
	ConstRowIteratorType arg2RowIt = arg2.begin();
	for (   ConstRowIteratorType arg1RowIt = arg1.begin();
			arg1RowIt != arg1RowItEnd, arg2RowIt != arg2RowItEnd;
			++arg1RowIt, ++arg2RowIt ) {
		ConstIteratorType row1ItEnd = arg1RowIt->end();
		ConstIteratorType row2ItEnd = arg2RowIt->end();
		ConstIteratorType row2It = arg2RowIt->begin();
		for (   ConstIteratorType row1It = arg1RowIt->begin();
				row1It != row1ItEnd, row2It != row2ItEnd;
				++row1It, ++row2It ) {
			ret += *row1It * *row2It;
		}
	}
	return ret;
}

/**
 *  \brief  dyadic product
 *
 *          Implements \f$\left(arg_{1} \otimes arg_{2}\right)_{i,j}:={arg_{1}}_{i} {arg_{2}}_{j}\f$
 *			RangeType1 should be fieldmatrix, RangeType2 fieldvector
 **/
template <class RangeType1, class RangeType2 >
static RangeType1 dyadicProduct(   const RangeType2& arg1,
								const RangeType2& arg2 )
{
	RangeType1 ret( 0.0 );
	typedef typename RangeType1::RowIterator
		MatrixRowIteratorType;
	typedef typename RangeType2::ConstIterator
		ConstVectorIteratorType;
	typedef typename RangeType2::Iterator
		VectorIteratorType;
	MatrixRowIteratorType rItEnd = ret.end();
	ConstVectorIteratorType arg1It = arg1.begin();
	for ( MatrixRowIteratorType rIt = ret.begin(); rIt != rItEnd; ++rIt ) {
		ConstVectorIteratorType arg2It = arg2.begin();
		VectorIteratorType vItEnd = rIt->end();
		for (   VectorIteratorType vIt = rIt->begin();
				vIt != vItEnd;
				++vIt ) {
			*vIt = *arg1It * *arg2It;
			++arg2It;
		}
		++arg1It;
	}
	return ret;
}

/** \brief a vector wrapper for continiously updating min,max,avg of some element type vector
  \todo find use? it's only used in minimal as testcase for itself...
  **/
template < class ElementType >
class MinMaxAvg {
	protected:
		typedef MinMaxAvg< ElementType >
			ThisType;
		typedef std::vector< ElementType >
			ElementsVec;
		typedef typename ElementsVec::const_iterator
			ElementsVecConstIterator;

	public:
		MinMaxAvg()
		{}

		template < class stl_container_type >
		MinMaxAvg( const stl_container_type& elements )
		{
			dune_static_assert( (boost::is_same< ElementType, typename stl_container_type::value_type >::value),
								 "cannot assign mismatching types" );
			acc_ = std::for_each( elements.begin(), elements.end(), acc_ );
		}

		ElementType min () const { return boost::accumulators::min(acc_); }
		ElementType max () const { return boost::accumulators::max(acc_); }
		ElementType average () const { return boost::accumulators::mean(acc_); }

		void DUNE_DEPRECATED push( const ElementType& el ) {
			acc_( el );
		}

		void operator()( const ElementType& el ) {
			acc_( el );
		}

		template < class Stream >
		void output( Stream& stream ) {
			stream << boost::format( "min: %e\tmax: %e\tavg: %e\n" ) % min() % max() % average();
		}

	protected:
		typedef boost::accumulators::stats<
				boost::accumulators::tag::max,
				boost::accumulators::tag::min,
				boost::accumulators::tag::mean >
			StatsType;
		boost::accumulators::accumulator_set< ElementType,StatsType > acc_;

		MinMaxAvg( const ThisType& other );
};

//! bound \param var in [\param min,\param max]
template <typename T> T clamp(const T var,const T min,const T max)
{
	return ( (var < min) ? min : ( var > max ) ? max : var );
}

//! docme
class MovingAverage
{
	double avg_;
	size_t steps_;
public:
	MovingAverage()
		:avg_(0.0),steps_(0)
	{}
	MovingAverage& operator += (double val)
	{
		avg_ += ( val - avg_ ) / ++steps_;
		return *this;
	}
	operator double () { return avg_; }
};

//! no-branch sign function
long sign(long x) { return long(x!=0) | (long(x>=0)-1);  }

} //end namespace Stuff

#endif // DUNE_STUFF_MATH_HH
<commit_msg>fix colonProduct loops<commit_after>#ifndef DUNE_STUFF_MATH_HH
#define DUNE_STUFF_MATH_HH

#include <vector>
#include <limits>
#include <algorithm>
#include <cstring>
#include <iostream>
#include "static_assert.hh"
#include <boost/static_assert.hpp>
#include <boost/fusion/include/void.hpp>
#include <boost/format.hpp>
#include <boost/accumulators/accumulators.hpp>
#include <boost/accumulators/statistics/stats.hpp>
#include <boost/accumulators/statistics/max.hpp>
#include <boost/accumulators/statistics/min.hpp>
#include <boost/accumulators/statistics/mean.hpp>

#include <dune/common/deprecated.hh>

namespace Stuff {

/** \todo DOCME **/
template <class SomeRangeType, class OtherRangeType >
static double colonProduct(    const SomeRangeType& arg1,
						const OtherRangeType& arg2 )
{
	dune_static_assert( SomeRangeType::cols == SomeRangeType::rows
			&& OtherRangeType::cols == OtherRangeType::rows
			&& int(OtherRangeType::cols) == int(SomeRangeType::rows), "RangeTypes_dont_fit" );

	double ret = 0.0;
	// iterators
	typedef typename SomeRangeType::ConstRowIterator
		ConstRowIteratorType;
	typedef typename SomeRangeType::row_type::ConstIterator
		ConstIteratorType;
	ConstRowIteratorType arg1RowItEnd = arg1.end();
	ConstRowIteratorType arg2RowItEnd = arg2.end();
	ConstRowIteratorType arg2RowIt = arg2.begin();
	for (   ConstRowIteratorType arg1RowIt = arg1.begin();
			arg1RowIt != arg1RowItEnd && arg2RowIt != arg2RowItEnd;
			++arg1RowIt, ++arg2RowIt ) {
		ConstIteratorType row1ItEnd = arg1RowIt->end();
		ConstIteratorType row2ItEnd = arg2RowIt->end();
		ConstIteratorType row2It = arg2RowIt->begin();
		for (   ConstIteratorType row1It = arg1RowIt->begin();
				row1It != row1ItEnd && row2It != row2ItEnd;
				++row1It, ++row2It ) {
			ret += *row1It * *row2It;
		}
	}
	return ret;
}

/**
 *  \brief  dyadic product
 *
 *          Implements \f$\left(arg_{1} \otimes arg_{2}\right)_{i,j}:={arg_{1}}_{i} {arg_{2}}_{j}\f$
 *			RangeType1 should be fieldmatrix, RangeType2 fieldvector
 **/
template <class RangeType1, class RangeType2 >
static RangeType1 dyadicProduct(   const RangeType2& arg1,
								const RangeType2& arg2 )
{
	RangeType1 ret( 0.0 );
	typedef typename RangeType1::RowIterator
		MatrixRowIteratorType;
	typedef typename RangeType2::ConstIterator
		ConstVectorIteratorType;
	typedef typename RangeType2::Iterator
		VectorIteratorType;
	MatrixRowIteratorType rItEnd = ret.end();
	ConstVectorIteratorType arg1It = arg1.begin();
	for ( MatrixRowIteratorType rIt = ret.begin(); rIt != rItEnd; ++rIt ) {
		ConstVectorIteratorType arg2It = arg2.begin();
		VectorIteratorType vItEnd = rIt->end();
		for (   VectorIteratorType vIt = rIt->begin();
				vIt != vItEnd;
				++vIt ) {
			*vIt = *arg1It * *arg2It;
			++arg2It;
		}
		++arg1It;
	}
	return ret;
}

/** \brief a vector wrapper for continiously updating min,max,avg of some element type vector
  \todo find use? it's only used in minimal as testcase for itself...
  **/
template < class ElementType >
class MinMaxAvg {
	protected:
		typedef MinMaxAvg< ElementType >
			ThisType;
		typedef std::vector< ElementType >
			ElementsVec;
		typedef typename ElementsVec::const_iterator
			ElementsVecConstIterator;

	public:
		MinMaxAvg()
		{}

		template < class stl_container_type >
		MinMaxAvg( const stl_container_type& elements )
		{
			dune_static_assert( (boost::is_same< ElementType, typename stl_container_type::value_type >::value),
								 "cannot assign mismatching types" );
			acc_ = std::for_each( elements.begin(), elements.end(), acc_ );
		}

		ElementType min () const { return boost::accumulators::min(acc_); }
		ElementType max () const { return boost::accumulators::max(acc_); }
		ElementType average () const { return boost::accumulators::mean(acc_); }

		void DUNE_DEPRECATED push( const ElementType& el ) {
			acc_( el );
		}

		void operator()( const ElementType& el ) {
			acc_( el );
		}

		template < class Stream >
		void output( Stream& stream ) {
			stream << boost::format( "min: %e\tmax: %e\tavg: %e\n" ) % min() % max() % average();
		}

	protected:
		typedef boost::accumulators::stats<
				boost::accumulators::tag::max,
				boost::accumulators::tag::min,
				boost::accumulators::tag::mean >
			StatsType;
		boost::accumulators::accumulator_set< ElementType,StatsType > acc_;

		MinMaxAvg( const ThisType& other );
};

//! bound \param var in [\param min,\param max]
template <typename T> T clamp(const T var,const T min,const T max)
{
	return ( (var < min) ? min : ( var > max ) ? max : var );
}

//! docme
class MovingAverage
{
	double avg_;
	size_t steps_;
public:
	MovingAverage()
		:avg_(0.0),steps_(0)
	{}
	MovingAverage& operator += (double val)
	{
		avg_ += ( val - avg_ ) / ++steps_;
		return *this;
	}
	operator double () { return avg_; }
};

//! no-branch sign function
long sign(long x) { return long(x!=0) | (long(x>=0)-1);  }

} //end namespace Stuff

#endif // DUNE_STUFF_MATH_HH
<|endoftext|>


<commit_before>/* -*- 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 <drawinglayer/primitive2d/graphicprimitivehelper2d.hxx>
#include <drawinglayer/animation/animationtiming.hxx>
#include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
#include <drawinglayer/primitive2d/animatedprimitive2d.hxx>
#include <drawinglayer/primitive2d/metafileprimitive2d.hxx>
#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
#include <drawinglayer/primitive2d/maskprimitive2d.hxx>
#include <basegfx/polygon/b2dpolygon.hxx>
#include <basegfx/polygon/b2dpolygontools.hxx>

//////////////////////////////////////////////////////////////////////////////
// helper class for animated graphics

#include <vcl/animate.hxx>
#include <vcl/graph.hxx>
#include <vcl/virdev.hxx>
#include <vcl/svapp.hxx>
#include <vcl/metaact.hxx>

//////////////////////////////////////////////////////////////////////////////
// includes for testing MetafilePrimitive2D::create2DDecomposition

//////////////////////////////////////////////////////////////////////////////

namespace
{
    struct animationStep
    {
        BitmapEx                                maBitmapEx;
        sal_uInt32                              mnTime;
    };

    class animatedBitmapExPreparator
    {
        ::Animation                             maAnimation;
        ::std::vector< animationStep >          maSteps;

        sal_uInt32 generateStepTime(sal_uInt32 nIndex) const;

    public:
        animatedBitmapExPreparator(const Graphic& rGraphic);

        sal_uInt32 count() const { return maSteps.size(); }
        sal_uInt32 loopCount() const { return (sal_uInt32)maAnimation.GetLoopCount(); }
        sal_uInt32 stepTime(sal_uInt32 a) const { return maSteps[a].mnTime; }
        const BitmapEx& stepBitmapEx(sal_uInt32 a) const { return maSteps[a].maBitmapEx; }
    };

    sal_uInt32 animatedBitmapExPreparator::generateStepTime(sal_uInt32 nIndex) const
    {
        const AnimationBitmap& rAnimBitmap = maAnimation.Get(sal_uInt16(nIndex));
        sal_uInt32 nWaitTime(rAnimBitmap.nWait * 10);

        // #115934#
        // Take care of special value for MultiPage TIFFs. ATM these shall just
        // show their first page. Later we will offer some switching when object
        // is selected.
        if(ANIMATION_TIMEOUT_ON_CLICK == rAnimBitmap.nWait)
        {
            // ATM the huge value would block the timer, so
            // use a long time to show first page (whole day)
            nWaitTime = 100 * 60 * 60 * 24;
        }

        // Bad trap: There are animated gifs with no set WaitTime (!).
        // In that case use a default value.
        if(0L == nWaitTime)
        {
            nWaitTime = 100L;
        }

        return nWaitTime;
    }

    animatedBitmapExPreparator::animatedBitmapExPreparator(const Graphic& rGraphic)
    :   maAnimation(rGraphic.GetAnimation())
    {
        OSL_ENSURE(GRAPHIC_BITMAP == rGraphic.GetType() && rGraphic.IsAnimated(), "animatedBitmapExPreparator: graphic is not animated (!)");

        // #128539# secure access to Animation, looks like there exist animated GIFs out there
        // with a step count of zero
        if(maAnimation.Count())
        {
            VirtualDevice aVirtualDevice(*Application::GetDefaultDevice());
            VirtualDevice aVirtualDeviceMask(*Application::GetDefaultDevice(), 1L);

            // Prepare VirtualDevices and their states
            aVirtualDevice.EnableMapMode(sal_False);
            aVirtualDeviceMask.EnableMapMode(sal_False);
            aVirtualDevice.SetOutputSizePixel(maAnimation.GetDisplaySizePixel());
            aVirtualDeviceMask.SetOutputSizePixel(maAnimation.GetDisplaySizePixel());
            aVirtualDevice.Erase();
            aVirtualDeviceMask.Erase();

            for(sal_uInt16 a(0L); a < maAnimation.Count(); a++)
            {
                animationStep aNextStep;
                aNextStep.mnTime = generateStepTime(a);

                // prepare step
                const AnimationBitmap& rAnimBitmap = maAnimation.Get(sal_uInt16(a));

                switch(rAnimBitmap.eDisposal)
                {
                    case DISPOSE_NOT:
                    {
                        aVirtualDevice.DrawBitmapEx(rAnimBitmap.aPosPix, rAnimBitmap.aBmpEx);
                        Bitmap aMask = rAnimBitmap.aBmpEx.GetMask();

                        if(aMask.IsEmpty())
                        {
                            const Point aEmpty;
                            const Rectangle aRect(aEmpty, aVirtualDeviceMask.GetOutputSizePixel());
                            const Wallpaper aWallpaper(COL_BLACK);
                            aVirtualDeviceMask.DrawWallpaper(aRect, aWallpaper);
                        }
                        else
                        {
                            BitmapEx aExpandVisibilityMask = BitmapEx(aMask, aMask);
                            aVirtualDeviceMask.DrawBitmapEx(rAnimBitmap.aPosPix, aExpandVisibilityMask);
                        }

                        break;
                    }
                    case DISPOSE_BACK:
                    {
                        // #i70772# react on no mask, for primitives, too.
                        const Bitmap aMask(rAnimBitmap.aBmpEx.GetMask());
                        const Bitmap aContent(rAnimBitmap.aBmpEx.GetBitmap());

                        aVirtualDeviceMask.Erase();
                        aVirtualDevice.DrawBitmap(rAnimBitmap.aPosPix, aContent);

                        if(aMask.IsEmpty())
                        {
                            const Rectangle aRect(rAnimBitmap.aPosPix, aContent.GetSizePixel());
                            aVirtualDeviceMask.SetFillColor(COL_BLACK);
                            aVirtualDeviceMask.SetLineColor();
                            aVirtualDeviceMask.DrawRect(aRect);
                        }
                        else
                        {
                            aVirtualDeviceMask.DrawBitmap(rAnimBitmap.aPosPix, aMask);
                        }

                        break;
                    }
                    case DISPOSE_FULL:
                    {
                        aVirtualDevice.DrawBitmapEx(rAnimBitmap.aPosPix, rAnimBitmap.aBmpEx);
                        break;
                    }
                    case DISPOSE_PREVIOUS :
                    {
                        aVirtualDevice.DrawBitmapEx(rAnimBitmap.aPosPix, rAnimBitmap.aBmpEx);
                        aVirtualDeviceMask.DrawBitmap(rAnimBitmap.aPosPix, rAnimBitmap.aBmpEx.GetMask());
                        break;
                    }
                }

                // create BitmapEx
                Bitmap aMainBitmap = aVirtualDevice.GetBitmap(Point(), aVirtualDevice.GetOutputSizePixel());
#if defined(MACOSX)
                AlphaMask aMaskBitmap( aVirtualDeviceMask.GetBitmap( Point(), aVirtualDeviceMask.GetOutputSizePixel()));
#else
                Bitmap aMaskBitmap = aVirtualDeviceMask.GetBitmap( Point(), aVirtualDeviceMask.GetOutputSizePixel());
#endif
                aNextStep.maBitmapEx = BitmapEx(aMainBitmap, aMaskBitmap);

                // add to vector
                maSteps.push_back(aNextStep);
            }
        }
    }
} // end of anonymous namespace

//////////////////////////////////////////////////////////////////////////////

namespace drawinglayer
{
    namespace primitive2d
    {
        Primitive2DSequence create2DDecompositionOfGraphic(
            const Graphic& rGraphic,
            const basegfx::B2DHomMatrix& rTransform)
        {
            Primitive2DSequence aRetval;

            switch(rGraphic.GetType())
            {
                case GRAPHIC_BITMAP :
                {
                    if(rGraphic.IsAnimated())
                    {
                        // prepare animation data
                        animatedBitmapExPreparator aData(rGraphic);

                        if(aData.count())
                        {
                            // create sub-primitives for animated bitmap and the needed animation loop
                            animation::AnimationEntryLoop aAnimationLoop(aData.loopCount() ? aData.loopCount() : 0xffff);
                            Primitive2DSequence aBitmapPrimitives(aData.count());

                            for(sal_uInt32 a(0); a < aData.count(); a++)
                            {
                                animation::AnimationEntryFixed aTime((double)aData.stepTime(a), (double)a / (double)aData.count());
                                aAnimationLoop.append(aTime);
                                aBitmapPrimitives[a] = new BitmapPrimitive2D(
                                    aData.stepBitmapEx(a),
                                    rTransform);
                            }

                            // prepare animation list
                            animation::AnimationEntryList aAnimationList;
                            aAnimationList.append(aAnimationLoop);

                            // create and add animated switch primitive
                            aRetval.realloc(1);
                            aRetval[0] = new AnimatedSwitchPrimitive2D(
                                aAnimationList,
                                aBitmapPrimitives,
                                false);
                        }
                    }
                    else if(rGraphic.getSvgData().get())
                    {
                        // embedded Svg fill, create embed transform
                        const basegfx::B2DRange& rSvgRange(rGraphic.getSvgData()->getRange());

                        if(basegfx::fTools::more(rSvgRange.getWidth(), 0.0) && basegfx::fTools::more(rSvgRange.getHeight(), 0.0))
                        {
                            // translate back to origin, scale to unit coordinates
                            basegfx::B2DHomMatrix aEmbedSvg(
                                basegfx::tools::createTranslateB2DHomMatrix(
                                    -rSvgRange.getMinX(),
                                    -rSvgRange.getMinY()));

                            aEmbedSvg.scale(
                                1.0 / rSvgRange.getWidth(),
                                1.0 / rSvgRange.getHeight());

                            // apply created object transformation
                            aEmbedSvg = rTransform * aEmbedSvg;

                            // add Svg primitives embedded
                            aRetval.realloc(1);
                            aRetval[0] = new TransformPrimitive2D(
                                aEmbedSvg,
                                rGraphic.getSvgData()->getPrimitive2DSequence());
                        }
                    }
                    else
                    {
                        aRetval.realloc(1);
                        aRetval[0] = new BitmapPrimitive2D(
                            rGraphic.GetBitmapEx(),
                            rTransform);
                    }

                    break;
                }

                case GRAPHIC_GDIMETAFILE :
                {
                    // create MetafilePrimitive2D
                    const GDIMetaFile& rMetafile = rGraphic.GetGDIMetaFile();

                    aRetval.realloc(1);
                    aRetval[0] = new MetafilePrimitive2D(
                        rTransform,
                        rMetafile);

                    // #i100357# find out if clipping is needed for this primitive. Unfortunately,
                    // there exist Metafiles who's content is bigger than the proposed PrefSize set
                    // at them. This is an error, but we need to work around this
                    const Size aMetaFilePrefSize(rMetafile.GetPrefSize());
                    const Size aMetaFileRealSize(
                        const_cast< GDIMetaFile& >(rMetafile).GetBoundRect(
                            *Application::GetDefaultDevice()).GetSize());

                    if(aMetaFileRealSize.getWidth() > aMetaFilePrefSize.getWidth()
                        || aMetaFileRealSize.getHeight() > aMetaFilePrefSize.getHeight())
                    {
                        // clipping needed. Embed to MaskPrimitive2D. Create children and mask polygon
                        basegfx::B2DPolygon aMaskPolygon(basegfx::tools::createUnitPolygon());
                        aMaskPolygon.transform(rTransform);

                        aRetval[0] = new MaskPrimitive2D(
                            basegfx::B2DPolyPolygon(aMaskPolygon),
                            aRetval);
                    }
                    break;
                }

                default:
                {
                    // nothing to create
                    break;
                }
            }

            return aRetval;
        }
    } // end of namespace primitive2d
} // end of namespace drawinglayer

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>fdo#70090: Avoid race in copy vs. modification of aRetval Sequence<commit_after>/* -*- 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 <drawinglayer/primitive2d/graphicprimitivehelper2d.hxx>
#include <drawinglayer/animation/animationtiming.hxx>
#include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
#include <drawinglayer/primitive2d/animatedprimitive2d.hxx>
#include <drawinglayer/primitive2d/metafileprimitive2d.hxx>
#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
#include <drawinglayer/primitive2d/maskprimitive2d.hxx>
#include <basegfx/polygon/b2dpolygon.hxx>
#include <basegfx/polygon/b2dpolygontools.hxx>

//////////////////////////////////////////////////////////////////////////////
// helper class for animated graphics

#include <vcl/animate.hxx>
#include <vcl/graph.hxx>
#include <vcl/virdev.hxx>
#include <vcl/svapp.hxx>
#include <vcl/metaact.hxx>

//////////////////////////////////////////////////////////////////////////////
// includes for testing MetafilePrimitive2D::create2DDecomposition

//////////////////////////////////////////////////////////////////////////////

namespace
{
    struct animationStep
    {
        BitmapEx                                maBitmapEx;
        sal_uInt32                              mnTime;
    };

    class animatedBitmapExPreparator
    {
        ::Animation                             maAnimation;
        ::std::vector< animationStep >          maSteps;

        sal_uInt32 generateStepTime(sal_uInt32 nIndex) const;

    public:
        animatedBitmapExPreparator(const Graphic& rGraphic);

        sal_uInt32 count() const { return maSteps.size(); }
        sal_uInt32 loopCount() const { return (sal_uInt32)maAnimation.GetLoopCount(); }
        sal_uInt32 stepTime(sal_uInt32 a) const { return maSteps[a].mnTime; }
        const BitmapEx& stepBitmapEx(sal_uInt32 a) const { return maSteps[a].maBitmapEx; }
    };

    sal_uInt32 animatedBitmapExPreparator::generateStepTime(sal_uInt32 nIndex) const
    {
        const AnimationBitmap& rAnimBitmap = maAnimation.Get(sal_uInt16(nIndex));
        sal_uInt32 nWaitTime(rAnimBitmap.nWait * 10);

        // #115934#
        // Take care of special value for MultiPage TIFFs. ATM these shall just
        // show their first page. Later we will offer some switching when object
        // is selected.
        if(ANIMATION_TIMEOUT_ON_CLICK == rAnimBitmap.nWait)
        {
            // ATM the huge value would block the timer, so
            // use a long time to show first page (whole day)
            nWaitTime = 100 * 60 * 60 * 24;
        }

        // Bad trap: There are animated gifs with no set WaitTime (!).
        // In that case use a default value.
        if(0L == nWaitTime)
        {
            nWaitTime = 100L;
        }

        return nWaitTime;
    }

    animatedBitmapExPreparator::animatedBitmapExPreparator(const Graphic& rGraphic)
    :   maAnimation(rGraphic.GetAnimation())
    {
        OSL_ENSURE(GRAPHIC_BITMAP == rGraphic.GetType() && rGraphic.IsAnimated(), "animatedBitmapExPreparator: graphic is not animated (!)");

        // #128539# secure access to Animation, looks like there exist animated GIFs out there
        // with a step count of zero
        if(maAnimation.Count())
        {
            VirtualDevice aVirtualDevice(*Application::GetDefaultDevice());
            VirtualDevice aVirtualDeviceMask(*Application::GetDefaultDevice(), 1L);

            // Prepare VirtualDevices and their states
            aVirtualDevice.EnableMapMode(sal_False);
            aVirtualDeviceMask.EnableMapMode(sal_False);
            aVirtualDevice.SetOutputSizePixel(maAnimation.GetDisplaySizePixel());
            aVirtualDeviceMask.SetOutputSizePixel(maAnimation.GetDisplaySizePixel());
            aVirtualDevice.Erase();
            aVirtualDeviceMask.Erase();

            for(sal_uInt16 a(0L); a < maAnimation.Count(); a++)
            {
                animationStep aNextStep;
                aNextStep.mnTime = generateStepTime(a);

                // prepare step
                const AnimationBitmap& rAnimBitmap = maAnimation.Get(sal_uInt16(a));

                switch(rAnimBitmap.eDisposal)
                {
                    case DISPOSE_NOT:
                    {
                        aVirtualDevice.DrawBitmapEx(rAnimBitmap.aPosPix, rAnimBitmap.aBmpEx);
                        Bitmap aMask = rAnimBitmap.aBmpEx.GetMask();

                        if(aMask.IsEmpty())
                        {
                            const Point aEmpty;
                            const Rectangle aRect(aEmpty, aVirtualDeviceMask.GetOutputSizePixel());
                            const Wallpaper aWallpaper(COL_BLACK);
                            aVirtualDeviceMask.DrawWallpaper(aRect, aWallpaper);
                        }
                        else
                        {
                            BitmapEx aExpandVisibilityMask = BitmapEx(aMask, aMask);
                            aVirtualDeviceMask.DrawBitmapEx(rAnimBitmap.aPosPix, aExpandVisibilityMask);
                        }

                        break;
                    }
                    case DISPOSE_BACK:
                    {
                        // #i70772# react on no mask, for primitives, too.
                        const Bitmap aMask(rAnimBitmap.aBmpEx.GetMask());
                        const Bitmap aContent(rAnimBitmap.aBmpEx.GetBitmap());

                        aVirtualDeviceMask.Erase();
                        aVirtualDevice.DrawBitmap(rAnimBitmap.aPosPix, aContent);

                        if(aMask.IsEmpty())
                        {
                            const Rectangle aRect(rAnimBitmap.aPosPix, aContent.GetSizePixel());
                            aVirtualDeviceMask.SetFillColor(COL_BLACK);
                            aVirtualDeviceMask.SetLineColor();
                            aVirtualDeviceMask.DrawRect(aRect);
                        }
                        else
                        {
                            aVirtualDeviceMask.DrawBitmap(rAnimBitmap.aPosPix, aMask);
                        }

                        break;
                    }
                    case DISPOSE_FULL:
                    {
                        aVirtualDevice.DrawBitmapEx(rAnimBitmap.aPosPix, rAnimBitmap.aBmpEx);
                        break;
                    }
                    case DISPOSE_PREVIOUS :
                    {
                        aVirtualDevice.DrawBitmapEx(rAnimBitmap.aPosPix, rAnimBitmap.aBmpEx);
                        aVirtualDeviceMask.DrawBitmap(rAnimBitmap.aPosPix, rAnimBitmap.aBmpEx.GetMask());
                        break;
                    }
                }

                // create BitmapEx
                Bitmap aMainBitmap = aVirtualDevice.GetBitmap(Point(), aVirtualDevice.GetOutputSizePixel());
#if defined(MACOSX)
                AlphaMask aMaskBitmap( aVirtualDeviceMask.GetBitmap( Point(), aVirtualDeviceMask.GetOutputSizePixel()));
#else
                Bitmap aMaskBitmap = aVirtualDeviceMask.GetBitmap( Point(), aVirtualDeviceMask.GetOutputSizePixel());
#endif
                aNextStep.maBitmapEx = BitmapEx(aMainBitmap, aMaskBitmap);

                // add to vector
                maSteps.push_back(aNextStep);
            }
        }
    }
} // end of anonymous namespace

//////////////////////////////////////////////////////////////////////////////

namespace drawinglayer
{
    namespace primitive2d
    {
        Primitive2DSequence create2DDecompositionOfGraphic(
            const Graphic& rGraphic,
            const basegfx::B2DHomMatrix& rTransform)
        {
            Primitive2DSequence aRetval;

            switch(rGraphic.GetType())
            {
                case GRAPHIC_BITMAP :
                {
                    if(rGraphic.IsAnimated())
                    {
                        // prepare animation data
                        animatedBitmapExPreparator aData(rGraphic);

                        if(aData.count())
                        {
                            // create sub-primitives for animated bitmap and the needed animation loop
                            animation::AnimationEntryLoop aAnimationLoop(aData.loopCount() ? aData.loopCount() : 0xffff);
                            Primitive2DSequence aBitmapPrimitives(aData.count());

                            for(sal_uInt32 a(0); a < aData.count(); a++)
                            {
                                animation::AnimationEntryFixed aTime((double)aData.stepTime(a), (double)a / (double)aData.count());
                                aAnimationLoop.append(aTime);
                                aBitmapPrimitives[a] = new BitmapPrimitive2D(
                                    aData.stepBitmapEx(a),
                                    rTransform);
                            }

                            // prepare animation list
                            animation::AnimationEntryList aAnimationList;
                            aAnimationList.append(aAnimationLoop);

                            // create and add animated switch primitive
                            aRetval.realloc(1);
                            aRetval[0] = new AnimatedSwitchPrimitive2D(
                                aAnimationList,
                                aBitmapPrimitives,
                                false);
                        }
                    }
                    else if(rGraphic.getSvgData().get())
                    {
                        // embedded Svg fill, create embed transform
                        const basegfx::B2DRange& rSvgRange(rGraphic.getSvgData()->getRange());

                        if(basegfx::fTools::more(rSvgRange.getWidth(), 0.0) && basegfx::fTools::more(rSvgRange.getHeight(), 0.0))
                        {
                            // translate back to origin, scale to unit coordinates
                            basegfx::B2DHomMatrix aEmbedSvg(
                                basegfx::tools::createTranslateB2DHomMatrix(
                                    -rSvgRange.getMinX(),
                                    -rSvgRange.getMinY()));

                            aEmbedSvg.scale(
                                1.0 / rSvgRange.getWidth(),
                                1.0 / rSvgRange.getHeight());

                            // apply created object transformation
                            aEmbedSvg = rTransform * aEmbedSvg;

                            // add Svg primitives embedded
                            aRetval.realloc(1);
                            aRetval[0] = new TransformPrimitive2D(
                                aEmbedSvg,
                                rGraphic.getSvgData()->getPrimitive2DSequence());
                        }
                    }
                    else
                    {
                        aRetval.realloc(1);
                        aRetval[0] = new BitmapPrimitive2D(
                            rGraphic.GetBitmapEx(),
                            rTransform);
                    }

                    break;
                }

                case GRAPHIC_GDIMETAFILE :
                {
                    // create MetafilePrimitive2D
                    const GDIMetaFile& rMetafile = rGraphic.GetGDIMetaFile();

                    aRetval.realloc(1);
                    aRetval[0] = new MetafilePrimitive2D(
                        rTransform,
                        rMetafile);

                    // #i100357# find out if clipping is needed for this primitive. Unfortunately,
                    // there exist Metafiles who's content is bigger than the proposed PrefSize set
                    // at them. This is an error, but we need to work around this
                    const Size aMetaFilePrefSize(rMetafile.GetPrefSize());
                    const Size aMetaFileRealSize(
                        const_cast< GDIMetaFile& >(rMetafile).GetBoundRect(
                            *Application::GetDefaultDevice()).GetSize());

                    if(aMetaFileRealSize.getWidth() > aMetaFilePrefSize.getWidth()
                        || aMetaFileRealSize.getHeight() > aMetaFilePrefSize.getHeight())
                    {
                        // clipping needed. Embed to MaskPrimitive2D. Create children and mask polygon
                        basegfx::B2DPolygon aMaskPolygon(basegfx::tools::createUnitPolygon());
                        aMaskPolygon.transform(rTransform);

                        Primitive2DReference mask = new MaskPrimitive2D(
                            basegfx::B2DPolyPolygon(aMaskPolygon),
                            aRetval);
                        aRetval[0] = mask;
                    }
                    break;
                }

                default:
                {
                    // nothing to create
                    break;
                }
            }

            return aRetval;
        }
    } // end of namespace primitive2d
} // end of namespace drawinglayer

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>