Fix for 18502, Christian Biesinger's BMP decoder and my ICO decoder. r/sr=pavlov,jband
This commit is contained in:
Родитель
8da6894701
Коммит
92dff5e7ec
|
@ -805,6 +805,7 @@ fi
|
||||||
modules/libpr0n/decoders/png/Makefile
|
modules/libpr0n/decoders/png/Makefile
|
||||||
modules/libpr0n/decoders/ppm/Makefile
|
modules/libpr0n/decoders/ppm/Makefile
|
||||||
modules/libpr0n/decoders/jpeg/Makefile
|
modules/libpr0n/decoders/jpeg/Makefile
|
||||||
|
modules/libpr0n/decoders/bmp/Makefile
|
||||||
"
|
"
|
||||||
|
|
||||||
MAKEFILES_gfx2="
|
MAKEFILES_gfx2="
|
||||||
|
|
|
@ -113,6 +113,8 @@ static char* gImageTypes[] = {
|
||||||
"image/x-png",
|
"image/x-png",
|
||||||
"image/x-art",
|
"image/x-art",
|
||||||
"image/x-jg",
|
"image/x-jg",
|
||||||
|
"image/bmp",
|
||||||
|
"image/x-icon",
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -113,6 +113,8 @@ static char* gImageTypes[] = {
|
||||||
"image/x-png",
|
"image/x-png",
|
||||||
"image/x-art",
|
"image/x-art",
|
||||||
"image/x-jg",
|
"image/x-jg",
|
||||||
|
"image/bmp",
|
||||||
|
"image/x-icon",
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -377,6 +377,8 @@ nsObjectFrame::GetSkipSides() const
|
||||||
#define IMAGE_EXT_JPG "jpg"
|
#define IMAGE_EXT_JPG "jpg"
|
||||||
#define IMAGE_EXT_PNG "png"
|
#define IMAGE_EXT_PNG "png"
|
||||||
#define IMAGE_EXT_XBM "xbm"
|
#define IMAGE_EXT_XBM "xbm"
|
||||||
|
#define IMAGE_EXT_BMP "bmp"
|
||||||
|
#define IMAGE_EXT_ICO "ico"
|
||||||
|
|
||||||
// #define DO_DIRTY_INTERSECT 1 // enable dirty rect intersection during paint
|
// #define DO_DIRTY_INTERSECT 1 // enable dirty rect intersection during paint
|
||||||
|
|
||||||
|
@ -399,7 +401,9 @@ void nsObjectFrame::IsSupportedImage(nsIContent* aContent, PRBool* aImage)
|
||||||
type.EqualsIgnoreCase(IMAGE_PPM) ||
|
type.EqualsIgnoreCase(IMAGE_PPM) ||
|
||||||
type.EqualsIgnoreCase(IMAGE_XBM) ||
|
type.EqualsIgnoreCase(IMAGE_XBM) ||
|
||||||
type.EqualsIgnoreCase(IMAGE_XBM2)||
|
type.EqualsIgnoreCase(IMAGE_XBM2)||
|
||||||
type.EqualsIgnoreCase(IMAGE_XBM3))
|
type.EqualsIgnoreCase(IMAGE_XBM3)||
|
||||||
|
type.EqualsIgnoreCase(IMAGE_BMP) ||
|
||||||
|
type.EqualsIgnoreCase(IMAGE_ICO))
|
||||||
{
|
{
|
||||||
*aImage = PR_TRUE;
|
*aImage = PR_TRUE;
|
||||||
}
|
}
|
||||||
|
@ -432,7 +436,9 @@ void nsObjectFrame::IsSupportedImage(nsIContent* aContent, PRBool* aImage)
|
||||||
if(ext.EqualsIgnoreCase(IMAGE_EXT_GIF) ||
|
if(ext.EqualsIgnoreCase(IMAGE_EXT_GIF) ||
|
||||||
ext.EqualsIgnoreCase(IMAGE_EXT_JPG) ||
|
ext.EqualsIgnoreCase(IMAGE_EXT_JPG) ||
|
||||||
ext.EqualsIgnoreCase(IMAGE_EXT_PNG) ||
|
ext.EqualsIgnoreCase(IMAGE_EXT_PNG) ||
|
||||||
ext.EqualsIgnoreCase(IMAGE_EXT_XBM))
|
ext.EqualsIgnoreCase(IMAGE_EXT_XBM) ||
|
||||||
|
ext.EqualsIgnoreCase(IMAGE_EXT_BMP) ||
|
||||||
|
ext.EqualsIgnoreCase(IMAGE_EXT_ICO))
|
||||||
{
|
{
|
||||||
*aImage = PR_TRUE;
|
*aImage = PR_TRUE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -377,6 +377,8 @@ nsObjectFrame::GetSkipSides() const
|
||||||
#define IMAGE_EXT_JPG "jpg"
|
#define IMAGE_EXT_JPG "jpg"
|
||||||
#define IMAGE_EXT_PNG "png"
|
#define IMAGE_EXT_PNG "png"
|
||||||
#define IMAGE_EXT_XBM "xbm"
|
#define IMAGE_EXT_XBM "xbm"
|
||||||
|
#define IMAGE_EXT_BMP "bmp"
|
||||||
|
#define IMAGE_EXT_ICO "ico"
|
||||||
|
|
||||||
// #define DO_DIRTY_INTERSECT 1 // enable dirty rect intersection during paint
|
// #define DO_DIRTY_INTERSECT 1 // enable dirty rect intersection during paint
|
||||||
|
|
||||||
|
@ -399,7 +401,9 @@ void nsObjectFrame::IsSupportedImage(nsIContent* aContent, PRBool* aImage)
|
||||||
type.EqualsIgnoreCase(IMAGE_PPM) ||
|
type.EqualsIgnoreCase(IMAGE_PPM) ||
|
||||||
type.EqualsIgnoreCase(IMAGE_XBM) ||
|
type.EqualsIgnoreCase(IMAGE_XBM) ||
|
||||||
type.EqualsIgnoreCase(IMAGE_XBM2)||
|
type.EqualsIgnoreCase(IMAGE_XBM2)||
|
||||||
type.EqualsIgnoreCase(IMAGE_XBM3))
|
type.EqualsIgnoreCase(IMAGE_XBM3)||
|
||||||
|
type.EqualsIgnoreCase(IMAGE_BMP) ||
|
||||||
|
type.EqualsIgnoreCase(IMAGE_ICO))
|
||||||
{
|
{
|
||||||
*aImage = PR_TRUE;
|
*aImage = PR_TRUE;
|
||||||
}
|
}
|
||||||
|
@ -432,7 +436,9 @@ void nsObjectFrame::IsSupportedImage(nsIContent* aContent, PRBool* aImage)
|
||||||
if(ext.EqualsIgnoreCase(IMAGE_EXT_GIF) ||
|
if(ext.EqualsIgnoreCase(IMAGE_EXT_GIF) ||
|
||||||
ext.EqualsIgnoreCase(IMAGE_EXT_JPG) ||
|
ext.EqualsIgnoreCase(IMAGE_EXT_JPG) ||
|
||||||
ext.EqualsIgnoreCase(IMAGE_EXT_PNG) ||
|
ext.EqualsIgnoreCase(IMAGE_EXT_PNG) ||
|
||||||
ext.EqualsIgnoreCase(IMAGE_EXT_XBM))
|
ext.EqualsIgnoreCase(IMAGE_EXT_XBM) ||
|
||||||
|
ext.EqualsIgnoreCase(IMAGE_EXT_BMP) ||
|
||||||
|
ext.EqualsIgnoreCase(IMAGE_EXT_ICO))
|
||||||
{
|
{
|
||||||
*aImage = PR_TRUE;
|
*aImage = PR_TRUE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,19 +88,160 @@
|
||||||
#include "nsIStyleSet.h"
|
#include "nsIStyleSet.h"
|
||||||
#include "nsIStyleContext.h"
|
#include "nsIStyleContext.h"
|
||||||
#include "nsBoxLayoutState.h"
|
#include "nsBoxLayoutState.h"
|
||||||
|
#include "nsIDOMDocument.h"
|
||||||
|
#include "nsIEventQueueService.h"
|
||||||
|
|
||||||
#include "nsIServiceManager.h"
|
#include "nsIServiceManager.h"
|
||||||
#include "nsIURI.h"
|
#include "nsIURI.h"
|
||||||
#include "nsNetUtil.h"
|
#include "nsNetUtil.h"
|
||||||
|
#include "nsGUIEvent.h"
|
||||||
|
|
||||||
#include "nsFormControlHelper.h"
|
#include "nsFormControlHelper.h"
|
||||||
|
|
||||||
#define ONLOAD_CALLED_TOO_EARLY 1
|
#define ONLOAD_CALLED_TOO_EARLY 1
|
||||||
|
|
||||||
|
static void PR_CALLBACK
|
||||||
|
HandleImagePLEvent(nsIContent *aContent, PRUint32 aMessage, PRUint32 aFlags)
|
||||||
|
{
|
||||||
|
nsCOMPtr<nsIDOMNode> node(do_QueryInterface(aContent));
|
||||||
|
|
||||||
|
if (!node) {
|
||||||
|
NS_ERROR("null or non-DOM node passed to HandleImagePLEvent!");
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIDOMDocument> dom_doc;
|
||||||
|
node->GetOwnerDocument(getter_AddRefs(dom_doc));
|
||||||
|
|
||||||
|
nsCOMPtr<nsIDocument> doc(do_QueryInterface(dom_doc));
|
||||||
|
|
||||||
|
if (!doc) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIPresShell> pres_shell;
|
||||||
|
doc->GetShellAt(0, getter_AddRefs(pres_shell));
|
||||||
|
|
||||||
|
if (!pres_shell) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIPresContext> pres_context;
|
||||||
|
pres_shell->GetPresContext(getter_AddRefs(pres_context));
|
||||||
|
|
||||||
|
if (!pres_context) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsEventStatus status = nsEventStatus_eIgnore;
|
||||||
|
nsEvent event;
|
||||||
|
event.eventStructType = NS_EVENT;
|
||||||
|
event.message = aMessage;
|
||||||
|
|
||||||
|
aContent->HandleDOMEvent(pres_context, &event, nsnull, aFlags, &status);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void PR_CALLBACK
|
||||||
|
HandleImageOnloadPLEvent(PLEvent *aEvent)
|
||||||
|
{
|
||||||
|
nsIContent *content = (nsIContent *)PL_GetEventOwner(aEvent);
|
||||||
|
|
||||||
|
HandleImagePLEvent(content, NS_IMAGE_LOAD,
|
||||||
|
NS_EVENT_FLAG_INIT | NS_EVENT_FLAG_CANT_BUBBLE);
|
||||||
|
|
||||||
|
NS_RELEASE(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void PR_CALLBACK
|
||||||
|
HandleImageOnerrorPLEvent(PLEvent *aEvent)
|
||||||
|
{
|
||||||
|
nsIContent *content = (nsIContent *)PL_GetEventOwner(aEvent);
|
||||||
|
|
||||||
|
HandleImagePLEvent(content, NS_IMAGE_ERROR, NS_EVENT_FLAG_INIT);
|
||||||
|
|
||||||
|
NS_RELEASE(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void PR_CALLBACK
|
||||||
|
DestroyImagePLEvent(PLEvent* aEvent)
|
||||||
|
{
|
||||||
|
delete aEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fire off a PLEvent that'll asynchronously call the image elements
|
||||||
|
// onload handler once handled. This is needed since the image library
|
||||||
|
// can't decide if it wants to call it's observer methods
|
||||||
|
// synchronously or asynchronously. If an image is loaded from the
|
||||||
|
// cache the notifications come back synchronously, but if the image
|
||||||
|
// is loaded from the netswork the notifications come back
|
||||||
|
// asynchronously.
|
||||||
|
|
||||||
|
void
|
||||||
|
FireDOMEvent(nsIContent* aContent, PRUint32 aMessage)
|
||||||
|
{
|
||||||
|
static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
|
||||||
|
|
||||||
|
nsCOMPtr<nsIEventQueueService> event_service =
|
||||||
|
do_GetService(kEventQueueServiceCID);
|
||||||
|
|
||||||
|
if (!event_service) {
|
||||||
|
NS_WARNING("Failed to get event queue service");
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIEventQueue> event_queue;
|
||||||
|
|
||||||
|
event_service->GetThreadEventQueue(NS_CURRENT_THREAD,
|
||||||
|
getter_AddRefs(event_queue));
|
||||||
|
|
||||||
|
if (!event_queue) {
|
||||||
|
NS_WARNING("Failed to get event queue from service");
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PLEvent *event = new PLEvent;
|
||||||
|
|
||||||
|
if (!event) {
|
||||||
|
// Out of memory, but none of our callers care, so just warn and
|
||||||
|
// don't fire the event
|
||||||
|
|
||||||
|
NS_WARNING("Out of memory?");
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PLHandleEventProc f;
|
||||||
|
|
||||||
|
switch (aMessage) {
|
||||||
|
case NS_IMAGE_LOAD :
|
||||||
|
f = (PLHandleEventProc)::HandleImageOnloadPLEvent;
|
||||||
|
|
||||||
|
break;
|
||||||
|
case NS_IMAGE_ERROR :
|
||||||
|
f = (PLHandleEventProc)::HandleImageOnerrorPLEvent;
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
NS_WARNING("Huh, I don't know how to fire this type of event?!");
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PL_InitEvent(event, aContent, f, (PLDestroyEventProc)::DestroyImagePLEvent);
|
||||||
|
|
||||||
|
// The event owns the content pointer now.
|
||||||
|
NS_ADDREF(aContent);
|
||||||
|
|
||||||
|
event_queue->PostEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// NS_NewToolbarFrame
|
// NS_NewImageBoxFrame
|
||||||
//
|
//
|
||||||
// Creates a new Toolbar frame and returns it in |aNewFrame|
|
// Creates a new image frame and returns it in |aNewFrame|
|
||||||
//
|
//
|
||||||
nsresult
|
nsresult
|
||||||
NS_NewImageBoxFrame ( nsIPresShell* aPresShell, nsIFrame** aNewFrame )
|
NS_NewImageBoxFrame ( nsIPresShell* aPresShell, nsIFrame** aNewFrame )
|
||||||
|
@ -615,9 +756,13 @@ NS_IMETHODIMP nsImageBoxFrame::OnStopContainer(imgIRequest *request, nsIPresCont
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP nsImageBoxFrame::OnStopDecode(imgIRequest *request, nsIPresContext *aPresContext, nsresult status, const PRUnichar *statusArg)
|
NS_IMETHODIMP nsImageBoxFrame::OnStopDecode(imgIRequest *request, nsIPresContext *aPresContext, nsresult aStatus, const PRUnichar *statusArg)
|
||||||
{
|
{
|
||||||
return NS_ERROR_NOT_IMPLEMENTED;
|
if (NS_FAILED(aStatus))
|
||||||
|
// Fire an onerror DOM event.
|
||||||
|
FireDOMEvent(mContent, NS_IMAGE_ERROR);
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP nsImageBoxFrame::FrameChanged(imgIContainer *container, nsIPresContext *aPresContext, gfxIImageFrame *newframe, nsRect * dirtyRect)
|
NS_IMETHODIMP nsImageBoxFrame::FrameChanged(imgIContainer *container, nsIPresContext *aPresContext, gfxIImageFrame *newframe, nsRect * dirtyRect)
|
||||||
|
@ -703,7 +848,9 @@ NS_IMETHODIMP nsImageBoxListener::OnStopDecode(imgIRequest *request, nsISupports
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
|
|
||||||
nsCOMPtr<nsIPresContext> pc(do_QueryInterface(cx));
|
nsCOMPtr<nsIPresContext> pc(do_QueryInterface(cx));
|
||||||
return mFrame->OnStopDecode(request, pc, status, statusArg);
|
nsresult rv = mFrame->OnStopDecode(request, pc, status, statusArg);
|
||||||
|
|
||||||
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP nsImageBoxListener::FrameChanged(imgIContainer *container, nsISupports *cx, gfxIImageFrame *newframe, nsRect * dirtyRect)
|
NS_IMETHODIMP nsImageBoxListener::FrameChanged(imgIContainer *container, nsISupports *cx, gfxIImageFrame *newframe, nsRect * dirtyRect)
|
||||||
|
|
|
@ -533,7 +533,7 @@ nsOutlinerBodyFrame::SetFocused(PRBool aFocused)
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsOutlinerBodyFrame::GetOutlinerBody(nsIDOMElement** aElement)
|
nsOutlinerBodyFrame::GetOutlinerBody(nsIDOMElement** aElement)
|
||||||
{
|
{
|
||||||
NS_ASSERTION(mContent, "no content, see bug #104878");
|
//NS_ASSERTION(mContent, "no content, see bug #104878");
|
||||||
if (!mContent)
|
if (!mContent)
|
||||||
return NS_ERROR_NULL_POINTER;
|
return NS_ERROR_NULL_POINTER;
|
||||||
|
|
||||||
|
|
|
@ -533,7 +533,7 @@ nsOutlinerBodyFrame::SetFocused(PRBool aFocused)
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsOutlinerBodyFrame::GetOutlinerBody(nsIDOMElement** aElement)
|
nsOutlinerBodyFrame::GetOutlinerBody(nsIDOMElement** aElement)
|
||||||
{
|
{
|
||||||
NS_ASSERTION(mContent, "no content, see bug #104878");
|
//NS_ASSERTION(mContent, "no content, see bug #104878");
|
||||||
if (!mContent)
|
if (!mContent)
|
||||||
return NS_ERROR_NULL_POINTER;
|
return NS_ERROR_NULL_POINTER;
|
||||||
|
|
||||||
|
|
|
@ -448,7 +448,9 @@ mime_find_class (const char *content_type, MimeHeaders *hdrs,
|
||||||
!nsCRT::strcasecmp(content_type, IMAGE_PNG) ||
|
!nsCRT::strcasecmp(content_type, IMAGE_PNG) ||
|
||||||
!nsCRT::strcasecmp(content_type, IMAGE_XBM) ||
|
!nsCRT::strcasecmp(content_type, IMAGE_XBM) ||
|
||||||
!nsCRT::strcasecmp(content_type, IMAGE_XBM2) ||
|
!nsCRT::strcasecmp(content_type, IMAGE_XBM2) ||
|
||||||
!nsCRT::strcasecmp(content_type, IMAGE_XBM3))
|
!nsCRT::strcasecmp(content_type, IMAGE_XBM3) ||
|
||||||
|
!nsCRT::strcasecmp(content_type, IMAGE_BMP) ||
|
||||||
|
!nsCRT::strcasecmp(content_type, IMAGE_ICO))
|
||||||
clazz = (MimeObjectClass *)&mimeInlineImageClass;
|
clazz = (MimeObjectClass *)&mimeInlineImageClass;
|
||||||
|
|
||||||
#ifdef ENABLE_SMIME
|
#ifdef ENABLE_SMIME
|
||||||
|
|
|
@ -26,7 +26,7 @@ VPATH = @srcdir@
|
||||||
|
|
||||||
include $(DEPTH)/config/autoconf.mk
|
include $(DEPTH)/config/autoconf.mk
|
||||||
|
|
||||||
DIRS = ppm png gif jpeg
|
DIRS = ppm png gif jpeg bmp
|
||||||
|
|
||||||
include $(topsrcdir)/config/rules.mk
|
include $(topsrcdir)/config/rules.mk
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
#
|
||||||
|
# The contents of this file are subject to the Mozilla Public
|
||||||
|
# License Version 1.1 (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.mozilla.org/MPL/
|
||||||
|
#
|
||||||
|
# Software distributed under the License is distributed on an "AS
|
||||||
|
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||||
|
# implied. See the License for the specific language governing
|
||||||
|
# rights and limitations under the License.
|
||||||
|
#
|
||||||
|
# The Original Code is mozilla.org code
|
||||||
|
#
|
||||||
|
# The Initial Developer of the Original Code is Netscape
|
||||||
|
# Communications Corporation. Portions created by Netscape are
|
||||||
|
# Copyright (C) 2001 Netscape Communications Corporation. All
|
||||||
|
# Rights Reserved.
|
||||||
|
#
|
||||||
|
# Contributor(s):
|
||||||
|
# Christian Biesinger <cbiesinger@web.de>
|
||||||
|
#
|
||||||
|
|
||||||
|
DEPTH = ../../../..
|
||||||
|
topsrcdir = @top_srcdir@
|
||||||
|
srcdir = @srcdir@
|
||||||
|
VPATH = @srcdir@
|
||||||
|
|
||||||
|
include $(DEPTH)/config/autoconf.mk
|
||||||
|
|
||||||
|
MODULE = imgbmp
|
||||||
|
LIBRARY_NAME = imgbmp
|
||||||
|
EXPORT_LIBRARY = 1
|
||||||
|
IS_COMPONENT = 1
|
||||||
|
MODULE_NAME = nsBMPModule
|
||||||
|
|
||||||
|
REQUIRES = xpcom \
|
||||||
|
necko \
|
||||||
|
gfx \
|
||||||
|
gfx2 \
|
||||||
|
imglib2 \
|
||||||
|
string \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
CPPSRCS = nsBMPDecoder.cpp nsICODecoder.cpp nsBMPModule.cpp
|
||||||
|
|
||||||
|
EXTRA_DSO_LDOPTS = $(MOZ_COMPONENT_LIBS) \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
include $(topsrcdir)/config/rules.mk
|
|
@ -0,0 +1,474 @@
|
||||||
|
/* vim:set tw=80 expandtab softtabstop=4 ts=4 sw=4: */
|
||||||
|
/* ----- BEGIN LICENSE BLOCK -----
|
||||||
|
* Version: MPL 1.1/LGPL 2.1/GPL 2.0
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Mozilla Public
|
||||||
|
* License Version 1.1 (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.mozilla.org/MPL/
|
||||||
|
*
|
||||||
|
* Software distributed under the License is distributed on an "AS
|
||||||
|
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||||
|
* implied. See the License for the specific language governing
|
||||||
|
* rights and limitations under the License.
|
||||||
|
*
|
||||||
|
* The Original Code is the Mozilla BMP Decoder.
|
||||||
|
*
|
||||||
|
* The Initial Developer of the Original Code is Christian Biesinger
|
||||||
|
* <cbiesinger@web.de>. Portions created by Christian Biesinger are
|
||||||
|
* Copyright (C) 2001 Christian Biesinger. All
|
||||||
|
* Rights Reserved.
|
||||||
|
*
|
||||||
|
* Contributor(s):
|
||||||
|
*
|
||||||
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||||
|
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||||
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||||
|
* of those above. If you wish to allow use of your version of this file only
|
||||||
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||||
|
* use your version of this file under the terms of the MPL, indicate your
|
||||||
|
* decision by deleting the provisions above and replace them with the notice
|
||||||
|
* and other provisions required by the LGPL or the GPL. If you do not delete
|
||||||
|
* the provisions above, a recipient may use your version of this file under
|
||||||
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||||
|
*
|
||||||
|
* ----- END LICENSE BLOCK ----- */
|
||||||
|
/* I got the format description from http://www.daubnet.com/formats/BMP.html */
|
||||||
|
|
||||||
|
/* This does not yet work in this version:
|
||||||
|
* o) Compressed Bitmaps, including ones using bitfields
|
||||||
|
* This decoder was tested on Windows, Linux and Mac. */
|
||||||
|
|
||||||
|
/* This is a Cross-Platform BMP Decoder, which should work everywhere, including
|
||||||
|
* Big-Endian machines like the PowerPC. */
|
||||||
|
|
||||||
|
#include "nsBMPDecoder.h"
|
||||||
|
|
||||||
|
#include "nsIInputStream.h"
|
||||||
|
#include "nsIComponentManager.h"
|
||||||
|
#include "nsIImage.h"
|
||||||
|
#include "nsMemory.h"
|
||||||
|
#include "imgIContainerObserver.h"
|
||||||
|
#include "nsRect.h"
|
||||||
|
|
||||||
|
#include "imgILoad.h"
|
||||||
|
|
||||||
|
#include "prcpucfg.h" // To get IS_LITTLE_ENDIAN / IS_BIG_ENDIAN
|
||||||
|
|
||||||
|
#include "ImageLogging.h"
|
||||||
|
|
||||||
|
PRLogModuleInfo *gBMPLog = PR_NewLogModule("BMPDecoder");
|
||||||
|
|
||||||
|
NS_IMPL_ISUPPORTS1(nsBMPDecoder, imgIDecoder)
|
||||||
|
|
||||||
|
nsBMPDecoder::nsBMPDecoder()
|
||||||
|
{
|
||||||
|
NS_INIT_ISUPPORTS();
|
||||||
|
mColors = nsnull;
|
||||||
|
mRow = nsnull;
|
||||||
|
mPos = mNumColors = mRowBytes = mCurLine = 0;
|
||||||
|
mLOH = 54;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsBMPDecoder::~nsBMPDecoder()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP nsBMPDecoder::Init(imgILoad *aLoad)
|
||||||
|
{
|
||||||
|
PR_LOG(gBMPLog, PR_LOG_DEBUG, ("nsBMPDecoder::Init(%p)\n", aLoad));
|
||||||
|
NS_ENSURE_ARG_POINTER(aLoad);
|
||||||
|
mObserver = do_QueryInterface(aLoad);
|
||||||
|
|
||||||
|
mImage = do_CreateInstance("@mozilla.org/image/container;1");
|
||||||
|
if (!mImage)
|
||||||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
|
||||||
|
mFrame = do_CreateInstance("@mozilla.org/gfx/image/frame;2");
|
||||||
|
if (!mFrame)
|
||||||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
|
||||||
|
nsresult rv = aLoad->SetImage(mImage);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP nsBMPDecoder::Close()
|
||||||
|
{
|
||||||
|
PR_LOG(gBMPLog, PR_LOG_DEBUG, ("nsBMPDecoder::Close()\n"));
|
||||||
|
mPos = 0;
|
||||||
|
delete[] mColors;
|
||||||
|
mColors = nsnull;
|
||||||
|
mNumColors = 0;
|
||||||
|
delete[] mRow;
|
||||||
|
mRow = nsnull;
|
||||||
|
mRowBytes = 0;
|
||||||
|
mCurLine = 0;
|
||||||
|
|
||||||
|
if (mObserver) {
|
||||||
|
mObserver->OnStopContainer(nsnull, nsnull, mImage);
|
||||||
|
mObserver->OnStopDecode(nsnull, nsnull, NS_OK, nsnull);
|
||||||
|
mObserver = nsnull;
|
||||||
|
}
|
||||||
|
mImage = nsnull;
|
||||||
|
mFrame = nsnull;
|
||||||
|
mLOH = 54;
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP nsBMPDecoder::Flush()
|
||||||
|
{
|
||||||
|
mFrame->SetMutable(PR_FALSE);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP nsBMPDecoder::WriteFrom(nsIInputStream *aInStr, PRUint32 aCount, PRUint32 *aRetval)
|
||||||
|
{
|
||||||
|
PR_LOG(gBMPLog, PR_LOG_DEBUG, ("nsBMPDecoder::WriteFrom(%p, %lu, %p)\n", aInStr, aCount, aRetval));
|
||||||
|
NS_ENSURE_ARG_POINTER(aInStr);
|
||||||
|
NS_ENSURE_ARG_POINTER(aRetval);
|
||||||
|
|
||||||
|
char* buffer = new char[aCount];
|
||||||
|
if (!buffer) {
|
||||||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
unsigned int realCount = aCount;
|
||||||
|
nsresult rv = aInStr->Read(buffer, aCount, &realCount);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
*aRetval = realCount;
|
||||||
|
|
||||||
|
rv = ProcessData(buffer, realCount);
|
||||||
|
delete []buffer;
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------
|
||||||
|
// Actual Data Processing
|
||||||
|
// ----------------------------------------
|
||||||
|
|
||||||
|
inline nsresult nsBMPDecoder::SetPixel(PRUint8*& aDecoded, PRUint8 idx)
|
||||||
|
{
|
||||||
|
PRUint8 red, green, blue;
|
||||||
|
red = mColors[idx].red;
|
||||||
|
green = mColors[idx].green;
|
||||||
|
blue = mColors[idx].blue;
|
||||||
|
return SetPixel(aDecoded, red, green, blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline nsresult nsBMPDecoder::SetPixel(PRUint8*& aDecoded, PRUint8 aRed, PRUint8 aGreen, PRUint8 aBlue)
|
||||||
|
{
|
||||||
|
#if defined(XP_MAC) || defined(XP_MACOSX)
|
||||||
|
*aDecoded++ = 0; // Mac needs this padding byte
|
||||||
|
#endif
|
||||||
|
#ifdef USE_RGB
|
||||||
|
*aDecoded++ = aRed;
|
||||||
|
*aDecoded++ = aGreen;
|
||||||
|
*aDecoded++ = aBlue;
|
||||||
|
#else
|
||||||
|
*aDecoded++ = aBlue;
|
||||||
|
*aDecoded++ = aGreen;
|
||||||
|
*aDecoded++ = aRed;
|
||||||
|
#endif
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline nsresult nsBMPDecoder::Set4BitPixel(PRUint8*& aDecoded, PRUint8 aData, PRUint32& aPos)
|
||||||
|
{
|
||||||
|
PRUint8 idx = aData >> 4;
|
||||||
|
nsresult rv = SetPixel(aDecoded, idx);
|
||||||
|
if ((++aPos >= mBIH.width) || NS_FAILED(rv))
|
||||||
|
return rv;
|
||||||
|
|
||||||
|
idx = aData & 0xF;
|
||||||
|
rv = SetPixel(aDecoded, idx);
|
||||||
|
++aPos;
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline nsresult nsBMPDecoder::SetData(PRUint8* aData)
|
||||||
|
{
|
||||||
|
NS_ENSURE_ARG_POINTER(aData);
|
||||||
|
PRUint32 bpr;
|
||||||
|
nsresult rv;
|
||||||
|
|
||||||
|
rv = mFrame->GetImageBytesPerRow(&bpr);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
PRUint32 offset = (mCurLine - 1) * bpr;
|
||||||
|
rv = mFrame->SetImageData(aData, bpr, offset);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
nsRect r(0, mCurLine, mBIH.width, 1);
|
||||||
|
rv = mObserver->OnDataAvailable(nsnull, nsnull, mFrame, &r);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_METHOD nsBMPDecoder::ProcessData(const char* aBuffer, PRUint32 aCount)
|
||||||
|
{
|
||||||
|
if (!aCount) // aCount=0 means EOF
|
||||||
|
return NS_OK;
|
||||||
|
|
||||||
|
nsresult rv;
|
||||||
|
if (mPos < 18) { /* In BITMAPFILEHEADER */
|
||||||
|
PRUint32 toCopy = 18 - mPos;
|
||||||
|
if (toCopy > aCount)
|
||||||
|
toCopy = aCount;
|
||||||
|
nsCRT::memcpy(mRawBuf + mPos, aBuffer, toCopy);
|
||||||
|
mPos += toCopy;
|
||||||
|
aCount -= toCopy;
|
||||||
|
aBuffer += toCopy;
|
||||||
|
}
|
||||||
|
if (mPos == 18) {
|
||||||
|
rv = mObserver->OnStartDecode(nsnull, nsnull);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
ProcessFileHeader();
|
||||||
|
if (mBFH.signature[0] != 'B' || mBFH.signature[1] != 'M')
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
if (mBFH.bihsize == 12)
|
||||||
|
mLOH = 26;
|
||||||
|
}
|
||||||
|
if (mPos >= 18 && mPos < mLOH) { /* In BITMAPINFOHEADER */
|
||||||
|
PRUint32 toCopy = mLOH - mPos;
|
||||||
|
if (toCopy > aCount)
|
||||||
|
toCopy = aCount;
|
||||||
|
nsCRT::memcpy(mRawBuf + (mPos - 18), aBuffer, toCopy);
|
||||||
|
mPos += toCopy;
|
||||||
|
aCount -= toCopy;
|
||||||
|
aBuffer += toCopy;
|
||||||
|
}
|
||||||
|
if (mPos == mLOH) {
|
||||||
|
ProcessInfoHeader();
|
||||||
|
PR_LOG(gBMPLog, PR_LOG_DEBUG, ("BMP image is %lux%lux%lu. compression=%lu\n",
|
||||||
|
mBIH.width, mBIH.height, mBIH.bpp, mBIH.compression));
|
||||||
|
if (mBIH.compression) {
|
||||||
|
PR_LOG(gBMPLog, PR_LOG_DEBUG, ("Don't yet support compressed BMPs\n"));
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mBIH.bpp <= 8) {
|
||||||
|
switch (mBIH.bpp) {
|
||||||
|
case 1:
|
||||||
|
mNumColors = 2;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
mNumColors = 16;
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
mNumColors = 256;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
if (mBIH.colors)
|
||||||
|
mNumColors = mBIH.colors;
|
||||||
|
|
||||||
|
mColors = new colorTable[mNumColors];
|
||||||
|
if (!mColors)
|
||||||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = mImage->Init(mBIH.width, mBIH.height, mObserver);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
rv = mObserver->OnStartContainer(nsnull, nsnull, mImage);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
mCurLine = mBIH.height;
|
||||||
|
|
||||||
|
mRow = new PRUint8[(mBIH.width * mBIH.bpp)/8 + 4];
|
||||||
|
// +4 because the line is padded to a 4 bit boundary, but I don't want
|
||||||
|
// to make exact calculations here, that's unnecessary.
|
||||||
|
// Also, it compensates rounding error.
|
||||||
|
if (!mRow) {
|
||||||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
rv = mFrame->Init(0, 0, mBIH.width, mBIH.height, GFXFORMAT);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
rv = mImage->AppendFrame(mFrame);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
mObserver->OnStartFrame(nsnull, nsnull, mFrame);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
}
|
||||||
|
PRUint8 bpc; // bytes per color
|
||||||
|
bpc = (mBFH.bihsize == 12) ? 3 : 4; // OS/2 Bitmaps have no padding byte
|
||||||
|
if (mColors && (mPos >= mLOH && (mPos < (mLOH + mNumColors * bpc)))) {
|
||||||
|
// We will receive (mNumColors * 4) bytes of color data
|
||||||
|
PRUint32 colorBytes = mPos - mLOH; // Number of bytes already received
|
||||||
|
PRUint8 colorNum = colorBytes / bpc; // Color which is currently received
|
||||||
|
PRUint8 at = colorBytes % bpc;
|
||||||
|
while (aCount && (mPos < (mLOH + mNumColors * bpc))) {
|
||||||
|
switch (at) {
|
||||||
|
case 0:
|
||||||
|
mColors[colorNum].blue = *aBuffer;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
mColors[colorNum].green = *aBuffer;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
mColors[colorNum].red = *aBuffer;
|
||||||
|
colorNum++;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
// This is a padding byte
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
mPos++; aBuffer++; aCount--;
|
||||||
|
at = (at + 1) % bpc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (aCount && (mPos < mBFH.dataoffset)) { // Skip whatever is between header and data
|
||||||
|
mPos++; aBuffer++; aCount--;
|
||||||
|
}
|
||||||
|
if (++mPos >= mBFH.dataoffset) {
|
||||||
|
if (!mBIH.compression) {
|
||||||
|
// Need to increment mPos, else we might get to mPos==mLOH again
|
||||||
|
// From now on, mPos is irrelevant
|
||||||
|
PRUint32 rowSize = (mBIH.bpp * mBIH.width + 7) / 8; // +7 to round up
|
||||||
|
if (rowSize % 4)
|
||||||
|
rowSize += (4 - (rowSize % 4)); // Pad to DWORD Boundary
|
||||||
|
PRUint32 toCopy;
|
||||||
|
do {
|
||||||
|
toCopy = rowSize - mRowBytes;
|
||||||
|
if (toCopy) {
|
||||||
|
if (toCopy > aCount)
|
||||||
|
toCopy = aCount;
|
||||||
|
nsCRT::memcpy(mRow + mRowBytes, aBuffer, toCopy);
|
||||||
|
aCount -= toCopy;
|
||||||
|
aBuffer += toCopy;
|
||||||
|
mRowBytes += toCopy;
|
||||||
|
}
|
||||||
|
if ((rowSize - mRowBytes) == 0) {
|
||||||
|
PRUint32 bpr;
|
||||||
|
rv = mFrame->GetImageBytesPerRow(&bpr);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
PRUint8* decoded = new PRUint8[bpr];
|
||||||
|
if (!decoded)
|
||||||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
|
||||||
|
PRUint8* p = mRow;
|
||||||
|
PRUint8* d = decoded;
|
||||||
|
PRUint32 lpos = 0;
|
||||||
|
switch (mBIH.bpp) {
|
||||||
|
case 1:
|
||||||
|
while (lpos < mBIH.width) {
|
||||||
|
PRInt8 bit;
|
||||||
|
PRUint8 idx;
|
||||||
|
for (bit = 7; bit >= 0; bit--) {
|
||||||
|
if (lpos >= mBIH.width)
|
||||||
|
break;
|
||||||
|
idx = (*p >> bit) & 1;
|
||||||
|
SetPixel(d, idx);
|
||||||
|
++lpos;
|
||||||
|
}
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
while (lpos < mBIH.width) {
|
||||||
|
Set4BitPixel(d, *p, lpos);
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
while (lpos < mBIH.width) {
|
||||||
|
SetPixel(d, *p);
|
||||||
|
++lpos;
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
while (lpos < mBIH.width) {
|
||||||
|
SetPixel(d,
|
||||||
|
(p[1] & 124) << 1,
|
||||||
|
((p[1] & 3) << 6) | ((p[0] & 224) >> 2),
|
||||||
|
(p[0] & 31) << 3);
|
||||||
|
|
||||||
|
++lpos;
|
||||||
|
p+=2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 32:
|
||||||
|
case 24:
|
||||||
|
while (lpos < mBIH.width) {
|
||||||
|
SetPixel(d, p[2], p[1], p[0]);
|
||||||
|
p += 2;
|
||||||
|
++lpos;
|
||||||
|
if (mBIH.bpp == 32)
|
||||||
|
p++; // Padding byte
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// This is probably the wrong place to check this...
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult rv = SetData(decoded);
|
||||||
|
delete[] decoded;
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
if (mCurLine == 1) { // Finished last line
|
||||||
|
return mObserver->OnStopFrame(nsnull, nsnull, mFrame);
|
||||||
|
}
|
||||||
|
mCurLine--; mRowBytes = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
} while (aCount > 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nsBMPDecoder::ProcessFileHeader()
|
||||||
|
{
|
||||||
|
nsCRT::memset(&mBFH, 0, sizeof(mBFH));
|
||||||
|
DOCOPY(&mBFH.signature, mRawBuf);
|
||||||
|
DOCOPY(&mBFH.filesize, mRawBuf + 2);
|
||||||
|
DOCOPY(&mBFH.reserved, mRawBuf + 6);
|
||||||
|
DOCOPY(&mBFH.dataoffset, mRawBuf + 10);
|
||||||
|
DOCOPY(&mBFH.bihsize, mRawBuf + 14);
|
||||||
|
|
||||||
|
// Now correct the endianness of the header
|
||||||
|
mBFH.filesize = LITTLE_TO_NATIVE32(mBFH.filesize);
|
||||||
|
mBFH.dataoffset = LITTLE_TO_NATIVE32(mBFH.dataoffset);
|
||||||
|
mBFH.bihsize = LITTLE_TO_NATIVE32(mBFH.bihsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void nsBMPDecoder::ProcessInfoHeader()
|
||||||
|
{
|
||||||
|
nsCRT::memset(&mBIH, 0, sizeof(mBIH));
|
||||||
|
if (mBFH.bihsize == 12) { // OS/2 Bitmap
|
||||||
|
nsCRT::memcpy(&mBIH.width, mRawBuf, 2);
|
||||||
|
nsCRT::memcpy(&mBIH.height, mRawBuf + 2, 2);
|
||||||
|
DOCOPY(&mBIH.planes, mRawBuf + 4);
|
||||||
|
DOCOPY(&mBIH.bpp, mRawBuf + 6);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
DOCOPY(&mBIH.width, mRawBuf);
|
||||||
|
DOCOPY(&mBIH.height, mRawBuf + 4);
|
||||||
|
DOCOPY(&mBIH.planes, mRawBuf + 8);
|
||||||
|
DOCOPY(&mBIH.bpp, mRawBuf + 10);
|
||||||
|
DOCOPY(&mBIH.compression, mRawBuf + 12);
|
||||||
|
DOCOPY(&mBIH.image_size, mRawBuf + 16);
|
||||||
|
DOCOPY(&mBIH.xppm, mRawBuf + 20);
|
||||||
|
DOCOPY(&mBIH.yppm, mRawBuf + 24);
|
||||||
|
DOCOPY(&mBIH.colors, mRawBuf + 28);
|
||||||
|
DOCOPY(&mBIH.important_colors, mRawBuf + 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert endianness
|
||||||
|
mBIH.width = LITTLE_TO_NATIVE32(mBIH.width);
|
||||||
|
mBIH.height = LITTLE_TO_NATIVE32(mBIH.height);
|
||||||
|
mBIH.planes = LITTLE_TO_NATIVE16(mBIH.planes);
|
||||||
|
mBIH.bpp = LITTLE_TO_NATIVE16(mBIH.bpp);
|
||||||
|
|
||||||
|
mBIH.compression = LITTLE_TO_NATIVE32(mBIH.compression);
|
||||||
|
mBIH.image_size = LITTLE_TO_NATIVE32(mBIH.image_size);
|
||||||
|
mBIH.xppm = LITTLE_TO_NATIVE32(mBIH.xppm);
|
||||||
|
mBIH.yppm = LITTLE_TO_NATIVE32(mBIH.yppm);
|
||||||
|
mBIH.colors = LITTLE_TO_NATIVE32(mBIH.colors);
|
||||||
|
mBIH.important_colors = LITTLE_TO_NATIVE32(mBIH.important_colors);
|
||||||
|
}
|
|
@ -0,0 +1,172 @@
|
||||||
|
/* vim:set tw=80 expandtab softtabstop=4 ts=4 sw=4: */
|
||||||
|
/* ----- BEGIN LICENSE BLOCK -----
|
||||||
|
* Version: MPL 1.1/LGPL 2.1/GPL 2.0
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Mozilla Public
|
||||||
|
* License Version 1.1 (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.mozilla.org/MPL/
|
||||||
|
*
|
||||||
|
* Software distributed under the License is distributed on an "AS
|
||||||
|
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||||
|
* implied. See the License for the specific language governing
|
||||||
|
* rights and limitations under the License.
|
||||||
|
*
|
||||||
|
* The Original Code is the Mozilla BMP Decoder.
|
||||||
|
*
|
||||||
|
* The Initial Developer of the Original Code is Christian Biesinger
|
||||||
|
* <cbiesinger@web.de>. Portions created by Christian Biesinger are
|
||||||
|
* Copyright (C) 2001 Christian Biesinger. All
|
||||||
|
* Rights Reserved.
|
||||||
|
*
|
||||||
|
* Contributor(s):
|
||||||
|
*
|
||||||
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||||
|
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||||
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||||
|
* of those above. If you wish to allow use of your version of this file only
|
||||||
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||||
|
* use your version of this file under the terms of the MPL, indicate your
|
||||||
|
* decision by deleting the provisions above and replace them with the notice
|
||||||
|
* and other provisions required by the LGPL or the GPL. If you do not delete
|
||||||
|
* the provisions above, a recipient may use your version of this file under
|
||||||
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||||
|
*
|
||||||
|
* ----- END LICENSE BLOCK ----- */
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _nsBMPDecoder_h
|
||||||
|
#define _nsBMPDecoder_h
|
||||||
|
|
||||||
|
#include "nsCOMPtr.h"
|
||||||
|
#include "imgIDecoder.h"
|
||||||
|
#include "imgIContainer.h"
|
||||||
|
#include "imgIDecoderObserver.h"
|
||||||
|
#include "gfxIImageFrame.h"
|
||||||
|
|
||||||
|
#define NS_BMPDECODER_CID \
|
||||||
|
{ /* {78c61626-4d1f-4843-9364-4652d98ff6e1} */ \
|
||||||
|
0x78c61626, \
|
||||||
|
0x4d1f, \
|
||||||
|
0x4843, \
|
||||||
|
{ 0x93, 0x64, 0x46, 0x52, 0xd9, 0x8f, 0xf6, 0xe1 } \
|
||||||
|
}
|
||||||
|
|
||||||
|
struct BMPFILEHEADER {
|
||||||
|
char signature[2]; // String "BM"
|
||||||
|
PRUint32 filesize;
|
||||||
|
PRInt32 reserved; // Zero
|
||||||
|
PRUint32 dataoffset; // Offset to raster data
|
||||||
|
|
||||||
|
PRUint32 bihsize;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BMPINFOHEADER {
|
||||||
|
PRUint32 width;
|
||||||
|
PRUint32 height;
|
||||||
|
PRUint16 planes; // =1
|
||||||
|
PRUint16 bpp; // Bits per pixel.
|
||||||
|
// The rest of the header is not available in OS/2 BMP Files
|
||||||
|
PRUint32 compression; // 0=no compression 1=8bit RLE 2=4bit RLE
|
||||||
|
PRUint32 image_size; // (compressed) image size. Can be 0 if compression==0
|
||||||
|
PRUint32 xppm; // Pixels per meter, horizontal
|
||||||
|
PRUint32 yppm; // Pixels per meter, vertical
|
||||||
|
PRUint32 colors; // Used Colors
|
||||||
|
PRUint32 important_colors; // Number of important colors. 0=all
|
||||||
|
};
|
||||||
|
|
||||||
|
struct colorTable {
|
||||||
|
PRUint8 red;
|
||||||
|
PRUint8 green;
|
||||||
|
PRUint8 blue;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bitFields {
|
||||||
|
PRUint32 red;
|
||||||
|
PRUint32 green;
|
||||||
|
PRUint32 blue;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define DOCOPY(dest, src) nsCRT::memcpy(dest, src, sizeof(dest))
|
||||||
|
|
||||||
|
#if defined WORDS_BIGENDIAN || defined IS_BIG_ENDIAN
|
||||||
|
#define LITTLE_TO_NATIVE16(x) ((((x) & 0xFF) << 8) | ((x) >> 8))
|
||||||
|
#define LITTLE_TO_NATIVE32(x) ((((x) & 0xFF) << 24) | \
|
||||||
|
((((x) >> 8) & 0xFF) << 16) | \
|
||||||
|
((((x) >> 16) & 0xFF) << 8) | \
|
||||||
|
((x) >> 24))
|
||||||
|
#else
|
||||||
|
#define LITTLE_TO_NATIVE16(x) x
|
||||||
|
#define LITTLE_TO_NATIVE32(x) x
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define BI_RLE8 1
|
||||||
|
#define BI_RLE4 2
|
||||||
|
#define BI_BITFIELDS 3
|
||||||
|
|
||||||
|
#if defined(XP_PC) || defined(XP_BEOS) || defined(MOZ_WIDGET_PHOTON)
|
||||||
|
#define GFXFORMAT gfxIFormats::BGR
|
||||||
|
#else
|
||||||
|
#define USE_RGB
|
||||||
|
#define GFXFORMAT gfxIFormats::RGB
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class nsBMPDecoder : public imgIDecoder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NS_DECL_ISUPPORTS
|
||||||
|
NS_DECL_IMGIDECODER
|
||||||
|
|
||||||
|
nsBMPDecoder();
|
||||||
|
virtual ~nsBMPDecoder();
|
||||||
|
|
||||||
|
private:
|
||||||
|
/** Processes the data.
|
||||||
|
* @param aBuffer Data to process.
|
||||||
|
* @oaram count Number of bytes in mBuffer */
|
||||||
|
NS_METHOD ProcessData(const char* aBuffer, PRUint32 aCount);
|
||||||
|
|
||||||
|
/** Sets the pixel data in aDecoded to the given values.
|
||||||
|
* The variable passed in as aDecoded will be moved on 3 bytes! */
|
||||||
|
inline nsresult SetPixel(PRUint8*& aDecoded, PRUint8 aIdx);
|
||||||
|
inline nsresult SetPixel(PRUint8*& aDecoded, PRUint8 aRed, PRUint8 aGreen, PRUint8 aBlue);
|
||||||
|
|
||||||
|
/** Sets one or two pixels; it is ensured that aPos is <= mBIH.width
|
||||||
|
* @param aDecoded where the data is stored. Will be moved 3 or 6 bytes,
|
||||||
|
* depending on whether one or two pixels are written.
|
||||||
|
* @param aData The values for the two pixels
|
||||||
|
* @param aPos Current position. Is incremented by one or two. */
|
||||||
|
inline nsresult Set4BitPixel(PRUint8*& aDecoded, PRUint8 aData, PRUint32& aPos);
|
||||||
|
|
||||||
|
/** Sets the image data at specified position. mCurLine is used
|
||||||
|
* to get the row
|
||||||
|
* @param aData The data */
|
||||||
|
inline nsresult SetData(PRUint8* aData);
|
||||||
|
|
||||||
|
nsCOMPtr<imgIDecoderObserver> mObserver;
|
||||||
|
|
||||||
|
nsCOMPtr<imgIContainer> mImage;
|
||||||
|
nsCOMPtr<gfxIImageFrame> mFrame;
|
||||||
|
|
||||||
|
PRUint32 mPos;
|
||||||
|
|
||||||
|
BMPFILEHEADER mBFH;
|
||||||
|
BMPINFOHEADER mBIH;
|
||||||
|
char mRawBuf[36];
|
||||||
|
|
||||||
|
PRUint32 mLOH; // Length of the header
|
||||||
|
|
||||||
|
PRUint32 mNumColors;
|
||||||
|
colorTable *mColors;
|
||||||
|
|
||||||
|
PRUint8 *mRow; // Holds one raw line of the image
|
||||||
|
PRUint32 mRowBytes; // How many bytes of the row were already received
|
||||||
|
PRUint32 mCurLine;
|
||||||
|
|
||||||
|
void ProcessFileHeader();
|
||||||
|
void ProcessInfoHeader();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,52 @@
|
||||||
|
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||||
|
* vim:set tw=80 expandtab softtabstop=4 ts=4 sw=4:
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Netscape Public
|
||||||
|
* License Version 1.1 (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.mozilla.org/NPL/
|
||||||
|
*
|
||||||
|
* Software distributed under the License is distributed on an "AS
|
||||||
|
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||||
|
* implied. See the License for the specific language governing
|
||||||
|
* rights and limitations under the License.
|
||||||
|
*
|
||||||
|
* The Original Code is mozilla.org code.
|
||||||
|
*
|
||||||
|
* The Initial Developer of the Original Code is Netscape
|
||||||
|
* Communications Corporation. Portions created by Netscape are
|
||||||
|
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||||
|
* Rights Reserved.
|
||||||
|
*
|
||||||
|
* Contributor(s):
|
||||||
|
* Chris Saari <saari@netscape.com>
|
||||||
|
* Christian Biesinger <cbiesinger@web.de>
|
||||||
|
* David Hyatt <hyatt@netscape.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "nsBMPDecoder.h"
|
||||||
|
#include "nsICODecoder.h"
|
||||||
|
#include "nsIComponentManager.h"
|
||||||
|
#include "nsIGenericFactory.h"
|
||||||
|
#include "nsISupports.h"
|
||||||
|
#include "nsCOMPtr.h"
|
||||||
|
|
||||||
|
NS_GENERIC_FACTORY_CONSTRUCTOR(nsICODecoder)
|
||||||
|
NS_GENERIC_FACTORY_CONSTRUCTOR(nsBMPDecoder)
|
||||||
|
|
||||||
|
static nsModuleComponentInfo components[] =
|
||||||
|
{
|
||||||
|
{ "ICO Decoder",
|
||||||
|
NS_ICODECODER_CID,
|
||||||
|
"@mozilla.org/image/decoder;2?type=image/x-icon",
|
||||||
|
nsICODecoderConstructor, },
|
||||||
|
|
||||||
|
{ "BMP Decoder",
|
||||||
|
NS_BMPDECODER_CID,
|
||||||
|
"@mozilla.org/image/decoder;2?type=image/bmp",
|
||||||
|
nsBMPDecoderConstructor, },
|
||||||
|
};
|
||||||
|
|
||||||
|
NS_IMPL_NSGETMODULE(nsBMPModule, components)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,555 @@
|
||||||
|
/* vim:set tw=80 expandtab softtabstop=4 ts=4 sw=4: */
|
||||||
|
/* ----- BEGIN LICENSE BLOCK -----
|
||||||
|
* Version: MPL 1.1/LGPL 2.1/GPL 2.0
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Mozilla Public
|
||||||
|
* License Version 1.1 (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.mozilla.org/MPL/
|
||||||
|
*
|
||||||
|
* Software distributed under the License is distributed on an "AS
|
||||||
|
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||||
|
* implied. See the License for the specific language governing
|
||||||
|
* rights and limitations under the License.
|
||||||
|
*
|
||||||
|
* The Original Code is the Mozilla ICO Decoder.
|
||||||
|
*
|
||||||
|
* The Initial Developer of the Original Code is Netscape.
|
||||||
|
* Portions created by Netscape are
|
||||||
|
* Copyright (C) 2001 Netscape. All
|
||||||
|
* Rights Reserved.
|
||||||
|
*
|
||||||
|
* Contributor(s):
|
||||||
|
* David Hyatt <hyatt@netscape.com> (Original Author)
|
||||||
|
*
|
||||||
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||||
|
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||||
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||||
|
* of those above. If you wish to allow use of your version of this file only
|
||||||
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||||
|
* use your version of this file under the terms of the MPL, indicate your
|
||||||
|
* decision by deleting the provisions above and replace them with the notice
|
||||||
|
* and other provisions required by the LGPL or the GPL. If you do not delete
|
||||||
|
* the provisions above, a recipient may use your version of this file under
|
||||||
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||||
|
*
|
||||||
|
* ----- END LICENSE BLOCK ----- */
|
||||||
|
|
||||||
|
/* This is a Cross-Platform ICO Decoder, which should work everywhere, including
|
||||||
|
* Big-Endian machines like the PowerPC. */
|
||||||
|
|
||||||
|
#include "nsICODecoder.h"
|
||||||
|
|
||||||
|
#include "nsIInputStream.h"
|
||||||
|
#include "nsIComponentManager.h"
|
||||||
|
#include "nsIImage.h"
|
||||||
|
#include "nsMemory.h"
|
||||||
|
#include "imgIContainerObserver.h"
|
||||||
|
#include "nsRect.h"
|
||||||
|
#include "nsCRT.h"
|
||||||
|
|
||||||
|
#include "imgILoad.h"
|
||||||
|
|
||||||
|
#include "prcpucfg.h" // To get IS_LITTLE_ENDIAN / IS_BIG_ENDIAN
|
||||||
|
|
||||||
|
NS_IMPL_ISUPPORTS1(nsICODecoder, imgIDecoder)
|
||||||
|
|
||||||
|
#define ICONCOUNTOFFSET 4
|
||||||
|
#define DIRENTRYOFFSET 6
|
||||||
|
#define BITMAPINFOSIZE 40
|
||||||
|
#define PREFICONSIZE 16
|
||||||
|
|
||||||
|
nsICODecoder::nsICODecoder()
|
||||||
|
{
|
||||||
|
NS_INIT_ISUPPORTS();
|
||||||
|
mPos = mNumColors = mCurLine = mRowBytes = mImageOffset = mCurrIcon = 0;
|
||||||
|
mColors = nsnull;
|
||||||
|
mRow = nsnull;
|
||||||
|
mDecodingAndMask = PR_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsICODecoder::~nsICODecoder()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP nsICODecoder::Init(imgILoad *aLoad)
|
||||||
|
{
|
||||||
|
mObserver = do_QueryInterface(aLoad);
|
||||||
|
|
||||||
|
mImage = do_CreateInstance("@mozilla.org/image/container;1");
|
||||||
|
if (!mImage)
|
||||||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
|
||||||
|
mFrame = do_CreateInstance("@mozilla.org/gfx/image/frame;2");
|
||||||
|
if (!mFrame)
|
||||||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
|
||||||
|
return aLoad->SetImage(mImage);
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP nsICODecoder::Close()
|
||||||
|
{
|
||||||
|
if (mObserver) {
|
||||||
|
mObserver->OnStopContainer(nsnull, nsnull, mImage);
|
||||||
|
mObserver->OnStopDecode(nsnull, nsnull, NS_OK, nsnull);
|
||||||
|
mObserver = nsnull;
|
||||||
|
}
|
||||||
|
|
||||||
|
mImage = nsnull;
|
||||||
|
mFrame = nsnull;
|
||||||
|
|
||||||
|
mPos = 0;
|
||||||
|
|
||||||
|
delete[] mColors;
|
||||||
|
mColors = nsnull;
|
||||||
|
|
||||||
|
mCurLine = 0;
|
||||||
|
mRowBytes = 0;
|
||||||
|
mImageOffset = 0;
|
||||||
|
mCurrIcon = 0;
|
||||||
|
mNumIcons = 0;
|
||||||
|
|
||||||
|
delete[] mRow;
|
||||||
|
mRow = nsnull;
|
||||||
|
|
||||||
|
mDecodingAndMask = PR_FALSE;
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP nsICODecoder::Flush()
|
||||||
|
{
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP nsICODecoder::WriteFrom(nsIInputStream *aInStr, PRUint32 aCount, PRUint32 *aRetval)
|
||||||
|
{
|
||||||
|
char* buffer = new char[aCount];
|
||||||
|
if (!buffer)
|
||||||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
|
||||||
|
unsigned int realCount = aCount;
|
||||||
|
nsresult rv = aInStr->Read(buffer, aCount, &realCount);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
*aRetval = realCount;
|
||||||
|
|
||||||
|
rv = ProcessData(buffer, realCount);
|
||||||
|
delete []buffer;
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult nsICODecoder::ProcessData(const char* aBuffer, PRUint32 aCount) {
|
||||||
|
if (!aCount) // aCount=0 means EOF
|
||||||
|
return NS_OK;
|
||||||
|
|
||||||
|
while (aCount && (mPos < ICONCOUNTOFFSET)) { // Skip to the # of icons.
|
||||||
|
mPos++; aBuffer++; aCount--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mPos == ICONCOUNTOFFSET && aCount >= 2) {
|
||||||
|
mNumIcons = LITTLE_TO_NATIVE16(((PRUint16*)aBuffer)[0]);
|
||||||
|
aBuffer += 2;
|
||||||
|
mPos += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mNumIcons == 0)
|
||||||
|
return NS_OK; // Nothing to do.
|
||||||
|
|
||||||
|
while (mCurrIcon < mNumIcons) {
|
||||||
|
if (mPos >= DIRENTRYOFFSET + (mCurrIcon*sizeof(mDirEntryArray)) &&
|
||||||
|
mPos < DIRENTRYOFFSET + ((mCurrIcon+1)*sizeof(mDirEntryArray))) {
|
||||||
|
PRUint32 toCopy = sizeof(mDirEntryArray) - (mPos - DIRENTRYOFFSET - mCurrIcon*sizeof(mDirEntryArray));
|
||||||
|
if (toCopy > aCount)
|
||||||
|
toCopy = aCount;
|
||||||
|
nsCRT::memcpy(mDirEntryArray + sizeof(mDirEntryArray) - toCopy, aBuffer, toCopy);
|
||||||
|
mPos += toCopy;
|
||||||
|
aCount -= toCopy;
|
||||||
|
aBuffer += toCopy;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mPos == 22+mCurrIcon*sizeof(mDirEntryArray)) {
|
||||||
|
ProcessDirEntry();
|
||||||
|
mCurrIcon++;
|
||||||
|
if (mImageOffset == 0 && ((mDirEntry.mWidth == PREFICONSIZE && mDirEntry.mHeight == PREFICONSIZE) || mCurrIcon == mNumIcons))
|
||||||
|
mImageOffset = mDirEntry.mImageOffset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (aCount && mPos < mImageOffset) { // Skip to our offset
|
||||||
|
mPos++; aBuffer++; aCount--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mCurrIcon == mNumIcons && mPos >= mImageOffset && mPos < mImageOffset + BITMAPINFOSIZE) {
|
||||||
|
// We've found the icon.
|
||||||
|
PRUint32 toCopy = sizeof(mBIHraw) - (mPos - mImageOffset);
|
||||||
|
if (toCopy > aCount)
|
||||||
|
toCopy = aCount;
|
||||||
|
|
||||||
|
nsCRT::memcpy(mBIHraw + (mPos - mImageOffset), aBuffer, toCopy);
|
||||||
|
mPos += toCopy;
|
||||||
|
aCount -= toCopy;
|
||||||
|
aBuffer += toCopy;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mPos == mImageOffset + BITMAPINFOSIZE) {
|
||||||
|
ProcessInfoHeader();
|
||||||
|
if (mBIH.bpp <= 8) {
|
||||||
|
switch (mBIH.bpp) {
|
||||||
|
case 1:
|
||||||
|
mNumColors = 2;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
mNumColors = 16;
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
mNumColors = 256;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
mColors = new colorTable[mNumColors];
|
||||||
|
if (!mColors)
|
||||||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adjust the height of the icon. The height is additive and is including
|
||||||
|
// both the XOR and AND masks. Therefore the height is twice as big and
|
||||||
|
// we can just divide by 2.
|
||||||
|
mBIH.height /= 2;
|
||||||
|
|
||||||
|
nsresult rv = mImage->Init(mBIH.width, mBIH.height, mObserver);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
rv = mObserver->OnStartContainer(nsnull, nsnull, mImage);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
mCurLine = mBIH.height;
|
||||||
|
mRow = new PRUint8[(mBIH.width * mBIH.bpp)/8 + 4];
|
||||||
|
// +4 because the line is padded to a 4 bit boundary, but I don't want
|
||||||
|
// to make exact calculations here, that's unnecessary.
|
||||||
|
// Also, it compensates rounding error.
|
||||||
|
if (!mRow)
|
||||||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
|
||||||
|
rv = mFrame->Init(0, 0, mBIH.width, mBIH.height, GFXFORMATALPHA);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
rv = mImage->AppendFrame(mFrame);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
mObserver->OnStartFrame(nsnull, nsnull, mFrame);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mColors && (mPos >= mImageOffset + BITMAPINFOSIZE) &&
|
||||||
|
(mPos < (mImageOffset + BITMAPINFOSIZE + mNumColors * 4))) {
|
||||||
|
// We will receive (mNumColors * 4) bytes of color data
|
||||||
|
PRUint32 colorBytes = mPos - (mImageOffset + 40); // Number of bytes already received
|
||||||
|
PRUint8 colorNum = colorBytes / 4; // Color which is currently received
|
||||||
|
PRUint8 at = colorBytes % 4;
|
||||||
|
while (aCount && (mPos < (mImageOffset + BITMAPINFOSIZE + mNumColors * 4))) {
|
||||||
|
switch (at) {
|
||||||
|
case 0:
|
||||||
|
mColors[colorNum].blue = *aBuffer;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
mColors[colorNum].green = *aBuffer;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
mColors[colorNum].red = *aBuffer;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
colorNum++; // This is a padding byte
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
mPos++; aBuffer++; aCount--;
|
||||||
|
at = (at + 1) % 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mDecodingAndMask && (mPos >= (mImageOffset + BITMAPINFOSIZE + mNumColors*4))) {
|
||||||
|
// Increment mPos to avoid re-processing the info header and/or color table.
|
||||||
|
mPos++;
|
||||||
|
|
||||||
|
PRUint32 rowSize = (mBIH.bpp * mBIH.width + 7) / 8; // +7 to round up
|
||||||
|
if (rowSize % 4)
|
||||||
|
rowSize += (4 - (rowSize % 4)); // Pad to DWORD Boundary
|
||||||
|
PRUint32 toCopy;
|
||||||
|
do {
|
||||||
|
toCopy = rowSize - mRowBytes;
|
||||||
|
if (toCopy) {
|
||||||
|
if (toCopy > aCount)
|
||||||
|
toCopy = aCount;
|
||||||
|
nsCRT::memcpy(mRow + mRowBytes, aBuffer, toCopy);
|
||||||
|
aCount -= toCopy;
|
||||||
|
aBuffer += toCopy;
|
||||||
|
mRowBytes += toCopy;
|
||||||
|
}
|
||||||
|
if ((rowSize - mRowBytes) == 0) {
|
||||||
|
PRUint8* decoded;
|
||||||
|
#ifdef XP_MAC
|
||||||
|
decoded = new PRUint8[mBIH.width * 4];
|
||||||
|
#else
|
||||||
|
decoded = new PRUint8[mBIH.width * 3];
|
||||||
|
#endif
|
||||||
|
if (!decoded)
|
||||||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
|
||||||
|
PRUint8* p = mRow;
|
||||||
|
PRUint8* d = decoded;
|
||||||
|
PRUint32 lpos = 0;
|
||||||
|
switch (mBIH.bpp) {
|
||||||
|
case 1:
|
||||||
|
while (lpos < mBIH.width) {
|
||||||
|
PRInt8 bit;
|
||||||
|
PRUint8 idx;
|
||||||
|
for (bit = 7; bit >= 0; bit--) {
|
||||||
|
if (lpos >= mBIH.width)
|
||||||
|
break;
|
||||||
|
idx = (*p >> bit) & 1;
|
||||||
|
SetPixel(d, idx);
|
||||||
|
++lpos;
|
||||||
|
}
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
while (lpos < mBIH.width) {
|
||||||
|
Set4BitPixel(d, *p, lpos);
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
while (lpos < mBIH.width) {
|
||||||
|
SetPixel(d, *p);
|
||||||
|
++lpos;
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
while (lpos < mBIH.width) {
|
||||||
|
SetPixel(d,
|
||||||
|
(p[1] & 124) << 1,
|
||||||
|
((p[1] & 3) << 6) | ((p[0] & 224) >> 2),
|
||||||
|
(p[0] & 31) << 3);
|
||||||
|
|
||||||
|
++lpos;
|
||||||
|
p+=2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 32:
|
||||||
|
case 24:
|
||||||
|
while (lpos < mBIH.width) {
|
||||||
|
SetPixel(d, p[2], p[1], p[0]);
|
||||||
|
p += 2;
|
||||||
|
++lpos;
|
||||||
|
if (mBIH.bpp == 32)
|
||||||
|
p++; // Padding byte
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// This is probably the wrong place to check this...
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult rv = SetData(decoded);
|
||||||
|
delete[] decoded;
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
if (mCurLine == 1)
|
||||||
|
mDecodingAndMask = PR_TRUE;
|
||||||
|
|
||||||
|
mCurLine--; mRowBytes = 0;
|
||||||
|
}
|
||||||
|
} while (!mDecodingAndMask && aCount > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mDecodingAndMask) {
|
||||||
|
mRowBytes = 0;
|
||||||
|
mBIH.bpp = 1;
|
||||||
|
mCurLine = mBIH.height;
|
||||||
|
delete []mRow;
|
||||||
|
mRow = new PRUint8[(mBIH.width * mBIH.bpp)/8 + 4];
|
||||||
|
PRUint32 rowSize = (mBIH.bpp * mBIH.width + 7) / 8; // +7 to round up
|
||||||
|
if (rowSize % 4)
|
||||||
|
rowSize += (4 - (rowSize % 4)); // Pad to DWORD Boundary
|
||||||
|
PRUint32 toCopy;
|
||||||
|
do {
|
||||||
|
toCopy = rowSize - mRowBytes;
|
||||||
|
if (toCopy) {
|
||||||
|
if (toCopy > aCount)
|
||||||
|
toCopy = aCount;
|
||||||
|
nsCRT::memcpy(mRow + mRowBytes, aBuffer, toCopy);
|
||||||
|
aCount -= toCopy;
|
||||||
|
aBuffer += toCopy;
|
||||||
|
mRowBytes += toCopy;
|
||||||
|
}
|
||||||
|
if ((rowSize - mRowBytes) == 0) {
|
||||||
|
PRUint8* decoded;
|
||||||
|
decoded = new PRUint8[mBIH.width/4];
|
||||||
|
|
||||||
|
if (!decoded)
|
||||||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
|
||||||
|
PRUint8* p = mRow;
|
||||||
|
PRUint32 lpos = 0;
|
||||||
|
while (lpos < mBIH.width/4) {
|
||||||
|
PRUint8 idx = *p;
|
||||||
|
idx ^= 255; // We complement the value, since our method of storing transparency is opposite
|
||||||
|
// what Win32 uses in its masks.
|
||||||
|
decoded[lpos] = idx;
|
||||||
|
lpos++;
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
nsresult rv = SetAlphaData(decoded);
|
||||||
|
delete[] decoded;
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
if (mCurLine == 1) {
|
||||||
|
mObserver->OnStopFrame(nsnull, nsnull, mFrame);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
mCurLine--; mRowBytes = 0;
|
||||||
|
}
|
||||||
|
} while (aCount > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nsICODecoder::ProcessDirEntry()
|
||||||
|
{
|
||||||
|
nsCRT::memset(&mDirEntry, 0, sizeof(mDirEntry));
|
||||||
|
DOCOPY(&mDirEntry.mWidth, mDirEntryArray);
|
||||||
|
DOCOPY(&mDirEntry.mHeight, mDirEntryArray+1);
|
||||||
|
DOCOPY(&mDirEntry.mColorCount, mDirEntryArray+2);
|
||||||
|
DOCOPY(&mDirEntry.mReserved, mDirEntryArray+3);
|
||||||
|
|
||||||
|
DOCOPY(&mDirEntry.mPlanes, mDirEntryArray+4);
|
||||||
|
mDirEntry.mPlanes = LITTLE_TO_NATIVE16(mDirEntry.mPlanes);
|
||||||
|
|
||||||
|
DOCOPY(&mDirEntry.mBitCount, mDirEntryArray+6);
|
||||||
|
mDirEntry.mBitCount = LITTLE_TO_NATIVE16(mDirEntry.mBitCount);
|
||||||
|
|
||||||
|
DOCOPY(&mDirEntry.mBytesInRes, mDirEntryArray+8);
|
||||||
|
mDirEntry.mBytesInRes = LITTLE_TO_NATIVE32(mDirEntry.mBytesInRes);
|
||||||
|
|
||||||
|
DOCOPY(&mDirEntry.mImageOffset, mDirEntryArray+12);
|
||||||
|
mDirEntry.mImageOffset = LITTLE_TO_NATIVE32(mDirEntry.mImageOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void nsICODecoder::ProcessInfoHeader() {
|
||||||
|
nsCRT::memset(&mBIH, 0, sizeof(mBIH));
|
||||||
|
// Ignoring the size; it should always be 40 for icons, anyway
|
||||||
|
|
||||||
|
DOCOPY(&mBIH.width, mBIHraw + 4);
|
||||||
|
DOCOPY(&mBIH.height, mBIHraw + 8);
|
||||||
|
DOCOPY(&mBIH.planes, mBIHraw + 12);
|
||||||
|
DOCOPY(&mBIH.bpp, mBIHraw + 14);
|
||||||
|
DOCOPY(&mBIH.compression, mBIHraw + 16);
|
||||||
|
DOCOPY(&mBIH.image_size, mBIHraw + 20);
|
||||||
|
DOCOPY(&mBIH.xppm, mBIHraw + 24);
|
||||||
|
DOCOPY(&mBIH.yppm, mBIHraw + 28);
|
||||||
|
DOCOPY(&mBIH.colors, mBIHraw + 32);
|
||||||
|
DOCOPY(&mBIH.important_colors, mBIHraw + 36);
|
||||||
|
|
||||||
|
// Convert endianness
|
||||||
|
mBIH.width = LITTLE_TO_NATIVE32(mBIH.width);
|
||||||
|
mBIH.height = LITTLE_TO_NATIVE32(mBIH.height);
|
||||||
|
mBIH.planes = LITTLE_TO_NATIVE16(mBIH.planes);
|
||||||
|
mBIH.bpp = LITTLE_TO_NATIVE16(mBIH.bpp);
|
||||||
|
|
||||||
|
mBIH.compression = LITTLE_TO_NATIVE32(mBIH.compression);
|
||||||
|
mBIH.image_size = LITTLE_TO_NATIVE32(mBIH.image_size);
|
||||||
|
mBIH.xppm = LITTLE_TO_NATIVE32(mBIH.xppm);
|
||||||
|
mBIH.yppm = LITTLE_TO_NATIVE32(mBIH.yppm);
|
||||||
|
mBIH.colors = LITTLE_TO_NATIVE32(mBIH.colors);
|
||||||
|
mBIH.important_colors = LITTLE_TO_NATIVE32(mBIH.important_colors);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------
|
||||||
|
// Actual Data Processing
|
||||||
|
// ----------------------------------------
|
||||||
|
|
||||||
|
inline nsresult nsICODecoder::SetPixel(PRUint8*& aDecoded, PRUint8 idx) {
|
||||||
|
PRUint8 red, green, blue;
|
||||||
|
red = mColors[idx].red;
|
||||||
|
green = mColors[idx].green;
|
||||||
|
blue = mColors[idx].blue;
|
||||||
|
return SetPixel(aDecoded, red, green, blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline nsresult nsICODecoder::SetPixel(PRUint8*& aDecoded, PRUint8 aRed, PRUint8 aGreen, PRUint8 aBlue) {
|
||||||
|
#ifdef XP_MAC
|
||||||
|
*aDecoded++ = 0; // Mac needs this padding byte
|
||||||
|
#endif
|
||||||
|
#ifdef USE_RGBA1
|
||||||
|
*aDecoded++ = aRed;
|
||||||
|
*aDecoded++ = aGreen;
|
||||||
|
*aDecoded++ = aBlue;
|
||||||
|
#else
|
||||||
|
*aDecoded++ = aBlue;
|
||||||
|
*aDecoded++ = aGreen;
|
||||||
|
*aDecoded++ = aRed;
|
||||||
|
#endif
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline nsresult nsICODecoder::Set4BitPixel(PRUint8*& aDecoded, PRUint8 aData, PRUint32& aPos)
|
||||||
|
{
|
||||||
|
PRUint8 idx = aData >> 4;
|
||||||
|
nsresult rv = SetPixel(aDecoded, idx);
|
||||||
|
if ((++aPos >= mBIH.width) || NS_FAILED(rv))
|
||||||
|
return rv;
|
||||||
|
|
||||||
|
idx = aData & 0xF;
|
||||||
|
rv = SetPixel(aDecoded, idx);
|
||||||
|
++aPos;
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline nsresult nsICODecoder::SetData(PRUint8* aData)
|
||||||
|
{
|
||||||
|
NS_ENSURE_ARG_POINTER(aData);
|
||||||
|
PRUint32 bpr;
|
||||||
|
nsresult rv;
|
||||||
|
|
||||||
|
rv = mFrame->GetImageBytesPerRow(&bpr);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
PRUint32 offset = (mCurLine - 1) * bpr;
|
||||||
|
// XXX Possibly aData doesn't contain bpr bytes of data;
|
||||||
|
// will SetImageData access that data?
|
||||||
|
rv = mFrame->SetImageData(aData, bpr, offset);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
nsRect r(0, mCurLine, mBIH.width, 1);
|
||||||
|
rv = mObserver->OnDataAvailable(nsnull, nsnull, mFrame, &r);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline nsresult nsICODecoder::SetAlphaData(PRUint8* aData)
|
||||||
|
{
|
||||||
|
NS_ENSURE_ARG_POINTER(aData);
|
||||||
|
PRUint32 bpr;
|
||||||
|
nsresult rv;
|
||||||
|
|
||||||
|
mFrame->GetAlphaBytesPerRow(&bpr);
|
||||||
|
|
||||||
|
PRUint32 offset = (mCurLine - 1) * bpr;
|
||||||
|
// XXX Possibly aData doesn't contain bpr bytes of data;
|
||||||
|
// will SetImageData access that data?
|
||||||
|
rv = mFrame->SetAlphaData(aData, bpr, offset);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
nsRect r(0, mCurLine, mBIH.width, 1);
|
||||||
|
rv = mObserver->OnDataAvailable(nsnull, nsnull, mFrame, &r);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
|
@ -0,0 +1,121 @@
|
||||||
|
/* vim:set tw=80 expandtab softtabstop=4 ts=4 sw=4: */
|
||||||
|
/* ----- BEGIN LICENSE BLOCK -----
|
||||||
|
* Version: MPL 1.1/LGPL 2.1/GPL 2.0
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Mozilla Public
|
||||||
|
* License Version 1.1 (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.mozilla.org/MPL/
|
||||||
|
*
|
||||||
|
* Software distributed under the License is distributed on an "AS
|
||||||
|
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||||
|
* implied. See the License for the specific language governing
|
||||||
|
* rights and limitations under the License.
|
||||||
|
*
|
||||||
|
* The Original Code is the Mozilla ICO Decoder.
|
||||||
|
*
|
||||||
|
* The Initial Developer of the Original Code is Netscape.
|
||||||
|
* Portions created by Netscape are
|
||||||
|
* Copyright (C) 2001 Netscape. All
|
||||||
|
* Rights Reserved.
|
||||||
|
*
|
||||||
|
* Contributor(s):
|
||||||
|
* David Hyatt <hyatt@netscape.com> (Original Author)
|
||||||
|
*
|
||||||
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||||
|
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||||
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||||
|
* of those above. If you wish to allow use of your version of this file only
|
||||||
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||||
|
* use your version of this file under the terms of the MPL, indicate your
|
||||||
|
* decision by deleting the provisions above and replace them with the notice
|
||||||
|
* and other provisions required by the LGPL or the GPL. If you do not delete
|
||||||
|
* the provisions above, a recipient may use your version of this file under
|
||||||
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||||
|
*
|
||||||
|
* ----- END LICENSE BLOCK ----- */
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _nsICODecoder_h
|
||||||
|
#define _nsICODecoder_h
|
||||||
|
|
||||||
|
#include "nsCOMPtr.h"
|
||||||
|
#include "imgIDecoder.h"
|
||||||
|
#include "imgIContainer.h"
|
||||||
|
#include "imgIDecoderObserver.h"
|
||||||
|
#include "gfxIImageFrame.h"
|
||||||
|
#include "nsBMPDecoder.h"
|
||||||
|
|
||||||
|
// {CB3EDE1A-0FA5-4e27-AAFE-0F7801E5A1F1}
|
||||||
|
#define NS_ICODECODER_CID \
|
||||||
|
{ 0xcb3ede1a, 0xfa5, 0x4e27, { 0xaa, 0xfe, 0xf, 0x78, 0x1, 0xe5, 0xa1, 0xf1 } }
|
||||||
|
|
||||||
|
#if defined(XP_PC) || defined(XP_BEOS) || defined(MOZ_WIDGET_PHOTON)
|
||||||
|
#define GFXFORMATALPHA gfxIFormats::BGR_A1
|
||||||
|
#else
|
||||||
|
#define USE_RGBA1
|
||||||
|
#define GFXFORMATALPHA gfxIFormats::RGB_A1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct IconDirEntry
|
||||||
|
{
|
||||||
|
PRUint8 mWidth;
|
||||||
|
PRUint8 mHeight;
|
||||||
|
PRUint8 mColorCount;
|
||||||
|
PRUint8 mReserved;
|
||||||
|
PRUint16 mPlanes;
|
||||||
|
PRUint16 mBitCount;
|
||||||
|
PRUint32 mBytesInRes;
|
||||||
|
PRUint32 mImageOffset;
|
||||||
|
};
|
||||||
|
|
||||||
|
class nsICODecoder : public imgIDecoder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NS_DECL_ISUPPORTS
|
||||||
|
NS_DECL_IMGIDECODER
|
||||||
|
|
||||||
|
nsICODecoder();
|
||||||
|
virtual ~nsICODecoder();
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Private helper methods
|
||||||
|
nsresult ProcessData(const char* aBuffer, PRUint32 aCount);
|
||||||
|
void ProcessDirEntry();
|
||||||
|
void ProcessInfoHeader();
|
||||||
|
|
||||||
|
nsresult SetPixel(PRUint8*& aDecoded, PRUint8 aIdx);
|
||||||
|
nsresult SetPixel(PRUint8*& aDecoded, PRUint8 aRed, PRUint8 aGreen, PRUint8 aBlue);
|
||||||
|
nsresult Set4BitPixel(PRUint8*& aDecoded, PRUint8 aData, PRUint32& aPos);
|
||||||
|
nsresult SetData(PRUint8* aData);
|
||||||
|
nsresult SetAlphaData(PRUint8* aData);
|
||||||
|
|
||||||
|
private:
|
||||||
|
nsCOMPtr<imgIDecoderObserver> mObserver;
|
||||||
|
nsCOMPtr<imgIContainer> mImage;
|
||||||
|
nsCOMPtr<gfxIImageFrame> mFrame;
|
||||||
|
|
||||||
|
PRBool mDecodingAndMask;
|
||||||
|
|
||||||
|
PRUint32 mPos;
|
||||||
|
PRUint16 mNumIcons;
|
||||||
|
PRUint16 mCurrIcon;
|
||||||
|
PRUint32 mImageOffset;
|
||||||
|
|
||||||
|
char mDirEntryArray[16];
|
||||||
|
IconDirEntry mDirEntry;
|
||||||
|
|
||||||
|
char mBIHraw[40];
|
||||||
|
BMPINFOHEADER mBIH;
|
||||||
|
|
||||||
|
PRUint32 mNumColors;
|
||||||
|
colorTable* mColors;
|
||||||
|
|
||||||
|
PRUint8* mRow; // Holds one raw line of the image
|
||||||
|
PRUint32 mRowBytes; // How many bytes of the row were already received
|
||||||
|
PRUint32 mCurLine;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
|
@ -21,6 +21,6 @@
|
||||||
|
|
||||||
DEPTH=..\..\..
|
DEPTH=..\..\..
|
||||||
|
|
||||||
DIRS = ppm gif png jpeg icon\win icon
|
DIRS = ppm gif png jpeg icon\win icon bmp
|
||||||
|
|
||||||
!include $(DEPTH)\config\rules.mak
|
!include $(DEPTH)\config\rules.mak
|
||||||
|
|
|
@ -45,6 +45,14 @@
|
||||||
#include "nsString.h"
|
#include "nsString.h"
|
||||||
#include "nsXPIDLString.h"
|
#include "nsXPIDLString.h"
|
||||||
|
|
||||||
|
#include "prcpucfg.h" // To get IS_LITTLE_ENDIAN / IS_BIG_ENDIAN
|
||||||
|
|
||||||
|
#if defined WORDS_BIGENDIAN || defined IS_BIG_ENDIAN
|
||||||
|
#define LITTLE_TO_NATIVE16(x) ((((x) & 0xFF) << 8) | ((x) >> 8))
|
||||||
|
#else
|
||||||
|
#define LITTLE_TO_NATIVE16(x) x
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(PR_LOGGING)
|
#if defined(PR_LOGGING)
|
||||||
PRLogModuleInfo *gImgLog = PR_NewLogModule("imgRequest");
|
PRLogModuleInfo *gImgLog = PR_NewLogModule("imgRequest");
|
||||||
#endif
|
#endif
|
||||||
|
@ -795,5 +803,96 @@ imgRequest::SniffMimeType(const char *buf, PRUint32 len)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (len >= 2 && !nsCRT::strncmp(buf, "BM", 2)) {
|
||||||
|
mContentType = nsCRT::strndup("image/bmp", 9);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ICOs always begin with a 2-byte 0 followed by a 2-byte 1.
|
||||||
|
// ALWAYS KEEP THIS SNIFF AT THE END OF THE FILE!
|
||||||
|
if (len >= 4 &&
|
||||||
|
((PRUint16*)buf)[0]==0 &&
|
||||||
|
(LITTLE_TO_NATIVE16(((PRUint16*)buf)[1]))==1) {
|
||||||
|
mContentType = nsCRT::strndup("image/x-icon", 12);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len >= 2 && !nsCRT::strncmp(buf, "BM", 2)) {
|
||||||
|
mContentType = nsCRT::strndup("image/bmp", 9);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ICOs always begin with a 2-byte 0 followed by a 2-byte 1.
|
||||||
|
if (len >= 4 && !nsCRT::memcmp(buf, "\000\000\001\000", 4)) {
|
||||||
|
mContentType = nsCRT::strndup("image/x-icon", 12);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len >= 2 && !nsCRT::strncmp(buf, "BM", 2)) {
|
||||||
|
mContentType = nsCRT::strndup("image/bmp", 9);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ICOs always begin with a 2-byte 0 followed by a 2-byte 1.
|
||||||
|
if (len >= 4 && !nsCRT::memcmp(buf, "\000\000\001\000", 4)) {
|
||||||
|
mContentType = nsCRT::strndup("image/x-icon", 12);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len >= 2 && !nsCRT::strncmp(buf, "BM", 2)) {
|
||||||
|
mContentType = nsCRT::strndup("image/bmp", 9);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ICOs always begin with a 2-byte 0 followed by a 2-byte 1.
|
||||||
|
if (len >= 4 && !nsCRT::memcmp(buf, "\000\000\001\000", 4)) {
|
||||||
|
mContentType = nsCRT::strndup("image/x-icon", 12);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len >= 2 && !nsCRT::strncmp(buf, "BM", 2)) {
|
||||||
|
mContentType = nsCRT::strndup("image/bmp", 9);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ICOs always begin with a 2-byte 0 followed by a 2-byte 1.
|
||||||
|
if (len >= 4 && !nsCRT::memcmp(buf, "\000\000\001\000", 4)) {
|
||||||
|
mContentType = nsCRT::strndup("image/x-icon", 12);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len >= 2 && !nsCRT::strncmp(buf, "BM", 2)) {
|
||||||
|
mContentType = nsCRT::strndup("image/bmp", 9);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ICOs always begin with a 2-byte 0 followed by a 2-byte 1.
|
||||||
|
if (len >= 4 && !nsCRT::memcmp(buf, "\000\000\001\000", 4)) {
|
||||||
|
mContentType = nsCRT::strndup("image/x-icon", 12);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len >= 2 && !nsCRT::strncmp(buf, "BM", 2)) {
|
||||||
|
mContentType = nsCRT::strndup("image/bmp", 9);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ICOs always begin with a 2-byte 0 followed by a 2-byte 1.
|
||||||
|
if (len >= 4 && !nsCRT::memcmp(buf, "\000\000\001\000", 4)) {
|
||||||
|
mContentType = nsCRT::strndup("image/x-icon", 12);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len >= 2 && !nsCRT::strncmp(buf, "BM", 2)) {
|
||||||
|
mContentType = nsCRT::strndup("image/bmp", 9);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ICOs always begin with a 2-byte 0 followed by a 2-byte 1.
|
||||||
|
if (len >= 4 && !nsCRT::memcmp(buf, "\000\000\001\000", 4)) {
|
||||||
|
mContentType = nsCRT::strndup("image/x-icon", 12);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* none of the above? I give up */
|
/* none of the above? I give up */
|
||||||
}
|
}
|
||||||
|
|
|
@ -101,6 +101,8 @@
|
||||||
#define IMAGE_XBM3 "image/xbm"
|
#define IMAGE_XBM3 "image/xbm"
|
||||||
#define IMAGE_ART "image/x-jg"
|
#define IMAGE_ART "image/x-jg"
|
||||||
#define IMAGE_TIFF "image/tiff"
|
#define IMAGE_TIFF "image/tiff"
|
||||||
|
#define IMAGE_BMP "image/bmp"
|
||||||
|
#define IMAGE_ICO "image/x-icon"
|
||||||
|
|
||||||
#define MESSAGE_EXTERNAL_BODY "message/external-body"
|
#define MESSAGE_EXTERNAL_BODY "message/external-body"
|
||||||
#define MESSAGE_NEWS "message/news"
|
#define MESSAGE_NEWS "message/news"
|
||||||
|
|
|
@ -492,6 +492,16 @@ nsXMLMIMEDataSource::InitFromHack() {
|
||||||
rv = AppendExtension(IMAGE_JPG, "jpg");
|
rv = AppendExtension(IMAGE_JPG, "jpg");
|
||||||
if (NS_FAILED(rv)) return rv;
|
if (NS_FAILED(rv)) return rv;
|
||||||
|
|
||||||
|
rv = AddMapping(IMAGE_BMP, "bmp", "BMP Image", nsnull);
|
||||||
|
if (NS_FAILED(rv)) return rv;
|
||||||
|
rv = AppendExtension(IMAGE_BMP, "bmp");
|
||||||
|
if (NS_FAILED(rv)) return rv;
|
||||||
|
|
||||||
|
rv = AddMapping(IMAGE_ICO, "ico", "ICO Image", nsnull);
|
||||||
|
if (NS_FAILED(rv)) return rv;
|
||||||
|
rv = AppendExtension(IMAGE_ICO, "ico");
|
||||||
|
if (NS_FAILED(rv)) return rv;
|
||||||
|
|
||||||
rv = AddMapping(IMAGE_PNG, "png", "PNG Image", nsnull);
|
rv = AddMapping(IMAGE_PNG, "png", "PNG Image", nsnull);
|
||||||
if (NS_FAILED(rv)) return rv;
|
if (NS_FAILED(rv)) return rv;
|
||||||
|
|
||||||
|
|
|
@ -47,11 +47,18 @@
|
||||||
#include "nsXPIDLString.h"
|
#include "nsXPIDLString.h"
|
||||||
#include "nsIPref.h"
|
#include "nsIPref.h"
|
||||||
|
|
||||||
|
#include "prcpucfg.h" // To get IS_LITTLE_ENDIAN / IS_BIG_ENDIAN
|
||||||
|
|
||||||
#define MAX_BUFFER_SIZE 1024
|
#define MAX_BUFFER_SIZE 1024
|
||||||
|
|
||||||
static NS_DEFINE_CID(kStreamConverterServiceCID, NS_STREAMCONVERTERSERVICE_CID);
|
static NS_DEFINE_CID(kStreamConverterServiceCID, NS_STREAMCONVERTERSERVICE_CID);
|
||||||
static NS_DEFINE_IID(kPrefServiceCID, NS_PREF_CID);
|
static NS_DEFINE_IID(kPrefServiceCID, NS_PREF_CID);
|
||||||
|
|
||||||
|
#if defined WORDS_BIGENDIAN || defined IS_BIG_ENDIAN
|
||||||
|
#define LITTLE_TO_NATIVE16(x) ((((x) & 0xFF) << 8) | ((x) >> 8))
|
||||||
|
#else
|
||||||
|
#define LITTLE_TO_NATIVE16(x) x
|
||||||
|
#endif
|
||||||
|
|
||||||
nsUnknownDecoder::nsUnknownDecoder()
|
nsUnknownDecoder::nsUnknownDecoder()
|
||||||
{
|
{
|
||||||
|
@ -401,6 +408,97 @@ void nsUnknownDecoder::SniffForImageMimeType(const char *buf, PRUint32 len)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (len >= 2 && !nsCRT::strncmp(buf, "BM", 2)) {
|
||||||
|
mContentType = NS_LITERAL_CSTRING("image/bmp");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ICOs always begin with a 2-byte 0 followed by a 2-byte 1.
|
||||||
|
// ALWAYS KEEP THIS SNIFF AT THE END OF THE FILE!
|
||||||
|
if (len >= 4 &&
|
||||||
|
((PRUint16*)buf)[0]==0 &&
|
||||||
|
(LITTLE_TO_NATIVE16(((PRUint16*)buf)[1]))==1) {
|
||||||
|
mContentType = NS_LITERAL_CSTRING("image/x-icon");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len >= 2 && !nsCRT::strncmp(buf, "BM", 2)) {
|
||||||
|
mContentType = NS_LITERAL_CSTRING("image/bmp");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ICOs always begin with a 2-byte 0 followed by a 2-byte 1.
|
||||||
|
if (len >= 4 && !nsCRT::memcmp(buf, "\000\000\001\000", 4)) {
|
||||||
|
mContentType = NS_LITERAL_CSTRING("image/x-icon");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len >= 2 && !nsCRT::strncmp(buf, "BM", 2)) {
|
||||||
|
mContentType = NS_LITERAL_CSTRING("image/bmp");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ICOs always begin with a 2-byte 0 followed by a 2-byte 1.
|
||||||
|
if (len >= 4 && !nsCRT::memcmp(buf, "\000\000\001\000", 4)) {
|
||||||
|
mContentType = NS_LITERAL_CSTRING("image/x-icon");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len >= 2 && !nsCRT::strncmp(buf, "BM", 2)) {
|
||||||
|
mContentType = NS_LITERAL_CSTRING("image/bmp");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ICOs always begin with a 2-byte 0 followed by a 2-byte 1.
|
||||||
|
if (len >= 4 && !nsCRT::memcmp(buf, "\000\000\001\000", 4)) {
|
||||||
|
mContentType = NS_LITERAL_CSTRING("image/x-icon");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len >= 2 && !nsCRT::strncmp(buf, "BM", 2)) {
|
||||||
|
mContentType = NS_LITERAL_CSTRING("image/bmp");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ICOs always begin with a 2-byte 0 followed by a 2-byte 1.
|
||||||
|
if (len >= 4 && !nsCRT::memcmp(buf, "\000\000\001\000", 4)) {
|
||||||
|
mContentType = NS_LITERAL_CSTRING("image/x-icon");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len >= 2 && !nsCRT::strncmp(buf, "BM", 2)) {
|
||||||
|
mContentType = NS_LITERAL_CSTRING("image/bmp");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ICOs always begin with a 2-byte 0 followed by a 2-byte 1.
|
||||||
|
if (len >= 4 && !nsCRT::memcmp(buf, "\000\000\001\000", 4)) {
|
||||||
|
mContentType = NS_LITERAL_CSTRING("image/x-icon");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len >= 2 && !nsCRT::strncmp(buf, "BM", 2)) {
|
||||||
|
mContentType = NS_LITERAL_CSTRING("image/bmp");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ICOs always begin with a 2-byte 0 followed by a 2-byte 1.
|
||||||
|
if (len >= 4 && !nsCRT::memcmp(buf, "\000\000\001\000", 4)) {
|
||||||
|
mContentType = NS_LITERAL_CSTRING("image/x-icon");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len >= 2 && !nsCRT::strncmp(buf, "BM", 2)) {
|
||||||
|
mContentType = NS_LITERAL_CSTRING("image/bmp");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ICOs always begin with a 2-byte 0 followed by a 2-byte 1.
|
||||||
|
if (len >= 4 && !nsCRT::memcmp(buf, "\000\000\001\000", 4)) {
|
||||||
|
mContentType = NS_LITERAL_CSTRING("image/x-icon");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* none of the above? I give up */
|
/* none of the above? I give up */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -101,6 +101,8 @@ static nsDefaultMimeTypeEntry defaultMimeEntries [] =
|
||||||
{ IMAGE_GIF, "gif", "GIF Image", 0,0 },
|
{ IMAGE_GIF, "gif", "GIF Image", 0,0 },
|
||||||
{ IMAGE_JPG, "jpeg,jpg", "JPEG Image", 0, 0 },
|
{ IMAGE_JPG, "jpeg,jpg", "JPEG Image", 0, 0 },
|
||||||
{ IMAGE_PNG, "png", "PNG Image", 0, 0 },
|
{ IMAGE_PNG, "png", "PNG Image", 0, 0 },
|
||||||
|
{ IMAGE_BMP, "bmp", "BMP Image", 0, 0 },
|
||||||
|
{ IMAGE_ICO, "ico", "ICO Image", 0, 0 },
|
||||||
{ APPLICATION_XPINSTALL, "xpi", "XPInstall Install", 'xpi*','MOSS' },
|
{ APPLICATION_XPINSTALL, "xpi", "XPInstall Install", 'xpi*','MOSS' },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1069,6 +1069,86 @@ static nsModuleComponentInfo components[] = {
|
||||||
NS_CONTENT_HANDLER_CONTRACTID_PREFIX"image/png",
|
NS_CONTENT_HANDLER_CONTRACTID_PREFIX"image/png",
|
||||||
nsBrowserContentHandlerConstructor
|
nsBrowserContentHandlerConstructor
|
||||||
},
|
},
|
||||||
|
{ "Browser Content Handler",
|
||||||
|
NS_BROWSERCONTENTHANDLER_CID,
|
||||||
|
NS_CONTENT_HANDLER_CONTRACTID_PREFIX"image/bmp",
|
||||||
|
nsBrowserContentHandlerConstructor
|
||||||
|
},
|
||||||
|
{ "Browser Content Handler",
|
||||||
|
NS_BROWSERCONTENTHANDLER_CID,
|
||||||
|
NS_CONTENT_HANDLER_CONTRACTID_PREFIX"image/x-icon",
|
||||||
|
nsBrowserContentHandlerConstructor
|
||||||
|
},
|
||||||
|
{ "Browser Content Handler",
|
||||||
|
NS_BROWSERCONTENTHANDLER_CID,
|
||||||
|
NS_CONTENT_HANDLER_CONTRACTID_PREFIX"image/bmp",
|
||||||
|
nsBrowserContentHandlerConstructor
|
||||||
|
},
|
||||||
|
{ "Browser Content Handler",
|
||||||
|
NS_BROWSERCONTENTHANDLER_CID,
|
||||||
|
NS_CONTENT_HANDLER_CONTRACTID_PREFIX"image/x-icon",
|
||||||
|
nsBrowserContentHandlerConstructor
|
||||||
|
},
|
||||||
|
{ "Browser Content Handler",
|
||||||
|
NS_BROWSERCONTENTHANDLER_CID,
|
||||||
|
NS_CONTENT_HANDLER_CONTRACTID_PREFIX"image/bmp",
|
||||||
|
nsBrowserContentHandlerConstructor
|
||||||
|
},
|
||||||
|
{ "Browser Content Handler",
|
||||||
|
NS_BROWSERCONTENTHANDLER_CID,
|
||||||
|
NS_CONTENT_HANDLER_CONTRACTID_PREFIX"image/x-icon",
|
||||||
|
nsBrowserContentHandlerConstructor
|
||||||
|
},
|
||||||
|
{ "Browser Content Handler",
|
||||||
|
NS_BROWSERCONTENTHANDLER_CID,
|
||||||
|
NS_CONTENT_HANDLER_CONTRACTID_PREFIX"image/bmp",
|
||||||
|
nsBrowserContentHandlerConstructor
|
||||||
|
},
|
||||||
|
{ "Browser Content Handler",
|
||||||
|
NS_BROWSERCONTENTHANDLER_CID,
|
||||||
|
NS_CONTENT_HANDLER_CONTRACTID_PREFIX"image/x-icon",
|
||||||
|
nsBrowserContentHandlerConstructor
|
||||||
|
},
|
||||||
|
{ "Browser Content Handler",
|
||||||
|
NS_BROWSERCONTENTHANDLER_CID,
|
||||||
|
NS_CONTENT_HANDLER_CONTRACTID_PREFIX"image/bmp",
|
||||||
|
nsBrowserContentHandlerConstructor
|
||||||
|
},
|
||||||
|
{ "Browser Content Handler",
|
||||||
|
NS_BROWSERCONTENTHANDLER_CID,
|
||||||
|
NS_CONTENT_HANDLER_CONTRACTID_PREFIX"image/x-icon",
|
||||||
|
nsBrowserContentHandlerConstructor
|
||||||
|
},
|
||||||
|
{ "Browser Content Handler",
|
||||||
|
NS_BROWSERCONTENTHANDLER_CID,
|
||||||
|
NS_CONTENT_HANDLER_CONTRACTID_PREFIX"image/bmp",
|
||||||
|
nsBrowserContentHandlerConstructor
|
||||||
|
},
|
||||||
|
{ "Browser Content Handler",
|
||||||
|
NS_BROWSERCONTENTHANDLER_CID,
|
||||||
|
NS_CONTENT_HANDLER_CONTRACTID_PREFIX"image/x-icon",
|
||||||
|
nsBrowserContentHandlerConstructor
|
||||||
|
},
|
||||||
|
{ "Browser Content Handler",
|
||||||
|
NS_BROWSERCONTENTHANDLER_CID,
|
||||||
|
NS_CONTENT_HANDLER_CONTRACTID_PREFIX"image/bmp",
|
||||||
|
nsBrowserContentHandlerConstructor
|
||||||
|
},
|
||||||
|
{ "Browser Content Handler",
|
||||||
|
NS_BROWSERCONTENTHANDLER_CID,
|
||||||
|
NS_CONTENT_HANDLER_CONTRACTID_PREFIX"image/x-icon",
|
||||||
|
nsBrowserContentHandlerConstructor
|
||||||
|
},
|
||||||
|
{ "Browser Content Handler",
|
||||||
|
NS_BROWSERCONTENTHANDLER_CID,
|
||||||
|
NS_CONTENT_HANDLER_CONTRACTID_PREFIX"image/bmp",
|
||||||
|
nsBrowserContentHandlerConstructor
|
||||||
|
},
|
||||||
|
{ "Browser Content Handler",
|
||||||
|
NS_BROWSERCONTENTHANDLER_CID,
|
||||||
|
NS_CONTENT_HANDLER_CONTRACTID_PREFIX"image/x-icon",
|
||||||
|
nsBrowserContentHandlerConstructor
|
||||||
|
},
|
||||||
{ "Browser Content Handler",
|
{ "Browser Content Handler",
|
||||||
NS_BROWSERCONTENTHANDLER_CID,
|
NS_BROWSERCONTENTHANDLER_CID,
|
||||||
NS_CONTENT_HANDLER_CONTRACTID_PREFIX"application/http-index-format",
|
NS_CONTENT_HANDLER_CONTRACTID_PREFIX"application/http-index-format",
|
||||||
|
|
|
@ -117,6 +117,7 @@ bin/components/libimggif.so
|
||||||
bin/components/libimgjpeg.so
|
bin/components/libimgjpeg.so
|
||||||
bin/components/libimgpng.so
|
bin/components/libimgpng.so
|
||||||
bin/components/libimgppm.so
|
bin/components/libimgppm.so
|
||||||
|
bin/components/libimgbmp.so
|
||||||
bin/components/libjsurl.so
|
bin/components/libjsurl.so
|
||||||
bin/components/liblwbrk.so
|
bin/components/liblwbrk.so
|
||||||
bin/components/libmork.so
|
bin/components/libmork.so
|
||||||
|
|
|
@ -128,6 +128,7 @@ bin\components\gkplugin.dll
|
||||||
bin\components\gkview.dll
|
bin\components\gkview.dll
|
||||||
bin\components\imggif.dll
|
bin\components\imggif.dll
|
||||||
bin\components\imgjpeg.dll
|
bin\components\imgjpeg.dll
|
||||||
|
bin\components\imgbmp.dll
|
||||||
bin\components\imglib2.dll
|
bin\components\imglib2.dll
|
||||||
bin\components\imglib2.xpt
|
bin\components\imglib2.xpt
|
||||||
bin\components\imgpng.dll
|
bin\components\imgpng.dll
|
||||||
|
|
Загрузка…
Ссылка в новой задаче