~ubuntu-branches/ubuntu/precise/kompozer/precise

« back to all changes in this revision

Viewing changes to mozilla/modules/libpr0n/decoders/icon/os2/nsIconChannel.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Anthony Yarusso
  • Date: 2007-08-27 01:11:03 UTC
  • Revision ID: james.westby@ubuntu.com-20070827011103-2jgf4s6532gqu2ka
Tags: upstream-0.7.10
ImportĀ upstreamĀ versionĀ 0.7.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*-
 
2
 *
 
3
 * The contents of this file are subject to the Mozilla Public
 
4
 * License Version 1.1 (the "License"); you may not use this file
 
5
 * except in compliance with the License. You may obtain a copy of
 
6
 * the License at http://www.mozilla.org/MPL/
 
7
 *
 
8
 * Software distributed under the License is distributed on an "AS
 
9
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 
10
 * implied. See the License for the specific language governing
 
11
 * rights and limitations under the License.
 
12
 *
 
13
 * The Original Code is mozilla.org code.
 
14
 *
 
15
 * The Initial Developer of the Original Code is Brian Ryner.
 
16
 * Portions created by Brian Ryner are Copyright (C) 2000 Brian Ryner.
 
17
 * All Rights Reserved.
 
18
 *
 
19
 * Contributor(s):
 
20
 *   Scott MacGregor <mscott@netscape.com>
 
21
 *   Neil Rashbrook <neil@parkwaycc.co.uk>
 
22
 *   IBM Corp.
 
23
 */
 
24
 
 
25
 
 
26
#include "nsIconChannel.h"
 
27
#include "nsIIconURI.h"
 
28
#include "nsIServiceManager.h"
 
29
#include "nsIInterfaceRequestor.h"
 
30
#include "nsIInterfaceRequestorUtils.h"
 
31
#include "nsXPIDLString.h"
 
32
#include "nsReadableUtils.h"
 
33
#include "nsMimeTypes.h"
 
34
#include "nsMemory.h"
 
35
#include "nsIStringStream.h"
 
36
#include "nsIURL.h"
 
37
#include "nsNetUtil.h"
 
38
#include "nsIFile.h"
 
39
#include "nsIFileURL.h"
 
40
#include "nsIMIMEService.h"
 
41
#include "nsCExternalHandlerService.h"
 
42
 
 
43
#define INCL_WINWORKPLACE
 
44
#define INCL_WIN
 
45
#define INCL_PM
 
46
#define INCL_DEV
 
47
#define INCL_GPI
 
48
#include <os2.h>
 
49
#include <stdlib.h> // for getenv
 
50
 
 
51
// From Windows
 
52
#define SHGFI_ICON               0x0001
 
53
#define SHGFI_USEFILEATTRIBUTES  0x0002
 
54
#define SHGFI_LARGEICON          0x0004
 
55
#define SHGFI_SMALLICON          0x0008
 
56
 
 
57
// Due to byte swap the second is first of the pair
 
58
#define FIRSTPEL(x) (0xF & (x >> 4))
 
59
#define SECONDPEL(x)  (0xF & x)
 
60
 
 
61
// forward declarations of a couple of helper methods.
 
62
// Takes a bitmap from the windows registry and converts it into 4 byte RGB data.
 
63
void ConvertColorBitMap(PBYTE aBitmapBuffer, PBITMAPINFO2 pBitMapInfo, nsCString& iconBuffer);
 
64
void ConvertMaskBitMap(PBYTE aBitMaskBuffer, PBITMAPINFO2 pBitMapInfo, nsCString& iconBuffer);
 
65
PRUint32 CalcWordAlignedRowSpan(PRUint32  aWidth, PRUint32 aBitCount);
 
66
 
 
67
// nsIconChannel methods
 
68
nsIconChannel::nsIconChannel()
 
69
{
 
70
}
 
71
 
 
72
nsIconChannel::~nsIconChannel()
 
73
{}
 
74
 
 
75
NS_IMPL_THREADSAFE_ISUPPORTS4(nsIconChannel, 
 
76
                              nsIChannel,
 
77
                              nsIRequest,
 
78
                              nsIRequestObserver,
 
79
                              nsIStreamListener)
 
80
 
 
81
nsresult nsIconChannel::Init(nsIURI* uri)
 
82
{
 
83
  NS_ASSERTION(uri, "no uri");
 
84
  mUrl = uri;
 
85
 
 
86
  nsresult rv;
 
87
  mPump = do_CreateInstance(NS_INPUTSTREAMPUMP_CONTRACTID, &rv);
 
88
  return rv;
 
89
}
 
90
 
 
91
////////////////////////////////////////////////////////////////////////////////
 
92
// nsIRequest methods:
 
93
 
 
94
NS_IMETHODIMP nsIconChannel::GetName(nsACString &result)
 
95
{
 
96
  return mUrl->GetSpec(result);
 
97
}
 
98
 
 
99
NS_IMETHODIMP nsIconChannel::IsPending(PRBool *result)
 
100
{
 
101
  return mPump->IsPending(result);
 
102
}
 
103
 
 
104
NS_IMETHODIMP nsIconChannel::GetStatus(nsresult *status)
 
105
{
 
106
  return mPump->GetStatus(status);
 
107
}
 
108
 
 
109
NS_IMETHODIMP nsIconChannel::Cancel(nsresult status)
 
110
{
 
111
  return mPump->Cancel(status);
 
112
}
 
113
 
 
114
NS_IMETHODIMP nsIconChannel::Suspend(void)
 
115
{
 
116
  return mPump->Suspend();
 
117
}
 
118
 
 
119
NS_IMETHODIMP nsIconChannel::Resume(void)
 
120
{
 
121
  return mPump->Resume();
 
122
}
 
123
 
 
124
NS_IMETHODIMP nsIconChannel::GetLoadGroup(nsILoadGroup* *aLoadGroup)
 
125
{
 
126
  *aLoadGroup = mLoadGroup;
 
127
  NS_IF_ADDREF(*aLoadGroup);
 
128
  return NS_OK;
 
129
}
 
130
 
 
131
NS_IMETHODIMP nsIconChannel::SetLoadGroup(nsILoadGroup* aLoadGroup)
 
132
{
 
133
  mLoadGroup = aLoadGroup;
 
134
  return NS_OK;
 
135
}
 
136
 
 
137
NS_IMETHODIMP nsIconChannel::GetLoadFlags(PRUint32 *aLoadAttributes)
 
138
{
 
139
  return mPump->GetLoadFlags(aLoadAttributes);
 
140
}
 
141
 
 
142
NS_IMETHODIMP nsIconChannel::SetLoadFlags(PRUint32 aLoadAttributes)
 
143
{
 
144
  return mPump->SetLoadFlags(aLoadAttributes);
 
145
}
 
146
 
 
147
////////////////////////////////////////////////////////////////////////////////
 
148
// nsIChannel methods:
 
149
 
 
150
NS_IMETHODIMP nsIconChannel::GetOriginalURI(nsIURI* *aURI)
 
151
{
 
152
  *aURI = mOriginalURI ? mOriginalURI : mUrl;
 
153
  NS_ADDREF(*aURI);
 
154
  return NS_OK;
 
155
}
 
156
 
 
157
NS_IMETHODIMP nsIconChannel::SetOriginalURI(nsIURI* aURI)
 
158
{
 
159
  mOriginalURI = aURI;
 
160
  return NS_OK;
 
161
}
 
162
 
 
163
NS_IMETHODIMP nsIconChannel::GetURI(nsIURI* *aURI)
 
164
{
 
165
  *aURI = mUrl;
 
166
  NS_IF_ADDREF(*aURI);
 
167
  return NS_OK;
 
168
}
 
169
 
 
170
NS_IMETHODIMP
 
171
nsIconChannel::Open(nsIInputStream **_retval)
 
172
{
 
173
  return MakeInputStream(_retval, PR_FALSE);
 
174
}
 
175
 
 
176
void InvertRows(PBYTE aInitialBuffer, PRUint32 sizeOfBuffer, PRUint32 numBytesPerRow)
 
177
{
 
178
  if (!numBytesPerRow) return;
 
179
 
 
180
  PRUint32 numRows = sizeOfBuffer / numBytesPerRow;
 
181
  void * temporaryRowHolder = (void *) nsMemory::Alloc(numBytesPerRow);
 
182
 
 
183
  PRUint32 currentRow = 0;
 
184
  PRUint32 lastRow = (numRows - 1) * numBytesPerRow;
 
185
  while (currentRow < lastRow)
 
186
  {
 
187
    // store the current row into a temporary buffer
 
188
    memcpy(temporaryRowHolder, (void *) &aInitialBuffer[currentRow], numBytesPerRow);
 
189
    memcpy((void *) &aInitialBuffer[currentRow], (void *)&aInitialBuffer[lastRow], numBytesPerRow);
 
190
    memcpy((void *) &aInitialBuffer[lastRow], temporaryRowHolder, numBytesPerRow);
 
191
    lastRow -= numBytesPerRow;
 
192
    currentRow += numBytesPerRow;
 
193
  }
 
194
 
 
195
  nsMemory::Free(temporaryRowHolder);
 
196
}
 
197
 
 
198
nsresult nsIconChannel::ExtractIconInfoFromUrl(nsIFile ** aLocalFile, PRUint32 * aDesiredImageSize, nsACString &aContentType, nsACString &aFileExtension)
 
199
{
 
200
  nsresult rv = NS_OK;
 
201
  nsCOMPtr<nsIMozIconURI> iconURI (do_QueryInterface(mUrl, &rv));
 
202
  NS_ENSURE_SUCCESS(rv, rv);
 
203
 
 
204
  iconURI->GetImageSize(aDesiredImageSize);
 
205
  iconURI->GetContentType(aContentType);
 
206
  iconURI->GetFileExtension(aFileExtension);
 
207
 
 
208
  nsCOMPtr<nsIURI> fileURI;
 
209
  rv = iconURI->GetIconFile(getter_AddRefs(fileURI));
 
210
  if (NS_FAILED(rv) || !fileURI) return NS_OK;
 
211
 
 
212
  nsCOMPtr<nsIFileURL>    fileURL = do_QueryInterface(fileURI, &rv);
 
213
  if (NS_FAILED(rv) || !fileURL) return NS_OK;
 
214
 
 
215
  nsCOMPtr<nsIFile> file;
 
216
  rv = fileURL->GetFile(getter_AddRefs(file));
 
217
  if (NS_FAILED(rv) || !file) return NS_OK;
 
218
  
 
219
  *aLocalFile = file;
 
220
  NS_IF_ADDREF(*aLocalFile);
 
221
  return NS_OK;
 
222
}
 
223
 
 
224
INT AddBGR(PRGB2 pColorTableEntry, nsCString& iconBuffer)
 
225
{
 
226
  iconBuffer.Append((char) pColorTableEntry->bBlue);
 
227
  iconBuffer.Append((char) pColorTableEntry->bGreen);
 
228
  iconBuffer.Append((char) pColorTableEntry->bRed);
 
229
  return 3;
 
230
}
 
231
 
 
232
void ConvertColorBitMap(PBYTE buffer, PBITMAPINFO2 pBitMapInfo, nsCString& iconBuffer)
 
233
{
 
234
  // windows inverts the row order in their bitmaps. So we need to invert the rows back into a top-down order.
 
235
 
 
236
  PRUint32 bytesPerPixel = pBitMapInfo->cBitCount / 8;
 
237
  PRUint32 unalignedBytesPerRowRGB = pBitMapInfo->cx * 3;
 
238
  PRInt32  iScanLineSize =  pBitMapInfo->cSize1;  // Stored early
 
239
  PRInt32  iIter;
 
240
 
 
241
  InvertRows(buffer, pBitMapInfo->cbImage, iScanLineSize);
 
242
 
 
243
  PRUint32 alignedBytesPerRowRGB = CalcWordAlignedRowSpan(pBitMapInfo->cx, 24);
 
244
  PRUint32 numBytesPaddingPerRowRGB = alignedBytesPerRowRGB - unalignedBytesPerRowRGB;
 
245
  PRUint32 pos = 0;
 
246
  if (numBytesPaddingPerRowRGB < 0)  // this should never happen.....
 
247
    numBytesPaddingPerRowRGB = 0;
 
248
 
 
249
  PRGB2 pColorTable = &pBitMapInfo->argbColor[0];  // Note Color tables are only valid for 1, 4, 8 BPP maps
 
250
 
 
251
  PRUint32 index = 0;
 
252
 
 
253
  // Many OS2 Icons are 16 colors or 4 BPP so we need to map the colors to RGB
 
254
  if (pBitMapInfo->cBitCount == 4 ||
 
255
      pBitMapInfo->cBitCount == 8  )
 
256
  {
 
257
    PBYTE pPelPair;
 
258
    PBYTE pPel;
 
259
    if (pBitMapInfo->cBitCount == 4)
 
260
    {
 
261
      iIter = (pBitMapInfo->cx + 1) / 2;  // Have 1/2 bytes as pels per row
 
262
    }
 
263
    else
 
264
    {
 
265
      iIter = pBitMapInfo->cx;  // Bytes = Pels
 
266
    }
 
267
    for (ULONG j = 0; j < pBitMapInfo->cy; j++)  //Number of rows
 
268
    {
 
269
      pPelPair = buffer;
 
270
      pPel     = (PBYTE)buffer;
 
271
      for(INT i = 0; i < iIter; i++)
 
272
      {
 
273
 
 
274
        if (pBitMapInfo->cBitCount == 4)
 
275
        {
 
276
          AddBGR(&pColorTable[FIRSTPEL(*pPelPair)], iconBuffer);
 
277
          AddBGR(&pColorTable[SECONDPEL(*pPelPair)], iconBuffer);
 
278
          pPelPair++;
 
279
        }
 
280
        else
 
281
        {
 
282
          AddBGR(&pColorTable[*pPel], iconBuffer);
 
283
          pPel++;
 
284
        }
 
285
      }
 
286
      if (numBytesPaddingPerRowRGB)
 
287
      {
 
288
        for (PRUint32 k = 0; k < numBytesPaddingPerRowRGB; k++)
 
289
        {
 
290
          iconBuffer.Append((char) 0);
 
291
        }
 
292
      }
 
293
      buffer += iScanLineSize;
 
294
    }
 
295
  }
 
296
//else
 
297
//// if each pixel uses 16 bits to describe the color then each R, G, and B value uses 5 bites. Use some fancy
 
298
//// bit operations to blow up the 16 bit case into 1 byte per component color. Actually windows
 
299
//// is using a 5:6:5 scheme. so the green component gets 6 bits....
 
300
//if (pBitMapInfo->cBitCount == 16)
 
301
//{
 
302
//  PRUint8 redValue, greenValue, blueValue;
 
303
//  while (index < pBitMapInfo->cbImage)
 
304
//  {
 
305
//    PRUint16 num = 0;
 
306
//    num = (PRUint8) buffer[index+1];
 
307
//    num <<= 8;
 
308
//    num |= (PRUint8) buffer[index];
 
309
//    // be sure to ignore the top bit
 
310
//    //num &= 0x7FFF; // only want the low 15 bits.....not the 16th...
 
311
//
 
312
//    // use num as an offset into the color table....get the RGBQuad entry and read out
 
313
//    // the RGB values.
 
314
//    //RGBQUAD rgbValues = pBitMapInfo->bmiColors[num];
 
315
//
 
316
//    //redValue = ( (num & 0xf800) >> 11);
 
317
//    //greenValue = ( (num & 0x07E0) >> 5);
 
318
//    //blueValue = ( num & 0x001F);
 
319
//
 
320
//    redValue = ((PRUint32) (((float)(num & 0xf800) / 0xf800) * 0xFF0000) & 0xFF0000)>> 16;
 
321
//    greenValue =  ((PRUint32)(((float)(num & 0x07E0) / 0x07E0) * 0x00FF00) & 0x00FF00)>> 8;
 
322
//    blueValue =  ((PRUint32)(((float)(num & 0x001F) / 0x001F) * 0x0000FF) & 0x0000FF);
 
323
//
 
324
//    // now we have the right RGB values...
 
325
//    iconBuffer.Append((char) blueValue);
 
326
//    iconBuffer.Append((char) greenValue);
 
327
//    iconBuffer.Append((char) redValue);
 
328
//    pos += 3;
 
329
//    if (pos == unalignedBytesPerRow && numBytesPaddingPerRow) // if we have reached the end of a current row, add padding to force dword alignment
 
330
//    {
 
331
//      pos = 0;
 
332
//      for (PRUint32 i = 0; i < numBytesPaddingPerRow; i++)
 
333
//      {
 
334
//        iconBuffer.Append((char) 0);
 
335
//      }
 
336
//    }
 
337
//    index += bytesPerPixel;
 
338
//  }
 
339
//}
 
340
  else // otherwise we must be using 32 bits per pixel so each component value is getting one byte...
 
341
  {
 
342
    while (index < pBitMapInfo->cbImage)
 
343
    {
 
344
      iconBuffer.Append((char) buffer[index]);
 
345
      iconBuffer.Append((char) buffer[index+1]);
 
346
      iconBuffer.Append((char) buffer[index+2]);
 
347
      pos += 3;
 
348
      if (pos == unalignedBytesPerRowRGB && numBytesPaddingPerRowRGB) // if we have reached the end of a current row, add padding to force dword alignment
 
349
      {
 
350
        pos = 0;
 
351
        for (PRUint32 i = 0; i < numBytesPaddingPerRowRGB; i++)
 
352
        {
 
353
          iconBuffer.Append((char) 0);
 
354
        }
 
355
      }
 
356
      index += bytesPerPixel;
 
357
    }
 
358
  }
 
359
}
 
360
 
 
361
PRUint32 CalcWordAlignedRowSpan(PRUint32  aWidth, PRUint32 aBitCount)
 
362
{
 
363
  PRUint32 spanBytes;
 
364
 
 
365
  spanBytes = (aWidth * aBitCount) >> 5;
 
366
 
 
367
  if (((PRUint32) aWidth * aBitCount) & 0x1F)
 
368
    spanBytes++;
 
369
 
 
370
  spanBytes <<= 2;
 
371
 
 
372
  return spanBytes;
 
373
}
 
374
 
 
375
void ConvertMaskBitMap(PBYTE aBitMaskBuffer, PBITMAPINFO2 pBitMapInfo, nsCString& iconBuffer)
 
376
{
 
377
  PRInt32  iScanLineSize =  pBitMapInfo->cSize1;  // Stored early
 
378
 
 
379
  InvertRows(aBitMaskBuffer, pBitMapInfo->cbImage, iScanLineSize);
 
380
  PRUint32 index = 0;
 
381
  // for some reason the bit mask on windows are flipped from the values we really want for transparency.
 
382
  // So complement each byte in the bit mask.
 
383
  while (index < pBitMapInfo->cbImage)
 
384
  {
 
385
    aBitMaskBuffer[index]^=255;
 
386
    index += 1;
 
387
  }
 
388
  iconBuffer.Append((char *) aBitMaskBuffer, pBitMapInfo->cbImage);
 
389
}
 
390
 
 
391
NS_IMETHODIMP nsIconChannel::AsyncOpen(nsIStreamListener *aListener, nsISupports *ctxt)
 
392
{
 
393
  nsCOMPtr<nsIInputStream> inStream;
 
394
  nsresult rv = MakeInputStream(getter_AddRefs(inStream), PR_TRUE);
 
395
  if (NS_FAILED(rv))
 
396
    return rv;
 
397
 
 
398
  // Init our streampump
 
399
  rv = mPump->Init(inStream, -1, -1, 0, 0, PR_FALSE);
 
400
  if (NS_FAILED(rv))
 
401
    return rv;
 
402
 
 
403
  rv = mPump->AsyncRead(this, ctxt);
 
404
  if (NS_SUCCEEDED(rv)) {
 
405
    // Store our real listener
 
406
    mListener = aListener;
 
407
    // Add ourself to the load group, if available
 
408
    if (mLoadGroup)
 
409
      mLoadGroup->AddRequest(this, nsnull);
 
410
  }
 
411
  return rv;
 
412
}
 
413
 
 
414
nsresult nsIconChannel::MakeInputStream(nsIInputStream** _retval, PRBool nonBlocking)
 
415
{
 
416
  nsXPIDLCString contentType;
 
417
  nsCAutoString filePath;
 
418
  nsCOMPtr<nsIFile> localFile; // file we want an icon for
 
419
  PRUint32 desiredImageSize;
 
420
  nsresult rv = ExtractIconInfoFromUrl(getter_AddRefs(localFile), &desiredImageSize, contentType, filePath);
 
421
  NS_ENSURE_SUCCESS(rv, rv);
 
422
 
 
423
  // if the file exists, we are going to use it's real attributes...otherwise we only want to use it for it's extension...
 
424
  UINT infoFlags = SHGFI_ICON;
 
425
 
 
426
  PRBool fileExists = PR_FALSE;
 
427
 
 
428
  if (localFile)
 
429
  {
 
430
    localFile->GetNativePath(filePath);
 
431
    localFile->Exists(&fileExists);
 
432
  }
 
433
 
 
434
  if (!fileExists)
 
435
   infoFlags |= SHGFI_USEFILEATTRIBUTES;
 
436
 
 
437
  if (desiredImageSize > 16)
 
438
    infoFlags |= SHGFI_LARGEICON;
 
439
  else
 
440
    infoFlags |= SHGFI_SMALLICON;
 
441
 
 
442
  // if we have a content type... then use it! but for existing files, we want
 
443
  // to show their real icon.
 
444
  if (!fileExists && !contentType.IsEmpty())
 
445
  {
 
446
    nsCOMPtr<nsIMIMEService> mimeService (do_GetService(NS_MIMESERVICE_CONTRACTID, &rv));
 
447
    NS_ENSURE_SUCCESS(rv, rv);
 
448
 
 
449
    nsXPIDLCString fileExt;
 
450
    mimeService->GetPrimaryExtension(contentType.get(), nsnull, getter_Copies(fileExt));
 
451
    // If the mime service does not know about this mime type, we show
 
452
    // the generic icon.
 
453
    // In any case, we need to insert a '.' before the extension.
 
454
    filePath = NS_LITERAL_CSTRING(".") + fileExt;
 
455
  }
 
456
 
 
457
  // (1) get an hIcon for the file
 
458
  PSZ pszFileName = (PSZ)filePath.get();
 
459
  HPOINTER hIcon = WinLoadFileIcon(pszFileName, FALSE);
 
460
  if ((hIcon == NULLHANDLE) && (pszFileName[0] == '.')) {
 
461
    /* Just trying to get an icon for an extension */
 
462
    /* Create a temporary file to try to get an icon */
 
463
    char* tmpdir = getenv("TMP");
 
464
    if (tmpdir) {
 
465
      char tmpfile[CCHMAXPATH];
 
466
      strcpy(tmpfile, tmpdir);
 
467
      strcat(tmpfile, pszFileName);
 
468
      FILE* fp = fopen(tmpfile, "wb+");
 
469
      if (fp) {
 
470
        fclose(fp);
 
471
        hIcon = WinLoadFileIcon(tmpfile, FALSE);
 
472
        remove(tmpfile);
 
473
      }
 
474
    }
 
475
  }
 
476
  if (hIcon == NULLHANDLE)
 
477
    return NS_ERROR_FAILURE;
 
478
  // we got a handle to an icon. Now we want to get a bitmap for the icon using GetIconInfo....
 
479
  POINTERINFO IconInfo;
 
480
  BOOL fRC = WinQueryPointerInfo(hIcon, &IconInfo);
 
481
  if (fRC == 0) {
 
482
    WinFreeFileIcon(hIcon);
 
483
    return NS_ERROR_FAILURE;
 
484
  }
 
485
  nsCString iconBuffer;
 
486
  BITMAPINFOHEADER2  BMHeader;
 
487
  HBITMAP            hBitmap;
 
488
  HBITMAP            hBitmapMask;
 
489
 
 
490
  // Decide which icon to use
 
491
  if ( infoFlags & SHGFI_LARGEICON )
 
492
  {
 
493
    hBitmap = IconInfo.hbmColor;
 
494
    hBitmapMask = IconInfo.hbmPointer;
 
495
  }
 
496
  else
 
497
  {
 
498
    hBitmap = IconInfo.hbmMiniColor;
 
499
    hBitmapMask = IconInfo.hbmMiniPointer;
 
500
  }
 
501
 
 
502
  // Get the basic info
 
503
  BMHeader.cbFix = sizeof(BMHeader);
 
504
  fRC =  GpiQueryBitmapInfoHeader(hBitmap, &BMHeader);
 
505
  if (fRC == 0) {
 
506
    WinFreeFileIcon(hIcon);
 
507
    return NS_ERROR_FAILURE;
 
508
  }
 
509
 
 
510
///// // Calulate size of color table
 
511
///// LONG cbColorTable;
 
512
///// if ( BMHeader.cBitCount > 8 )
 
513
///// {
 
514
/////   cbColorTable = 0;
 
515
///// }
 
516
///// else
 
517
///// {
 
518
/////   cbColorTable = 1 << BMHeader.cBitCount;
 
519
///// }
 
520
  LONG cbBitMapInfo = sizeof(BITMAPINFO2) + (sizeof(RGB2) * 255); // Max possible
 
521
  LONG iScanLineSize =  ((BMHeader.cBitCount * BMHeader.cx + 31) / 32) * 4;
 
522
  LONG cbBuffer = iScanLineSize * BMHeader.cy;
 
523
  // Allocate buffers, fill w/ 0
 
524
  PBITMAPINFO2 pBitMapInfo = (PBITMAPINFO2)nsMemory::Alloc(cbBitMapInfo);
 
525
  memset(pBitMapInfo, 0, cbBitMapInfo);
 
526
  PBYTE buffer = (PBYTE)nsMemory::Alloc(cbBuffer);
 
527
  memset(buffer, 0, cbBuffer);
 
528
  // Copy over the header info
 
529
  *((PBITMAPINFOHEADER2)pBitMapInfo ) = BMHeader;
 
530
 
 
531
  // Create DC
 
532
  DEVOPENSTRUC  dop = {NULL, "DISPLAY", NULL, NULL, NULL, NULL, NULL, NULL, NULL};
 
533
  HDC hdc = DevOpenDC( (HAB)0, OD_MEMORY, "*", 5L, (PDEVOPENDATA)&dop, NULLHANDLE);
 
534
  SIZEL sizel = {0,0};
 
535
  HPS hps = GpiCreatePS((HAB)0, hdc, &sizel, GPIA_ASSOC | PU_PELS | GPIT_MICRO);
 
536
 
 
537
  // Not sure if you need this but it is good form
 
538
  HBITMAP hOldBM = GpiSetBitmap(hps, hBitmap);
 
539
 
 
540
  // Get those bits
 
541
  LONG lScanLines = GpiQueryBitmapBits(hps, 0L, (LONG)BMHeader.cy, buffer, pBitMapInfo);
 
542
  if (lScanLines > 0)
 
543
  {
 
544
    // Set this since it is used all over
 
545
    pBitMapInfo->cbImage =  cbBuffer;
 
546
    pBitMapInfo->cSize1  =  iScanLineSize;
 
547
 
 
548
    // temporary hack alert...currently moz-icon urls only support 16, 24 and 32 bit color. we don't support
 
549
    // 8, 4 or 1 bit color yet. So convert OS/2 4 BPP to RGB
 
550
 
 
551
    // The first 2 bytes into our output buffer needs to be the width and the height (in pixels) of the icon
 
552
    // as specified by our data format.
 
553
    iconBuffer.Assign((char) pBitMapInfo->cx);
 
554
    iconBuffer.Append((char) pBitMapInfo->cy);
 
555
 
 
556
    ConvertColorBitMap(buffer, pBitMapInfo, iconBuffer);
 
557
 
 
558
    // now we need to tack on the alpha data...which is hbmMask
 
559
 
 
560
    memset(pBitMapInfo, 0, cbBitMapInfo);
 
561
    BMHeader.cbFix = sizeof(BMHeader);
 
562
    fRC =  GpiQueryBitmapInfoHeader(hBitmapMask, &BMHeader);
 
563
    iScanLineSize =  ((BMHeader.cBitCount * BMHeader.cx + 31) / 32) * 4;
 
564
    LONG cbBufferMask = iScanLineSize * BMHeader.cy;
 
565
    if (cbBufferMask > cbBuffer)  // Need more for mask
 
566
    {
 
567
      nsMemory::Free(buffer);
 
568
      buffer = (PBYTE)nsMemory::Alloc(cbBufferMask);
 
569
      memset(buffer, 0, cbBufferMask);
 
570
    }
 
571
 
 
572
    *((PBITMAPINFOHEADER2)pBitMapInfo ) = BMHeader;
 
573
    hOldBM = GpiSetBitmap(hps, hBitmapMask);
 
574
 
 
575
    lScanLines = GpiQueryBitmapBits(hps, 0L, (LONG)BMHeader.cy, buffer, pBitMapInfo);
 
576
    if (lScanLines > 0)
 
577
    {
 
578
      pBitMapInfo->cbImage =  cbBufferMask;
 
579
      pBitMapInfo->cSize1  =  iScanLineSize;
 
580
      ConvertMaskBitMap(buffer, pBitMapInfo, iconBuffer);
 
581
 
 
582
      // Now, create a pipe and stuff our data into it
 
583
      nsCOMPtr<nsIInputStream> inStream;
 
584
      nsCOMPtr<nsIOutputStream> outStream;
 
585
      rv = NS_NewPipe(getter_AddRefs(inStream), getter_AddRefs(outStream),
 
586
                      iconBuffer.Length(), iconBuffer.Length(), nonBlocking);
 
587
      if (NS_SUCCEEDED(rv)) {
 
588
        PRUint32 written;
 
589
        rv = outStream->Write(iconBuffer.get(), iconBuffer.Length(), &written);
 
590
        if (NS_SUCCEEDED(rv)) {
 
591
          NS_ADDREF(*_retval = inStream);
 
592
        }
 
593
      }
 
594
    } // if we have a mask buffer to apply
 
595
 
 
596
  } // if we got color info
 
597
  nsMemory::Free(buffer);
 
598
  nsMemory::Free(pBitMapInfo);
 
599
  if (hps)
 
600
  {
 
601
    GpiAssociate(hps, NULLHANDLE);
 
602
    GpiDestroyPS(hps);
 
603
  }
 
604
  if (hdc)
 
605
  {
 
606
    DevCloseDC(hdc);
 
607
  }
 
608
  if (hIcon)
 
609
    WinFreeFileIcon(hIcon);
 
610
 
 
611
  return rv;
 
612
}
 
613
 
 
614
NS_IMETHODIMP nsIconChannel::GetContentType(nsACString &aContentType) 
 
615
{
 
616
  aContentType = NS_LITERAL_CSTRING("image/icon");
 
617
  return NS_OK;
 
618
}
 
619
 
 
620
NS_IMETHODIMP
 
621
nsIconChannel::SetContentType(const nsACString &aContentType)
 
622
{
 
623
  // It doesn't make sense to set the content-type on this type
 
624
  // of channel...
 
625
  return NS_ERROR_FAILURE;
 
626
}
 
627
 
 
628
NS_IMETHODIMP nsIconChannel::GetContentCharset(nsACString &aContentCharset) 
 
629
{
 
630
  aContentCharset.Truncate();
 
631
  return NS_OK;
 
632
}
 
633
 
 
634
NS_IMETHODIMP
 
635
nsIconChannel::SetContentCharset(const nsACString &aContentCharset)
 
636
{
 
637
  // It doesn't make sense to set the content-charset on this type
 
638
  // of channel...
 
639
  return NS_ERROR_FAILURE;
 
640
}
 
641
 
 
642
NS_IMETHODIMP nsIconChannel::GetContentLength(PRInt32 *aContentLength)
 
643
{
 
644
  *aContentLength = mContentLength;
 
645
  return NS_OK;
 
646
}
 
647
 
 
648
NS_IMETHODIMP nsIconChannel::SetContentLength(PRInt32 aContentLength)
 
649
{
 
650
  NS_NOTREACHED("nsIconChannel::SetContentLength");
 
651
  return NS_ERROR_NOT_IMPLEMENTED;
 
652
}
 
653
 
 
654
NS_IMETHODIMP nsIconChannel::GetOwner(nsISupports* *aOwner)
 
655
{
 
656
  *aOwner = mOwner.get();
 
657
  NS_IF_ADDREF(*aOwner);
 
658
  return NS_OK;
 
659
}
 
660
 
 
661
NS_IMETHODIMP nsIconChannel::SetOwner(nsISupports* aOwner)
 
662
{
 
663
  mOwner = aOwner;
 
664
  return NS_OK;
 
665
}
 
666
 
 
667
NS_IMETHODIMP nsIconChannel::GetNotificationCallbacks(nsIInterfaceRequestor* *aNotificationCallbacks)
 
668
{
 
669
  *aNotificationCallbacks = mCallbacks.get();
 
670
  NS_IF_ADDREF(*aNotificationCallbacks);
 
671
  return NS_OK;
 
672
}
 
673
 
 
674
NS_IMETHODIMP nsIconChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aNotificationCallbacks)
 
675
{
 
676
  mCallbacks = aNotificationCallbacks;
 
677
  return NS_OK;
 
678
}
 
679
 
 
680
NS_IMETHODIMP nsIconChannel::GetSecurityInfo(nsISupports * *aSecurityInfo)
 
681
{
 
682
  *aSecurityInfo = nsnull;
 
683
  return NS_OK;
 
684
}
 
685
 
 
686
// nsIRequestObserver methods
 
687
NS_IMETHODIMP nsIconChannel::OnStartRequest(nsIRequest* aRequest, nsISupports* aContext)
 
688
{
 
689
  if (mListener)
 
690
    return mListener->OnStartRequest(this, aContext);
 
691
  return NS_OK;
 
692
}
 
693
 
 
694
NS_IMETHODIMP nsIconChannel::OnStopRequest(nsIRequest* aRequest, nsISupports* aContext, nsresult aStatus)
 
695
{
 
696
  if (mListener) {
 
697
    mListener->OnStopRequest(this, aContext, aStatus);
 
698
    mListener = nsnull;
 
699
  }
 
700
 
 
701
  // Remove from load group
 
702
  if (mLoadGroup)
 
703
    mLoadGroup->RemoveRequest(this, nsnull, aStatus);
 
704
 
 
705
  return NS_OK;
 
706
}
 
707
 
 
708
// nsIStreamListener methods
 
709
NS_IMETHODIMP nsIconChannel::OnDataAvailable(nsIRequest* aRequest,
 
710
                                             nsISupports* aContext,
 
711
                                             nsIInputStream* aStream,
 
712
                                             PRUint32 aOffset,
 
713
                                             PRUint32 aCount)
 
714
{
 
715
  if (mListener)
 
716
    return mListener->OnDataAvailable(this, aContext, aStream, aOffset, aCount);
 
717
  return NS_OK;
 
718
}