webengine/osswebengine/WebCore/platform/graphics/symbian/ImageSymbian.cpp
changeset 0 dd21522fd290
child 1 7c90e6132015
--- /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());
+    }
+}
+
+}