--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/webengine/osswebengine/WebCore/platform/graphics/symbian/ImageSymbian.cpp Mon Mar 30 12:54:55 2009 +0300
@@ -0,0 +1,499 @@
+/*
+ * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "BitmapImage.h"
+#include "FloatRect.h"
+#include "ImageObserver.h"
+#include "IntRect.h"
+#include "PlatformString.h"
+#include "Timer.h"
+#include <wtf/Vector.h>
+#include <wtf/HashMap.h>
+#include "GraphicsContext.h"
+#include "WebCoreGraphicsContext.h"
+#include "bitmap/MaskedBitmap.h"
+#include "bitmap/AnimationDecoder.h"
+#include "String.h"
+#include "StringHash.h"
+#include "DebugStream.h"
+#include "ZoomFactor.h"
+
+#include <data_caging_path_literals.hrh>
+
+// work around bidi.h conflict
+#include <../bidi.h>
+#include <AknsConstants.h>
+#include <AknsUtils.h>
+#include <AknsItemID.h>
+#include <AknsConstants.h>
+#include <eikenv.h>
+
+#ifdef __GCCE__
+#include <WebKitIcons_gcce.mbg>
+#else
+#include <WebKitIcons.mbg>
+#endif
+
+namespace WebCore {
+
+CMaskedBitmap* loadAknIcon(int id, float sizeAdjust);
+
+void FrameData::clear()
+{
+ if (m_frame) {
+ // FIXME: should come up with a better mechanism to handle the lifetime
+ // of native bitmaps. Maybe ref-counting?
+ // Caching frames anyway is a bad-idea for Symbian OS, because it consumes
+ // a lot of memory for long gif animations.
+
+ delete m_frame;
+ m_frame = 0;
+ m_duration = 0.;
+ m_hasAlpha = true;
+ }
+}
+
+BitmapImage::BitmapImage(ImageObserver* observer)
+ : Image(observer)
+ , m_currentFrame(0)
+ , m_frames(0)
+ , m_frameTimer(0)
+ , m_repetitionCount(0)
+ , m_repetitionsComplete(0)
+ , m_maskedBitmap( 0 )
+ , m_isSolidColor(false)
+ , m_animatingImageType(true)
+ , m_animationFinished(false)
+ , m_allDataReceived(false)
+ , m_haveSize(false)
+ , m_sizeAvailable(false)
+ , m_decodedSize(0)
+{
+ initPlatformData();
+
+ m_frames.clear();
+ m_source.setDecoderListener( observer );
+}
+
+BitmapImage::BitmapImage(CMaskedBitmap* bitmap)
+ : m_currentFrame(0)
+ , m_frameTimer(0)
+ , m_repetitionCount(0)
+ , m_repetitionsComplete(0)
+ , m_maskedBitmap( bitmap )
+ , m_imageObserver(0)
+ , m_isSolidColor(false)
+ , m_animatingImageType(true)
+ , m_animationFinished(false)
+ , m_allDataReceived(true)
+ , m_haveSize(false)
+ , m_sizeAvailable(false)
+ , m_decodedSize(0)
+{
+ initPlatformData();
+
+ // setup the image frames
+ m_frames.resize(1);
+ m_frames[0].m_frame = bitmap;
+ m_haveSize = true;
+ m_sizeAvailable = true;
+ m_size = IntSize(bitmap->SizeInPixels());
+}
+
+BitmapImage::~BitmapImage()
+{
+ destroyDecodedData();
+ stopAnimation();
+ invalidatePlatformData();
+}
+
+void BitmapImage::destroyDecodedData(bool)
+{
+ // Destroy the cached images and release them,
+ // only cache one image in Symbian port.
+ if (m_frames.size()) {
+ m_frames.last().clear();
+ invalidatePlatformData();
+ }
+}
+
+IntSize BitmapImage::size() const
+{
+ if (m_sizeAvailable && !m_haveSize) {
+ m_size = m_source.size();
+ m_haveSize = true;
+ }
+ return m_size;
+}
+
+void BitmapImage::setMimeType(const String& mimeType)
+{
+ m_source.setMimeType(mimeType);
+}
+
+const String& BitmapImage::getMimeType()
+{
+ return m_source.getMimeType();
+}
+
+bool BitmapImage::dataChanged(bool allDataReceived)
+{
+ destroyDecodedData(true);
+
+ // Feed all the data we've seen so far to the image decoder.
+ m_allDataReceived = allDataReceived;
+ m_source.setData(m_data.get(), allDataReceived);
+
+ // Image properties will not be available until the first frame of the file
+ // reaches kCGImageStatusIncomplete.
+ return isSizeAvailable();
+}
+
+size_t BitmapImage::frameCount()
+{
+ if (m_frames.size()==1 && !m_source.initialized())
+ return 1;
+ return m_source.frameCount();
+}
+
+bool BitmapImage::isSizeAvailable()
+{
+ if (m_sizeAvailable)
+ return true;
+
+ m_sizeAvailable = m_source.isSizeAvailable();
+
+ return m_sizeAvailable;
+
+}
+
+// don't cache the frame
+NativeImagePtr BitmapImage::frameAtIndex(size_t index)
+{
+ if (index >= frameCount())
+ return 0;
+
+ if (index < m_frames.size())
+ return m_frames[index].m_frame;
+
+ return m_source.createFrameAtIndex(index);
+}
+
+float BitmapImage::frameDurationAtIndex(size_t index)
+{
+ if (index >= frameCount())
+ return 0;
+
+ // in millseconds
+ return m_source.frameDurationAtIndex(index);
+}
+
+bool BitmapImage::frameHasAlphaAtIndex(size_t index)
+{
+ if (index >= frameCount())
+ return 0;
+
+ return m_source.frameHasAlphaAtIndex(index);
+}
+
+bool BitmapImage::shouldAnimate()
+{
+ return (m_animatingImageType && frameCount() > 1 && !m_animationFinished && m_imageObserver);
+}
+
+void BitmapImage::startAnimation()
+{
+ if (m_frameTimer || !shouldAnimate() || frameCount() <= 1)
+ return;
+
+ m_frameTimer = new Timer<BitmapImage>(this, &BitmapImage::advanceAnimation);
+ m_frameTimer->startOneShot(frameDurationAtIndex(m_currentFrame));
+}
+
+void BitmapImage::stopAnimation()
+{
+ // This timer is used to animate all occurrences of this BitmapImage. Don't invalidate
+ // the timer unless all renderers have stopped drawing.
+ delete m_frameTimer;
+ m_frameTimer = 0;
+}
+
+void BitmapImage::resetAnimation()
+{
+ stopAnimation();
+ m_currentFrame = 0;
+ m_repetitionsComplete = 0;
+ m_animationFinished = false;
+}
+
+void BitmapImage::advanceAnimation(Timer<BitmapImage>* timer)
+{
+ // Stop the animation.
+ stopAnimation();
+
+ // See if anyone is still paying attention to this animation. If not, we don't
+ // advance and will simply pause the animation.
+ if (imageObserver() && imageObserver()->shouldPauseAnimation(this))
+ return;
+
+ m_currentFrame++;
+ m_repetitionCount = m_source.decoder()->getLoopCount();
+ if(m_repetitionCount == -1) m_repetitionCount++;
+ if (m_currentFrame >= frameCount()) {
+ m_repetitionsComplete += 1;
+ if (m_repetitionCount && m_repetitionsComplete >= m_repetitionCount) {
+ m_animationFinished = false;
+ m_currentFrame--;
+ return;
+ }
+ m_currentFrame = 0;
+ }
+
+ m_source.decoder()->LoadFrame( m_currentFrame );
+}
+
+void BitmapImage::initPlatformData()
+{
+}
+
+void BitmapImage::invalidatePlatformData()
+{
+ // tot fixme: we need to flash the image data here.
+}
+
+struct IconData {
+ int m_id;
+ float m_sizeAdjust;
+};
+
+const IconData missingImageData = { EMbmWebkiticonsQgn_indi_wml_image_not_shown, 1.2 };
+const IconData missingObjectData = { EMbmWebkiticonsQgn_prop_wml_object, 1.2 };
+const IconData selectArrowData = { EMbmWebkiticonsQgn_prop_wml_selectarrow, 0.9 };
+const IconData selectFileData = { EMbmWebkiticonsQgn_prop_wml_selectfile, 0.9 };
+const IconData radioButtonOnData = { EMbmWebkiticonsQgn_prop_wml_radiobutt_on, 0.9 };
+const IconData radioButtonOffData = { EMbmWebkiticonsQgn_prop_wml_radiobutt_off, 0.9 };
+const IconData checkBoxOnData = { EMbmWebkiticonsQgn_prop_wml_checkbox_on, 0.9 };
+const IconData checkBoxOffData = { EMbmWebkiticonsQgn_prop_wml_checkbox_off, 0.9 };
+
+Image* Image::loadPlatformResource(const char *name)
+{
+ static HashMap<String,const IconData*> resourceIds;
+ if (resourceIds.isEmpty()) {
+ resourceIds.set("missingImage", &missingImageData);
+ resourceIds.set("missingObject", &missingObjectData );
+ resourceIds.set("selectArrow", &selectArrowData);
+ resourceIds.set("selectFile", &selectFileData);
+ resourceIds.set("radioButtonOn", &radioButtonOnData);
+ resourceIds.set("radioButtonOff", &radioButtonOffData);
+ resourceIds.set("checkBoxOn", &checkBoxOnData);
+ resourceIds.set("checkBoxOff", &checkBoxOffData);
+ }
+ if (const IconData* data = resourceIds.get(name)) {
+ CMaskedBitmap* bm = loadAknIcon(data->m_id,data->m_sizeAdjust);
+ if (bm) {
+ BitmapImage* im = new BitmapImage(bm);
+ return im;
+ }
+ }
+ return 0;
+}
+
+void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatRect& src, CompositeOperator op)
+{
+ WebCoreGraphicsContext* context = ctxt->platformContext();
+
+ CMaskedBitmap* bm = frameAtIndex(m_currentFrame);
+ if (!bm) // If it's too early we won't have an BitmapImage yet.
+ return;
+
+ TRect target(enclosingIntRect(dst));
+ TRect source(enclosingIntRect(src));
+
+ bm->DrawBitmap(context->gc(), xForm(target), source);
+
+ startAnimation();
+
+}
+
+#ifdef __GCCE__
+_LIT( KBrowserSvgFile, "Webkiticons_gcce.mif" );
+#else
+_LIT( KBrowserSvgFile, "webkiticons.mif" );
+#endif
+
+TPtrC iconFileName()
+{
+ static HBufC* filename = 0;
+ if (!filename) {
+ TFileName mbmDrive;
+ TParse parse;
+ Dll::FileName( mbmDrive );
+ Dll::FileName( mbmDrive );
+ parse.Set( mbmDrive, NULL, NULL );
+ mbmDrive = parse.Drive();
+ filename = HBufC::New( KMaxFileName );
+ filename->Des().Append( mbmDrive );
+ filename->Des().Append( KDC_APP_BITMAP_DIR );
+ filename->Des().Append( KBrowserSvgFile );
+ }
+ return *filename;
+}
+
+CMaskedBitmap* loadAknIcon(int id, float sizeAdjust)
+{
+ CEikonEnv* eikEnv = CEikonEnv::Static();
+ CWsScreenDevice& screenDev = *eikEnv->ScreenDevice();
+
+ int dpi = screenDev.VerticalTwipsToPixels(KTwipsPerInch);
+ int px = (int)10*sizeAdjust;
+ // dpi adjustments
+ if ((200 > dpi) && (dpi >= 120))
+ px *= 1.7;
+ else if ((210 > dpi) && (dpi >= 200))
+ px *= 2.1;
+ else if ((400 > dpi) && (dpi >= 210))
+ px *= 2.2;
+ else if (dpi >= 400)
+ px *= 4.2;
+
+ CFbsBitmap* bitmap=0;
+ CFbsBitmap* mask=0;
+ MAknsSkinInstance* skin = AknsUtils::SkinInstance();
+ TRAPD(error, AknsUtils::CreateIconL( skin,
+ KAknsIIDDefault,
+ bitmap,
+ mask,
+ iconFileName(),
+ id,
+ id+1));
+ if (error!=KErrNone)
+ return 0;
+
+ AknIconUtils::SetSize(bitmap,TSize(px,px)); //rect.Rect().Size());
+ AknIconUtils::SetSize(mask,TSize(px,px)); //rect.Rect().Size());
+ return new CMaskedBitmap(bitmap,mask);
+}
+
+CMaskedBitmap* BitmapImage::getMaskedBitmap()
+{
+ if (m_maskedBitmap)
+ return m_maskedBitmap;
+
+ m_maskedBitmap = m_source.createFrameAtIndex(0);
+ return m_maskedBitmap;
+}
+
+void BitmapImage::drawPattern(GraphicsContext* ctxt, const FloatRect& srcRect, const AffineTransform& patternTransform,
+ const FloatPoint& phase, CompositeOperator, const FloatRect& dstRect)
+{
+ WebCoreGraphicsContext* context = ctxt->platformContext();
+
+ CMaskedBitmap* bm = frameAtIndex(m_currentFrame);
+ if(!bm || bm->IsFullyTransparent())
+ return;
+
+ IntSize intrinsicImageSize = size();
+ TSize scaledSize( xForm(TSize(srcRect.width(), srcRect.height())) );
+
+ scaledSize.iWidth = scaledSize.iWidth < 1 ? 1 : scaledSize.iWidth;
+ scaledSize.iHeight = scaledSize.iHeight < 1 ? 1 : scaledSize.iHeight;
+
+ if( scaledSize != TSize(intrinsicImageSize) ) {
+ bm = bm->ScaleImageToSize(scaledSize);
+ }
+
+ if ( bm->SizeInPixels() == TSize(1,1) && !bm->HasMask() ) {
+ checkForSolidColor();
+ }
+
+ CFbsBitmap* dstBmp = context->contentBuffer();
+
+ if (dstBmp != NULL) {
+ TSize sz = dstBmp->SizeInPixels();
+
+ // calculate target rect
+ TRect trgRect( xForm(dstRect) );
+ TRect clip(trgRect);
+ if (context->hasClipping())
+ {
+ clip.Intersection(context->clippingRect());
+ }
+
+ // start point in source image
+ TPoint point( xForm(TPoint(phase.x(), phase.y())) );
+ TPoint off( point.iX%scaledSize.iWidth, point.iY%scaledSize.iHeight );
+ off = TPoint( off.iX < 0 ? off.iX + scaledSize.iWidth : off.iX,
+ off.iY < 0 ? off.iY + scaledSize.iHeight : off.iY );
+
+ // transform coordinates to bitmap space
+ TRect bmpRect( clip );
+ TPoint orig( context->origin() );
+
+ TWebCoreSavedContext savedContext = context->save();
+ context->setClippingRect(bmpRect);
+ bm->TileInBitmapRect(context->gc(), bmpRect, point);
+ context->restore(savedContext);
+
+ /*bmpRect.Move( orig );
+ if( bmpRect.Intersects( TRect( TPoint(0,0), sz ) ) ) {
+ // offscreen bitmap space to aRect space
+ TPoint so( bmpRect.iTl );
+ so -= (trgRect.iTl + orig);
+ so += off;
+
+ // tiling the image
+ //bm->TileInBitmapRect( dstBmp, bmpRect, so );
+ bm->TileInBitmapRect(context->gc(), bmpRect, point);
+ }*/
+ }
+}
+
+void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const AffineTransform& patternTransform,
+ const FloatPoint& phase, CompositeOperator op, const FloatRect& destRect)
+{
+ // this function is not really needed for Symbian
+ notImplemented();
+}
+
+void BitmapImage::checkForSolidColor()
+{
+ if ( m_source.decoder()->decodeInProgress() || m_isSolidColor ) return;
+
+ CMaskedBitmap* bm = frameAtIndex(m_currentFrame);
+
+ if(!bm)
+ return;
+
+ if ( frameCount() == 1 ) {
+ TRgb bgColor;
+ bm->Bitmap().GetPixel(bgColor, bm->SizeInPixels().AsPoint() );
+ m_isSolidColor = true;
+ m_solidColor = Color(bgColor.Red(), bgColor.Green(), bgColor.Blue(), bgColor.Alpha());
+ }
+}
+
+}