bool MapPainterCanvas::HasPattern(const MapParameter& parameter,
                    const FillStyle& style)
  {
    // Pattern already loaded with error
    if (style.GetPatternId()==0) {
      return false;
    }

    int patternIndex=style.GetPatternId()-1;

    if (patternIndex<mPatternLoaded.size() &&
        mPatternLoaded[patternIndex])
    {
      return true;
    }

    jmethodID methodId=mJniEnv->GetMethodID(mPainterClass, "loadPatternPNG",
                                            "(Ljava/lang/String;I)Z");

    if (!methodId)
      return false;

    for (std::list<std::string>::const_iterator path=parameter.GetPatternPaths().begin();
         path!=parameter.GetPatternPaths().end();
         ++path) {
      std::string filename=*path+"/"+style.GetPatternName()+".png";

      jstring patternName=mJniEnv->NewStringUTF(filename.c_str());

      bool loaded=mJniEnv->CallIntMethod(mPainterObject, methodId,
                                         patternName, patternIndex);

      mJniEnv->DeleteLocalRef(patternName);

      if (loaded)
      {
        if (patternIndex>=mPatternLoaded.size())
        {
          mPatternLoaded.resize(patternIndex+1, false);
        }

        mPatternLoaded[patternIndex]=true;

        return true;
      }
    }

    // Error loading icon file
    style.SetPatternId(0);
    return false;
  }
  bool MapPainterCanvas::DrawMap(const StyleConfig& styleConfig,
                 const Projection& projection,
                 const MapParameter& parameter,
                 const MapData& data,
                 JNIEnv *env,
                 jobject object)
  {
    mJniEnv=env;
    mPainterClass=env->FindClass("osm/scout/MapPainterCanvas");
    mPainterObject=object;

    mMinimumLineWidth=parameter.GetLineMinWidthPixel()*25.4/parameter.GetDPI();

    return Draw(styleConfig, projection, parameter, data);
  }
  void MapPainterAgg::SetOutlineFont(const Projection& projection,
                                     const MapParameter& parameter,
                                     double size)
  {
    if (!fontEngine->load_font(parameter.GetFontName().c_str(),
                               0,
                               agg::glyph_ren_outline)) {
      std::cout << "Cannot load font '" << parameter.GetFontName() << "'" << std::endl;
      return;

    }

    //fontEngine->resolution(72);
    fontEngine->width(size*projection.ConvertWidthToPixel(parameter.GetFontSize()));
    fontEngine->height(size*projection.ConvertWidthToPixel(parameter.GetFontSize()));
    fontEngine->hinting(true);
    fontEngine->flip_y(true);
  }
  void MapPainterAgg::DrawFill(const Projection& projection,
                               const MapParameter& parameter,
                               const FillStyle& fillStyle,
                               agg::path_storage& path)
  {
    if (fillStyle.GetFillColor().IsVisible()) {
      renderer_aa->color(agg::rgba(fillStyle.GetFillColor().GetR(),
                                   fillStyle.GetFillColor().GetG(),
                                   fillStyle.GetFillColor().GetB(),
                                   fillStyle.GetFillColor().GetA()));

      agg::render_scanlines(*rasterizer,*scanlineP8,*renderer_aa);
    }

    double borderWidth=projection.ConvertWidthToPixel(fillStyle.GetBorderWidth());

    if (borderWidth>=parameter.GetLineMinWidthPixel()) {
      renderer_aa->color(agg::rgba(fillStyle.GetBorderColor().GetR(),
                                   fillStyle.GetBorderColor().GetG(),
                                   fillStyle.GetBorderColor().GetB(),
                                   fillStyle.GetBorderColor().GetA()));

      if (fillStyle.GetBorderDash().empty()) {
        agg::conv_stroke<agg::path_storage> stroke(path);

        stroke.width(borderWidth);
        stroke.line_cap(agg::round_cap);

        rasterizer->add_path(stroke);

        agg::render_scanlines(*rasterizer,*scanlineP8,*renderer_aa);
      }
      else {
        agg::conv_dash<agg::path_storage>                    dasher(path);
        agg::conv_stroke<agg::conv_dash<agg::path_storage> > stroke(dasher);

        stroke.width(borderWidth);

        stroke.line_cap(agg::butt_cap);

        for (size_t i=0; i<fillStyle.GetBorderDash().size(); i+=2) {
          dasher.add_dash(fillStyle.GetBorderDash()[i]*borderWidth,
                          fillStyle.GetBorderDash()[i+1]*borderWidth);
        }

        rasterizer->add_path(stroke);

        agg::render_scanlines(*rasterizer,*scanlineP8,*renderer_aa);
      }
    }
  }
void MapPainterSVG::DrawLabel(const Projection& projection,
                              const MapParameter& parameter,
                              const LabelData& label)
{
    if (dynamic_cast<const TextStyle*>(label.style.get())!=NULL) {
        const TextStyle* style=dynamic_cast<const TextStyle*>(label.style.get());
#if defined(OSMSCOUT_MAP_SVG_HAVE_LIB_PANGO)
        PangoFontDescription* font=GetFont(projection,
                                           parameter,
                                           label.fontSize);
#endif

        // TODO: This is not the exact placement, we cannot just move vertical by fontSize, but we must move the actual
        // text height. For this we need the text bounding box in LabelData.

        stream << "    <text";
        stream << " x=\"" << label.x << "\"";
        stream << " y=\"" << label.y+projection.ConvertWidthToPixel(label.fontSize*parameter.GetFontSize()) << "\"";
        stream << " font-family=\"" << parameter.GetFontName() << "\"";
        stream << " font-size=\"" << projection.ConvertWidthToPixel(label.fontSize*parameter.GetFontSize()) << "\"";
        stream << " fill=\"" << GetColorValue(style->GetTextColor()) << "\"";

        if (label.alpha!=1.0) {
            stream << " fill-opacity=\"" << label.alpha << "\"";
        }

        stream << ">";
        stream << label.text;
        stream << "</text>" << std::endl;

        /*
        stream << "<rect x=\"" << label.bx1 << "\"" << " y=\"" << label.by1 << "\"" <<" width=\"" << label.bx2-label.bx1 << "\"" << " height=\"" << label.by2-label.by1 << "\""
                << " fill=\"none\" stroke=\"blue\"/>" << std::endl;*/
    }
    else if (dynamic_cast<const ShieldStyle*>(label.style.get())!=NULL) {
        const ShieldStyle* style=dynamic_cast<const ShieldStyle*>(label.style.get());
#if defined(OSMSCOUT_MAP_SVG_HAVE_LIB_PANGO)
        PangoFontDescription* font=GetFont(projection,
                                           parameter,
                                           label.fontSize);
#endif
        // Shield background
        stream << "    <rect";
        stream << " x=\"" << label.bx1 << "\"";
        stream << " y=\"" << label.by1 << "\"";
        stream << " width=\"" << label.bx2-label.bx1+1 << "\"";
        stream << " height=\"" << label.by2-label.by1+1 << "\"";
        stream << " fill=\"" << GetColorValue(style->GetBgColor()) << "\"";
        stream << " stroke=\"none\"";
        stream <<  "/>" << std::endl;

        // Shield inner border
        stream << "    <rect";
        stream << " x=\"" << label.bx1+2 << "\"";
        stream << " y=\"" << label.by1+2 << "\"";
        stream << " width=\"" << label.bx2-label.bx1+1-4 << "\"";
        stream << " height=\"" << label.by2-label.by1+1-4 << "\"";
        stream << " fill=\"none\"";
        stream << " stroke=\"" << GetColorValue(style->GetBorderColor()) << "\"";
        stream << " stroke-width=\"1\"";
        stream <<  "/>" << std::endl;

        // TODO: This is not the exact placement, we cannot just move vertical by fontSize, but we must move the actual
        // text height. For this we need the text bounding box in LabelData.

        stream << "    <text";
        stream << " x=\"" << label.x << "\"";
        stream << " y=\"" << label.y+projection.ConvertWidthToPixel(label.fontSize*parameter.GetFontSize()) << "\"";
        stream << " font-family=\"" << parameter.GetFontName() << "\"";
        stream << " font-size=\"" << projection.ConvertWidthToPixel(label.fontSize*parameter.GetFontSize()) << "\"";
        stream << " fill=\"" << GetColorValue(style->GetTextColor()) << "\"";

        if (label.alpha!=1.0) {
            stream << " fill-opacity=\"" << label.alpha << "\"";
        }

        stream << ">";
        stream << label.text;
        stream << "</text>" << std::endl;
    }
}
  void MapPainterCanvas::DrawFillStyle(const Projection& projection,
                                      const MapParameter& parameter,
                                      const FillStyle& fill)
  {
    if (fill.HasPattern() &&
        projection.GetMagnification()>=fill.GetPatternMinMag() &&
        HasPattern(parameter,fill)) {

      jint patternId=fill.GetPatternId()-1;

      jmethodID methodId=mJniEnv->GetMethodID(mPainterClass, "drawPatternArea",
                                            "(I)V");
    
      if (!methodId)
        return;
    
      mJniEnv->CallVoidMethod(mPainterObject, methodId, patternId);
    }
    else if (fill.GetFillColor().IsVisible()) {

      jint color=GetColorInt(fill.GetFillColor());

      jmethodID methodId=mJniEnv->GetMethodID(mPainterClass, "drawFilledArea",
                                            "(I)V");
    
      if (!methodId)
        return;
    
      mJniEnv->CallVoidMethod(mPainterObject, methodId, color);
    }

    // Draw  border
    if (fill.GetBorderWidth()>0 &&
        fill.GetBorderColor().IsVisible() &&
        fill.GetBorderWidth()>=mMinimumLineWidth)
    {
      double borderWidth=ConvertWidthToPixel(parameter,
                                             fill.GetBorderWidth());

      if (borderWidth>=parameter.GetLineMinWidthPixel()) {

        jfloatArray javaDash=NULL;
        float *dashArray=NULL;

        std::vector<double> dash=fill.GetBorderDash();

        if (!dash.empty())
        {
          javaDash=mJniEnv->NewFloatArray(dash.size());

          dashArray=new float[dash.size()];

          for(int i=0; i<dash.size(); i++)
          {
            dashArray[i]=dash[i]*borderWidth;
          }

          mJniEnv->SetFloatArrayRegion(javaDash, 0, dash.size(), dashArray);
        }

        jmethodID methodId=mJniEnv->GetMethodID(mPainterClass, "drawAreaBorder",
                                            "(IF[F)V");

        jint javaColor=GetColorInt(fill.GetBorderColor());
    
        mJniEnv->CallVoidMethod(mPainterObject, methodId, javaColor,
                               (jfloat)borderWidth, javaDash);

      }
    }
  }