nsresult nsIconChannel::MakeInputStream(nsIInputStream **_retval,
                                        bool nonBlocking)
{

  // get some details about this icon
  nsCOMPtr<nsIFile> localFile;
  uint32_t desiredImageSize;
  nsXPIDLCString contentType;
  nsAutoCString filePath;
  nsresult rv = ExtractIconInfoFromUrl(getter_AddRefs(localFile),
                                       &desiredImageSize, contentType,
                                       filePath);
  NS_ENSURE_SUCCESS(rv, rv);

  // if the file exists, get its path
  bool fileExists = false;
  if (localFile) {
    localFile->GetNativePath(filePath);
    localFile->Exists(&fileExists);
  }

  // get the file's icon from either the WPS or PM
  bool fWpsIcon = false;
  HPOINTER hIcon = GetIcon(filePath, fileExists,
                           desiredImageSize <= 16, &fWpsIcon);
  if (hIcon == NULLHANDLE)
    return NS_ERROR_FAILURE;

  // get the color & mask bitmaps used by the icon
  POINTERINFO IconInfo;
  if (!WinQueryPointerInfo(hIcon, &IconInfo)) {
    DestroyIcon(hIcon, fWpsIcon);
    return NS_ERROR_FAILURE;
  }

  // if we need a mini-icon, use those bitmaps if present;
  // otherwise, signal that the icon needs to be shrunk
  bool fShrink = FALSE;
  if (desiredImageSize <= 16) {
    if (IconInfo.hbmMiniPointer) {
      IconInfo.hbmColor = IconInfo.hbmMiniColor;
      IconInfo.hbmPointer = IconInfo.hbmMiniPointer;
    } else {
      fShrink = TRUE;
    }
  }

  // various resources to be allocated
  PBITMAPINFO2  pBMInfo = 0;
  uint8_t*      pInBuf  = 0;
  uint8_t*      pOutBuf = 0;
  HDC           hdc     = 0;
  HPS           hps     = 0;

  // using this dummy do{...}while(0) "loop" guarantees that resources will
  // be deallocated, but eliminates the need for nesting, and generally makes
  // testing for & dealing with errors pretty painless (just 'break')
  do {
    rv = NS_ERROR_FAILURE;

    // get the details for the color bitmap;  if there isn't one
    // or this is 1-bit color, exit
    BITMAPINFOHEADER2  BMHeader;
    BMHeader.cbFix = sizeof(BMHeader);
    if (!IconInfo.hbmColor ||
        !GpiQueryBitmapInfoHeader(IconInfo.hbmColor, &BMHeader) ||
        BMHeader.cBitCount == 1)
      break;

    // alloc space for the color bitmap's info, including its color table
    uint32_t cbBMInfo = sizeof(BITMAPINFO2) + (sizeof(RGB2) * 255);
    pBMInfo = (PBITMAPINFO2)nsMemory::Alloc(cbBMInfo);
    if (!pBMInfo)
      break;

    // alloc space for the color bitmap data
    uint32_t cbInRow = ALIGNEDBPR(BMHeader.cx, BMHeader.cBitCount);
    uint32_t cbInBuf = cbInRow * BMHeader.cy;
    pInBuf = (uint8_t*)nsMemory::Alloc(cbInBuf);
    if (!pInBuf)
      break;
    memset(pInBuf, 0, cbInBuf);

    // alloc space for the BGRA32 bitmap we're creating
    uint32_t cxOut    = fShrink ? BMHeader.cx / 2 : BMHeader.cx;
    uint32_t cyOut    = fShrink ? BMHeader.cy / 2 : BMHeader.cy;
    uint32_t cbOutBuf = 2 + ALIGNEDBPR(cxOut, 32) * cyOut;
    pOutBuf = (uint8_t*)nsMemory::Alloc(cbOutBuf);
    if (!pOutBuf)
      break;
    memset(pOutBuf, 0, cbOutBuf);

    // create a DC and PS
    DEVOPENSTRUC dop = {NULL, "DISPLAY", NULL, NULL, NULL, NULL, NULL, NULL, NULL};
    hdc = DevOpenDC((HAB)0, OD_MEMORY, "*", 5L, (PDEVOPENDATA)&dop, NULLHANDLE);
    if (!hdc)
      break;

    SIZEL sizel = {0,0};
    hps = GpiCreatePS((HAB)0, hdc, &sizel, GPIA_ASSOC | PU_PELS | GPIT_MICRO);
    if (!hps)
      break;

    // get the color bits
    memset(pBMInfo, 0, cbBMInfo);
    *((PBITMAPINFOHEADER2)pBMInfo) = BMHeader;
    GpiSetBitmap(hps, IconInfo.hbmColor);
    if (GpiQueryBitmapBits(hps, 0L, (LONG)BMHeader.cy,
                           (BYTE*)pInBuf, pBMInfo) <= 0)
      break;

    // The first 2 bytes are the width & height of the icon in pixels,
    // the remaining bytes are BGRA32 (B in first byte, A in last)
    uint8_t* outPtr = pOutBuf;
    *outPtr++ = (uint8_t)cxOut;
    *outPtr++ = (uint8_t)cyOut;

    // convert the color bitmap
    pBMInfo->cbImage = cbInBuf;
    ConvertColorBitMap(pInBuf, pBMInfo, outPtr, fShrink);

    // now we need to tack on the alpha data, so jump back to the first
    // pixel in the output buffer
    outPtr = pOutBuf+2;

    // Get the mask info
    BMHeader.cbFix = sizeof(BMHeader);
    if (!GpiQueryBitmapInfoHeader(IconInfo.hbmPointer, &BMHeader))
      break;

    // if the existing input buffer isn't large enough, reallocate it
    cbInRow = ALIGNEDBPR(BMHeader.cx, BMHeader.cBitCount);
    if ((cbInRow * BMHeader.cy) > cbInBuf)  // Need more for mask
    {
      cbInBuf = cbInRow * BMHeader.cy;
      nsMemory::Free(pInBuf);
      pInBuf = (uint8_t*)nsMemory::Alloc(cbInBuf);
      memset(pInBuf, 0, cbInBuf);
    }

    // get the mask/alpha bits
    memset(pBMInfo, 0, cbBMInfo);
    *((PBITMAPINFOHEADER2)pBMInfo) = BMHeader;
    GpiSetBitmap(hps, IconInfo.hbmPointer);
    if (GpiQueryBitmapBits(hps, 0L, (LONG)BMHeader.cy,
                           (BYTE*)pInBuf, pBMInfo) <= 0)
      break;

    // convert the mask/alpha bitmap
    pBMInfo->cbImage = cbInBuf;
    ConvertMaskBitMap(pInBuf, pBMInfo, outPtr, fShrink);

    // create a pipe
    nsCOMPtr<nsIInputStream> inStream;
    nsCOMPtr<nsIOutputStream> outStream;
    rv = NS_NewPipe(getter_AddRefs(inStream), getter_AddRefs(outStream),
                    cbOutBuf, cbOutBuf, nonBlocking);
    if (NS_FAILED(rv))
      break;

    // put our data into the pipe
    uint32_t written;
    rv = outStream->Write(reinterpret_cast<const char*>(pOutBuf),
                          cbOutBuf, &written);
    if (NS_FAILED(rv))
      break;

    // success! so addref the pipe
    NS_ADDREF(*_retval = inStream);
  } while (0);

  // free all the resources we allocated
  if (pOutBuf)
    nsMemory::Free(pOutBuf);
  if (pInBuf)
    nsMemory::Free(pInBuf);
  if (pBMInfo)
    nsMemory::Free(pBMInfo);
  if (hps) {
    GpiAssociate(hps, NULLHANDLE);
    GpiDestroyPS(hps);
  }
  if (hdc)
    DevCloseDC(hdc);
  if (hIcon)
    DestroyIcon(hIcon, fWpsIcon);

  return rv;
}
Beispiel #2
0
nsresult nsIconChannel::MakeInputStream(nsIInputStream** _retval, PRBool nonBlocking)
{
  nsXPIDLCString contentType;
  nsCAutoString filePath;
  nsCAutoString fileExtension;
  nsCOMPtr<nsIFile> localFile; // File we want an icon for
  PRUint32 desiredImageSize;
  nsresult rv = ExtractIconInfoFromUrl(getter_AddRefs(localFile), &desiredImageSize, contentType, fileExtension);
  NS_ENSURE_SUCCESS(rv, rv);

  PRUint32 iconSize = 16;
  if (desiredImageSize > 16)
    iconSize = 32;

  PRUint32 alphaBytesPerRow = (iconSize / 8);
  if (iconSize % 32 != 0)
    alphaBytesPerRow = ((iconSize / 32) + 1) * 4;
    
  PRBool fileExists = PR_FALSE;
  if (localFile)
  {
    localFile->GetNativePath(filePath);
    localFile->Exists(&fileExists);
  }
  
  // Get the native icon.
  // 1) If it is for an actual local file, BNodeInfo::GetTrackerIcon.
  // 2) If the local file does not exist, use the content type 
  //    and BMimeType::GetIcon
  BBitmap nativeIcon(BRect(0, 0, iconSize - 1, iconSize - 1), B_CMAP8);
  if (!nativeIcon.IsValid())
    return NS_ERROR_OUT_OF_MEMORY;

  PRBool gotBitmap = PR_FALSE;
  if (fileExists)
  {
    BNode localNode(filePath.get());
    // BeOS doesn't MIME type foreign files immediately - 
    // If there is no type attribute then we can force an identify
    if (localNode.ReadAttr("BEOS:TYPE", B_STRING_TYPE, 0, NULL, 0) != B_OK)
    	update_mime_info(filePath.get(), 0, 1, 1);

    BNodeInfo localNodeInfo(&localNode);
    if (iconSize == 16)
    {
      if (localNodeInfo.GetTrackerIcon(&nativeIcon, B_MINI_ICON) == B_OK)
        gotBitmap = PR_TRUE;
    }
    else
    {
      if (localNodeInfo.GetTrackerIcon(&nativeIcon, B_LARGE_ICON) == B_OK)
        gotBitmap = PR_TRUE;
    }
  }

  // If we haven't got a bitmap yet, use the content type
  if (!gotBitmap)    
  {
    // If no content type specified, use mozilla's mime service to guess a mime type
    if (contentType.IsEmpty())
    {
      nsCOMPtr<nsIMIMEService> mimeService (do_GetService("@mozilla.org/mime;1", &rv));
      if (NS_SUCCEEDED(rv))
        mimeService->GetTypeFromExtension(fileExtension, contentType);
      // If unrecognised extension - set to generic file
      if (contentType.IsEmpty())
        contentType = "application/octet-stream";
    }
    // Create BeOS-Native MIME type info - if unheard of, set to generic file
    BMimeType mimeType(contentType.get());
    if (!mimeType.IsInstalled())
    	mimeType.SetTo("application/octet-stream");
    if (iconSize == 16)
    {
      if (mimeType.GetIcon(&nativeIcon, B_MINI_ICON) == B_OK)
        gotBitmap = PR_TRUE;
    }
    else
    {
      if (mimeType.GetIcon(&nativeIcon, B_LARGE_ICON) == B_OK)
        gotBitmap = PR_TRUE;
    }
  }
  
  if (!gotBitmap)
    return NS_ERROR_NOT_AVAILABLE;

  BScreen mainScreen(B_MAIN_SCREEN_ID);
  if (!mainScreen.IsValid())
    return NS_ERROR_NOT_AVAILABLE;

  // Got a bitmap and color space info - convert data to mozilla's icon format
  PRUint32 iconLength = 2 + iconSize * iconSize * 4;
  uint8 *buffer = new uint8[iconLength];
  if (!buffer)
    return NS_ERROR_OUT_OF_MEMORY;

  uint8* destByte = buffer;
  *(destByte++) = iconSize;
  *(destByte++) = iconSize;

  // RGB data
  uint8* sourceByte = (uint8*)nativeIcon.Bits();
  for(PRUint32 iconRow = 0; iconRow < iconSize; iconRow++)
  {
    sourceByte = (uint8*)nativeIcon.Bits() + nativeIcon.BytesPerRow() * iconRow;
    for(PRUint32 iconCol = 0; iconCol < iconSize; iconCol++)
    {
      if (*sourceByte != B_TRANSPARENT_MAGIC_CMAP8)
      {
        rgb_color colorVal = mainScreen.ColorForIndex(*sourceByte);
#ifdef IS_LITTLE_ENDIAN
        *(destByte++) = colorVal.blue;
        *(destByte++) = colorVal.green;
        *(destByte++) = colorVal.red;
        *(destByte++) = uint8(255);
#else
        *(destByte++) = uint8(255);
        *(destByte++) = colorVal.red;
        *(destByte++) = colorVal.green;
        *(destByte++) = colorVal.blue;
#endif
      }
      else
      {
        *destByte++ = 0;
        *destByte++ = 0;
        *destByte++ = 0;
        *destByte++ = 0;
      }
      // original code had a conditional here:
      // if (iconCol < iconSize - 1) 
      // Leaving this comment in case complications arise later
      sourceByte++;
    }
  }

  NS_ASSERTION(buffer + iconLength == destByte, "size miscalculation");
  
  // Now, create a pipe and stuff our data into it
  nsCOMPtr<nsIInputStream> inStream;
  nsCOMPtr<nsIOutputStream> outStream;
  rv = NS_NewPipe(getter_AddRefs(inStream), getter_AddRefs(outStream),
                  iconLength, iconLength, nonBlocking);
  if (NS_SUCCEEDED(rv))
  {
    PRUint32 written;
    rv = outStream->Write((char*)buffer, iconLength, &written);
    if (NS_SUCCEEDED(rv))
      NS_ADDREF(*_retval = inStream);
  }
  delete [] buffer;
  
  return rv;
}