#ifndef __INK_SVG_PROFILE_H__ #define __INK_SVG_PROFILE_H__ /* * A class for managing which SVG Profiles are used. * * Authors: * Ted Gould * * Copyright (C) 2004 Authors * * Released under GNU GPL, read the file 'COPYING' for more information */ namespace Inkscape { /** \brief A class that contains information on which SVG profiles are marked for the object. The basic functionality here is to allow marking of which profiles are supported or required by some other object. The basic implementation of that is a bitfield, a data type that has bits to be able to be set depending on whether or not that particular feature is available. This implementation is a little more complex for a coulple of reasons. The first reason for making it be more complex is to make it into a nice C++ friendly class, where the actual bits aren't required by the calling application. This is accomplished by use of the \c SvgProfileType enum, and having the various fields in there. The second reason that this is more complex is that it is reasonable that the enum will grow to be greater than the native integer of a given system. As more profiles and distinctions are made, there will have to be more entries in the enum. In order to combat this, the \c BitField class was created. This creates consistent operations independent of how many integers are used to represent the particular bitfield. The entire class has been optimized for inlining and compiler reduction of code. All entires should allow being put in a structure or other static allocation. For most operations, simple and/or instructions in the processor is required after optimization. Adding additional profiles to the class is as easy as adding entires into the enum. Adding additional aggregates requires adding to the enum, and adding the aggregate into the constructor for the class. */ class SvgProfile { public: /** \brief The enum listing all the different profiles supported, and some aggregate ones supported. \note This \c enum should not be used for anything other than passing data into the constructor of \c SvgProfile. The optimization of the constructor is best when it is passed a static value. So, passing this enum through a function, and then constructing the \c SvgProfile would be less than ideal. Plus, as far as memory goes, today, they take up the same amount of memory. */ enum SvgProfileType { BASIC_OPERATION = 0, /**< This describes a feature that is part of the basic functionality of Inkscape itself. This would be like save or open. */ SVG_BASE_1_0, /**< The base SVG spec version 1.0 */ SVG_BASE_1_1, /**< The base SVG spec version 1.1 */ SVG_BASE_1_2, /**< The base SVG spec version 1.2 */ SVG_BASE_2_0, /**< The base SVG spec version 2.0 */ SVG_MOBILE_TINY_1_1, /**< The mobile SVG spec Tiny profile version 1.1 */ SVG_MOBILE_BASIC_1_1, /**< The mobile SVG spec Basic profile version 1.1 */ SVG_MOBILE_TINY_1_2, /**< The mobile SVG spec Tiny profile version 1.2 */ SVG_MOBILE_BASIC_1_2, /**< The mobile SVG spec Basic profile version 1.2 */ SVG_PRINT_1_1, /**< */ PROFILE_UNIQUE_CNT, /**< A marker to separate between the entires that are unique, and those which are aggregates of them. */ SVG_BASE_ALL, /**< Every version of the SVG Base spec */ SVG_MOBILE_ALL, /**< Every version and profile in SVG Mobile */ SVG_TINY_ALL, /**< Every version of the tiny profile in SVG Mobile */ SVG_BASIC_ALL, /**< Every version of the basic profile in SVG Mobile */ ALL /**< All, everything, basically doesn't tell you anything at all */ }; private: /** \brief The core of the \c SvgProfile class, this implements a bitfield which can be several integers large with standard operations independent of size. */ class BitField { /** \brief A quick way identify the number of bits in an integer. */ #define BITS_IN_INT (sizeof(int) * 8) /** \brief The size of the array which is being used. */ #define ARRAY_SIZE (((PROFILE_UNIQUE_CNT - 1) / BITS_IN_INT) + 1) /** \brief The actuall array holding the bitfield. */ unsigned int bits[ARRAY_SIZE]; public: /** \brief Constructor for the bitfield, it clears the \c bits array by setting things to zero. */ inline BitField(void) { for (int i = 0; i < ARRAY_SIZE; i++) { bits[i] = 0; } } /** \brief Constructs a bitfield by passing in another array describing how the bits should look. The function just copies the array into \c bits. */ inline BitField(unsigned int in_bits[ARRAY_SIZE]) { for (int i = 0; i < ARRAY_SIZE; i++) { bits[i] = in_bits[i]; } } /** \brief The equals operator, but it doesn't do quite that. This function checks to see if there are bits that are similarly high in both bitfields. */ inline bool operator == (const BitField &in_field) const { for (int i = 0; i < ARRAY_SIZE; i++) { if (bits[i] & in_field.bits[i] != 0) return true; } return false; } /** \brief A convience function to set a particular bit in the bitfield This function first find which integer the bit is in by dividing by \c BITS_IN_INT and then which bit in the integer by getting the modulus. The selected integer is the \c |= with a \c 1 shifted left by the possition. */ inline void set (const unsigned int pos) { unsigned int array_pos = pos / BITS_IN_INT; unsigned int bit_pos = pos % BITS_IN_INT; bits[array_pos] |= 1 << bit_pos; } /** \brief Does a bitwise \c OR on two bitfields. It does this for the entire \c bits array. */ inline BitField operator | (const BitField &other) const { unsigned int local_bits[ARRAY_SIZE]; for (int i = 0; i < ARRAY_SIZE; i++) { local_bits[i] = bits[i] | other.bits[i]; } return BitField(local_bits); } /** \brief Causes one \c BitField to take on the values stored in a different bitfield. */ inline BitField & operator = (const BitField &other) { for (int i = 0; i < ARRAY_SIZE; i++) { bits[i] = other.bits[i]; } return *this; } /** \brief Does a logical \c OR of the bitfield with another bitfield. It does this by using \c |=. */ inline BitField & operator |= (const BitField &other) { for (int i = 0; i < ARRAY_SIZE; i++) { bits[i] |= other.bits[i]; } return *this; } #undef BITS_IN_INT #undef ARRAY_SIZE }; /** \brief The actual data stored on the profile. */ BitField _profile; /** \brief Create an SvgProfile with an already created bitfield \param in_field The bitfield that should be used in the profile This function just copies the incoming bitfield into the one which is allocated for this. */ inline SvgProfile (const BitField &in_field) { _profile = in_field; } public: /** \brief A constructor for \c SvgProfile which sets up the bitfield based on the \c SvgProfileType getting passed in. This function has basically two different modes of operation depending on whether the requested value is a pure profile or and aggregate. If it is pure, then that bit is set in \c _profile and the function exits. Otherwise a case statement is used to determine which aggregate is called, and then setting all of the bits for that aggregate. */ inline SvgProfile (SvgProfileType type) { if (type < PROFILE_UNIQUE_CNT) { _profile.set(type); } else { /* Okay, so this could be done by OR'ing a bunch of these together, but I thought that would reduce the chance of the compiler actually figuring it all out and optimizing everything. This is already getting pretty complex. */ switch (type) { case SVG_BASE_ALL: _profile.set(SVG_BASE_1_0); _profile.set(SVG_BASE_1_1); _profile.set(SVG_BASE_1_2); _profile.set(SVG_BASE_2_0); break; case SVG_BASIC_ALL: _profile.set(SVG_MOBILE_BASIC_1_1); _profile.set(SVG_MOBILE_BASIC_1_2); break; case SVG_TINY_ALL: _profile.set(SVG_MOBILE_TINY_1_1); _profile.set(SVG_MOBILE_TINY_1_2); break; case SVG_MOBILE_ALL: _profile.set(SVG_MOBILE_BASIC_1_1); _profile.set(SVG_MOBILE_BASIC_1_2); _profile.set(SVG_MOBILE_TINY_1_1); _profile.set(SVG_MOBILE_TINY_1_2); break; case ALL: _profile.set(SVG_BASE_1_0); _profile.set(SVG_BASE_1_1); _profile.set(SVG_BASE_1_2); _profile.set(SVG_BASE_2_0); _profile.set(SVG_MOBILE_BASIC_1_1); _profile.set(SVG_MOBILE_BASIC_1_2); _profile.set(SVG_MOBILE_TINY_1_1); _profile.set(SVG_MOBILE_TINY_1_2); break; }; } return; }; /** \brief A function to check equality of two \c SvgProfiles. It doesn't quite check equality though, it more ensures that there is a profile supported by both objects. This would be similar to: (a & b) != 0 in a standard bitfield impelemtation. But is done this way for simplicity. */ inline bool operator == (const SvgProfile &in_profile) const { return _profile == in_profile._profile; }; /** \brief A function allow combining of \c SvgProfiles with each other into a larger \c SvgProfile. */ inline SvgProfile operator | (const SvgProfile &other) const { return SvgProfile(_profile | other._profile); } /** \brief A quick way to add additional profiles to the currently allocated object. */ inline SvgProfile & operator |= (const SvgProfile &other) { _profile |= other._profile; return *this; } }; } /* namespace Inkscape */ #endif /* __INK_SVG_PROFILE_H__ */ /* Local Variables: mode:c++ c-file-style:"stroustrup" c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) indent-tabs-mode:nil fill-column:99 End: */ // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :