I found a post from John Fultz with a pretty clear explanation of how graphical functions work:
In version 6, the kernel has absolutely no involvement in creating the rendered image. The steps taken when displaying a graph in version 6 are very similar to those used to display non-graphical output. It works as follows:
1) The expression is evaluated and ultimately produces something with head Graphics[] or Graphics3D[] .
2) The resulting expression is passed through MakeBoxes . MakeBoxes has a set of rules that turns a graphic expression into an input field, which the front end is used to represent the graphic. For example.
In[9]:= MakeBoxes[Graphics[{Point[{0, 0}]}], StandardForm]
Out[9]= GraphicsBox[{PointBox[{0, 0}]}]
Inside, we call it a “set," an expression. It may be a little strange thinking of graphics as “typing”, but it is fundamentally the same operation that occurs for typing typesetting (which has worked this way for 11 years), so I will use this term.
3) The received set expression is sent via MathLink to the front end.
4) The front analyzes the set of expressions and creates internal objects that usually have a one-to-one correspondence between the expression for the set.
5) The front part makes the inner objects.
This means that the conversion is performed in the kernel by calling MakeBoxes .
This call can be intercepted using high-level code:
list = {}; MakeBoxes[expr_, form_] /; (AppendTo[list, HoldComplete[expr]]; True) := Null; HoldComplete[Rotate[Style[expr, Red], 0.5]] ClearAll[MakeBoxes]; list
Here is what we get as a conclusion:

You can see that MakeBoxes does not HoldAllComplete attribute.
The list of characters that are automatically converted before sending to FrontEnd can be obtained from FormatValues :
In[1]:= list = Select[Names["*"], ToExpression[#, InputForm, Function[symbol, Length[ FormatValues@symbol ] > 0, HoldAll]] &]; list