1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/graphics/fbs/fontandbitmapserver/sfbs/fbsglyphdataiterator.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,465 @@
1.4 +// Copyright (c) 2009-2010 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +//
1.18 +
1.19 +#include <e32def.h>
1.20 +#include <gdi.h>
1.21 +#include <graphics/gdi/gdistructs.h>
1.22 +#include <graphics/gdi/gdiconsts.h>
1.23 +#include <graphics/fbsglyphdataiterator.h>
1.24 +#include "FbsMessage.h"
1.25 +#include "UTILS.H"
1.26 +
1.27 +const TInt KFbsGlyphDataIterCodeInvalid = -1;
1.28 +
1.29 +extern void Panic(TFbsPanic aPanic);
1.30 +
1.31 +/**
1.32 +The default constructor sets the iterator to a closed and empty state. It
1.33 +is the only way of constructing an iterator as instances cannot be copied by
1.34 +assignment or passed by value.
1.35 + */
1.36 +EXPORT_C RFbsGlyphDataIterator::RFbsGlyphDataIterator() :
1.37 + iImpl(NULL)
1.38 + {
1.39 + }
1.40 +
1.41 +/**
1.42 +For a given font (aFont), this method retrieves the glyph data for a list of
1.43 +glyph codes (aGlyphCodes), containing a number (aCount) of codes. On success,
1.44 +the iterator is initialised with the data for the first glyph in aGlyphCodes.
1.45 +
1.46 +The memory allocated to aGlyphCodes must not be freed or altered while the
1.47 +iterator is in use (i.e. until the iterator has been closed).
1.48 +
1.49 +Open() may not be called on an already open iterator. In order to re-open an
1.50 +iterator, it must first be closed by a call tor Close().
1.51 +
1.52 +If a glyph code is passed in that is not a recognised glyph code for the
1.53 +associated font, an empty-box glyph will be returned. This behaviour is
1.54 +consistent with CFbsFont::GetCharacterData().
1.55 +
1.56 +@pre The iterator is not already open.
1.57 +
1.58 +@param aFont The font to provide the glyph code data for.
1.59 +@param aGlyphCodes An array of glyph codes that the iterator will
1.60 + provide data for. This memory allocated for this array must not be
1.61 + freed before the iterator is closed.
1.62 +@param aCount The number of glyph codes in aGlyphCodes.
1.63 +
1.64 +@return
1.65 + KErrNone, if the iterator is successfully initialised to retrieve
1.66 + the glyph data;
1.67 + KErrInUse, if the iterator is already open, in which case the state of
1.68 + the iterator is left unchanged;
1.69 + KErrNoMemory, if the iterator cannot be opened due to insufficient
1.70 + system memory;
1.71 + KErrNotSupported, if aFont refers to a bitmap font or an outline & shadow
1.72 + font, if the required version of the hardware driver is not available
1.73 + (EGL 1.3 or later is required), or if RSgImages are not supported by
1.74 + the system;
1.75 + KErrArgument, if aCount is negative or zero, or if aGlyphCodes is null.
1.76 + */
1.77 +EXPORT_C TInt RFbsGlyphDataIterator::Open(CFbsFont& aFont, const TUint* aGlyphCodes, TInt aCount)
1.78 + {
1.79 + if (iImpl)
1.80 + {
1.81 + return KErrInUse;
1.82 + }
1.83 + if ((aCount <= 0) || !aGlyphCodes)
1.84 + {
1.85 + return KErrArgument;
1.86 + }
1.87 + if (!aFont.Address()->IsOpenFont())
1.88 + {
1.89 + return KErrNotSupported;
1.90 + }
1.91 + TInt glyphBitmapType = aFont.Address()->GlyphBitmapType();
1.92 + if (!( (glyphBitmapType == EMonochromeGlyphBitmap) || (glyphBitmapType == EAntiAliasedGlyphBitmap) ))
1.93 + {
1.94 + //Only supported bitmap types can be used i.e. EMonochromeGlyphBitmap or EAntiAliasedGlyphBitmap
1.95 + return KErrNotSupported;
1.96 + }
1.97 + // Check that the max width and height of the font are both no more than 2048.
1.98 + // This is the smallest maximum size an RSgImage can be created with.
1.99 + // This limit is arbitrarily set as it should cover nearly all use cases.
1.100 + const TInt KMaxFontSizeInPixels = 2048;
1.101 + TInt maxHeight = aFont.FontMaxHeight();
1.102 + TInt maxWidth = aFont.MaxCharWidthInPixels();
1.103 + if ( (KMaxFontSizeInPixels < maxHeight) || (KMaxFontSizeInPixels < maxWidth) )
1.104 + {
1.105 + return KErrTooBig;
1.106 + }
1.107 + // Construct implementor object that holds the state for the iterator.
1.108 + iImpl = new CGlyphDataIteratorImpl(aFont.iHandle, aGlyphCodes, aCount);
1.109 + if (!iImpl)
1.110 + {
1.111 + return KErrNoMemory;
1.112 + }
1.113 + TInt err = iImpl->Initialise();
1.114 + if (err != KErrNone)
1.115 + {
1.116 + Close();
1.117 + }
1.118 + return err;
1.119 + }
1.120 +
1.121 +/**
1.122 +Moves the iterator to the data for the next glyph code in the array passed
1.123 +into RFbsGlyphDataIterator::Open(). Data for the glyph can then be accessed
1.124 +using the Image(), Rect() and Metrics() methods.
1.125 +
1.126 +Once Next() has been called, the references returned by Image(), Rect() and
1.127 +Metrics() methods during the previous iteration should be considered invalid
1.128 +and must be discarded.
1.129 +
1.130 +Calling Next() repeatedly will iterate through the glyph data for all the glyph
1.131 +codes, until it has reached the last glyph code in the array (assuming no errors
1.132 +are encountered), at which point KErrNotFound is returned, and the array of glyph
1.133 +codes passed to RFbsGlyphDataIterator::Open() can safely be deleted.
1.134 +
1.135 +If the call was successful, KErrNone is returned. If an error is encountered an
1.136 +error code will be returned and the state of the iterator is left unchanged.
1.137 +
1.138 +@pre The iterator has been opened by a successful call to Open().
1.139 +@post The properties of the iterator are of the glyph corresponding
1.140 + to the next code passed in the array to Open(). However, if an error code
1.141 + was returned, the state of the iterator is unchanged.
1.142 +
1.143 +@return
1.144 + KErrNone, if the iterator was successfully advanced;
1.145 + KErrNotFound, if the iterator is already at the last element and cannot
1.146 + be advanced any further;
1.147 + KErrNoMemory, if there is insufficient system memory available;
1.148 + KErrNoGraphicsMemory, if there is insufficient graphics memory available.
1.149 +
1.150 +@panic FBSCLI 31, if the iterator is not open.
1.151 +@panic FBSERV -8, if as a result of this call, communication with the
1.152 + server is invoked, and the associated CFbsFont has been destroyed.
1.153 + */
1.154 +EXPORT_C TInt RFbsGlyphDataIterator::Next()
1.155 + {
1.156 + __ASSERT_ALWAYS(iImpl, Panic(EFbsPanicGlyphDataIteratorClosed));
1.157 + return iImpl->Next();
1.158 + }
1.159 +
1.160 +/**
1.161 +Closes the iterator and releases its internal resources. After calling, all data
1.162 +retrieved by the iterator is no longer safe to use. Once closed, this iterator
1.163 +can be re-opened. Calling Close() on an already closed iterator has no effect.
1.164 +
1.165 +Once an iterator is closed, the array of glyphs (aGlyphCodes) passed to
1.166 +RFbsGlyphDataIterator::Open() can safely be deleted.
1.167 +
1.168 +@post The iterator is closed.
1.169 + */
1.170 +EXPORT_C void RFbsGlyphDataIterator::Close()
1.171 + {
1.172 + delete iImpl;
1.173 + iImpl = NULL;
1.174 + }
1.175 +
1.176 +/**
1.177 +Returns a reference to the RSgImage that contains the glyph for the current
1.178 +iteration. The image representation of the glyph is the same as the image
1.179 +returned by the existing CFbsFont::GetCharacterData() method (i.e. an alpha mask).
1.180 +
1.181 +The RSgImage should only be considered a temporary handle for use in this
1.182 +iteration, and should not be used after a call to Next() or Close() has
1.183 +been made.
1.184 +
1.185 +Note: For glyphs such as space which have no visible representation, Image()
1.186 +will return a null image handle (i.e. RSgImage::IsNull() returns ETrue). This
1.187 +cannot be used for drawing. In this case Rect() will be empty however
1.188 +Metrics() will still be valid.
1.189 +
1.190 +@pre The iterator has been initialised by successfully calling Open().
1.191 +
1.192 +@return A handle to the image where the glyph for this iteration is stored.
1.193 +
1.194 +@panic FBSCLI 31, if the iterator is not open.
1.195 + */
1.196 +EXPORT_C const RSgImage& RFbsGlyphDataIterator::Image() const
1.197 + {
1.198 + __ASSERT_ALWAYS(iImpl, Panic(EFbsPanicGlyphDataIteratorClosed));
1.199 + __ASSERT_DEBUG(!iImpl->iGlyphBatch.IsEmpty(), Panic(EFbsPanicGlyphDataIteratorInvalidState));
1.200 + return iImpl->iGlyphBatch.First()->iImage;
1.201 + }
1.202 +
1.203 +/**
1.204 +Returns the area within the RSgImage where the glyph for the current
1.205 +iteration is located. The reference returned by Rect() should be considered
1.206 +temporary for use within this iteration and should not be used after a call to
1.207 +Next() or Close() has been made.
1.208 +
1.209 +@pre The iterator has been initialised by successfully calling Open().
1.210 +
1.211 +@return A rectangle representing the position and size in pixels,
1.212 + of the glyph for this iteration on the RSgImage provided by Image().
1.213 +
1.214 +@panic FBSCLI 31, if the iterator is not open.
1.215 + */
1.216 +EXPORT_C const TRect& RFbsGlyphDataIterator::Rect() const
1.217 + {
1.218 + __ASSERT_ALWAYS(iImpl, Panic(EFbsPanicGlyphDataIteratorClosed));
1.219 + __ASSERT_DEBUG(!iImpl->iGlyphBatch.IsEmpty(), Panic(EFbsPanicGlyphDataIteratorInvalidState));
1.220 + return iImpl->iGlyphDataIterRect;
1.221 + }
1.222 +
1.223 +/**
1.224 +Returns the glyph metrics for the current iteration. The reference returned by
1.225 +Metrics() should be considered temporary for use within this iteration and
1.226 +should not be used after a call to Next() or Close() has been made.
1.227 +
1.228 +@pre The iterator has been initialised by successfully calling Open().
1.229 +
1.230 +@return The metrics for the glyph at the current iteration.
1.231 +
1.232 +@panic FBSCLI 31, if the iterator is not open.
1.233 + */
1.234 +EXPORT_C const TOpenFontCharMetrics& RFbsGlyphDataIterator::Metrics() const
1.235 + {
1.236 + __ASSERT_ALWAYS(iImpl, Panic(EFbsPanicGlyphDataIteratorClosed));
1.237 + __ASSERT_DEBUG(!iImpl->iGlyphBatch.IsEmpty(), Panic(EFbsPanicGlyphDataIteratorInvalidState));
1.238 + return iImpl->iGlyphBatch.First()->iInfo.iMetrics;
1.239 + }
1.240 +
1.241 +/**
1.242 +Returns the glyph code associated with the data for the current iteration.
1.243 +
1.244 +@pre The iterator has been initialised by successfully calling Open().
1.245 +
1.246 +@return The glyph code of the glyph at the current iteration.
1.247 +
1.248 +@panic FBSCLI 31, if the iterator is not open.
1.249 + */
1.250 +EXPORT_C TUint RFbsGlyphDataIterator::GlyphCode() const
1.251 + {
1.252 + __ASSERT_ALWAYS(iImpl, Panic(EFbsPanicGlyphDataIteratorClosed));
1.253 + __ASSERT_DEBUG(!iImpl->iGlyphBatch.IsEmpty(), Panic(EFbsPanicGlyphDataIteratorInvalidState));
1.254 + return iImpl->iGlyphDataIterCodes[iImpl->iGlyphDataIterCodeIndex];
1.255 + }
1.256 +
1.257 +
1.258 +/**
1.259 +Constructs a CGlyphDataIteratorImpl.
1.260 +@param aFbsFontHandle The handle of the FbsFont that the iterator is working with.
1.261 +@param aGlyphCodes The array of glyph codes sent to RFbsGlyphDataIterator::Open()
1.262 +@param aCount The number of glyph codes in aGlyphCodes.
1.263 + */
1.264 +CGlyphDataIteratorImpl::CGlyphDataIteratorImpl(TInt aFbsFontHandle, const TUint* aGlyphCodes, TInt aCount) :
1.265 + iGlyphBatch(_FOFF(TGlyphBatchItem, iLink)),
1.266 + iGlyphDataIterCodes(aGlyphCodes),
1.267 + iGlyphDataIterCodeCount(aCount),
1.268 + iGlyphDataIterCodeIndex(KFbsGlyphDataIterCodeInvalid),
1.269 + iFbsFontHandle(aFbsFontHandle)
1.270 + {
1.271 + }
1.272 +
1.273 +/**
1.274 +Destructor. Releases all resources, disconnects from server and frees any
1.275 +items in the list of batched items.
1.276 + */
1.277 +CGlyphDataIteratorImpl::~CGlyphDataIteratorImpl()
1.278 + {
1.279 + if (iFbs)
1.280 + {
1.281 + if (iGlyphDataIterCodeIndex != KFbsGlyphDataIterCodeInvalid)
1.282 + {
1.283 + //Send the No-Op command to ensure that the "In Transit" RSgImage(s) are closed.
1.284 + iFbs->SendCommand(EFbsMessNoOp);
1.285 + }
1.286 + RFbsSession::Disconnect();
1.287 + iFbs = NULL;
1.288 + }
1.289 + while (!iGlyphBatch.IsEmpty())
1.290 + {
1.291 + TGlyphBatchItem* item = iGlyphBatch.First();
1.292 + item->iImage.Close();
1.293 + iGlyphBatch.Remove(*item);
1.294 + delete item;
1.295 + }
1.296 + iGlyphBatch.Reset();
1.297 + }
1.298 +
1.299 +/**
1.300 +Sets up the CGlyphDataIteratorImpl, populating the first batch of glyphs.
1.301 +Should only be called once, immediately after construction.
1.302 + */
1.303 +TInt CGlyphDataIteratorImpl::Initialise()
1.304 + {
1.305 + __ASSERT_DEBUG(iFbsFontHandle, Panic(EFbsPanicGlyphDataIteratorInvalidState));
1.306 + __ASSERT_DEBUG(iGlyphDataIterCodes, Panic(EFbsPanicGlyphDataIteratorInvalidState));
1.307 + __ASSERT_DEBUG(iGlyphDataIterCodeCount, Panic(EFbsPanicGlyphDataIteratorInvalidState));
1.308 + __ASSERT_DEBUG(iGlyphDataIterCodeIndex == KFbsGlyphDataIterCodeInvalid, Panic(EFbsPanicGlyphDataIteratorInvalidState));
1.309 +
1.310 + // If the client already has a session open, this is just a reference counting exercise and should incur no performance impact.
1.311 + TInt err = RFbsSession::Connect();
1.312 + if (err == KErrNone)
1.313 + {
1.314 + iFbs = RFbsSession::GetSession();
1.315 + err = UpdateGlyphBatch(0);
1.316 + }
1.317 + if (err == KErrNone)
1.318 + {
1.319 + iGlyphDataIterCodeIndex = 0;
1.320 + UpdateGlyphRect();
1.321 + }
1.322 + return err;
1.323 + }
1.324 +
1.325 +/**
1.326 +Increments the current iteration if possible, re-sending the request
1.327 +for more glyphs if the current batch of glyphs is down to the last
1.328 +item.
1.329 +@see RFbsGlyphDataIterator::Next()
1.330 + */
1.331 +TInt CGlyphDataIteratorImpl::Next()
1.332 + {
1.333 + __ASSERT_DEBUG(!iGlyphBatch.IsEmpty(), Panic(EFbsPanicGlyphDataIteratorInvalidState));
1.334 + if ( (iGlyphDataIterCodeIndex + 1) >= iGlyphDataIterCodeCount)
1.335 + {
1.336 + return KErrNotFound;
1.337 + }
1.338 + TInt err = UpdateGlyphBatch(iGlyphDataIterCodeIndex + 1);
1.339 + if (err == KErrNone)
1.340 + {
1.341 + ++iGlyphDataIterCodeIndex;
1.342 + // Close the current image and pop the head of the batch.
1.343 + TGlyphBatchItem* item = iGlyphBatch.First();
1.344 + item->iImage.Close();
1.345 + iGlyphBatch.Remove(*item);
1.346 + delete item;
1.347 + __ASSERT_DEBUG(!iGlyphBatch.IsEmpty(), Panic(EFbsPanicGlyphDataIteratorInvalidState));
1.348 + UpdateGlyphRect();
1.349 + }
1.350 + return err;
1.351 + }
1.352 +
1.353 +/**
1.354 +Checks whether a call to the server is required to get a new batch of glyph
1.355 +info, and processes the response from the server as necessary.
1.356 +
1.357 +@param aIndex Specifies the index into the glyph array which needs to be in
1.358 +the active glyph batch. If it is not there, a request is made to the server
1.359 +to get it.
1.360 +@return KErrNone if getting at least one glyph succeeded or a call to the
1.361 + server was not necessary, otherwise one of the system wide error codes.
1.362 +@panic FBSCLI 31 (debug only), if the iterator is not open
1.363 +@panic FBSCLI 33 (debug only), if an unexpected number of glyphs was received
1.364 + as a result of requesting glyphs from the server, or if the current batch
1.365 + of glyphs is empty when there should be at least one item.
1.366 + */
1.367 +TInt CGlyphDataIteratorImpl::UpdateGlyphBatch(TInt aIndex)
1.368 + {
1.369 + __ASSERT_DEBUG(Rng(0, aIndex, iGlyphDataIterCodeCount - 1), Panic(EFbsPanicGlyphDataIteratorIndexOutOfRange));
1.370 +
1.371 + TInt err = KErrNone;
1.372 +
1.373 + TBool needMoreGlyphs = EFalse;
1.374 + if (iGlyphBatch.IsEmpty())
1.375 + {
1.376 + // Current batch is empty, must request more. Should only get here when the iterator
1.377 + // is first opened, since one item should always be in the list from then on.
1.378 + __ASSERT_DEBUG(aIndex == 0, Panic(EFbsPanicGlyphDataIteratorInvalidState));
1.379 + needMoreGlyphs = ETrue;
1.380 + }
1.381 + else if (iGlyphBatch.IsLast(iGlyphBatch.First()))
1.382 + {
1.383 + // Only one item in the list.
1.384 + needMoreGlyphs = ETrue;
1.385 + }
1.386 +
1.387 + if (needMoreGlyphs)
1.388 + {
1.389 + // If the array of batched images is empty OR only one left, means we need to request a new batch.
1.390 + // We make sure there is at least one glyph in the batch so the iterator is always usable even
1.391 + // when a failure to move to the next iteration occurs.
1.392 +
1.393 + TBool glyphAddedToBatch = EFalse;
1.394 + TUint glyphCodes[KMaxGlyphBatchSize];
1.395 +
1.396 + TInt numGlyphsToRequest = Min(iGlyphDataIterCodeCount - aIndex, KMaxGlyphBatchSize);
1.397 + (void)Mem::Copy(glyphCodes, &(iGlyphDataIterCodes[aIndex]), sizeof(TUint) * numGlyphsToRequest);
1.398 + TPckg<TUint[KMaxGlyphBatchSize]> argGlyphCodes(glyphCodes);
1.399 +
1.400 + TGlyphImageInfo rcvdGlyphInfo[KMaxGlyphBatchSize];
1.401 + TPckg<TGlyphImageInfo[KMaxGlyphBatchSize]> argGlyphInfo(rcvdGlyphInfo);
1.402 +
1.403 + if (numGlyphsToRequest < KMaxGlyphBatchSize)
1.404 + {
1.405 + argGlyphCodes.SetLength(numGlyphsToRequest * sizeof(TUint));
1.406 + argGlyphInfo.SetLength(numGlyphsToRequest * sizeof(TGlyphImageInfo));
1.407 + }
1.408 +
1.409 + err = iFbs->SendCommand(EFbsMessGetGlyphs, TIpcArgs(iFbsFontHandle, &argGlyphCodes, &argGlyphInfo));
1.410 + if (err == KErrNone)
1.411 + {
1.412 + __ASSERT_DEBUG(argGlyphInfo.Length() % sizeof(TGlyphImageInfo) == 0, Panic(EFbsPanicGlyphDataIteratorInvalidState));
1.413 + TInt numRcvdGlyphs = argGlyphInfo.Length() / sizeof(TGlyphImageInfo);
1.414 + __ASSERT_DEBUG(numRcvdGlyphs > 0, Panic(EFbsPanicGlyphDataIteratorInvalidState));
1.415 + __ASSERT_DEBUG(numRcvdGlyphs <= KMaxGlyphBatchSize, Panic(EFbsPanicGlyphDataIteratorInvalidState));
1.416 +
1.417 + // Store the received glyph data, and open the image handles so that the IDs
1.418 + // will not be released by FbServ between now and the client using them.
1.419 + // If a failure occurs while processing one of the recevied glyphs,
1.420 + // abort the rest but keep the ones that succeeded.
1.421 + for (TInt i = 0; (i < numRcvdGlyphs) && (err == KErrNone); ++i)
1.422 + {
1.423 + TGlyphBatchItem* glyphEntry = new TGlyphBatchItem;
1.424 + if (!glyphEntry)
1.425 + {
1.426 + err = KErrNoMemory;
1.427 + }
1.428 + else
1.429 + {
1.430 + glyphEntry->iInfo = rcvdGlyphInfo[i];
1.431 +
1.432 + RSgImage glyphImage;
1.433 + if (rcvdGlyphInfo[i].iImageId != KSgNullDrawableId)
1.434 + {
1.435 + err = glyphEntry->iImage.Open(rcvdGlyphInfo[i].iImageId);
1.436 + }
1.437 + if (err == KErrNone)
1.438 + {
1.439 + iGlyphBatch.AddLast(*glyphEntry);
1.440 + glyphAddedToBatch = ETrue;
1.441 + }
1.442 + else
1.443 + {
1.444 + delete glyphEntry;
1.445 + }
1.446 + }
1.447 + }
1.448 + }
1.449 + if (err != KErrNone && glyphAddedToBatch)
1.450 + {
1.451 + // There was an error adding an item to the batch. Rather than return the
1.452 + // error to the client, ignore it and use what glyphs we successfully batched.
1.453 + err = KErrNone;
1.454 + }
1.455 + }
1.456 + return err;
1.457 + }
1.458 +
1.459 +/**
1.460 +Updates the glyph rectangle member based on the current glyph metrics.
1.461 +@post The iGlyphDataIterRect member is updated to reflect the position
1.462 + and size of the currently active glyph.
1.463 + */
1.464 +void CGlyphDataIteratorImpl::UpdateGlyphRect()
1.465 + {
1.466 + iGlyphDataIterRect.iTl = TPoint(iGlyphBatch.First()->iInfo.iPosX, iGlyphBatch.First()->iInfo.iPosY);
1.467 + iGlyphDataIterRect.SetSize(TSize(iGlyphBatch.First()->iInfo.iMetrics.Width(), iGlyphBatch.First()->iInfo.iMetrics.Height()));
1.468 + }