#include "api.h" #include namespace raven { static void put(std::span bytes,size_t at,uint64_t value,size_t count=4) { for (size_t i=0;i>(i*8)); } bool NativeDesktop::text_dispatch(std::string_view name) { const bool output=name=="TextOutW" || name=="ExtTextOutW"; const bool extent_query=name=="GetTextExtentPoint32W" || name=="GetTextExtentPointW" || name=="GetTextExtentExPointW"; if (name!="GetTextMetricsW" && !extent_query && !output) return false; const auto args=process.api_arguments(name=="ExtTextOutW" ? 8 : name=="TextOutW" ? 5 : name=="GetTextExtentExPointW" ? 7 : extent_query ? 4 : 2); uint64_t result=0; try { if(output){ if(name=="ExtTextOutW")result=text_output(args); else{const std::array extended{args[0],args[1],args[2],0,0,args[3],args[4],0};result=text_output(extended);} process.return_api(result);return true; } auto *dc=objects.dc(args[0]); if (!dc) throw uint32_t(6); if(extent_query && !uint32_t(args[2])){ std::array zero{};const auto output=name=="GetTextExtentExPointW" ? args[6] : args[3]; process.validate_write_memory(output,8); if(name=="GetTextExtentExPointW" && args[4])process.validate_write_memory(args[4],4); process.write_memory(output,zero); if(name=="GetTextExtentExPointW" && args[4])process.write_memory(args[4],std::span(zero).first(4)); process.return_api(1);return true; } { const auto *font=objects.font(dc->font); if (!font) throw uint32_t(6); if (name=="GetTextMetricsW") { const auto info=objects.text().metrics(font->definition); std::array bytes{}; put(bytes,0,uint32_t(info.height)); put(bytes,4,uint32_t(info.ascent)); put(bytes,8,uint32_t(info.descent)); put(bytes,12,uint32_t(info.internal_leading)); put(bytes,16,uint32_t(info.external_leading)); put(bytes,20,uint32_t(info.average_width)); put(bytes,24,uint32_t(info.maximum_width)); put(bytes,28,400); put(bytes,36,96); put(bytes,40,96); put(bytes,44,info.first,2); put(bytes,46,info.last,2); put(bytes,48,info.default_character,2); put(bytes,50,info.break_character,2); bytes[55]=info.pitch; process.write_memory(args[1],bytes); result=1; } else { const auto count=int32_t(uint32_t(args[2])); if (count<0 || count>4096) throw uint32_t(87); const auto source=count ? process.read_memory(args[1],size_t(count)*2) : std::vector{}; std::vector text(size_t(count),0); for (size_t i=0;idefinition,text); if (name!="GetTextExtentExPointW") { std::array bytes{}; put(bytes,0,uint32_t(extent.width)); put(bytes,4,uint32_t(extent.height)); process.write_memory(args[3],bytes); result=1; }else{ const auto widths=objects.text().advances(font->definition,text);size_t fit=widths.size(); if(args[4]){fit=0;while(fit bytes{};put(bytes,0,uint32_t(extent.width));put(bytes,4,uint32_t(extent.height));process.write_memory(args[6],bytes); if(args[4]){put(bytes,0,fit);process.write_memory(args[4],std::span(bytes).first(4));} if(args[5] && !widths.empty()){std::vector output(widths.size()*4);for(size_t i=0;i args) { auto *dc=objects.dc(args[0]);if(!dc)throw uint32_t(6); const auto options=uint32_t(args[3]),count=uint32_t(args[6]); if(options & ~6U)throw uint32_t(120); if(count>4096)throw uint32_t(87); std::optional rect; if(args[4] && options){ const auto bytes=process.read_memory(args[4],16);std::array fields{}; for(size_t i=0;i<4;++i){uint32_t value=0;for(size_t b=0;b<4;++b)value|=uint32_t(bytes[i*4+b])<<(b*8);fields[i]=int32_t(value);} rect=DesktopRect{fields[0],fields[1],fields[2],fields[3]}; } if(!count && (!(options & 2) || !rect))return 1; auto *bitmap=objects.bitmap(dc->bitmap);if(!bitmap || bitmap->depth!=32)throw uint32_t(120); const auto x=int64_t(int32_t(args[1]))+dc->origin_x,y=int64_t(int32_t(args[2]))+dc->origin_y; std::vector mask(size_t(bitmap->width)*bitmap->height); int64_t advance=0;int32_t height=0; if(count){ const auto *font=objects.font(dc->font);if(!font)throw uint32_t(6); const auto bytes=process.read_memory(args[5],size_t(count)*2);std::vector text(count); for(size_t i=0;idefinition,text);advance=extent.width;height=extent.height; std::vector> positions; if(args[7]){ const auto steps=process.read_memory(args[7],size_t(count)*4);positions.reserve(count);advance=0; for(size_t i=0;iINT32_MAX)throw uint32_t(120); positions.push_back({int32_t(advance),0});uint32_t value=0; for(size_t b=0;b<4;++b)value|=uint32_t(steps[i*4+b])<<(b*8); advance+=int32_t(value); } if(advanceINT32_MAX)throw uint32_t(120); } if(x>=INT32_MIN && x<=INT32_MAX && y>=INT32_MIN && y<=INT32_MAX) mask=objects.text().mask(font->definition,text,bitmap->width,bitmap->height,int32_t(x),int32_t(y),positions); } const auto pixels=bitmap->pixels(); bool changed=false; for(uint32_t row=0;rowheight;++row)for(uint32_t column=0;columnwidth;++column){ if(!dc->contains(column,row))continue; const auto logical_x=int64_t(column)-dc->origin_x,logical_y=int64_t(row)-dc->origin_y; const bool inside=rect && logical_x>=rect->left && logical_xright && logical_y>=rect->top && logical_ybottom; if((options & 4) && rect && !inside)continue; const bool ink=mask[size_t(row)*bitmap->width+column]!=0; const bool background=((options & 2) && inside) || (count && dc->background_mode==2 && int64_t(column)>=std::min(x,x+advance) && int64_t(column)=y && int64_t(row)text_color : dc->background_color; const auto at=(size_t(bitmap->top_down ? row : bitmap->height-1-row)*bitmap->width+column)*4; pixels[at]=uint8_t(color>>16);pixels[at+1]=uint8_t(color>>8);pixels[at+2]=uint8_t(color);pixels[at+3]=0;changed=true; } if(changed){ if(dc->window && dc->leased && updated)updated(dc->window); } return 1; } }